| | 2137 | |
| | 2138 | model JunctionVolume |
| | 2139 | "Splitting/joining component with static balances for a dynamic control volume" |
| | 2140 | import Modelica_Fluid.Types; |
| | 2141 | import Modelica_Fluid.Types.PortFlowDirection; |
| | 2142 | outer Modelica_Fluid.System system "System properties"; |
| | 2143 | |
| | 2144 | replaceable package Medium = Modelica.Media.Interfaces.PartialMedium |
| | 2145 | "Fluid medium model" |
| | 2146 | annotation (choicesAllMatching=true); |
| | 2147 | parameter SI.Volume V "Volume"; |
| | 2148 | |
| | 2149 | // Assumptions |
| | 2150 | parameter Modelica_Fluid.Types.Dynamics dynamicsType=system.dynamicsType |
| | 2151 | "Dynamics option" |
| | 2152 | annotation(Evaluate=true, Dialog(tab = "Assumptions")); |
| | 2153 | |
| | 2154 | SI.InternalEnergy U "Internal energy"; |
| | 2155 | SI.Mass m "Total mass"; |
| | 2156 | SI.Mass[Medium.nXi] mXi "Independent masses"; |
| | 2157 | |
| | 2158 | Modelica_Fluid.Interfaces.FluidPort_a port_1( |
| | 2159 | redeclare package Medium=Medium, |
| | 2160 | m_flow(min=if (portFlowDirection_1==PortFlowDirection.Entering) then 0.0 else -Modelica.Constants.inf, |
| | 2161 | max=if (portFlowDirection_1==PortFlowDirection.Leaving) then 0.0 else Modelica.Constants.inf)) |
| | 2162 | annotation (Placement(transformation(extent={{-110,-10},{-90,10}}, |
| | 2163 | rotation=0))); |
| | 2164 | Modelica_Fluid.Interfaces.FluidPort_b port_2( |
| | 2165 | redeclare package Medium=Medium, |
| | 2166 | m_flow(min=if (portFlowDirection_2==PortFlowDirection.Entering) then 0.0 else -Modelica.Constants.inf, |
| | 2167 | max=if (portFlowDirection_2==PortFlowDirection.Leaving) then 0.0 else Modelica.Constants.inf)) |
| | 2168 | annotation (Placement(transformation(extent={{90,-10},{110,10}}, rotation= |
| | 2169 | 0))); |
| | 2170 | Modelica_Fluid.Interfaces.FluidPort_a port_3( |
| | 2171 | redeclare package Medium=Medium, |
| | 2172 | m_flow(min=if (portFlowDirection_3==PortFlowDirection.Entering) then 0.0 else -Modelica.Constants.inf, |
| | 2173 | max=if (portFlowDirection_3==PortFlowDirection.Leaving) then 0.0 else Modelica.Constants.inf)) |
| | 2174 | annotation (Placement(transformation(extent={{-10,90},{10,110}}, rotation= |
| | 2175 | 0))); |
| | 2176 | |
| | 2177 | Medium.ExtraProperty C[Medium.nC] "Trace substance mixture content"; |
| | 2178 | Medium.BaseProperties medium(preferredMediumStates=true); |
| | 2179 | |
| | 2180 | parameter Types.Init initType=system.initType "Initialization option" |
| | 2181 | annotation(Evaluate=true,Dialog(tab="Initialization")); |
| | 2182 | parameter Medium.AbsolutePressure p_start "Start value of pressure" |
| | 2183 | annotation(Dialog(tab="Initialization")); |
| | 2184 | parameter Boolean use_T_start=true |
| | 2185 | "=true, use T_start, otherwise h_start" |
| | 2186 | annotation(Dialog(tab="Initialization"),Evaluate=true); |
| | 2187 | parameter Medium.Temperature T_start= |
| | 2188 | if use_T_start then system.T_start else Medium.temperature_phX(p_start,h_start,X_start) |
| | 2189 | "Start value of temperature" |
| | 2190 | annotation(Dialog(tab="Initialization",enable=use_T_start)); |
| | 2191 | parameter Medium.SpecificEnthalpy h_start= |
| | 2192 | if use_T_start then Medium.specificEnthalpy_pTX(p_start,T_start,X_start) else Medium.h_default |
| | 2193 | "Start value of specific enthalpy" |
| | 2194 | annotation(Dialog(tab="Initialization",enable=not use_T_start)); |
| | 2195 | parameter Medium.MassFraction X_start[Medium.nX]=Medium.X_default |
| | 2196 | "Start value of mass fractions m_i/m" |
| | 2197 | annotation (Dialog(tab="Initialization",enable=Medium.nXi>0)); |
| | 2198 | |
| | 2199 | protected |
| | 2200 | parameter PortFlowDirection portFlowDirection_1=PortFlowDirection.Bidirectional |
| | 2201 | "Flow direction for port_1" |
| | 2202 | annotation(Dialog(tab="Advanced")); |
| | 2203 | parameter PortFlowDirection portFlowDirection_2=PortFlowDirection.Bidirectional |
| | 2204 | "Flow direction for port_2" |
| | 2205 | annotation(Dialog(tab="Advanced")); |
| | 2206 | parameter PortFlowDirection portFlowDirection_3=PortFlowDirection.Bidirectional |
| | 2207 | "Flow direction for port_3" |
| | 2208 | annotation(Dialog(tab="Advanced")); |
| | 2209 | |
| | 2210 | annotation (Icon(coordinateSystem( |
| | 2211 | preserveAspectRatio=true, |
| | 2212 | extent={{-100,-100},{100,100}}, |
| | 2213 | grid={1,1}), graphics={ |
| | 2214 | Rectangle( |
| | 2215 | extent={{-100,41},{100,-47}}, |
| | 2216 | lineColor={0,0,0}, |
| | 2217 | fillPattern=FillPattern.HorizontalCylinder, |
| | 2218 | fillColor={192,192,192}), |
| | 2219 | Rectangle( |
| | 2220 | extent={{-100,37},{100,-43}}, |
| | 2221 | lineColor={0,0,0}, |
| | 2222 | fillPattern=FillPattern.HorizontalCylinder, |
| | 2223 | fillColor={0,127,255}), |
| | 2224 | Rectangle( |
| | 2225 | extent={{-34,100},{34,37}}, |
| | 2226 | lineColor={0,0,0}, |
| | 2227 | fillPattern=FillPattern.VerticalCylinder, |
| | 2228 | fillColor={192,192,192}), |
| | 2229 | Rectangle( |
| | 2230 | extent={{-30,100},{30,35}}, |
| | 2231 | lineColor={0,0,0}, |
| | 2232 | fillPattern=FillPattern.VerticalCylinder, |
| | 2233 | fillColor={0,127,255}), |
| | 2234 | Ellipse( |
| | 2235 | extent={{-9,10},{11,-10}}, |
| | 2236 | lineColor={0,0,0}, |
| | 2237 | fillColor={0,0,0}, |
| | 2238 | fillPattern=FillPattern.Solid), |
| | 2239 | Text( |
| | 2240 | extent={{-150,-60},{150,-100}}, |
| | 2241 | lineColor={0,0,255}, |
| | 2242 | textString="%name")}), |
| | 2243 | Diagram(coordinateSystem( |
| | 2244 | preserveAspectRatio=false, |
| | 2245 | extent={{-100,-100},{100,100}}, |
| | 2246 | grid={1,1}), graphics)); |
| | 2247 | initial equation |
| | 2248 | // Initial conditions |
| | 2249 | if initType == Types.Init.NoInit then |
| | 2250 | // no initial equations |
| | 2251 | elseif initType == Types.Init.InitialValues then |
| | 2252 | medium.p = p_start; |
| | 2253 | medium.h = h_start; |
| | 2254 | elseif initType == Types.Init.SteadyState then |
| | 2255 | der(medium.p) = 0; |
| | 2256 | der(medium.h) = 0; |
| | 2257 | elseif initType == Types.Init.SteadyStateHydraulic then |
| | 2258 | der(medium.p) = 0; |
| | 2259 | medium.h = h_start; |
| | 2260 | else |
| | 2261 | assert(false, "Unsupported initialization option"); |
| | 2262 | end if; |
| | 2263 | |
| | 2264 | equation |
| | 2265 | // Only one connection allowed to a port to avoid unwanted ideal mixing |
| | 2266 | /* |
| | 2267 | assert(cardinality(port_1) <= 1," |
| | 2268 | port_1 of volume can at most be connected to one component. |
| | 2269 | If two or more connections are present, ideal mixing takes |
| | 2270 | place with these connections which is usually not the intention |
| | 2271 | of the modeller. |
| | 2272 | "); |
| | 2273 | assert(cardinality(port_2) <= 1," |
| | 2274 | port_2 of volume can at most be connected to one component. |
| | 2275 | If two or more connections are present, ideal mixing takes |
| | 2276 | place with these connections which is usually not the intention |
| | 2277 | of the modeller. |
| | 2278 | "); |
| | 2279 | assert(cardinality(port_3) <= 1," |
| | 2280 | port_3 of volume can at most be connected to one component. |
| | 2281 | If two or more connections are present, ideal mixing takes |
| | 2282 | place with these connections which is usually not the intention |
| | 2283 | of the modeller. |
| | 2284 | "); |
| | 2285 | */ |
| | 2286 | |
| | 2287 | // Boundary conditions |
| | 2288 | port_1.h_outflow = medium.h; |
| | 2289 | port_2.h_outflow = medium.h; |
| | 2290 | port_3.h_outflow = medium.h; |
| | 2291 | |
| | 2292 | port_1.Xi_outflow = medium.Xi; |
| | 2293 | port_2.Xi_outflow = medium.Xi; |
| | 2294 | port_3.Xi_outflow = medium.Xi; |
| | 2295 | |
| | 2296 | // Internal quantities |
| | 2297 | m = medium.d*V; |
| | 2298 | mXi = m*medium.Xi; |
| | 2299 | U = m*medium.u; |
| | 2300 | |
| | 2301 | // Mass balances |
| | 2302 | if dynamicsType < Types.Dynamics.SteadyStateMass then |
| | 2303 | der(m) = port_1.m_flow + port_2.m_flow + port_3.m_flow "Mass balance"; |
| | 2304 | der(mXi) = port_1.m_flow*actualStream(port_1.Xi_outflow) |
| | 2305 | + port_2.m_flow*actualStream(port_2.Xi_outflow) |
| | 2306 | + port_3.m_flow*actualStream(port_3.Xi_outflow) |
| | 2307 | "Component mass balances"; |
| | 2308 | else |
| | 2309 | 0 = port_1.m_flow + port_2.m_flow + port_3.m_flow "Mass balance"; |
| | 2310 | zeros(Medium.nXi) = port_1.m_flow*actualStream(port_1.Xi_outflow) |
| | 2311 | + port_2.m_flow*actualStream(port_2.Xi_outflow) |
| | 2312 | + port_3.m_flow*actualStream(port_3.Xi_outflow) |
| | 2313 | "Component mass balances"; |
| | 2314 | end if; |
| | 2315 | |
| | 2316 | /* |
| | 2317 | zeros(Medium.nC) = port_1.m_flow*actualStream(port_1.C_outflow) |
| | 2318 | + port_2.m_flow*actualStream(port_2.C_outflow) |
| | 2319 | + port_3.m_flow*actualStream(port_3.C_outflow) |
| | 2320 | "Trace substance mass balances"; |
| | 2321 | */ |
| | 2322 | |
| | 2323 | // Momentum balance (suitable for compressible media) |
| | 2324 | port_1.p = medium.p; |
| | 2325 | port_2.p = medium.p; |
| | 2326 | port_3.p = medium.p; |
| | 2327 | |
| | 2328 | // Energy balance |
| | 2329 | if dynamicsType < Types.Dynamics.SteadyState then |
| | 2330 | der(U) = port_1.m_flow*actualStream(port_1.h_outflow) |
| | 2331 | + port_2.m_flow*actualStream(port_2.h_outflow) |
| | 2332 | + port_3.m_flow*actualStream(port_3.h_outflow); |
| | 2333 | else |
| | 2334 | 0 = port_1.m_flow*actualStream(port_1.h_outflow) |
| | 2335 | + port_2.m_flow*actualStream(port_2.h_outflow) |
| | 2336 | + port_3.m_flow*actualStream(port_3.h_outflow); |
| | 2337 | end if; |
| | 2338 | end JunctionVolume; |
| | 2339 | |
| | 2340 | model GenericJunction |
| | 2341 | "Branching component with balances for a dynamic control volume" |
| | 2342 | import Modelica.Constants; |
| | 2343 | import Modelica_Fluid.Types; |
| | 2344 | import Modelica_Fluid.Types.ModelStructure; |
| | 2345 | outer Modelica_Fluid.System system "System properties"; |
| | 2346 | parameter Integer nPorts_a(min=1)=1 "Number of ports on side a"; |
| | 2347 | parameter Integer nPorts_b(min=1)=1 "Number of ports on side b"; |
| | 2348 | replaceable package Medium = Modelica.Media.Interfaces.PartialMedium |
| | 2349 | "Fluid medium model" |
| | 2350 | annotation (choicesAllMatching=true); |
| | 2351 | parameter SI.Volume V "Volume"; |
| | 2352 | parameter SI.Pressure dp_nominal "nominal (linear) pressure drop" annotation(Dialog(enable=not modelStructure==ModelStructure.avb)); |
| | 2353 | parameter SI.MassFlowRate m_flow_nominal "nominal mass flow rate" annotation(Dialog(enable=not modelStructure==ModelStructure.avb)); |
| | 2354 | |
| | 2355 | SI.InternalEnergy U "Internal energy"; |
| | 2356 | SI.Mass m "Total mass"; |
| | 2357 | SI.Mass[Medium.nXi] mXi "Independent masses"; |
| | 2358 | |
| | 2359 | Interfaces.FluidStatePorts_a[nPorts_a] ports_a( |
| | 2360 | redeclare each package Medium=Medium, |
| | 2361 | m_flow(each min=if allowFlowReversal then -Constants.inf else 0)) |
| | 2362 | "Fluid connectors a (positive design flow direction is from ports_a to ports_b)" |
| | 2363 | annotation (Placement( |
| | 2364 | transformation(extent={{-110,40},{-90,-40}}, rotation=0))); |
| | 2365 | Interfaces.FluidStatePorts_b[nPorts_b] ports_b( |
| | 2366 | redeclare each package Medium=Medium, |
| | 2367 | m_flow(each max=if allowFlowReversal then +Constants.inf else 0)) |
| | 2368 | "Fluid connectors b (positive design flow direction is from ports_a to ports_b)" |
| | 2369 | annotation (Placement( |
| | 2370 | transformation(extent={{90,40},{110,-40}}, rotation=0))); |
| | 2371 | Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort |
| | 2372 | "Thermal port" |
| | 2373 | annotation (Placement(transformation(extent={{-10,90},{10,110}}, rotation=0))); |
| | 2374 | Medium.ExtraProperty C[Medium.nC] "Trace substance mixture content"; |
| | 2375 | Medium.BaseProperties medium(T(start=T_start),p(start=p_start),h(start=h_start),X(start=X_start), preferredMediumStates=true); |
| | 2376 | |
| | 2377 | // Assumptions |
| | 2378 | parameter Boolean allowFlowReversal = system.allowFlowReversal |
| | 2379 | "allow flow reversal, false restricts to design direction (port_a -> port_b)" |
| | 2380 | annotation(Dialog(tab="Assumptions"), Evaluate=true); |
| | 2381 | parameter Modelica_Fluid.Types.Dynamics dynamicsType=system.dynamicsType |
| | 2382 | "Dynamics option" |
| | 2383 | annotation(Evaluate=true, Dialog(tab = "Assumptions")); |
| | 2384 | |
| | 2385 | // Initialization |
| | 2386 | parameter Types.Init initType=Types.Init.NoInit "Initialization option" |
| | 2387 | annotation(Evaluate=true,Dialog(tab="Initialization")); |
| | 2388 | parameter Medium.AbsolutePressure p_start "Start value of pressure" |
| | 2389 | annotation(Dialog(tab="Initialization")); |
| | 2390 | parameter Boolean use_T_start=true |
| | 2391 | "=true, use T_start, otherwise h_start" |
| | 2392 | annotation(Dialog(tab="Initialization"),Evaluate=true); |
| | 2393 | parameter Medium.Temperature T_start= |
| | 2394 | if use_T_start then system.T_start else Medium.temperature_phX(p_start,h_start,X_start) |
| | 2395 | "Start value of temperature" |
| | 2396 | annotation(Dialog(tab="Initialization",enable=use_T_start)); |
| | 2397 | parameter Medium.SpecificEnthalpy h_start= |
| | 2398 | if use_T_start then Medium.specificEnthalpy_pTX(p_start,T_start,X_start) else Medium.h_default |
| | 2399 | "Start value of specific enthalpy" |
| | 2400 | annotation(Dialog(tab="Initialization",enable=not use_T_start)); |
| | 2401 | parameter Medium.MassFraction X_start[Medium.nX]=Medium.X_default |
| | 2402 | "Start value of mass fractions m_i/m" |
| | 2403 | annotation (Dialog(tab="Initialization",enable=Medium.nXi>0)); |
| | 2404 | |
| | 2405 | parameter ModelStructure modelStructure=ModelStructure.avb annotation(Evaluate=true); |
| | 2406 | |
| | 2407 | Medium.EnthalpyFlowRate ports_a_H_flow[nPorts_a]; |
| | 2408 | Medium.EnthalpyFlowRate ports_b_H_flow[nPorts_b]; |
| | 2409 | Medium.MassFlowRate ports_a_mXi_flow[nPorts_a,Medium.nXi]; |
| | 2410 | Medium.MassFlowRate ports_b_mXi_flow[nPorts_b,Medium.nXi]; |
| | 2411 | Medium.ExtraPropertyFlowRate ports_a_mC_flow[nPorts_a,Medium.nC]; |
| | 2412 | Medium.ExtraPropertyFlowRate ports_b_mC_flow[nPorts_b,Medium.nC]; |
| | 2413 | |
| | 2414 | annotation (Icon(coordinateSystem( |
| | 2415 | preserveAspectRatio=true, |
| | 2416 | extent={{-100,-100},{100,100}}, |
| | 2417 | grid={1,1}), graphics={ |
| | 2418 | Ellipse( |
| | 2419 | extent={{-19,0},{1,-20}}, |
| | 2420 | lineColor={0,0,0}, |
| | 2421 | fillColor={0,0,0}, |
| | 2422 | fillPattern=FillPattern.Solid), |
| | 2423 | Ellipse( |
| | 2424 | extent={{-100,100},{100,-100}}, |
| | 2425 | lineColor={0,0,0}, |
| | 2426 | fillPattern=FillPattern.Sphere, |
| | 2427 | fillColor={0,128,255}), |
| | 2428 | Ellipse( |
| | 2429 | extent={{-9,10},{11,-10}}, |
| | 2430 | lineColor={0,0,0}, |
| | 2431 | fillColor={0,0,0}, |
| | 2432 | fillPattern=FillPattern.Solid), |
| | 2433 | Text( |
| | 2434 | extent={{-150,150},{150,110}}, |
| | 2435 | lineColor={0,0,255}, |
| | 2436 | fillPattern=FillPattern.HorizontalCylinder, |
| | 2437 | fillColor={0,127,255}, |
| | 2438 | textString="%name")}), |
| | 2439 | Diagram(coordinateSystem( |
| | 2440 | preserveAspectRatio=false, |
| | 2441 | extent={{-100,-100},{100,100}}, |
| | 2442 | grid={1,1}), graphics)); |
| | 2443 | |
| | 2444 | initial equation |
| | 2445 | // Initial conditions |
| | 2446 | if initType == Types.Init.NoInit then |
| | 2447 | // no initial equations |
| | 2448 | elseif initType == Types.Init.InitialValues then |
| | 2449 | medium.p = p_start; |
| | 2450 | medium.h = h_start; |
| | 2451 | elseif initType == Types.Init.SteadyState then |
| | 2452 | der(medium.p) = 0; |
| | 2453 | der(medium.h) = 0; |
| | 2454 | elseif initType == Types.Init.SteadyStateHydraulic then |
| | 2455 | der(medium.p) = 0; |
| | 2456 | medium.h = h_start; |
| | 2457 | else |
| | 2458 | assert(false, "Unsupported initialization option"); |
| | 2459 | end if; |
| | 2460 | |
| | 2461 | equation |
| | 2462 | // Only one connection allowed to a port to avoid unwanted ideal mixing |
| | 2463 | /* |
| | 2464 | for i in 1:nPorts_a loop |
| | 2465 | assert(cardinality(ports_a[i]) <= 1," |
| | 2466 | ports_a[" + String(i) + "] of volume can at most be connected to one component. |
| | 2467 | If two or more connections are present, ideal mixing takes |
| | 2468 | place with these connections which is usually not the intention |
| | 2469 | of the modeller. |
| | 2470 | "); |
| | 2471 | end for; |
| | 2472 | |
| | 2473 | for i in 1:nPorts_b loop |
| | 2474 | assert(cardinality(ports_b[i]) <= 1," |
| | 2475 | ports_a[" + String(i) + "] of volume can at most be connected to one component. |
| | 2476 | If two or more connections are present, ideal mixing takes |
| | 2477 | place with these connections which is usually not the intention |
| | 2478 | of the modeller. |
| | 2479 | "); |
| | 2480 | end for; |
| | 2481 | */ |
| | 2482 | |
| | 2483 | heatPort.T = medium.T; |
| | 2484 | |
| | 2485 | if dynamicsType < Types.Dynamics.SteadyStateMass then |
| | 2486 | sum(ports_a.m_flow)+sum(ports_b.m_flow) = der(m) "Mass balance"; |
| | 2487 | |
| | 2488 | for i in 1:Medium.nXi loop |
| | 2489 | sum(ports_a_mXi_flow[:,i])+sum(ports_b_mXi_flow[:,i]) = der(mXi[i]) |
| | 2490 | "Substance mass balance"; |
| | 2491 | end for; |
| | 2492 | else |
| | 2493 | sum(ports_a.m_flow)+sum(ports_b.m_flow) = 0 "Mass balance"; |
| | 2494 | |
| | 2495 | for i in 1:Medium.nXi loop |