diff --git a/Chemical/Boundaries.mo b/Chemical/Boundaries.mo new file mode 100644 index 0000000..8d7e104 --- /dev/null +++ b/Chemical/Boundaries.mo @@ -0,0 +1,1670 @@ +within Chemical; +package Boundaries "This package contains boundary models for the stream." +extends Modelica.Icons.SourcesPackage; + + model Substance "Substance in solution" + extends Icons.Substance; + + Modelica.Units.SI.Concentration c(displayUnit="mmol/l") + "Molar concentration of particles"; + + extends Internal.PartialSubstanceInSolutionWithAdditionalPorts; + + parameter Boolean use_mass_start = true "use mass_start, otherwise amountOfSubstance_start" + annotation (Evaluate=true, choices(checkBox=true), Dialog(group="Initialization")); + + parameter Modelica.Units.SI.Mass mass_start=1 + "Initial mass of the substance" + annotation (HideResult=not use_mass_start, Dialog(group="Initialization", enable=use_mass_start)); + + parameter Modelica.Units.SI.AmountOfSubstance amountOfSubstance_start=1 + "Initial amount of substance base molecules" + annotation (HideResult=use_mass_start, Dialog(group="Initialization", enable=not use_mass_start)); + + Modelica.Units.SI.Mass mass=amountOfBaseMolecules* + molarMassOfBaseMolecule "Mass"; + + parameter Boolean calculateClusteringHeat = true "Only for self clustering substances" + annotation(Evaluate=true, choices(checkBox=true), Dialog(tab = "Clustering", enable = stateOfMatter.selfClustering(substanceData))); + + protected + parameter Modelica.Units.SI.Mass m_start=if use_mass_start then mass_start else + amountOfSubstance_start*molarMassOfBaseMolecule; + + parameter Modelica.Units.SI.MolarMass molarMassOfBaseMolecule = stateOfMatter.molarMassOfBaseMolecule(substanceData); + + Modelica.Units.SI.AmountOfSubstance amountOfBaseMolecules(start= + m_start/molarMassOfBaseMolecule) + "Amount of base molecules inside all clusters in compartment"; + + Modelica.Units.SI.AmountOfSubstance amountOfFreeMolecule(start= + m_start*stateOfMatter.specificAmountOfFreeBaseMolecule( + substanceData, + T=system.T_ambient, + p=system.p_ambient)) + "Amount of free molecules not included inside any clusters in compartment"; + + Modelica.Units.SI.AmountOfSubstance amountOfParticles(start= + m_start*stateOfMatter.specificAmountOfParticles( + substanceData, + T=system.T_ambient, + p=system.p_ambient)) + "Amount of particles/clusters in compartment"; + + Modelica.Units.SI.MoleFraction SelfClustering_K=exp(-SelfClustering_dG/( + Modelica.Constants.R*solution.T)) + "Dissociation constant of hydrogen bond between base molecules"; + + Modelica.Units.SI.ChemicalPotential SelfClustering_dG= + stateOfMatter.selfClusteringBondEnthalpy(substanceData) + - solution.T * stateOfMatter.selfClusteringBondEntropy(substanceData) + "Gibbs energy of hydrogen bond between H2O molecules"; + + Modelica.Units.SI.AmountOfSubstance amountOfBonds + "Amount of hydrogen bonds between molecules in compartment"; + + Real logn(stateSelect=StateSelect.prefer, start=log(m_start/molarMassOfBaseMolecule)) + "Natural logarithm of the amount of base molecules in solution"; + + parameter Boolean EnthalpyNotUsed=false annotation ( + Evaluate=true, + HideResult=true, + choices(checkBox=true), + Dialog(tab="Advanced", group="Performance")); + + initial equation + + amountOfBaseMolecules = m_start/molarMassOfBaseMolecule; + + equation + + if stateOfMatter.selfClustering(substanceData) then + + //Liquid cluster theory - equilibrium: + //x[i] = x*(K*x)^i .. mole fraction of cluster composed with i base molecules + //amountOfParticles/solution.n = x/(1-K*x); //sum(x[i]) + //amountOfBaseMolecules/solution.n = x/((1-K*x)^2); //sum(i*x[i]) + //amountOfHydrogenBonds/solution.n = x*x*K/((1-K*x)^2); //sum((i-1)*x[i]) + + amountOfParticles*(1 - SelfClustering_K*x) = amountOfFreeMolecule; + + //Calculation of "abs(amountOfBaseMolecules*(1 - SelfClustering_K*x)) = amountOfParticles": + x = ((2*SelfClustering_K+solution.n/amountOfBaseMolecules) - sqrt((4*SelfClustering_K*solution.n/amountOfBaseMolecules)+(solution.n/amountOfBaseMolecules)^2)) / (2*(SelfClustering_K^2)); + + amountOfBonds = amountOfBaseMolecules*x*SelfClustering_K; + + //TODO: may be the volume of the same number of free water molecules is different as volume of the same number of water molecules in cluster .. + //TODO: more precise calculation of other properties + + //der(enthalpy) = solution.dH + q*actualStream(port_a.h_outflow); + //enthalpy = molarEnthalpy*amountOfBaseMolecules + amountOfAdditionalBonds*bondEnthalpy; + solution.dH =if (EnthalpyNotUsed) then 0 else der(molarEnthalpy)* + amountOfBaseMolecules + q*molarEnthalpy - n_flow_out*h_out - n_flow_in*h_in + ( + if (calculateClusteringHeat) then stateOfMatter.selfClusteringBondEnthalpy( + substanceData)*der(amountOfBonds) else 0) + "heat transfer from other substances in solution [J/s]"; + + solution.Gj =amountOfBaseMolecules*u_out + amountOfBonds*SelfClustering_dG + "Gibbs energy of the substance"; + + else + + amountOfParticles = amountOfFreeMolecule; + amountOfBaseMolecules = amountOfFreeMolecule; + amountOfBonds = 0; + + //der(enthalpy) = solution.dH + q*actualStream(port_a.h_outflow); + //enthalpy = molarEnthalpy*amountOfBaseMolecules; + solution.dH = + if (EnthalpyNotUsed) then 0 + else der(molarEnthalpy)*amountOfBaseMolecules + q*molarEnthalpy + - n_flow_out*h_out - n_flow_in*h_in + "heat transfer from other substances in solution [J/s]"; + + solution.Gj = amountOfBaseMolecules*u_out "Gibbs energy of the substance [J]"; + + end if; + + //The main accumulation equation is "der(amountOfBaseMolecules)=q" + // However, the numerical solvers can handle it in form of log(n) much better. :-) + der(logn) = (q/amountOfBaseMolecules) "accumulation of amountOfBaseMolecules=exp(logn) [mol]"; + amountOfBaseMolecules = exp(logn); + + x = amountOfFreeMolecule/solution.n "mole fraction [mol/mol]"; + + c = amountOfParticles/solution.V "concentration [mol/m3]"; + + //solution flows + solution.i = Modelica.Constants.F*z*q + + Modelica.Constants.F*der(z)*amountOfBaseMolecules "change of sunstance charge [A]"; + solution.dV = molarVolume*q + der(molarVolume)*amountOfBaseMolecules "change of substance volume [m3/s]"; + + //extensive properties + solution.nj = amountOfParticles; + solution.mj = amountOfBaseMolecules*molarMassOfBaseMolecule; + solution.Vj = amountOfBaseMolecules*molarVolume; + solution.Qj = Modelica.Constants.F*amountOfBaseMolecules*z; + solution.Ij = (1/2)*(amountOfBaseMolecules*z^2); + + annotation(Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100}, + {100,100}}), graphics={Text( + extent={{-84,22},{92,64}}, + lineColor={128,0,255}, + textString="%name")}), Documentation(revisions=" +
2009-2015 by Marek Matejak, Charles University, Prague, Czech Republic
+", info=" +where n is amount of the substance and x is mole fraction.
+The main class from “Chemical” package is called "Substance". It has one chemical connector, where chemical potential and molar flow is presented. An amount of solute "n" is accumulated by molar flow inside an instance of this class. In the default setting the amount of solution "n(solution)" is set to 55.6 as amount of water in one liter, so in this setting the concentration of very diluted solution in pure water at “mol/L” has the same value as the amount of substance at “mol”. But in the advanced settings the default amount of solution can be changed by parameter or using solution port to connect with solution. The molar flow at the port can be also negative, which means that the solute leaves the Substance instance.
+
The recalculation between mole fraction, molarity and molality can be written as follows:
x = n/n(solution) = b * m(solvent)/n(solution) = c * V(solution)/n(solution)
+where m(solvent) is mass of solvent, V(solution) is volume of solution, b=n/m(solvent) is molality of the substance, c=n/V(solution) is molarity of the substance.
+If the amount of solution is selected to the number of total solution moles per one kilogram of solvent then the values of x will be the same as molality.
+If the amount of solution is selected to the number of total solution moles in one liter of solution then the values of x will be the same as molarity.
+
Definition of electro-chemical potential:
where
+x .. mole fraction of the substance in the solution
+T .. temperature in Kelvins
+v .. relative eletric potential of the solution
+z .. elementary charge of the substance (like -1 for electron, +2 for Ca^2+)
+R .. gas constant
+F .. Faraday constant
+gamma .. activity coefficient
+u° .. chemical potential of pure substance
+DfG .. free Gibbs energy of formation of the substance
+DfH .. free enthalpy of formation of the substance
+DfS .. free entropy of formation of the substance
+
Be carefull, DfS is not the same as absolute entropy of the substance S° from III. thermodinamic law! It must be calculated from tabulated value of DfG(298.15 K) and DfH as DfS=(DfH - DfG)/298.15.
Source of a Chemical substance stream. The state can be given as fix values or as a real signal.
+Before its inertance the source has an inertial potential of 0 by definition.
+")); + end Source; + + model Sink "Boundary model of sink" + + parameter Boolean potentialFromInput = false "If true electro-chemical potential comes from real input"; + parameter Modelica.Units.SI.ChemicalPotential u0_par=0 "Electro-chemical potential setpoint of Sink" annotation (Dialog(enable=not pressureFromInput)); + parameter Chemical.Utilities.Units.Inertance L=dropOfCommons.L "Inertance of electro-chemical potential" annotation (Dialog(tab="Advanced")); + + Chemical.Interfaces.Inlet inlet annotation (Placement(transformation(extent={{-120,-20},{-80,20}}))); + + Modelica.Blocks.Interfaces.RealInput u0_var(unit="J/mol") if potentialFromInput "Potential setpoint [J/mol]" + annotation (Placement( + transformation( + extent={{-20,-20},{20,20}}, + rotation=180, + origin={20,0}), iconTransformation( + extent={{-20,-20},{20,20}}, + rotation=180, + origin={20,0}))); + + protected + outer Chemical.DropOfCommons dropOfCommons; + + Modelica.Blocks.Interfaces.RealInput u0(unit="J/mol") "Internal electro-chemical potential connector"; + Modelica.Units.SI.ChemicalPotential r; + + Modelica.Units.SI.ChemicalPotential u=inlet.u; + + equation + + connect(u0_var, u0); + if not potentialFromInput then + u0 = u0_par; + end if; + + der(inlet.n_flow)*L = inlet.r - r; + r + u = u0; + + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle( + extent={{-56,76},{4,-84}}, + lineColor={158,66,200}, + lineThickness=0.5, + fillColor={215,215,215}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None), + Rectangle( + extent={{-60,80},{0,-80}}, + lineColor={158,66,200}, + lineThickness=0.5, + fillColor={194,138,221}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None), + Line( + points={{-100,0},{-60,0}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{-60,80},{-60,-80}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{-12,80},{-12,-80}}, + color={255,255,255}, + thickness=1), + Line( + points={{-28,80},{-28,-80}}, + color={255,255,255}, + thickness=0.5), + Line(points={{-44,80},{-44,-80}}, color={255,255,255})}), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" +Sink for a thermofluid stream. The pressure can be set or given by a real signal via input connector.
+The inertial pressure after the sinks inertance is by definition the difference between the input pressure and the set pressure. The sink therefore acts by definition as the origin of the energy to accelerate the stream.
+")); + end Sink; + + model TerminalSource "Source that imposes n_flow = 0" + + parameter Modelica.Units.SI.Time TC=0.1 "Time constant for electro-chemical potential adaption" annotation (Dialog(tab="Advanced")); + parameter Modelica.Units.SI.MolarEnthalpy h=0 "Source enthalpy"; + parameter Modelica.Units.SI.ChemicalPotential u_0=0 "Initial potential"; + + Chemical.Interfaces.Outlet outlet + annotation (Placement(transformation(extent={{80,-20},{120,20}}), iconTransformation(extent={{80,-20},{120,20}}))); + + protected + Modelica.Units.SI.ChemicalPotential u(stateSelect=StateSelect.prefer); + + initial equation + u = u_0; + + equation + outlet.n_flow = 0; + + TC * der(u) = outlet.r; + outlet.u = u; + outlet.h = h; + + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Rectangle( + extent={{34,26},{74,-34}}, + lineColor={158,66,200}, + lineThickness=0.5, + fillColor={215,215,215}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None), + Line( + points={{50,0},{100,0}}, + color={158,66,200}, + thickness=0.5), + Rectangle( + extent={{30,30},{70,-30}}, + lineColor={158,66,200}, + lineThickness=0.5, + fillColor={194,138,221}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None), + Line( + points={{70,30},{30,-30}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{30,30},{70,-30}}, + color={158,66,200}, + thickness=0.5)}), Diagram(coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" +Source that terminates the flow.
+It imposes a n_flow=0 boundary and with a time constant, adapts the pressure such that the inertial electro-chemical potetntial r goes to zero.
+")); + end TerminalSource; + + model TerminalSink "Sink that imposes m_flow=0" + + Chemical.Interfaces.Inlet inlet + annotation (Placement(transformation(extent={{-120,-20},{-80,20}}), iconTransformation(extent={{-120,-20},{-80,20}}))); + + equation + inlet.n_flow = 0; + + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Line( + points={{-100,0},{-50,0}}, + color={158,66,200}, + thickness=0.5), + Rectangle( + extent={{-56,26},{-16,-34}}, + lineColor={158,66,200}, + lineThickness=0.5, + fillColor={215,215,215}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None), + Rectangle( + extent={{-60,30},{-20,-30}}, + lineColor={158,66,200}, + lineThickness=0.5, + fillColor={194,138,221}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None), + Line( + points={{-20,30},{-60,-30}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{-60,30},{-20,-30}}, + color={158,66,200}, + thickness=0.5)}), Diagram(coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" +Sink that terminates the flow.
+It imposes a m_flow=0 boundary.
+")); + end TerminalSink; + + package Tests "Tests for the boundary package" + extends Modelica.Icons.ExamplesPackage; + + model SourceSink "Test for source and sink model" + extends Modelica.Icons.Example; + + inner Chemical.DropOfCommons dropOfCommons annotation (Placement(transformation(extent={{58,-74},{78,-54}}))); + Source source( + u0_par=-200000, L=0, + outlet(n_flow(start=0, fixed=true))) + annotation (Placement(transformation(extent={{-32,10},{-12,30}}))); + Sink sink(u0_par=-100000) + annotation (Placement(transformation(extent={{14,10},{34,30}}))); + Source source1( + u0_par=-200000, + outlet(n_flow(start=0, fixed=true))) + annotation (Placement(transformation(extent={{-32,-30},{-12,-10}}))); + Sink sink1( + L=0, + u0_par=-100000) + annotation (Placement(transformation(extent={{14,-30},{34,-10}}))); + equation + connect(sink.inlet, source.outlet) annotation (Line( + points={{14,20},{-12,20}}, + color={28,108,200}, + thickness=0.5)); + connect(sink1.inlet, source1.outlet) annotation (Line( + points={{14,-20},{-12,-20}}, + color={28,108,200}, + thickness=0.5)); + + annotation (experiment(StopTime=1, Tolerance=1e-6, Interval=0.001), + Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" +Owner: Michael Meißner
+")); + end SourceSink; + + model Volumes "Test Volumes" + extends Modelica.Icons.Example; + + replaceable package Medium = ThermofluidStream.Media.myMedia.Air.SimpleAir constrainedby ThermofluidStream.Media.myMedia.Interfaces.PartialMedium + "Medium package" annotation (Documentation(info=" ++Medium package used in the Test. +
+")); + + package MediumMix = ThermofluidStream.Media.myMedia.IdealGases.MixtureGases.CombustionAir + "Medium package" + annotation (Documentation(info=" ++Medium package used in the Test of the MixVolumes. +
+")); + + inner ThermofluidStream.DropOfCommons dropOfCommons(assertionLevel=AssertionLevel.warning) + annotation (Placement(transformation(extent={{70,-170},{90,-150}}))); + Source source(redeclare package Medium = Medium, + p0_par=200000, + outlet(m_flow(start=0, fixed=true))) + annotation (Placement(transformation(extent={{-70,-60},{-50,-40}}))); + Sink sink(redeclare package Medium = Medium, p0_par=100000) + annotation (Placement(transformation(extent={{50,-60},{70,-40}}))); + Source source1(redeclare package Medium = Medium, p0_par=200000) + annotation (Placement(transformation(extent={{-70,-90},{-50,-70}}))); + Sink sink1(redeclare package Medium = Medium, p0_par=100000) + annotation (Placement(transformation(extent={{50,-90},{70,-70}}))); + Modelica.Thermal.HeatTransfer.Sources.FixedTemperature fixedTemperature(T( + displayUnit="K") = 500) + annotation (Placement(transformation(extent={{-48,-120},{-28,-100}}))); + ThermofluidStream.Processes.FlowResistance flowResistance( + redeclare package Medium = Medium, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.01, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.laminarTurbulentPressureLoss (material=ThermofluidStream.Processes.Internal.Material.wood)) + annotation (Placement(transformation(extent={{20,-90},{40,-70}}))); + ThermofluidStream.Processes.FlowResistance flowResistance1( + redeclare package Medium = Medium, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.01, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.laminarTurbulentPressureLoss (material=ThermofluidStream.Processes.Internal.Material.wood)) + annotation (Placement(transformation(extent={{-40,-90},{-20,-70}}))); + Source source2(redeclare package Medium = MediumMix, p0_par=200000) + annotation (Placement(transformation(extent={{-70,10},{-50,30}}))); + Source source3(redeclare package Medium = MediumMix, p0_par=200000) + annotation (Placement(transformation(extent={{-70,-30},{-50,-10}}))); + Sink sink2(redeclare package Medium = MediumMix, p0_par=100000) + annotation (Placement(transformation(extent={{50,-10},{70,10}}))); + ThermofluidStream.Processes.FlowResistance flowResistance2( + redeclare package Medium = MediumMix, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.01, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.laminarTurbulentPressureLoss (material=ThermofluidStream.Processes.Internal.Material.wood)) + annotation (Placement(transformation(extent={{-40,10},{-20,30}}))); + ThermofluidStream.Processes.FlowResistance flowResistance3( + redeclare package Medium = MediumMix, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.01, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.laminarTurbulentPressureLoss (material=ThermofluidStream.Processes.Internal.Material.wood)) + annotation (Placement(transformation(extent={{-40,-30},{-20,-10}}))); + ThermofluidStream.Processes.FlowResistance flowResistance4( + redeclare package Medium = MediumMix, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.01, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.laminarTurbulentPressureLoss (material=ThermofluidStream.Processes.Internal.Material.wood)) + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + Source source4( + redeclare package Medium = MediumMix, + p0_par=200000, + Xi0_par={1,0}) + annotation (Placement(transformation(extent={{-70,80},{-50,100}}))); + Source source5( + redeclare package Medium = MediumMix, + p0_par=200000, + Xi0_par={0,1}) + annotation (Placement(transformation(extent={{-70,40},{-50,60}}))); + Sink sink3(redeclare package Medium = MediumMix, p0_par=100000) + annotation (Placement(transformation(extent={{50,60},{70,80}}))); + ThermofluidStream.Processes.FlowResistance flowResistance5( + redeclare package Medium = MediumMix, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.1, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=1e5)) + annotation (Placement(transformation(extent={{-40,80},{-20,100}}))); + ThermofluidStream.Processes.FlowResistance flowResistance6( + redeclare package Medium = MediumMix, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.1, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=2e5)) + annotation (Placement(transformation(extent={{-40,40},{-20,60}}))); + ThermofluidStream.Processes.FlowResistance flowResistance8( + redeclare package Medium = MediumMix, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.1, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=1e1)) + annotation (Placement(transformation(extent={{20,60},{40,80}}))); + Source source6(redeclare package Medium = Medium, p0_par=180000) + annotation (Placement(transformation(extent={{-70,-160},{-50,-140}}))); + Sink sink4(redeclare package Medium = Medium, p0_par=130000) + annotation (Placement(transformation(extent={{50,-200},{70,-180}}))); + ThermofluidStream.Processes.FlowResistance flowResistance7( + redeclare package Medium = Medium, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.1, + l=1, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.laminarTurbulentPressureLoss (material=ThermofluidStream.Processes.Internal.Material.wood)) + annotation (Placement(transformation(extent={{-40,-160},{-20,-140}}))); + ThermofluidStream.Processes.FlowResistance flowResistance9( + redeclare package Medium = Medium, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.1, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.laminarTurbulentPressureLoss (material=ThermofluidStream.Processes.Internal.Material.wood)) + annotation (Placement(transformation(extent={{20,-200},{40,-180}}))); + Source source7(redeclare package Medium = Medium, p0_par=100000) + annotation (Placement(transformation(extent={{-70,110},{-50,130}}))); + Sink sink5(redeclare package Medium = Medium, p0_par=200000) + annotation (Placement(transformation(extent={{50,110},{70,130}}))); + ThermofluidStream.Processes.FlowResistance flowResistance10( + redeclare package Medium = Medium, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r(displayUnit="mm") = 0.01, + l=1, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=1e5)) + annotation (Placement(transformation(extent={{20,110},{40,130}}))); + ThermofluidStream.Processes.FlowResistance flowResistance11( + redeclare package Medium = Medium, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r(displayUnit="mm") = 0.01, + l=1, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=1e5)) + annotation (Placement(transformation(extent={{-40,110},{-20,130}}))); + Source source8( + redeclare package Medium = MediumMix, + p0_par=200000, + Xi0_par={1,0}) + annotation (Placement(transformation(extent={{-70,180},{-50,200}}))); + Source source9( + redeclare package Medium = MediumMix, + p0_par=100000, + Xi0_par={0,1}) + annotation (Placement(transformation(extent={{-70,140},{-50,160}}))); + Sink sink6(redeclare package Medium = MediumMix, p0_par=300000) + annotation (Placement(transformation(extent={{50,160},{70,180}}))); + ThermofluidStream.Processes.FlowResistance flowResistance12( + redeclare package Medium = MediumMix, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.1, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=1e5)) + annotation (Placement(transformation(extent={{-40,180},{-20,200}}))); + ThermofluidStream.Processes.FlowResistance flowResistance13( + redeclare package Medium = MediumMix, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.1, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=2e5)) + annotation (Placement(transformation(extent={{-40,140},{-20,160}}))); + ThermofluidStream.Processes.FlowResistance flowResistance14( + redeclare package Medium = MediumMix, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r=0.1, + l=10, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=1e1)) + annotation (Placement(transformation(extent={{20,160},{40,180}}))); + equation + connect(volume.inlet, source.outlet) annotation (Line( + points={{-30,-50},{-50,-50}}, + color={28,108,200}, + thickness=0.5)); + connect(volume.outlet, flexVolume1.inlet) annotation (Line( + points={{-10,-50},{10,-50}}, + color={28,108,200}, + thickness=0.5)); + connect(flexVolume1.outlet, sink.inlet) annotation (Line( + points={{30,-50},{50,-50}}, + color={28,108,200}, + thickness=0.5)); + + connect(fixedTemperature.port,heatportVolume. heatPort) + annotation (Line(points={{-28,-110},{0,-110},{0,-88}}, color={191,0,0})); + connect(heatportVolume.outlet,flowResistance. inlet) annotation (Line( + points={{10,-80},{20,-80}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance.outlet,sink1. inlet) annotation (Line( + points={{40,-80},{50,-80}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance1.inlet,source1. outlet) annotation (Line( + points={{-40,-80},{-50,-80}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance1.outlet,heatportVolume. inlet) annotation (Line( + points={{-20,-80},{-10,-80}}, + color={28,108,200}, + thickness=0.5)); + connect(source2.outlet, flowResistance2.inlet) annotation (Line( + points={{-50,20},{-40,20}}, + color={28,108,200}, + thickness=0.5)); + connect(source3.outlet, flowResistance3.inlet) annotation (Line( + points={{-50,-20},{-40,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(volumeMix.outlet, flowResistance4.inlet) annotation (Line( + points={{10,0},{20,0}}, + color={28,108,200}, + thickness=0.5)); + connect(sink2.inlet, flowResistance4.outlet) annotation (Line( + points={{50,0},{40,0}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance3.outlet, volumeMix.inlet[1]) annotation (Line( + points={{-20,-20},{-16,-20},{-16,-0.5},{-10,-0.5}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance2.outlet, volumeMix.inlet[2]) annotation (Line( + points={{-20,20},{-16,20},{-16,0.5},{-10,0.5}}, + color={28,108,200}, + thickness=0.5)); + connect(source4.outlet,flowResistance5. inlet) annotation (Line( + points={{-50,90},{-40,90}}, + color={28,108,200}, + thickness=0.5)); + connect(source5.outlet,flowResistance6. inlet) annotation (Line( + points={{-50,50},{-40,50}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance6.outlet, volumeMix1.inlet[1]) annotation (Line( + points={{-20,50},{-16,50},{-16,69.5},{-10,69.5}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance5.outlet, volumeMix1.inlet[2]) annotation (Line( + points={{-20,90},{-16,90},{-16,70.5},{-10,70.5}}, + color={28,108,200}, + thickness=0.5)); + connect(sink3.inlet, flowResistance8.outlet) annotation (Line( + points={{50,70},{40,70}}, + color={28,108,200}, + thickness=0.5)); + connect(volumeMix1.outlet, flowResistance8.inlet) annotation (Line( + points={{10,70},{20,70}}, + color={28,108,200}, + thickness=0.5)); + connect(source6.outlet, flowResistance7.inlet) annotation (Line( + points={{-50,-150},{-40,-150}}, + color={28,108,200}, + thickness=0.5)); + connect(heatportVolume1.inlet, flowResistance7.outlet) + annotation (Line( + points={{-8,-150},{-20,-150}}, + color={28,108,200}, + thickness=0.5)); + connect(heatportVolume2.outlet, flowResistance9.inlet) + annotation (Line( + points={{10,-190},{20,-190}}, + color={28,108,200}, + thickness=0.5)); + connect(sink4.inlet, flowResistance9.outlet) annotation (Line( + points={{50,-190},{40,-190}}, + color={28,108,200}, + thickness=0.5)); + connect(heatportVolume3.heatPort, heatportVolume.heatPort) annotation (Line(points={{42,-110},{0,-110},{0,-88}}, + color={191,0,0})); + connect(volumeMix2.heatPort, heatportVolume.heatPort) annotation (Line(points={{42,-140},{28,-140},{28,-110},{0,-110},{0,-88}}, + color={191,0,0})); + connect(volume1.outlet, flowResistance10.inlet) annotation (Line( + points={{8,120},{20,120}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance10.outlet, sink5.inlet) annotation (Line( + points={{40,120},{50,120}}, + color={28,108,200}, + thickness=0.5)); + connect(volume1.inlet, flowResistance11.outlet) annotation (Line( + points={{-12,120},{-20,120}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance11.inlet, source7.outlet) annotation (Line( + points={{-40,120},{-50,120}}, + color={28,108,200}, + thickness=0.5)); + connect(source8.outlet, flowResistance12.inlet) annotation (Line( + points={{-50,190},{-40,190}}, + color={28,108,200}, + thickness=0.5)); + connect(source9.outlet, flowResistance13.inlet) annotation (Line( + points={{-50,150},{-40,150}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance13.outlet, volumeMix3.inlet[1]) + annotation (Line( + points={{-20,150},{-14,150},{-14,169.5},{-8,169.5}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance12.outlet, volumeMix3.inlet[2]) + annotation (Line( + points={{-20,190},{-14,190},{-14,170.5},{-8,170.5}}, + color={28,108,200}, + thickness=0.5)); + connect(sink6.inlet, flowResistance14.outlet) annotation (Line( + points={{50,170},{40,170}}, + color={28,108,200}, + thickness=0.5)); + connect(volumeMix3.outlet, flowResistance14.inlet) annotation (Line( + points={{12,170},{20,170}}, + color={28,108,200}, + thickness=0.5)); + annotation (experiment(StopTime=1, Tolerance=1e-6, Interval=0.001), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{100,100}})), + Diagram( + coordinateSystem(preserveAspectRatio=false, extent={{-100,-200},{100,200}})), + Documentation(info=" +This test purposely violates the asserts for reversed mass-flows to test the behavior of volumes for prolonged reversed massflow for some of the volumes. The assert is set to warning.
+
Owner: Michael Meißner
+Medium package used in the Test. +
+")); + + inner ThermofluidStream.DropOfCommons dropOfCommons annotation (Placement(transformation(extent={{50,-70},{70,-50}}))); + Sink sink2(redeclare package Medium = Medium, + pressureFromInput=true, + p0_par=100000) + annotation (Placement(transformation(extent={{8,4},{28,24}}))); + Modelica.Blocks.Sources.Pulse pulse( + amplitude=5e4, + width=35, + period=2, + offset=0.8e5, + startTime=0.2) + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + TerminalSource terminalSource(redeclare package Medium = Medium, TC=0.1) annotation (Placement(transformation(extent={{-26,4},{-6,24}}))); + TerminalSink terminalSink(redeclare package Medium = Medium) annotation (Placement(transformation(extent={{8,-26},{28,-6}}))); + Source source(redeclare package Medium = Medium, pressureFromInput=true) annotation (Placement(transformation(extent={{-26,-26},{-6,-6}}))); + equation + + connect(pulse.y, sink2.p0_var) annotation (Line(points={{-39,0},{26,0},{26,14},{20,14}}, color={0,0,127})); + connect(sink2.inlet, terminalSource.outlet) annotation (Line( + points={{8,14},{-6,14}}, + color={28,108,200}, + thickness=0.5)); + connect(source.outlet, terminalSink.inlet) annotation (Line( + points={{-6,-16},{8,-16}}, + color={28,108,200}, + thickness=0.5)); + connect(source.p0_var, sink2.p0_var) annotation (Line(points={{-18,-10},{-26,-10},{-26,0},{26,0},{26,14},{20,14}}, color={0,0,127})); + annotation (experiment(StopTime=10, Tolerance=1e-6, Interval=0.01), + Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" +Owner: Michael Meißner
+")); + end TerminalSourceSink; + + model VolumesDirectCoupling "Test Volumes" + extends Modelica.Icons.Example; + + replaceable package Medium = ThermofluidStream.Media.myMedia.Water.StandardWater constrainedby ThermofluidStream.Media.myMedia.Interfaces.PartialMedium + "Medium package" + annotation (choicesAllMatching=true, Documentation(info=" ++Medium package used in the Test. +
+")); + + package MediumMix = ThermofluidStream.Media.myMedia.IdealGases.MixtureGases.CombustionAir + "Medium package" + annotation (Documentation(info=" ++Medium package used in the Test of the MixVolumes. +
+")); + + inner ThermofluidStream.DropOfCommons dropOfCommons(k_volume_damping=0.5, assertionLevel=AssertionLevel.warning) + annotation (Placement(transformation(extent={{70,-148},{90,-128}}))); + Sink sink4(redeclare package Medium = Medium, p0_par=130000) + annotation (Placement(transformation(extent={{36,-10},{56,10}}))); + Source source(redeclare package Medium = Medium, + p0_par=200000, + outlet(m_flow(start=0, fixed=true))) + annotation (Placement(transformation(extent={{-58,-96},{-38,-76}}))); + Sink sink1(redeclare package Medium = Medium, p0_par=130000) + annotation (Placement(transformation(extent={{36,-30},{56,-10}}))); + Source source1(redeclare package Medium = Medium, + p0_par=200000, + outlet(m_flow(start=0, fixed=true))) + annotation (Placement(transformation(extent={{-58,-118},{-38,-98}}))); + Sink sink2(redeclare package Medium = Medium, p0_par=130000) + annotation (Placement(transformation(extent={{36,-50},{56,-30}}))); + Sink sink3(redeclare package Medium = Medium, p0_par=101000) + annotation (Placement(transformation(extent={{36,-76},{56,-56}}))); + equation + + connect(heatportVolume2.outlet, sink4.inlet) annotation (Line( + points={{10,0},{36,0}}, + color={28,108,200}, + thickness=0.5)); + connect(source.outlet, heatportVolume1.inlet) annotation (Line( + points={{-38,-86},{-10,-86}}, + color={28,108,200}, + thickness=0.5)); + connect(heatportVolume4.inlet, heatportVolume3.outlet) annotation (Line( + points={{10,30},{-10,30}}, + color={28,108,200}, + thickness=0.5)); + connect(heatportVolume6.inlet, heatportVolume5.outlet) annotation (Line( + points={{10,60},{-10,60}}, + color={28,108,200}, + thickness=0.5)); + connect(heatportVolume7.outlet, sink1.inlet) annotation (Line( + points={{10,-20},{36,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(heatportVolume9.inlet, heatportVolume8.outlet) annotation (Line( + points={{10,88},{-10,88}}, + color={28,108,200}, + thickness=0.5)); + connect(source1.outlet, heatportVolume10.inlet) annotation (Line( + points={{-38,-108},{-10,-108}}, + color={28,108,200}, + thickness=0.5)); + connect(heatportVolume11.outlet, sink2.inlet) annotation (Line( + points={{10,-40},{36,-40}}, + color={28,108,200}, + thickness=0.5)); + connect(heatportVolume13.inlet, heatportVolume12.outlet) + annotation (Line( + points={{10,112},{-10,112}}, + color={28,108,200}, + thickness=0.5)); + connect(heatportVolume14.outlet, sink3.inlet) annotation (Line( + points={{10,-66},{36,-66}}, + color={28,108,200}, + thickness=0.5)); + annotation (experiment( + StopTime=0.05, + Interval=5e-06, + Tolerance=1e-07, + __Dymola_Algorithm="Dassl"), + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{100,100}})), + Diagram( + coordinateSystem(preserveAspectRatio=false, extent={{-100,-160},{100,160}})), + Documentation(info=" +This test uses deceased tolerance and saves more points (smaller output interval) because of the different time-scales and relative stiff equation system.
+
Owner: Michael Meißner
Owner: Michael Meißner
+")); + end DynamicBoundaries; + + model PhaseSeperator + extends Modelica.Icons.Example; + + package Medium = ThermofluidStream.Media.myMedia.Water.StandardWater; + + Boundaries.Source source( + redeclare package Medium = Medium, + setEnthalpy=true, + enthalpyFromInput=true, + p0_par=120000, + h0_par=2000) annotation (Placement(transformation(extent={{-90,10},{-70,30}}))); + Boundaries.Sink sink(redeclare package Medium = Medium, p0_par=100000) annotation (Placement(transformation(extent={{76,-30},{96,-10}}))); + + ThermofluidStream.Sensors.TwoPhaseSensorSelect twoPhaseSensorSelect( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.TwoPhaseQuantities.x_kgpkg) annotation (Placement(transformation(extent={{-56,-38},{-36,-18}}))); + ThermofluidStream.Sensors.TwoPhaseSensorSelect twoPhaseSensorSelect1( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.TwoPhaseQuantities.x_kgpkg) annotation (Placement(transformation(extent={{20,-50},{40,-30}}))); + ThermofluidStream.Sensors.TwoPhaseSensorSelect twoPhaseSensorSelect2( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.TwoPhaseQuantities.x_kgpkg) annotation (Placement(transformation(extent={{20,30},{40,50}}))); + ThermofluidStream.Sensors.TwoPhaseSensorSelect twoPhaseSensorSelect3( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.TwoPhaseQuantities.x_kgpkg) annotation (Placement(transformation(extent={{64,-52},{84,-32}}))); + Modelica.Blocks.Sources.TimeTable + timeTable( + table=[0.0,1500e3; 24.9,1500e3; 25.1,3500e3; 49.9,3500e3; 50.1,1500e3; 74.9,1500e3; 75.1,410e3; 99.9,410e3; 100.1,1500e3; 124.9,1500e3; 1e10, + 1500e3], + offset=0, + startTime=0) annotation (Placement(transformation(extent={{-120,-16},{-100,4}}))); + ThermofluidStream.Processes.FlowResistance flowResistance1( + redeclare package Medium = Medium, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r(displayUnit="cm") = 0.05, + l=1, + computeL=false, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=5000)) + annotation (Placement(transformation(extent={{-40,10},{-20,30}}))); + ThermofluidStream.Processes.FlowResistance flowResistance2( + redeclare package Medium = Medium, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r(displayUnit="cm") = 0.05, + l=1, + computeL=false, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=5000)) + annotation (Placement(transformation(extent={{-40,-30},{-20,-10}}))); + ThermofluidStream.Processes.FlowResistance flowResistance( + redeclare package Medium = Medium, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r(displayUnit="cm") = 0.05, + l=1, + computeL=false, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=5000)) + annotation (Placement(transformation(extent={{30,10},{50,30}}))); + ThermofluidStream.Processes.FlowResistance flowResistance3( + redeclare package Medium = Medium, + initM_flow=ThermofluidStream.Utilities.Types.InitializationMethods.state, + r(displayUnit="cm") = 0.05, + l=1, + computeL=false, + redeclare function pLoss = ThermofluidStream.Processes.Internal.FlowResistance.linearQuadraticPressureLoss (k=5000)) + annotation (Placement(transformation(extent={{30,-30},{50,-10}}))); + ThermofluidStream.Sensors.TwoPhaseSensorSelect twoPhaseSensorSelect4( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.TwoPhaseQuantities.x_kgpkg) annotation (Placement(transformation(extent={{-8,-50},{12,-30}}))); + ThermofluidStream.Sensors.TwoPhaseSensorSelect twoPhaseSensorSelect5( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.TwoPhaseQuantities.x_kgpkg) annotation (Placement(transformation(extent={{-8,30},{12,50}}))); + ThermofluidStream.Sensors.SingleSensorSelect singleSensorSelect( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.Quantities.p_bar) annotation (Placement(transformation(extent={{-8,38},{12,58}}))); + ThermofluidStream.Sensors.SingleSensorSelect singleSensorSelect1( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.Quantities.p_bar) annotation (Placement(transformation(extent={{20,38},{40,58}}))); + ThermofluidStream.Sensors.SingleSensorSelect singleSensorSelect2( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.Quantities.p_bar) annotation (Placement(transformation(extent={{-8,-58},{12,-38}}))); + ThermofluidStream.Sensors.SingleSensorSelect singleSensorSelect3( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.Quantities.p_bar) annotation (Placement(transformation(extent={{20,-58},{40,-38}}))); + ThermofluidStream.Sensors.SingleSensorSelect singleSensorSelect4( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.Quantities.p_bar) annotation (Placement(transformation(extent={{64,-60},{84,-40}}))); + ThermofluidStream.Sensors.SingleSensorSelect singleSensorSelect5( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.Quantities.p_bar) annotation (Placement(transformation(extent={{-56,-46},{-36,-26}}))); + Boundaries.Source source1( + redeclare package Medium = Medium, + setEnthalpy=true, + enthalpyFromInput=true, + p0_par=120000, + h0_par=2000) annotation (Placement(transformation(extent={{-90,-30},{-70,-10}}))); + ThermofluidStream.Sensors.TwoPhaseSensorSelect twoPhaseSensorSelect6( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.TwoPhaseQuantities.x_kgpkg) annotation (Placement(transformation(extent={{-56,20},{-36,40}}))); + ThermofluidStream.Sensors.SingleSensorSelect singleSensorSelect6( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.Quantities.p_bar) annotation (Placement(transformation(extent={{-56,28},{-36,48}}))); + Boundaries.Sink sink1(redeclare package Medium = Medium, p0_par=100000) annotation (Placement(transformation(extent={{76,10},{96,30}}))); + ThermofluidStream.Sensors.TwoPhaseSensorSelect twoPhaseSensorSelect7( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.TwoPhaseQuantities.x_kgpkg) annotation (Placement(transformation(extent={{64,32},{84,52}}))); + ThermofluidStream.Sensors.SingleSensorSelect singleSensorSelect7( + redeclare package Medium = Medium, + digits=2, + quantity=ThermofluidStream.Sensors.Internal.Types.Quantities.p_bar) annotation (Placement(transformation(extent={{64,40},{84,60}}))); + inner ThermofluidStream.DropOfCommons dropOfCommons(assertionLevel=AssertionLevel.warning) + annotation (Placement(transformation(extent={{-86,-72},{-66,-52}}))); + equation + connect(source.h0_var, timeTable.y) annotation (Line(points={{-82,20},{-90,20},{-90,-6},{-99,-6}}, color={0,0,127})); + connect(twoPhaseSensorSelect1.inlet, accumulator.outlet) + annotation (Line( + points={{20,-40},{16,-40},{16,-20},{10,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(twoPhaseSensorSelect2.inlet,receiver. outlet) + annotation (Line( + points={{20,40},{16,40},{16,20},{10,20}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance1.outlet,receiver. inlet) annotation (Line( + points={{-20,20},{-10,20}}, + color={28,108,200}, + thickness=0.5)); + connect(accumulator.inlet, flowResistance2.outlet) annotation (Line( + points={{-10,-20},{-20,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance3.inlet, accumulator.outlet) annotation (Line( + points={{30,-20},{10,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(flowResistance.inlet,receiver. outlet) annotation (Line( + points={{30,20},{10,20}}, + color={28,108,200}, + thickness=0.5)); + connect(twoPhaseSensorSelect4.inlet, flowResistance2.outlet) + annotation (Line( + points={{-8,-40},{-14,-40},{-14,-20},{-20,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(twoPhaseSensorSelect5.inlet,receiver. inlet) + annotation (Line( + points={{-8,40},{-14,40},{-14,20},{-10,20}}, + color={28,108,200}, + thickness=0.5)); + connect(singleSensorSelect.inlet,receiver. inlet) + annotation (Line( + points={{-8,48},{-14,48},{-14,20},{-10,20}}, + color={28,108,200}, + thickness=0.5)); + connect(singleSensorSelect1.inlet,receiver. outlet) + annotation (Line( + points={{20,48},{16,48},{16,20},{10,20}}, + color={28,108,200}, + thickness=0.5)); + connect(singleSensorSelect3.inlet, accumulator.outlet) + annotation (Line( + points={{20,-48},{16,-48},{16,-20},{10,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(singleSensorSelect2.inlet, flowResistance2.outlet) + annotation (Line( + points={{-8,-48},{-14,-48},{-14,-20},{-20,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(source.outlet, flowResistance1.inlet) annotation (Line( + points={{-70,20},{-40,20}}, + color={28,108,200}, + thickness=0.5)); + connect(source1.outlet, flowResistance2.inlet) + annotation (Line( + points={{-70,-20},{-56,-20},{-56,-20},{-40,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(source1.h0_var, timeTable.y) annotation (Line(points={{-82,-20},{-90,-20},{-90,-6},{-99,-6}}, color={0,0,127})); + connect(twoPhaseSensorSelect.inlet, flowResistance2.inlet) + annotation (Line( + points={{-56,-28},{-60,-28},{-60,-20},{-40,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(singleSensorSelect5.inlet, flowResistance2.inlet) + annotation (Line( + points={{-56,-36},{-60,-36},{-60,-20},{-40,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(singleSensorSelect6.inlet, flowResistance1.inlet) + annotation (Line( + points={{-56,38},{-60,38},{-60,20},{-40,20}}, + color={28,108,200}, + thickness=0.5)); + connect(twoPhaseSensorSelect6.inlet, flowResistance1.inlet) + annotation (Line( + points={{-56,30},{-60,30},{-60,20},{-40,20}}, + color={28,108,200}, + thickness=0.5)); + connect(sink.inlet, flowResistance3.outlet) annotation (Line( + points={{76,-20},{50,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(sink1.inlet, flowResistance.outlet) annotation (Line( + points={{76,20},{50,20}}, + color={28,108,200}, + thickness=0.5)); + connect(singleSensorSelect4.inlet, flowResistance3.outlet) + annotation (Line( + points={{64,-50},{60,-50},{60,-20},{50,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(twoPhaseSensorSelect3.inlet, flowResistance3.outlet) + annotation (Line( + points={{64,-42},{60,-42},{60,-20},{50,-20}}, + color={28,108,200}, + thickness=0.5)); + connect(twoPhaseSensorSelect7.inlet, flowResistance.outlet) + annotation (Line( + points={{64,42},{60,42},{60,20},{50,20}}, + color={28,108,200}, + thickness=0.5)); + connect(singleSensorSelect7.inlet, flowResistance.outlet) + annotation (Line( + points={{64,50},{60,50},{60,20},{50,20}}, + color={28,108,200}, + thickness=0.5)); + annotation (Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{100,100}})), + Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-120,-100},{120,100}})), + experiment(StopTime=125, Tolerance=1e-6, Interval=0.125, __Dymola_Algorithm="Dassl"), + Documentation(info=" +Owner: Michael Meißner
+")); + end PhaseSeperator; + annotation (Documentation(info=" ++Test package for the Boundaries package of ThermofluidStream. +
+")); + end Tests; + + package Internal "Partials and Internal functions" + extends Modelica.Icons.InternalPackage; + + partial model PartialSubstance + import Chemical; + + outer Modelica.Fluid.System system "System wide properties"; + + parameter Real L=1e-5; + + parameter Boolean useInlet = false "If true inlet is added"; + parameter Boolean useOutlet = true "If true outlet is added"; + + Interfaces.Inlet inlet( + r=r_in, + n_flow=n_flow_in, + u=u_in, + h=h_in) if useInlet "The substance entering" + annotation (Placement(transformation(extent={{90,-10},{110,10}}), iconTransformation(extent={{-110,-10},{-90,10}}))); + + Chemical.Interfaces.Outlet outlet(r=r_out,n_flow=n_flow_out,u=u_out,h=h_out) if useOutlet "The substance exiting" + annotation (Placement(transformation(extent={{90,-10},{110,10}}))); + + replaceable package stateOfMatter = Interfaces.Incompressible constrainedby Interfaces.StateOfMatter + "Substance model to translate data into substance properties" + annotation (choices( + choice(redeclare package stateOfMatter = + Chemical.Interfaces.Incompressible "Incompressible"), + choice(redeclare package stateOfMatter = + Chemical.Interfaces.IdealGas "Ideal Gas"), + choice(redeclare package stateOfMatter = + Chemical.Interfaces.IdealGasMSL "Ideal Gas from MSL"), + choice(redeclare package stateOfMatter = + Chemical.Interfaces.IdealGasShomate "Ideal Gas using Shomate model"))); + + parameter stateOfMatter.SubstanceData substanceData + "Definition of the substance" + annotation (choicesAllMatching = true); + + parameter Modelica.Units.SI.MolarFlowRate n_flow_assert(max=0) = -dropOfCommons.n_flow_reg "Assertion threshold for negative molar flows" + annotation(Dialog(tab="Advanced")); + + Modelica.Units.SI.MoleFraction x "Mole fraction of the substance"; + + Modelica.Units.SI.ActivityOfSolute a + "Activity of the substance (mole-fraction based)"; + + Real r; + + protected + outer Chemical.DropOfCommons dropOfCommons; + + Modelica.Units.SI.ActivityCoefficient gamma + "Activity coefficient of the substance"; + + Modelica.Units.SI.ChargeNumberOfIon z "Charge number of ion"; + + Modelica.Units.SI.Temperature temperature + "Temperature of the solution"; + + Modelica.Units.SI.Pressure pressure "Pressure of the solution"; + + Modelica.Units.SI.ElectricPotential electricPotential + "Electric potential of the solution"; + + Modelica.Units.SI.MoleFraction moleFractionBasedIonicStrength + "Ionic strength of the solution"; + + //Modelica.Units.SI.MolarMass molarMass "Molar mass of the substance"; + + Modelica.Units.SI.MolarEnthalpy molarEnthalpy + "Molar enthalpy of the substance"; + + Modelica.Units.SI.MolarEntropy molarEntropyPure + "Molar entropy of the pure substance"; + + Modelica.Units.SI.ChemicalPotential u0 + "Chemical potential of the pure substance"; + + Modelica.Units.SI.ChemicalPotential uPure + "Electro-Chemical potential of the pure substance"; + + Modelica.Units.SI.MolarVolume molarVolume + "Molar volume of the substance"; + + Modelica.Units.SI.MolarVolume molarVolumePure + "Molar volume of the pure substance"; + + Modelica.Units.SI.MolarVolume molarVolumeExcess + "Molar volume excess of the substance in solution (typically it is negative as can be negative)"; + + // Modelica.SIunits.MolarHeatCapacity molarHeatCapacityCp + // "Molar heat capacity of the substance at constant pressure"; + + Real r_in,n_flow_in,u_in,h_in; + Real r_out,n_flow_out,u_out,h_out; + + equation + assert(n_flow_in > n_flow_assert, "Negative massflow at Volume inlet", dropOfCommons.assertionLevel); + assert(-n_flow_out > n_flow_assert, "Positive massflow at Volume outlet", dropOfCommons.assertionLevel); + assert(x > 0, "Molar fraction must be positive"); + + + //aliases + gamma = stateOfMatter.activityCoefficient(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); + z = stateOfMatter.chargeNumberOfIon(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); + // molarMass = stateOfMatter.molarMass(substanceData); + + molarEnthalpy = stateOfMatter.molarEnthalpy(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); + molarEntropyPure = stateOfMatter.molarEntropyPure(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); + u0 = stateOfMatter.chemicalPotentialPure( + substanceData, + temperature, + pressure, + electricPotential, + moleFractionBasedIonicStrength); + uPure = stateOfMatter.electroChemicalPotentialPure( + substanceData, + temperature, + pressure, + electricPotential, + moleFractionBasedIonicStrength); + molarVolume = stateOfMatter.molarVolume(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); + molarVolumePure = stateOfMatter.molarVolumePure(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); + molarVolumeExcess = stateOfMatter.molarVolumeExcess(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); + // molarHeatCapacityCp = stateOfMatter.molarHeatCapacityCp(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); + + //activity of the substance + a = gamma*x; + + //electro-chemical potential of the substance in the solution + u_out = stateOfMatter.chemicalPotentialPure( + substanceData, + temperature, + pressure, + electricPotential, + moleFractionBasedIonicStrength) + + Modelica.Constants.R*temperature*log(a) + + z*Modelica.Constants.F*electricPotential; + + h_out = molarEnthalpy; + der(n_flow_out)*L = r_out; + der(n_flow_in)*L = r_in - r; + + u_out = u_in + r; + + if not useInlet then + n_flow_in = 0; + h_in = 0; + u_in = u_out; + end if; + if not useOutlet then + n_flow_out = 0; + end if; + + annotation ( + Documentation(revisions=" +2009-2015
+Marek Matejak, Charles University, Prague, Czech Republic
+")); + end PartialSubstance; + + partial model PartialSubstanceInSolution "Substance properties for components, where the substance is connected with the solution" + + Interfaces.SolutionPort solution "To connect substance with solution, where is pressented" + annotation (Placement(transformation(extent={{-70,-110},{-50,-90}}), iconTransformation(extent={{-70,-110},{-50,-90}}))); + + extends Boundaries.Internal.PartialSubstance; + + protected + Modelica.Units.SI.AmountOfSubstance amountOfSolution + "Amount of all solution particles"; + + equation + + //aliases + temperature = solution.T; + pressure = solution.p; + electricPotential = solution.v; + amountOfSolution = solution.n; + moleFractionBasedIonicStrength = solution.I; + + end PartialSubstanceInSolution; + + partial model PartialSubstanceInSolutionWithAdditionalPorts "Substance properties for components, where the substance is connected with the solution" + + extends Boundaries.Internal.PartialSubstanceInSolution; + + Modelica.Units.SI.MolarFlowRate q + "Molar flow rate of the substance into the component"; + + Interfaces.SubstanceMassPort_a port_m "Substance mass fraction port" annotation (Placement(transformation(extent={{92,-110},{112,-90}}))); + + Interfaces.SubstanceMolarityPort_a port_c annotation (Placement(transformation(extent={{90,90},{110,110}}))); + + equation + //molar mass flow + q=(n_flow_in + n_flow_out + port_c.q + port_m.m_flow/stateOfMatter.molarMassOfBaseMolecule(substanceData)); + + //substance mass fraction + port_m.x_mass = solution.mj/solution.m; + port_c.c = solution.nj/solution.V; + + end PartialSubstanceInSolutionWithAdditionalPorts; + annotation (Documentation(info=" +This package contains all internal functions, partials, and other (e.g. experimental) models for the Boundaries package.
+")); + end Internal; + annotation (Documentation(revisions=" +(c) 2020-2021, DLR, Institute of System Dynamics and Control
+ +", info=" +The boundaries are Sorces and Sinks, as well as Volumes, that are conceptually a source and a sink with extra equations and act as loop breakers in closes cycles, and therefore are also boundaries.
+")); +end Boundaries; diff --git a/Chemical/DropOfCommons.mo b/Chemical/DropOfCommons.mo new file mode 100644 index 0000000..306f02d --- /dev/null +++ b/Chemical/DropOfCommons.mo @@ -0,0 +1,45 @@ +within Chemical; +model DropOfCommons "Model for global parameters" + + parameter Chemical.Utilities.Units.Inertance L=1e-5 "Inertance of the molar flow through electro-chemical process" annotation (Dialog(tab="Advanced")); + + parameter Modelica.Units.SI.MolarFlowRate n_flow_reg = 0.01 "Regularization threshold of molar flow rate" + annotation(Dialog(group="Regularization")); + + parameter AssertionLevel assertionLevel = AssertionLevel.error "Global assertion level"; + + annotation (defaultComponentName="dropOfCommons", + defaultComponentPrefixes="inner", + missingInnerMessage=" +Your model is using an outer \"dropOfCommons\" component but +an inner \"dropOfCommons\" component is not defined. +Use Chemical.DropOfCommons in your model +to specify system properties.",Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Ellipse( + extent={{-80,-60},{80,-100}}, + fillColor={175,175,175}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None), + Polygon( + points={{0,100},{16,36},{80,-32},{0,-100},{-82,-30},{-18,36},{0,100}}, + lineColor={194,138,221}, + smooth=Smooth.Bezier, + fillColor={158,66,200}, + fillPattern=FillPattern.Solid), + Polygon( + points={{6,42},{20,16},{44,-14},{22,-38},{6,42}}, + smooth=Smooth.Bezier, + fillColor={194,138,221}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None), + Polygon( + points={{-6,-76},{-40,-62},{-56,-30},{-30,-44},{-6,-76}}, + pattern=LinePattern.None, + smooth=Smooth.Bezier, + fillColor={90,34,117}, + fillPattern=FillPattern.Solid)}), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(revisions=" +2023, Marek Mateják
+")); +end DropOfCommons; diff --git a/Chemical/Examples.mo b/Chemical/Examples.mo index 1b9e813..474dc69 100644 --- a/Chemical/Examples.mo +++ b/Chemical/Examples.mo @@ -89,11 +89,11 @@ extends Modelica.Icons.ExamplesPackage; {-30,-90},{60,-90},{60,-98}},color={127,127,0})); connect(B.port_a, reaction.substrates[1]) annotation (Line( - points={{-14,-14},{-10,-14},{-10,4},{4,4}}, + points={{-14,-14},{-10,-14},{-10,1},{4,1}}, color={158,66,200}, thickness=1)); connect(A.port_a, reaction.substrates[2]) annotation (Line( - points={{-14,12},{-10,12},{-10,0},{4,0}}, + points={{-14,12},{-10,12},{-10,3},{4,3}}, color={158,66,200}, thickness=1)); annotation ( Documentation(revisions=" @@ -6221,23 +6221,20 @@ extends Modelica.Icons.ExamplesPackage; Chemical.Components.Solution solution annotation (Placement(transformation(extent={{-100,-100},{100,100}}))); - Chemical.Components.SubstanceS A( + Chemical.Boundaries.Substance A( useInlet=false, useOutlet=true, substanceData(MolarWeight=1), use_mass_start=false, - amountOfSubstance_start=0.9) - annotation (Placement(transformation(extent={{-52,-8},{-32,12}}))); + amountOfSubstance_start=0.9) annotation (Placement(transformation(extent={{-52,-8},{-32,12}}))); - Chemical.Components.Process reaction(n_flow_0=7000) - annotation (Placement(transformation(extent={{-10,-8},{10,12}}))); - Chemical.Components.SubstanceS B( + Chemical.Processes.Process reaction(n_flow_0=7000) annotation (Placement(transformation(extent={{-10,-8},{10,12}}))); + Chemical.Boundaries.Substance B( useInlet=true, useOutlet=false, substanceData(DfG=-R*T_25degC*log(K), MolarWeight=1), use_mass_start=false, - amountOfSubstance_start=0.1) - annotation (Placement(transformation(extent={{42,-10},{62,10}}))); + amountOfSubstance_start=0.1) annotation (Placement(transformation(extent={{42,-10},{62,10}}))); Components.Solution solution1 annotation (Placement(transformation(extent={{118,-98},{318,102}}))); @@ -6253,6 +6250,7 @@ extends Modelica.Icons.ExamplesPackage; use_mass_start=false, amountOfSubstance_start=0.1) annotation (Placement(transformation(extent={{280,-6},{260,14}}))); + inner DropOfCommons dropOfCommons(assertionLevel=AssertionLevel.warning) annotation (Placement(transformation(extent={{40,60},{60,80}}))); equation connect(A.solution, solution.solution) annotation (Line( points={{-48,-8},{-48,-92},{60,-92},{60,-98}}, @@ -6285,4 +6283,87 @@ extends Modelica.Icons.ExamplesPackage; Icon(coordinateSystem(extent={{-100,-100},{340,100}})), __Dymola_experimentSetupOutput); end SimpleReactionS; + + model SimpleReaction2S "The simple chemical reaction A+B<->C with equilibrium [C]/([A]*[B]) = 2, where [A] is molar concentration of A in water" + extends Modelica.Icons.Example; + + constant Real Kb(unit="kg/mol") = 2 + "Molarity based dissociation constant of the reaction with one more reactant"; + + constant Real Kx(unit="1") = Kb*55.508 + "Mole fraction based dissociation constant of the reaction with one more reactant in the pure water"; + + constant Modelica.Units.SI.Temperature T_25degC=298.15 "Temperature"; + constant Real R = Modelica.Constants.R "Gas constant"; + + Chemical.Components.Solution solution + annotation (Placement(transformation(extent={{-100,-100},{100,100}}))); + + Boundaries.Substance A( + useInlet=false, + useOutlet=true, + use_mass_start=false, + amountOfSubstance_start=0.1) annotation (Placement(transformation(extent={{-34,2},{-14,22}}))); + Chemical.Components.Reaction reaction(nS=2, nP=1) + annotation (Placement(transformation(extent={{4,-8},{24,12}}))); + Boundaries.Substance B( + useInlet=false, + useOutlet=true, + use_mass_start=false, + amountOfSubstance_start=0.1) annotation (Placement(transformation(extent={{-34,-24},{-14,-4}}))); + Boundaries.Substance C( + useInlet=true, + useOutlet=false, + substanceData(DfG=-R*T_25degC*log(Kx)), + use_mass_start=false, + amountOfSubstance_start=0.1) annotation (Placement(transformation(extent={{48,-8},{68,12}}))); + + Components.Solution solution1 + annotation (Placement(transformation(extent={{138,-100},{338,100}}))); + Components.Substance A1(use_mass_start=false, amountOfSubstance_start=0.1) + annotation (Placement(transformation(extent={{204,2},{224,22}}))); + Components.Reaction reaction1(nS=2, nP=1) + annotation (Placement(transformation(extent={{242,-8},{262,12}}))); + Components.Substance B1(use_mass_start=false, amountOfSubstance_start=0.1) + annotation (Placement(transformation(extent={{204,-24},{224,-4}}))); + Components.Substance C1( + substanceData(DfG=-R*T_25degC*log(Kx)), + use_mass_start=false, + amountOfSubstance_start=0.1) + annotation (Placement(transformation(extent={{306,-8},{286,12}}))); + equation + connect(A.solution, solution.solution) annotation (Line( + points={{-30,2},{-30,-90},{60,-90},{60,-98}}, + color={127,127,0})); + connect(C.solution, solution.solution) annotation (Line(points={{52,-8},{66,-8},{66,-90},{60,-90},{60,-98}}, + color={127,127,0})); + connect(B.solution, solution.solution) annotation (Line(points={{-30,-24}, + {-30,-90},{60,-90},{60,-98}},color={127,127,0})); + + connect(reaction1.products[1], C1.port_a) annotation (Line( + points={{262,2},{286,2}}, + color={158,66,200}, + thickness=1)); + connect(A1.solution, solution1.solution) annotation (Line(points={{208,2},{132,2},{132,-106},{298,-106},{298,-98}}, color={127,127,0})); + connect(C1.solution, solution1.solution) annotation (Line(points={{302,-8},{344,-8},{344,-106},{298,-106},{298,-98}}, color={127,127,0})); + connect(B1.solution, solution1.solution) annotation (Line(points={{208,-24},{132,-24},{132,-106},{298,-106},{298,-98}}, color={127,127,0})); + connect(B1.port_a, reaction1.substrates[1]) + annotation (Line( + points={{224,-14},{224,-16},{232,-16},{232,1},{242,1}}, + color={158,66,200}, + thickness=1)); + connect(A1.port_a, reaction1.substrates[2]) annotation (Line( + points={{224,12},{234,12},{234,3},{242,3}}, + color={158,66,200}, + thickness=1)); + annotation ( Documentation(revisions=" +2015-2018
+Marek Matejak, Charles University, Prague, Czech Republic
+", info=" +Simple reaction demonstrating equilibria between substance A, B, and substance C, mixed in one solution. Observe the molar concentration (A.c) and molar fraction. Note, that molar fractions (A.x and B.x and C.x) are always summed to 1 for the whole solution.
+"), + experiment(StopTime=0.0001, __Dymola_Algorithm="Dassl"), + Diagram(coordinateSystem(extent={{-100,-100},{340,100}})), + Icon(coordinateSystem(extent={{-100,-100},{340,100}}))); + end SimpleReaction2S; end Examples; diff --git a/Chemical/Processes.mo b/Chemical/Processes.mo new file mode 100644 index 0000000..30e368e --- /dev/null +++ b/Chemical/Processes.mo @@ -0,0 +1,211 @@ +within Chemical; +package Processes + model Process "Electro-chemical process" + extends Interfaces.SISOFlow; + extends Interfaces.ConditionalKinetics; + + parameter Real kE(unit="mol/J")=0 "Kinetic turnover coefficient"; + + equation + //the main equation + + n_flow = - kC * du * exp(-kE*abs(du)); + + annotation ( Documentation(revisions=" +2009-2015 by Marek Matejak, Charles University, Prague, Czech Republic
+", info=" +Diffusion of the substance as equilibration of electro-chemical potentials.
+"), + Icon(graphics={Rectangle(extent={{-100,40},{100,-40}}, lineColor={28,108,200})})); + end Process; + + model Reaction "Chemical Reaction" + extends Interfaces.ConditionalKinetics; + import Chemical.Utilities.Types.InitializationMethods; + + parameter StateSelect n_flowStateSelect = StateSelect.default "State select for n_flow" + annotation(Dialog(tab="Advanced")); + parameter InitializationMethods initN_flow = Chemical.Utilities.Types.InitializationMethods.none "Initialization method for n_flow" + annotation(Dialog(tab= "Initialization", group="Molar flow")); + parameter Modelica.Units.SI.MolarFlowRate n_flow_0 = 0 "Initial value for n_flow" + annotation(Dialog(tab= "Initialization", group="Molar flow", enable=(initN_flow == InitializationMethods.state))); + parameter Utilities.Units.MolarFlowAcceleration n_acceleration_0 = 0 "Initial value for der(n_flow)" + annotation(Dialog(tab= "Initialization", group="Molar flow", enable=(initN_flow == InitializationMethods.derivative))); + + + parameter Modelica.Units.SI.Time TC=0.1 "Time constant for electro-chemical potential adaption" annotation (Dialog(tab="Advanced")); + parameter Utilities.Units.Inertance L = dropOfCommons.L "Inertance of the flow" + annotation(Dialog(tab="Advanced")); + + parameter Integer nS=0 "Number of substrate types" + annotation ( HideResult=true, Evaluate=true, Dialog(connectorSizing=true, tab="General",group="Ports")); + + parameter Modelica.Units.SI.StoichiometricNumber s[nS]=ones(nS) + "Stoichiometric reaction coefficient for substrates" + annotation (HideResult=true); + + parameter Integer nP=0 "Number of product types" + annotation ( HideResult=true, Evaluate=true, Dialog(connectorSizing=true, tab="General",group="Ports")); + + parameter Modelica.Units.SI.StoichiometricNumber p[nP]=ones(nP) + "Stoichiometric reaction coefficients for products" + annotation (HideResult=true); + + parameter Real kE(unit="mol/J")=0 "Kinetic turnover coefficient" + annotation(Dialog(group="Chemical kinetics")); + + Modelica.Units.SI.MolarFlowRate rr(stateSelect=n_flowStateSelect) "Reaction molar flow rate"; + + Interfaces.Inlet substrates[nS] annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=180, + origin={-100,0}), iconTransformation( + extent={{10,-10},{-10,10}}, + rotation=180, + origin={-100,0}))); + + Interfaces.Outlet products[nP] annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=180, + origin={100,0}), iconTransformation( + extent={{10,-10},{-10,10}}, + rotation=180, + origin={100,0}))); + + Modelica.Units.SI.MolarEnthalpy h_mix; + + protected + outer DropOfCommons dropOfCommons; + Modelica.Units.SI.ChemicalPotential du; + + initial equation + if initN_flow == InitializationMethods.state then + rr = n_flow_0; + elseif initN_flow == InitializationMethods.derivative then + der(rr) = n_acceleration_0; + elseif initN_flow == InitializationMethods.steadyState then + der(rr) = 0; + end if; + + equation + //the main equation + du = ((p * products.u) - (s * substrates.u)); + rr = - kC * du * exp(-kE*abs(du)); + + //reaction molar rates + rr*s = substrates.n_flow; + rr*p = -products.n_flow; + + products.h = h_mix*ones(nP); + + if + (rr>0) then + h_mix*(products.n_flow*ones(nP)) + substrates.n_flow*substrates.h = 0; + else + h_mix = 0; + end if; + + if nP>0 then + (p * products.r) = (s * substrates.r) - der(rr)*L; + for i in 2:nP loop + //first product is based on inertial potential, + //other products are provided as source + der(products[i].u).*TC = products[i].r; + end for; + end if; + + annotation ( + Icon(coordinateSystem(preserveAspectRatio=false,extent={{-100,-100},{ + 100,100}}), graphics={ + Rectangle( + extent={{-100,-30},{100,30}}, + lineColor={0,0,127}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-100,-72},{100,-40}}, + lineColor={128,0,255}, + textString="%name"), + Polygon( + points={{-60,6},{-60,4},{54,4},{54,4},{18,14},{18,6},{-60,6}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid), + Polygon( + points={{54,-8},{54,-6},{-60,-6},{-60,-6},{-24,-16},{-24,-8},{54,-8}}, + lineColor={0,0,0}, + fillColor={0,0,0}, + fillPattern=FillPattern.Solid)}), + Documentation(revisions=" +2013-2020 by Marek Matejak, Charles University, Prague, Czech Republic
+", info=" +s1·S1 + .. + snS·SnS <-> p1·P1 + .. + pnP·PnP
+By redefinition of stoichometry as vi = -si, Ai = Si for i=1..nS vi = pi-nS, Ai = Pi-nS for i=nS+1..nS+nP
+So the reaction can be written also as 0 = ∑ (vi · Ai)
+K = product(a(S).^s) / product( a(P).^s ) = product(a(A).^v) |
+dissociation constant |
+
ΔrG = ∑ (vi · ΔfGi) = ΔrH - T·ΔrS = -R·T·log(K) |
+molar Gibb's energy of the reaction |
+
ΔrH = ∑ (vi · ΔfHi) |
+molar enthalpy of the reaction |
+
+ | molar entropy of the reaction |
+
Ai |
+i-th substance |
+
vi |
+stochiometric coefficients of i-th substance |
+
K |
+dissociation constant (activity based) |
+
a(Ai)=fi*xi |
+activity of the substance A |
+
fi |
+activity coefficient of the substance A |
+
xi |
+mole fraction of the substance A |
+
ΔfHi |
+molar enthalpy of formation of i-th substance |
+
ΔfGi |
+molar Gibbs energy of formation of i-th substance |
+
ΔfSi |
+molar entropy of formation of i-th substance |
+
Δrω |
+change of number of microstates of particles by reaction |
+
+ | + |
Medium package used in the component. Make sure it is the same one as all the components connected to all fluid ports are using.
+")); + end JunctionX1; + + model JunctionX2 "2 to 2 X-Junction" + + parameter Modelica.Units.SI.MolarFlowRate n_flow_eps=dropOfCommons.n_flow_reg "Regularization threshold for small mass flows" + annotation (Dialog(tab="Advanced")); + parameter Chemical.Utilities.Units.Inertance L=dropOfCommons.L "Inertance on each Branch of Component" annotation (Dialog(tab="Advanced")); + + Chemical.Interfaces.Outlet outleta + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=180, + origin={-100,0}))); + Chemical.Interfaces.Outlet outletb + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={100,0}))); + Chemical.Interfaces.Inlet inletA + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=-90, + origin={0,100}))); + Chemical.Interfaces.Inlet inletB + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=90, + origin={0,-100}))); + JunctionNM junctionNM(N=2, M=2, final L=L, final n_flow_eps=n_flow_eps) + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=270, + origin={0,20}))); + + protected + outer Chemical.DropOfCommons dropOfCommons; + + equation + + connect(junctionNM.outlets[1], outleta) annotation (Line( + points={{-0.5,10},{-1,10},{-1,0},{-100,0}}, + color={158,66,200}, + thickness=0.5)); + connect(junctionNM.outlets[2], outletb) annotation (Line( + points={{0.5,10},{1,10},{1,0},{100,0}}, + color={158,66,200}, + thickness=0.5)); + connect(junctionNM.inlets[1], inletA) annotation (Line( + points={{-0.5,30},{-0.5,66},{0,66},{0,100}}, + color={158,66,200}, + thickness=0.5)); + connect(inletB, junctionNM.inlets[2]) annotation (Line( + points={{0,-100},{0,-40},{40,-40},{40,52},{0.5,52},{0.5,30}}, + color={158,66,200}, + thickness=0.5)); + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Line( + points={{-100,0},{0,0}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{100,0}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{0,100}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,-100},{0,0}}, + color={158,66,200}, + thickness=0.5), + Ellipse( + extent={{-6,6},{6,-6}}, + lineColor={158,66,200}, + fillColor={194,138,221}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), + Text( + extent={{-60,100},{-20,60}}, + textColor={175,175,175}, + textString="A"), + Text( + extent={{60,-100},{20,-60}}, + textColor={175,175,175}, + textString="B"), + Text( + extent={{-60,-20},{-100,-60}}, + textColor={175,175,175}, + textString="a"), + Text( + extent={{50,20},{90,60}}, + textColor={175,175,175}, + textString="b")}), + Diagram(coordinateSystem(preserveAspectRatio=false))); + end JunctionX2; + + model JunctionX3 "3 to 1 X-Junction" + + parameter Modelica.Units.SI.MolarFlowRate n_flow_eps=dropOfCommons.n_flow_reg "Regularization threshold for small mass flows" + annotation (Dialog(tab="Advanced")); + parameter Chemical.Utilities.Units.Inertance L=dropOfCommons.L "Inertance on each Branch of Component" annotation (Dialog(tab="Advanced")); + + Chemical.Interfaces.Outlet outlet + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=180, + origin={-100,0}))); + Chemical.Interfaces.Inlet inletA + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=-90, + origin={0,100}))); + Chemical.Interfaces.Inlet inletB + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=180, + origin={100,0}))); + Chemical.Interfaces.Inlet inletC + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=90, + origin={0,-100}))); + JunctionN junctionN(final N=3, final L=L, + final n_flow_eps=n_flow_eps) + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={-40,0}))); + + protected + outer Chemical.DropOfCommons dropOfCommons; + + equation + + connect(junctionN.inlets[2], inletB) annotation (Line( + points={{-30,0},{100,0}}, + color={158,66,200}, + thickness=0.5)); + connect(inletC, junctionN.inlets[3]) annotation (Line( + points={{0,-100},{0,-0.666667},{-30,-0.666667}}, + color={158,66,200}, + thickness=0.5)); + connect(inletA, junctionN.inlets[1]) annotation (Line( + points={{0,100},{0,0.666667},{-30,0.666667}}, + color={158,66,200}, + thickness=0.5)); + connect(junctionN.outlet, outlet) annotation (Line( + points={{-50,0},{-100,0}}, + color={158,66,200}, + thickness=0.5)); + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Line( + points={{-100,0},{0,0}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{100,0}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{0,100}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{0,-100}}, + color={158,66,200}, + thickness=0.5), + Ellipse( + extent={{-6,6},{6,-6}}, + lineColor={158,66,200}, + fillColor={194,138,221}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), + Text( + extent={{-60,100},{-20,60}}, + textColor={175,175,175}, + textString="A"), + Text( + extent={{50,20},{90,60}}, + textColor={175,175,175}, + textString="B"), + Text( + extent={{60,-100},{20,-60}}, + textColor={175,175,175}, + textString="C")}), + Diagram(coordinateSystem(preserveAspectRatio=false))); + end JunctionX3; + + model SplitterN "Splitter with one inlet and N outlets" + + parameter Integer N(min=1) = 1 "Number of outputs"; + parameter Chemical.Utilities.Units.Inertance L=dropOfCommons.L "Inertance on each Branch of Component" annotation (Dialog(tab="Advanced")); + + Chemical.Interfaces.Inlet inlet "inlet" + annotation (Placement(transformation(extent={{-120,-20},{-80,20}}), iconTransformation(extent={{-120,-20},{-80,20}}))); + Chemical.Interfaces.Outlet outlets[N] "vector of N outlets" + annotation (Placement(transformation(extent={{80,-20},{120,20}}), iconTransformation(extent={{80,-20},{120,20}}))); + + protected + outer Chemical.DropOfCommons dropOfCommons; + + Modelica.Units.SI.ChemicalPotential r_mix; + + equation + -der(inlet.n_flow) * L = inlet.r - r_mix; + + for i in 1:N loop + der(outlets[i].n_flow) * L = outlets[i].r - r_mix; + outlets[i].u = inlet.u; + outlets[i].h = inlet.h; + end for; + + sum(outlets.n_flow) + inlet.n_flow = 0; + + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Line( + points={{0,0},{96,10}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{96,-10}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{-100,0},{100,0}}, + color={158,66,200}, + thickness=0.5), + Ellipse( + extent={{-6,6},{6,-6}}, + lineColor={158,66,200}, + fillColor={194,138,221}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), + Text( + extent={{90,80},{50,40}}, + textColor={175,175,175}, + textString="%N")}), + Diagram(coordinateSystem(preserveAspectRatio=false))); + end SplitterN; + + model JunctionN "Junction with N inlets and one outlet" + + parameter Integer N(min=1) = 1 "Number of inlets"; + parameter Modelica.Units.SI.MolarFlowRate n_flow_eps=dropOfCommons.n_flow_reg "Regularization threshold for small molar flows" + annotation (Dialog(tab="Advanced")); + parameter Chemical.Utilities.Units.Inertance L=dropOfCommons.L "Inertance on each Branch of Component" annotation (Dialog(tab="Advanced")); + + Chemical.Interfaces.Inlet inlets[N] "vector of N inlets" + annotation (Placement(transformation(extent={{-120,-20},{-80,20}}), iconTransformation(extent={{-120,-20},{-80,20}}))); + Chemical.Interfaces.Outlet outlet "outlet" + annotation (Placement(transformation(extent={{80,-20},{120,20}}), iconTransformation(extent={{80,-20},{120,20}}))); + + // these are needed by DynamicJunctionN + output Real w[N](each unit="1") "regularized weighting factor for specific enthalpy"; + + + protected + outer Chemical.DropOfCommons dropOfCommons; + + Modelica.Units.SI.ChemicalPotential u[N]=inlets.u "(steady molar-flow) electro-chemical potential at inlets"; + Modelica.Units.SI.MolarEnthalpy h[N]=inlets.h "molar enthapy at inlets"; + + Modelica.Units.SI.ChemicalPotential u_mix "(steady mass-flow) electro-chemical potential at the outlet"; + Modelica.Units.SI.ChemicalPotential r_mix "inertial electro-chemical potential at outlet"; + Modelica.Units.SI.MolarEnthalpy h_mix "molar enthalpy at outlet"; + + Modelica.Units.SI.ChemicalPotential r_in[N]; + + equation + sum(inlets.n_flow) + outlet.n_flow = 0; + + for i in 1:N loop + der(inlets[i].n_flow) * L = inlets[i].r - r_in[i]; + + u[i] + r_in[i] = u_mix + r_mix; + w[i] = (abs(inlets[i].n_flow)+n_flow_eps) / (sum(abs(inlets.n_flow))+N*n_flow_eps); + end for; + der(outlet.n_flow) * L = outlet.r - r_mix; + + u_mix = sum(w.*u); + h_mix = sum(w.*h); + + outlet.u = u_mix; + outlet.h = h_mix; + + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Line( + points={{-100,0},{100,0}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{-100,10}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{-100,-10}}, + color={158,66,200}, + thickness=0.5), + Ellipse( + extent={{-6,6},{6,-6}}, + lineColor={158,66,200}, + fillColor={194,138,221}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), + Text( + extent={{-90,80},{-50,40}}, + textColor={175,175,175}, + textString="%N")}), + Diagram(coordinateSystem(preserveAspectRatio=false))); + end JunctionN; + + model JunctionNM "Junction with N inlets and M outlets" + + parameter Integer N(min=1) = 1 "Number of inputs"; + parameter Integer M(min=1) = 1 "Number of outputs"; + parameter Modelica.Units.SI.MolarFlowRate n_flow_eps=dropOfCommons.n_flow_reg "Regularization threshold for small mass flows" + annotation (Dialog(tab="Advanced")); + parameter Chemical.Utilities.Units.Inertance L=dropOfCommons.L "Inertance on each Branch of Component" annotation (Dialog(tab="Advanced")); + + Chemical.Interfaces.Inlet inlets[N] "vector of N inlets" annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={-100,0}), iconTransformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={-100,0}))); + Chemical.Interfaces.Outlet outlets[M] "vector of N outlets" annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={100,0}), iconTransformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={100,0}))); + SplitterN splitterN( + final N=M, + final L=L) + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={18,0}))); + JunctionN junctionN( + final N=N, + final L=L, + final n_flow_eps=n_flow_eps) + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-14,0}))); + + protected + outer Chemical.DropOfCommons dropOfCommons; + + equation + + connect(junctionN.inlets, inlets) annotation (Line( + points={{-24,0},{-62,0},{-62,0},{-100,0}}, + color={158,66,200}, + thickness=0.5)); + connect(junctionN.outlet, splitterN.inlet) annotation (Line( + points={{-4,0},{8,0}}, + color={158,66,200}, + thickness=0.5)); + connect(splitterN.outlets, outlets) annotation (Line( + points={{28,0},{100,0}}, + color={158,66,200}, + thickness=0.5)); + annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={ + Line( + points={{-100,0},{100,0}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{-100,10}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{-100,-10}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{96,10}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{0,0},{96,-10}}, + color={158,66,200}, + thickness=0.5), + Ellipse( + extent={{-6,6},{6,-6}}, + lineColor={158,66,200}, + fillColor={194,138,221}, + fillPattern=FillPattern.Solid, + lineThickness=0.5), + Text( + extent={{-90,80},{-50,40}}, + textColor={175,175,175}, + textString="%N"), + Text( + extent={{90,80},{50,40}}, + textColor={175,175,175}, + textString="%M")}), + Diagram(coordinateSystem(preserveAspectRatio=false))); + end JunctionNM; +annotation (Documentation(revisions=" +(c) 2020-2021, DLR, Institute of System Dynamics and Control
+ +"), Icon(graphics={ + Line( + points={{-80,0},{12,0}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{12,0},{80,-80}}, + color={158,66,200}, + thickness=0.5), + Line( + points={{12,0},{80,80}}, + color={158,66,200}, + thickness=0.5), + Ellipse( + extent={{6,6},{18,-6}}, + lineColor={158,66,200}, + fillColor={194,138,221}, + fillPattern=FillPattern.Solid, + lineThickness=0.5)})); +end Topology; diff --git a/Chemical/Utilities.mo b/Chemical/Utilities.mo new file mode 100644 index 0000000..c08684a --- /dev/null +++ b/Chemical/Utilities.mo @@ -0,0 +1,31 @@ +within Chemical; +package Utilities + package Units + type Inertance = Real (quantity = "ChemicalInertance",unit = "J.s2.mol-2", start=1e-5, nominal=1e-5, min=0) "Inertance of electro-chemical process"; + type MolarFlowAcceleration =Real(quantity="MolarFlowAcceleration", unit="mol/s2") "Acceleration Unit for a MolarFlow" + annotation (Documentation(info=" +Acceleration Unit for a MolarFlow
+ ")); + end Units; + + package Types + type InitializationMethods = enumeration( + none + "No initialization", + steadyState + "Steady state initialization (derivatives of states are zero)", + state + "Initialization with initial states", + derivative + "Initialization with initial derivatives of states") "Choices for initialization of a state." + annotation ( + Icon(coordinateSystem(preserveAspectRatio=false)), + Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" ++Choices for initialization of a state. +
+")); + end Types; +end Utilities; diff --git a/Chemical/package.mo b/Chemical/package.mo index 776054c..4d6c537 100644 --- a/Chemical/package.mo +++ b/Chemical/package.mo @@ -1253,398 +1253,6 @@ package Chemical "Physical Chemistry" ")); end Stream; - package Internal - - partial model PartialSubstance - - outer Modelica.Fluid.System system "System wide properties"; - - parameter Real L=1e-4; - - parameter Boolean useInlet = true "If true inlet is added"; - parameter Boolean useOutlet = false "If true outlet is added"; - - Interfaces.SubstanceInlet inlet(r=r_in,n_flow=n_flow_in,u=u_in,h=h_in,n=n_in) if useInlet "The substance entering" - annotation (Placement(transformation(extent={{90,-10},{110,10}}), iconTransformation(extent={{-110,-10},{-90,10}}))); - - Interfaces.SubstanceOutlet outlet(r=r_out,n_flow=n_flow_out,u=u_out,h=h_out,n=n_out) if useOutlet "The substance exiting" - annotation (Placement(transformation(extent={{90,-10},{110,10}}))); - - replaceable package stateOfMatter = Interfaces.Incompressible constrainedby Interfaces.StateOfMatter - "Substance model to translate data into substance properties" - annotation (choices( - choice(redeclare package stateOfMatter = - Chemical.Interfaces.Incompressible "Incompressible"), - choice(redeclare package stateOfMatter = - Chemical.Interfaces.IdealGas "Ideal Gas"), - choice(redeclare package stateOfMatter = - Chemical.Interfaces.IdealGasMSL "Ideal Gas from MSL"), - choice(redeclare package stateOfMatter = - Chemical.Interfaces.IdealGasShomate "Ideal Gas using Shomate model"))); - - parameter stateOfMatter.SubstanceData substanceData - "Definition of the substance" - annotation (choicesAllMatching = true); - - Modelica.Units.SI.MoleFraction x "Mole fraction of the substance"; - - Modelica.Units.SI.ActivityOfSolute a - "Activity of the substance (mole-fraction based)"; - - Real r; - protected - Modelica.Units.SI.ActivityCoefficient gamma - "Activity coefficient of the substance"; - - Modelica.Units.SI.ChargeNumberOfIon z "Charge number of ion"; - - Modelica.Units.SI.Temperature temperature - "Temperature of the solution"; - - Modelica.Units.SI.Pressure pressure "Pressure of the solution"; - - Modelica.Units.SI.ElectricPotential electricPotential - "Electric potential of the solution"; - - Modelica.Units.SI.MoleFraction moleFractionBasedIonicStrength - "Ionic strength of the solution"; - - //Modelica.Units.SI.MolarMass molarMass "Molar mass of the substance"; - - Modelica.Units.SI.MolarEnthalpy molarEnthalpy - "Molar enthalpy of the substance"; - - Modelica.Units.SI.MolarEntropy molarEntropyPure - "Molar entropy of the pure substance"; - - Modelica.Units.SI.ChemicalPotential u0 - "Chemical potential of the pure substance"; - - Modelica.Units.SI.ChemicalPotential uPure - "Electro-Chemical potential of the pure substance"; - - Modelica.Units.SI.MolarVolume molarVolume - "Molar volume of the substance"; - - Modelica.Units.SI.MolarVolume molarVolumePure - "Molar volume of the pure substance"; - - Modelica.Units.SI.MolarVolume molarVolumeExcess - "Molar volume excess of the substance in solution (typically it is negative as can be negative)"; - - // Modelica.SIunits.MolarHeatCapacity molarHeatCapacityCp - // "Molar heat capacity of the substance at constant pressure"; - - Real r_in,n_flow_in,u_in,h_in,n_in; - Real r_out,n_flow_out,u_out,h_out,n_out; - - equation - //aliases - gamma = stateOfMatter.activityCoefficient(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); - z = stateOfMatter.chargeNumberOfIon(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); - // molarMass = stateOfMatter.molarMass(substanceData); - - molarEnthalpy = stateOfMatter.molarEnthalpy(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); - molarEntropyPure = stateOfMatter.molarEntropyPure(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); - u0 = stateOfMatter.chemicalPotentialPure( - substanceData, - temperature, - pressure, - electricPotential, - moleFractionBasedIonicStrength); - uPure = stateOfMatter.electroChemicalPotentialPure( - substanceData, - temperature, - pressure, - electricPotential, - moleFractionBasedIonicStrength); - molarVolume = stateOfMatter.molarVolume(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); - molarVolumePure = stateOfMatter.molarVolumePure(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); - molarVolumeExcess = stateOfMatter.molarVolumeExcess(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); - // molarHeatCapacityCp = stateOfMatter.molarHeatCapacityCp(substanceData,temperature,pressure,electricPotential,moleFractionBasedIonicStrength); - - //activity of the substance - a = gamma*x; - - //electro-chemical potential of the substance in the solution - u_out = stateOfMatter.chemicalPotentialPure( - substanceData, - temperature, - pressure, - electricPotential, - moleFractionBasedIonicStrength) - + Modelica.Constants.R*temperature*log(a) - + z*Modelica.Constants.F*electricPotential; - - h_out = molarEnthalpy; - der(n_flow_out)*L = r_out; - -der(n_flow_in)*L = r_in - r; - - //der(n_flow_out/n_out)*L = r_out; - //der(n_flow_in/n_in)*L = r_in - r; - - r = u_in - u_out; - - if not useInlet then - n_flow_in = 0; - h_in = 0; - u_in = u_out; - n_in = n_out; - end if; - if not useOutlet then - n_flow_out = 0; - end if; - - annotation ( - Documentation(revisions=" -2009-2015
-Marek Matejak, Charles University, Prague, Czech Republic
-")); - end PartialSubstance; - - partial model PartialSubstanceInSolution "Substance properties for components, where the substance is connected with the solution" - - Interfaces.SolutionPort solution "To connect substance with solution, where is pressented" - annotation (Placement(transformation(extent={{-70,-110},{-50,-90}}), iconTransformation(extent={{-70,-110},{-50,-90}}))); - - extends PartialSubstance; - - protected - Modelica.Units.SI.AmountOfSubstance amountOfSolution - "Amount of all solution particles"; - - equation - - //aliases - temperature = solution.T; - pressure = solution.p; - electricPotential = solution.v; - amountOfSolution = solution.n; - moleFractionBasedIonicStrength = solution.I; - - end PartialSubstanceInSolution; - - partial model PartialSubstanceInSolutionWithAdditionalPorts "Substance properties for components, where the substance is connected with the solution" - - extends PartialSubstanceInSolution; - - Modelica.Units.SI.MolarFlowRate q - "Molar flow rate of the substance into the component"; - - Interfaces.SubstanceMassPort_a port_m "Substance mass fraction port" annotation (Placement(transformation(extent={{92,-110},{112,-90}}))); - - Interfaces.SubstanceMolarityPort_a port_c annotation (Placement(transformation(extent={{90,90},{110,110}}))); - - equation - //molar mass flow - q=(n_flow_in + n_flow_out + port_c.q + port_m.m_flow/stateOfMatter.molarMassOfBaseMolecule(substanceData)); - - //substance mass fraction - port_m.x_mass = solution.mj/solution.m; - port_c.c = solution.nj/solution.V; - - end PartialSubstanceInSolutionWithAdditionalPorts; - end Internal; - - model SubstanceS "Substance in solution" - extends Icons.Substance; - - - Modelica.Units.SI.Concentration c(displayUnit="mmol/l") - "Molar concentration of particles"; - - extends Internal.PartialSubstanceInSolutionWithAdditionalPorts; - - parameter Boolean use_mass_start = true "use mass_start, otherwise amountOfSubstance_start" - annotation (Evaluate=true, choices(checkBox=true), Dialog(group="Initialization")); - - parameter Modelica.Units.SI.Mass mass_start=1 - "Initial mass of the substance" - annotation (HideResult=not use_mass_start, Dialog(group="Initialization", enable=use_mass_start)); - - parameter Modelica.Units.SI.AmountOfSubstance amountOfSubstance_start=1 - "Initial amount of substance base molecules" - annotation (HideResult=use_mass_start, Dialog(group="Initialization", enable=not use_mass_start)); - - Modelica.Units.SI.Mass mass=amountOfBaseMolecules* - molarMassOfBaseMolecule "Mass"; - - parameter Boolean calculateClusteringHeat = true "Only for self clustering substances" - annotation(Evaluate=true, choices(checkBox=true), Dialog(tab = "Clustering", enable = stateOfMatter.selfClustering(substanceData))); - - protected - parameter Modelica.Units.SI.Mass m_start=if use_mass_start then mass_start else - amountOfSubstance_start*molarMassOfBaseMolecule; - - parameter Modelica.Units.SI.MolarMass molarMassOfBaseMolecule = stateOfMatter.molarMassOfBaseMolecule(substanceData); - - Modelica.Units.SI.AmountOfSubstance amountOfBaseMolecules(start= - m_start/molarMassOfBaseMolecule) - "Amount of base molecules inside all clusters in compartment"; - - Modelica.Units.SI.AmountOfSubstance amountOfFreeMolecule(start= - m_start*stateOfMatter.specificAmountOfFreeBaseMolecule( - substanceData, - T=system.T_ambient, - p=system.p_ambient)) - "Amount of free molecules not included inside any clusters in compartment"; - - Modelica.Units.SI.AmountOfSubstance amountOfParticles(start= - m_start*stateOfMatter.specificAmountOfParticles( - substanceData, - T=system.T_ambient, - p=system.p_ambient)) - "Amount of particles/clusters in compartment"; - - Modelica.Units.SI.MoleFraction SelfClustering_K=exp(-SelfClustering_dG/( - Modelica.Constants.R*solution.T)) - "Dissociation constant of hydrogen bond between base molecules"; - - Modelica.Units.SI.ChemicalPotential SelfClustering_dG= - stateOfMatter.selfClusteringBondEnthalpy(substanceData) - - solution.T * stateOfMatter.selfClusteringBondEntropy(substanceData) - "Gibbs energy of hydrogen bond between H2O molecules"; - - Modelica.Units.SI.AmountOfSubstance amountOfBonds - "Amount of hydrogen bonds between molecules in compartment"; - - Real logn(stateSelect=StateSelect.prefer, start=log(m_start/molarMassOfBaseMolecule)) - "Natural logarithm of the amount of base molecules in solution"; - - parameter Boolean EnthalpyNotUsed=false annotation ( - Evaluate=true, - HideResult=true, - choices(checkBox=true), - Dialog(tab="Advanced", group="Performance")); - - initial equation - - amountOfBaseMolecules = m_start/molarMassOfBaseMolecule; - - - equation - - n_out = amountOfFreeMolecule; - - if stateOfMatter.selfClustering(substanceData) then - - //Liquid cluster theory - equilibrium: - //x[i] = x*(K*x)^i .. mole fraction of cluster composed with i base molecules - //amountOfParticles/solution.n = x/(1-K*x); //sum(x[i]) - //amountOfBaseMolecules/solution.n = x/((1-K*x)^2); //sum(i*x[i]) - //amountOfHydrogenBonds/solution.n = x*x*K/((1-K*x)^2); //sum((i-1)*x[i]) - - amountOfParticles*(1 - SelfClustering_K*x) = amountOfFreeMolecule; - - //Calculation of "abs(amountOfBaseMolecules*(1 - SelfClustering_K*x)) = amountOfParticles": - x = ((2*SelfClustering_K+solution.n/amountOfBaseMolecules) - sqrt((4*SelfClustering_K*solution.n/amountOfBaseMolecules)+(solution.n/amountOfBaseMolecules)^2)) / (2*(SelfClustering_K^2)); - - amountOfBonds = amountOfBaseMolecules*x*SelfClustering_K; - - //TODO: may be the volume of the same number of free water molecules is different as volume of the same number of water molecules in cluster .. - //TODO: more precise calculation of other properties - - //der(enthalpy) = solution.dH + q*actualStream(port_a.h_outflow); - //enthalpy = molarEnthalpy*amountOfBaseMolecules + amountOfAdditionalBonds*bondEnthalpy; - solution.dH =if (EnthalpyNotUsed) then 0 else der(molarEnthalpy)* - amountOfBaseMolecules + q*molarEnthalpy - n_flow_out*h_out - n_flow_in*h_in + ( - if (calculateClusteringHeat) then stateOfMatter.selfClusteringBondEnthalpy( - substanceData)*der(amountOfBonds) else 0) - "heat transfer from other substances in solution [J/s]"; - - solution.Gj =amountOfBaseMolecules*u_out + amountOfBonds*SelfClustering_dG - "Gibbs energy of the substance"; - - else - - amountOfParticles = amountOfFreeMolecule; - amountOfBaseMolecules = amountOfFreeMolecule; - amountOfBonds = 0; - - //der(enthalpy) = solution.dH + q*actualStream(port_a.h_outflow); - //enthalpy = molarEnthalpy*amountOfBaseMolecules; - solution.dH = - if (EnthalpyNotUsed) then 0 - else der(molarEnthalpy)*amountOfBaseMolecules + q*molarEnthalpy - - n_flow_out*h_out - n_flow_in*h_in - "heat transfer from other substances in solution [J/s]"; - - solution.Gj = amountOfBaseMolecules*u_out "Gibbs energy of the substance [J]"; - - end if; - - //The main accumulation equation is "der(amountOfBaseMolecules)=q" - // However, the numerical solvers can handle it in form of log(n) much better. :-) - der(logn) = (q/amountOfBaseMolecules) "accumulation of amountOfBaseMolecules=exp(logn) [mol]"; - amountOfBaseMolecules = exp(logn); - - x = amountOfFreeMolecule/solution.n "mole fraction [mol/mol]"; - - c = amountOfParticles/solution.V "concentration [mol/m3]"; - - //solution flows - solution.i = Modelica.Constants.F*z*q + - Modelica.Constants.F*der(z)*amountOfBaseMolecules "change of sunstance charge [A]"; - solution.dV = molarVolume*q + der(molarVolume)*amountOfBaseMolecules "change of substance volume [m3/s]"; - - //extensive properties - solution.nj = amountOfParticles; - solution.mj = amountOfBaseMolecules*molarMassOfBaseMolecule; - solution.Vj = amountOfBaseMolecules*molarVolume; - solution.Qj = Modelica.Constants.F*amountOfBaseMolecules*z; - solution.Ij = (1/2)*(amountOfBaseMolecules*z^2); - - annotation(Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100}, - {100,100}}), graphics={Text( - extent={{-84,22},{92,64}}, - lineColor={128,0,255}, - textString="%name")}), Documentation(revisions=" -2009-2015 by Marek Matejak, Charles University, Prague, Czech Republic
-", info=" -where n is amount of the substance and x is mole fraction.
-The main class from “Chemical” package is called "Substance". It has one chemical connector, where chemical potential and molar flow is presented. An amount of solute "n" is accumulated by molar flow inside an instance of this class. In the default setting the amount of solution "n(solution)" is set to 55.6 as amount of water in one liter, so in this setting the concentration of very diluted solution in pure water at “mol/L” has the same value as the amount of substance at “mol”. But in the advanced settings the default amount of solution can be changed by parameter or using solution port to connect with solution. The molar flow at the port can be also negative, which means that the solute leaves the Substance instance.
-
The recalculation between mole fraction, molarity and molality can be written as follows:
x = n/n(solution) = b * m(solvent)/n(solution) = c * V(solution)/n(solution)
-where m(solvent) is mass of solvent, V(solution) is volume of solution, b=n/m(solvent) is molality of the substance, c=n/V(solution) is molarity of the substance.
-If the amount of solution is selected to the number of total solution moles per one kilogram of solvent then the values of x will be the same as molality.
-If the amount of solution is selected to the number of total solution moles in one liter of solution then the values of x will be the same as molarity.
-
Definition of electro-chemical potential:
where
-x .. mole fraction of the substance in the solution
-T .. temperature in Kelvins
-v .. relative eletric potential of the solution
-z .. elementary charge of the substance (like -1 for electron, +2 for Ca^2+)
-R .. gas constant
-F .. Faraday constant
-gamma .. activity coefficient
-u° .. chemical potential of pure substance
-DfG .. free Gibbs energy of formation of the substance
-DfH .. free enthalpy of formation of the substance
-DfS .. free entropy of formation of the substance
-
Be carefull, DfS is not the same as absolute entropy of the substance S° from III. thermodinamic law! It must be calculated from tabulated value of DfG(298.15 K) and DfH as DfS=(DfH - DfG)/298.15.
2009-2015 by Marek Matejak, Charles University, Prague, Czech Republic
-", info=" -Diffusion of the substance as equilibration of electro-chemical potentials.
-"), Icon(graphics={Rectangle(extent={{-100,40},{100,-40}}, lineColor={28,108,200})})); - end Process; end Components; package Sensors "Chemical sensors" @@ -5530,7 +5138,7 @@ end solution_temperature_;