| | 174 | model DistributedPipe "Distributed pipe model" |
| | 175 | |
| | 176 | import Modelica_Fluid.Types; |
| | 177 | import Modelica_Fluid.Types.ModelStructure; |
| | 178 | |
| | 179 | // distributed volume model |
| | 180 | extends Modelica_Fluid.Volumes.BaseClasses.PartialDistributedVolume( |
| | 181 | final n = nNodes, |
| | 182 | Qs_flow=heatTransfer.Q_flow); |
| | 183 | |
| | 184 | // extending PartialPipe |
| | 185 | extends Modelica_Fluid.Pipes.BaseClasses.PartialPipe( |
| | 186 | final port_a_exposesState = (modelStructure == ModelStructure.av_b) or (modelStructure == ModelStructure.avb), |
| | 187 | final port_b_exposesState = (modelStructure == ModelStructure.a_vb) or (modelStructure == ModelStructure.avb)); |
| | 188 | |
| | 189 | // Discretization |
| | 190 | parameter Integer nNodes(min=1)=1 "Number of discrete flow volumes"; |
| | 191 | |
| | 192 | parameter Types.ModelStructure modelStructure=Types.ModelStructure.a_v_b |
| | 193 | "Determines whether flow or volume models are present at the ports" annotation(Evaluate=true); |
| | 194 | |
| | 195 | parameter Boolean lumpedPressure=false |
| | 196 | "=true to lump all pressure nodes into one" |
| | 197 | annotation(Dialog(tab="Advanced", group="Pressure drop"),Evaluate=true); |
| | 198 | final parameter Integer iLumped=integer(n/2)+1 |
| | 199 | "Index of control volume that representative state" annotation(Evaluate=true); |
| | 200 | final parameter Integer nFlowsLumped=if modelStructure==Types.ModelStructure.a_v_b then 2 else if (modelStructure==Types.ModelStructure.a_vb or modelStructure==Types.ModelStructure.av_b) then 1 else 0; |
| | 201 | final parameter Integer nFlowsDistributed=if modelStructure==Types.ModelStructure.a_v_b then n+1 else if (modelStructure==Types.ModelStructure.a_vb or modelStructure==Types.ModelStructure.av_b) then n else n-1; |
| | 202 | final parameter Integer nFlows=if lumpedPressure then nFlowsLumped else nFlowsDistributed; |
| | 203 | |
| | 204 | // Advanced model options |
| | 205 | parameter Boolean use_approxPortProperties=false |
| | 206 | "=true, port properties for pressure drop correlation are taken from neighboring control volume" |
| | 207 | annotation(Dialog(tab="Advanced", group="Pressure drop"),Evaluate=true); |
| | 208 | Medium.ThermodynamicState state_a "state defined by volume outside port_a"; |
| | 209 | Medium.ThermodynamicState state_b "state defined by volume outside port_b"; |
| | 210 | Medium.ThermodynamicState[nFlows+1] flowState |
| | 211 | "state vector for pressureDrop model"; |
| | 212 | |
| | 213 | replaceable PressureDrop pressureDrop( |
| | 214 | redeclare final package Medium = Medium, |
| | 215 | final n=nFlows, |
| | 216 | state=flowState, |
| | 217 | final allowFlowReversal=allowFlowReversal, |
| | 218 | final p_a_start=p_a_start, |
| | 219 | final p_b_start=p_b_start, |
| | 220 | final m_flow_start=m_flow_start, |
| | 221 | final roughness=roughness, |
| | 222 | diameter=4*crossArea/perimeter, |
| | 223 | final length=length, |
| | 224 | final height_ab=height_ab, |
| | 225 | final g=system.g) "Edit pressure drop parameters" |
| | 226 | annotation (editButton=true,Placement(transformation(extent={{-77,-57},{77, |
| | 227 | -23}}, |
| | 228 | rotation=0))); |
| | 229 | |
| | 230 | // Flow quantities |
| | 231 | Medium.MassFlowRate[n+1] m_flow(each min=if allowFlowReversal then -Modelica.Constants.inf else |
| | 232 | 0, each start=m_flow_start) |
| | 233 | "Mass flow rates of fluid across segment boundaries"; |
| | 234 | Medium.MassFlowRate[n+1, Medium.nXi] mXi_flow |
| | 235 | "Independent mass flow rates across segment boundaries"; |
| | 236 | Medium.EnthalpyFlowRate[n+1] H_flow |
| | 237 | "Enthalpy flow rates of fluid across segment boundaries"; |
| | 238 | |
| | 239 | // Wall heat transfer |
| | 240 | Interfaces.HeatPorts_a[nNodes] heatPorts |
| | 241 | annotation (Placement(transformation(extent={{-10,44},{10,64}}), iconTransformation(extent={{-30,44},{32,60}}))); |
| | 242 | |
| | 243 | replaceable HeatTransfer heatTransfer( |
| | 244 | redeclare each final package Medium = Medium, |
| | 245 | final n=n, |
| | 246 | diameter=4*crossArea/perimeter, |
| | 247 | area=perimeter*length, |
| | 248 | final crossArea=crossArea, |
| | 249 | final length=length, |
| | 250 | state=medium.state, |
| | 251 | m_flow = 0.5*(m_flow[1:n]+m_flow[2:n+1])) "Edit heat transfer parameters" |
| | 252 | annotation (editButton=true, Placement(transformation(extent={{-20,-5},{20,35}}, rotation=0))); |
| | 253 | |
| | 254 | equation |
| | 255 | // Only one connection allowed to a port to avoid unwanted ideal mixing |
| | 256 | assert(cardinality(port_a) <= 1 or (modelStructure == ModelStructure.a_vb) or (modelStructure == ModelStructure.a_v_b)," |
| | 257 | port_a exposing volume with selected modelStructure shall at most be connected to one component. |
| | 258 | If two or more connections are present, ideal mixing takes |
| | 259 | place with these connections which is usually not the intention |
| | 260 | of the modeller. Use a Junctions.MultiPort. |
| | 261 | "); |
| | 262 | assert(cardinality(port_b) <= 1 or (modelStructure == ModelStructure.av_b) or (modelStructure == ModelStructure.a_v_b)," |
| | 263 | port_b exposing volume with selected modelStructure shall at most be connected to one component. |
| | 264 | If two or more connections are present, ideal mixing takes |
| | 265 | place with these connections which is usually not the intention |
| | 266 | of the modeller. Use a Junctions.MultiPort. |
| | 267 | "); |
| | 268 | |
| | 269 | // Source/sink terms for mass and energy balances |
| | 270 | fluidVolume=fill(V/nNodes, n); |
| | 271 | Ws_flow=zeros(n); |
| | 272 | for i in 1:n loop |
| | 273 | ms_flow[i] = m_flow[i] - m_flow[i + 1]; |
| | 274 | msXi_flow[i, :] = mXi_flow[i, :] - mXi_flow[i + 1, :]; |
| | 275 | end for; |
| | 276 | for i in 1:n loop |
| | 277 | Hs_flow[i] = H_flow[i] - H_flow[i + 1]; |
| | 278 | end for; |
| | 279 | |
| | 280 | // Distributed flow quantities, upwind discretization |
| | 281 | for i in 2:n loop |
| | 282 | H_flow[i] = semiLinear(m_flow[i], medium[i - 1].h, medium[i].h); |
| | 283 | mXi_flow[i, :] = semiLinear(m_flow[i], medium[i - 1].Xi, medium[i].Xi); |
| | 284 | end for; |
| | 285 | H_flow[1] = semiLinear(port_a.m_flow, inStream(port_a.h_outflow), medium[1].h); |
| | 286 | H_flow[n + 1] = -semiLinear(port_b.m_flow, inStream(port_b.h_outflow), medium[n].h); |
| | 287 | mXi_flow[1, :] = semiLinear(port_a.m_flow, inStream(port_a.Xi_outflow), medium[1].Xi); |
| | 288 | mXi_flow[n + 1, :] = -semiLinear(port_b.m_flow, inStream(port_b.Xi_outflow), medium[n].Xi); |
| | 289 | |
| | 290 | // Boundary conditions |
| | 291 | port_a.h_outflow = medium[1].h; |
| | 292 | port_b.h_outflow = medium[nNodes].h; |
| | 293 | port_a.m_flow = m_flow[1]; |
| | 294 | port_b.m_flow = -m_flow[n + 1]; |
| | 295 | port_a.C_outflow = inStream(port_b.C_outflow); |
| | 296 | port_b.C_outflow = inStream(port_a.C_outflow); |
| | 297 | |
| | 298 | if use_approxPortProperties and n > 0 then |
| | 299 | state_a = Medium.setState_phX(port_a.p, medium[1].h, medium[1].Xi); |
| | 300 | state_b = Medium.setState_phX(port_b.p, medium[n].h, medium[n].Xi); |
| | 301 | else |
| | 302 | state_a = Medium.setState_phX(port_a.p, inStream(port_a.h_outflow), inStream(port_a.Xi_outflow)); |
| | 303 | state_b = Medium.setState_phX(port_a.p, inStream(port_b.h_outflow), inStream(port_b.Xi_outflow)); |
| | 304 | end if; |
| | 305 | |
| | 306 | if lumpedPressure then |
| | 307 | fill(medium[1].p, n-1) = medium[2:n].p; |
| | 308 | if modelStructure == ModelStructure.a_v_b then |
| | 309 | flowState[1] = state_a; |
| | 310 | flowState[2] = medium[iLumped].state; |
| | 311 | flowState[3] = state_b; |
| | 312 | elseif modelStructure == ModelStructure.av_b then |
| | 313 | flowState[1] = medium[iLumped].state; |
| | 314 | flowState[2] = state_b; |
| | 315 | elseif modelStructure == ModelStructure.a_vb then |
| | 316 | flowState[1] = state_a; |
| | 317 | flowState[2] = medium[iLumped].state; |
| | 318 | else // avb |
| | 319 | flowState[1] = medium[iLumped].state; |
| | 320 | end if; |
| | 321 | m_flow[1] = pressureDrop.m_flow[1]; |
| | 322 | m_flow[n+1] = pressureDrop.m_flow[nFlows]; |
| | 323 | else |
| | 324 | if modelStructure == ModelStructure.a_v_b then |
| | 325 | flowState[1] = state_a; |
| | 326 | flowState[2:n+1] = medium[1:n].state; |
| | 327 | flowState[n+2] = state_b; |
| | 328 | //m_flow = pressureDrop.m_flow; |
| | 329 | for i in 1:n+1 loop |
| | 330 | m_flow[i] = pressureDrop.m_flow[i]; |
| | 331 | end for; |
| | 332 | elseif modelStructure == ModelStructure.av_b then |
| | 333 | flowState[1:n] = medium[1:n].state; |
| | 334 | flowState[n+1] = state_b; |
| | 335 | //m_flow[2:n+1] = pressureDrop.m_flow; |
| | 336 | for i in 2:n+1 loop |
| | 337 | m_flow[i] = pressureDrop.m_flow[i-1]; |
| | 338 | end for; |
| | 339 | port_a.p = medium[1].p; |
| | 340 | elseif modelStructure == ModelStructure.a_vb then |
| | 341 | flowState[1] = state_a; |
| | 342 | flowState[2:n+1] = medium[1:n].state; |
| | 343 | //m_flow[1:n] = pressureDrop.m_flow; |
| | 344 | for i in 1:n loop |
| | 345 | m_flow[i] = pressureDrop.m_flow[i]; |
| | 346 | end for; |
| | 347 | port_b.p = medium[n].p; |
| | 348 | else // avb |
| | 349 | flowState[1:n] = medium[1:n].state; |
| | 350 | //m_flow[2:n] = pressureDrop.m_flow[1:n-1]; |
| | 351 | for i in 2:n loop |
| | 352 | m_flow[i] = pressureDrop.m_flow[i-1]; |
| | 353 | end for; |
| | 354 | port_a.p = medium[1].p; |
| | 355 | port_b.p = medium[n].p; |
| | 356 | end if; |
| | 357 | end if; |
| | 358 | |
| | 359 | connect(heatPorts, heatTransfer.wallHeatPort) |
| | 360 | annotation (Line(points={{0,54},{0,29}}, color={191,0,0})); |
| | 361 | |
| | 362 | annotation (defaultComponentName="pipe", |
| | 363 | Icon(coordinateSystem(preserveAspectRatio=true, extent={{-100,-100},{100,100}}, |
| | 364 | grid={1,1}), graphics={ |
| | 365 | Ellipse( |
| | 366 | extent={{-72,10},{-52,-10}}, |
| | 367 | lineColor={0,0,0}, |
| | 368 | fillColor={0,0,0}, |
| | 369 | fillPattern=FillPattern.Solid), |
| | 370 | Ellipse( |
| | 371 | extent={{-30,10},{-10,-10}}, |
| | 372 | lineColor={0,0,0}, |
| | 373 | fillColor={0,0,0}, |
| | 374 | fillPattern=FillPattern.Solid), |
| | 375 | Ellipse( |
| | 376 | extent={{10,10},{30,-10}}, |
| | 377 | lineColor={0,0,0}, |
| | 378 | fillColor={0,0,0}, |
| | 379 | fillPattern=FillPattern.Solid), |
| | 380 | Ellipse( |
| | 381 | extent={{50,10},{70,-10}}, |
| | 382 | lineColor={0,0,0}, |
| | 383 | fillColor={0,0,0}, |
| | 384 | fillPattern=FillPattern.Solid)}), |
| | 385 | Diagram(coordinateSystem(preserveAspectRatio=true, extent={{-100,-100},{100, |
| | 386 | 100}}, |
| | 387 | grid={1,1}), |
| | 388 | graphics), |
| | 389 | Documentation(info="<html> |
| | 390 | <p>Distributed pipe model based on <a href=\"Modelica:Modelica_Fluid.Pipes.BaseClasses.PartialPipe\">PartialPipe</a>. The total volume is a parameter. Mass and Energy balance are inherited from <a href=\"Modelica:Modelica_Fluid.Volumes.BaseClasses.PartialDistributedVolume\">PartialDistributedVolume</a>. |
| | 391 | The additional component <b><tt>HeatTransfer</tt></b> specifies the source term <tt>Qs_flow</tt> in the energy balance. The default component uses a constant coefficient of heat transfer to model convective heat transfer between segment boundary (<tt>heatPorts</tt>) and the bulk flow. |
| | 392 | The <tt>HeatTransfer</tt> model is replaceable and can be exchanged with any model extended from <a href=\"Modelica:Modelica_Fluid.Pipes.BaseClasses.HeatTransfer.PartialPipeHeatTransfer\">PartialPipeHeatTransfer</a>.</p> |
| | 393 | <p>Pressure drop correlations (algebraic and possibly non-linear flow model) correlate the pressure in the first control volume with the pressure in port_a and the pressures of port_b and the nth control volume, respectively.</p> |
| | 394 | <p><b>Momentum balance</b></p> |
| | 395 | <p>The momentum balance is determined by the replaceable <b><tt>PressureDrop</tt></b> component. |
| | 396 | The default setting is steady-state <a href=\"Modelica:Modelica_Fluid.Pipes.BaseClasses.PressureDrop.QuadraticTurbulentFlow\">QuadraticTurbulentFlow</a>. |
| | 397 | The momentum balances are formed across the segment boundaries (staggered grid). The default symmetric model is characterized by half a momentum balance on each end of the flow model resulting in a total of n-1 full and 2 half momentum balances. Connecting two pipes therefore results in an algebraic pressure at the ports. Specifying a good start value for the port pressure is essential in order to solve large systems. Non-symmetric variations are obtained by chosing a different value for the parameter <tt><b>modelStructure</b></tt>. Options include: |
| | 398 | <ul> |
| | 399 | <li><tt>a_v_b</tt>: default setting with two half momentum balances</li> |
| | 400 | <li><tt>av_b</tt>: full momentum balance between nth volume and <tt>port_b</tt>, potential pressure state at <tt>port_a</tt></li> |
| | 401 | <li><tt>a_vb</tt>: full momentum balance between first volume and <tt>port_a</tt>, potential pressure state at <tt>port_b</tt></li> |
| | 402 | <li><tt>avb</tt>: nNodes-1 momentum balances between first and nth volume, potential pressure states at both ports. It's use should be avoided, since not the entire pipe length is taken into account. |
| | 403 | </ul></p> |
| | 404 | |
| | 405 | <p>The term <tt>dp</tt> contains |
| | 406 | <ul> |
| | 407 | <li>pressure drop due to friction and other dissipative losses</li> |
| | 408 | <li>gravity effects for non-horizontal pipes</li> |
| | 409 | </ul> |
| | 410 | It does not model changes in pressure resulting from significant variation of flow velocity along the flow path (with the assumption of a constant cross sectional area it must result from fluid density changes, such as in two-phase flow). |
| | 411 | |
| | 412 | When connecting two components, e.g. two pipes, the momentum balance across the connection point reduces to</p> |
| | 413 | <pre>pipe1.port_b.p = pipe2.port_a.p</pre> |
| | 414 | <p>This is only true if the flow velocity remains the same on each side of the connection. For any significant change in diameter (and if the resulting effects, such as change in kinetic energy, cannot be neglected) an adapter component should be used. This also allows for taking into account friction losses with respect to the actual geometry of the connection point.</p> |
| | 415 | |
| | 416 | </html>", |
| | 417 | revisions="<html> |
| | 418 | <ul> |
| | 419 | <li><i>4 Dec 2008</i> |
| | 420 | by Rüdiger Franke:<br> |
| | 421 | Derived model from original DistributedPipe models</li> |
| | 422 | <li><i>04 Mar 2006</i> |
| | 423 | by Katrin Prölß:<br> |
| | 424 | Model added to the Fluid library</li> |
| | 425 | </ul> |
| | 426 | </html>")); |
| | 427 | |
| | 428 | end DistributedPipe; |