SEFluidCompartment.hxx
1/* Distributed under the Apache License, Version 2.0.
2 See accompanying NOTICE file for details.*/
3
4#include "cdm/properties/SEScalarVolumePerTime.h"
5#include "cdm/properties/SEScalarPressure.h"
6#include "cdm/properties/SEScalarVolume.h"
7#include "cdm/properties/SERunningAverage.h"
8
9template<FLUID_COMPARTMENT_TEMPLATE>
10SEFluidCompartment<FLUID_COMPARTMENT_TYPES>::SEFluidCompartment(const std::string& name, Logger* logger) : SECompartment(name, logger), m_Nodes(logger)
11{
12 m_SampleFlow = false;
13 m_InFlow = nullptr;
14 m_OutFlow = nullptr;
15 m_AverageInFlow = nullptr;
16 m_AverageOutFlow = nullptr;
17 m_AverageInFlow_mL_Per_s = nullptr;
18 m_AverageOutFlow_mL_Per_s = nullptr;
19 m_Pressure = nullptr;
20 m_Volume = nullptr;
21}
22template<FLUID_COMPARTMENT_TEMPLATE>
24{
25 Clear();
26}
27
28template<FLUID_COMPARTMENT_TEMPLATE>
30{
32 m_SampleFlow = false;
33 SAFE_DELETE(m_InFlow);
34 SAFE_DELETE(m_OutFlow);
35 SAFE_DELETE(m_AverageInFlow);
36 SAFE_DELETE(m_AverageOutFlow);
37 SAFE_DELETE(m_AverageInFlow_mL_Per_s);
38 SAFE_DELETE(m_AverageOutFlow_mL_Per_s);
39 SAFE_DELETE(m_Pressure);
40 SAFE_DELETE(m_Volume);
41 m_Links.clear();
42 m_FluidChildren.clear();
43 DELETE_VECTOR(m_SubstanceQuantities);
44 m_Nodes.Clear();
45}
46
47template<FLUID_COMPARTMENT_TEMPLATE>
49{
50 if (name.compare("InFlow") == 0)
51 return &GetInFlow();
52 if (name.compare("OutFlow") == 0)
53 return &GetOutFlow();
54 if (name.compare("AverageInFlow") == 0)
55 return &GetAverageInFlow();
56 if (name.compare("AverageOutFlow") == 0)
57 return &GetAverageOutFlow();
58 if (name.compare("Pressure") == 0)
59 return &GetPressure();
60 if (name.compare("Volume") == 0)
61 return &GetVolume();
62 return nullptr;
63}
64
65template<FLUID_COMPARTMENT_TEMPLATE>
67{
68 if (HasChildren())
69 Fatal("You cannot map nodes to compartments with children.");
70 else
71 m_Nodes.MapNode(node);
72}
73
74template<FLUID_COMPARTMENT_TEMPLATE>
76{
77 if (m_SampleFlow)
78 {
79 m_AverageInFlow_mL_Per_s->Sample(GetInFlow(VolumePerTimeUnit::mL_Per_s));
80 m_AverageOutFlow_mL_Per_s->Sample(GetOutFlow(VolumePerTimeUnit::mL_Per_s));
81 if (StartCycle)
82 {
83 m_AverageInFlow->SetValue(m_AverageInFlow_mL_Per_s->Value(), VolumePerTimeUnit::mL_Per_s);
84 m_AverageOutFlow->SetValue(m_AverageOutFlow_mL_Per_s->Value(), VolumePerTimeUnit::mL_Per_s);
85 m_AverageInFlow_mL_Per_s->Invalidate();
86 m_AverageOutFlow_mL_Per_s->Invalidate();
87 }
88 }
89}
90
91template<FLUID_COMPARTMENT_TEMPLATE>
93{
94 m_SampleFlow = true;
95 GetAverageInFlow();
96 GetAverageOutFlow();
97}
98
99template<FLUID_COMPARTMENT_TEMPLATE>
101{
102 if (m_Links.empty())
103 return false;
104 for (auto* link : m_Links)
105 if (link->HasFlow())
106 return true;
107 return false;
108}
109template<FLUID_COMPARTMENT_TEMPLATE>
111{
112 if (m_InFlow == nullptr)
113 m_InFlow = new SEScalarVolumePerTime();
114 m_InFlow->SetReadOnly(false);
115 if (m_Links.empty())
116 m_InFlow->Invalidate();
117 else
118 m_InFlow->SetValue(CalculateInFlow_mL_Per_s(), VolumePerTimeUnit::mL_Per_s);
119 m_InFlow->SetReadOnly(true);
120 return *m_InFlow;
121}
122template<FLUID_COMPARTMENT_TEMPLATE>
124{
125 if (m_Links.empty())
126 return SEScalar::dNaN();
127 return Convert(CalculateInFlow_mL_Per_s(), VolumePerTimeUnit::mL_Per_s, unit);
128}
129
130template<FLUID_COMPARTMENT_TEMPLATE>
132{
133 return m_AverageInFlow == nullptr ? false : m_AverageInFlow->IsValid();
134}
135template<FLUID_COMPARTMENT_TEMPLATE>
137{
138 if (m_AverageInFlow == nullptr)
139 {
140 m_AverageInFlow = new SEScalarVolumePerTime();
141 m_AverageInFlow_mL_Per_s = new SERunningAverage();
142 }
143 return *m_AverageInFlow;
144}
145template<FLUID_COMPARTMENT_TEMPLATE>
147{
148 if (m_AverageInFlow == nullptr)
149 return SEScalar::dNaN();
150 return m_AverageInFlow->GetValue(unit);
151}
152
153template<FLUID_COMPARTMENT_TEMPLATE>
155{
156 if (m_Links.empty())
157 return false;
158 for (auto* link : m_Links)
159 if (link->HasFlow())
160 return true;
161 return false;
162}
163template<FLUID_COMPARTMENT_TEMPLATE>
165{
166 if (m_OutFlow == nullptr)
167 m_OutFlow = new SEScalarVolumePerTime();
168 m_OutFlow->SetReadOnly(false);
169 if (m_Links.empty())
170 m_OutFlow->Invalidate();
171 else
172 m_OutFlow->SetValue(CalculateOutFlow_mL_Per_s(), VolumePerTimeUnit::mL_Per_s);
173 m_OutFlow->SetReadOnly(true);
174 return *m_OutFlow;
175}
176template<FLUID_COMPARTMENT_TEMPLATE>
178{
179 if (m_Links.empty())
180 return SEScalar::dNaN();
181 return Convert(CalculateOutFlow_mL_Per_s(), VolumePerTimeUnit::mL_Per_s, unit);
182}
183
184template<FLUID_COMPARTMENT_TEMPLATE>
186{
187 return m_AverageOutFlow == nullptr ? false : m_AverageOutFlow->IsValid();
188}
189template<FLUID_COMPARTMENT_TEMPLATE>
191{
192 if (m_AverageOutFlow == nullptr)
193 {
194 m_AverageOutFlow = new SEScalarVolumePerTime();
195 m_AverageOutFlow_mL_Per_s = new SERunningAverage();
196 }
197 return *m_AverageOutFlow;
198}
199template<FLUID_COMPARTMENT_TEMPLATE>
201{
202 if (m_AverageOutFlow == nullptr)
203 return SEScalar::dNaN();
204 return m_AverageOutFlow->GetValue(unit);
205}
206
207template<FLUID_COMPARTMENT_TEMPLATE>
209{
210 double flow_mL_Per_s = 0;
211
213 for (auto* link : m_IncomingLinks)
214 {
215 // Positive flow on an incoming path, is flow into the compartment
216 f = &link->GetFlow();
217 if (f->IsPositive() || f->IsZero())
218 flow_mL_Per_s += f->GetValue(VolumePerTimeUnit::mL_Per_s);
219 }
220 for (auto* link : m_OutgoingLinks)
221 {// Negative flow on an outgoing path, is flow into the compartment
222 f = &link->GetFlow();
223 if (f->IsNegative() || f->IsZero())
224 flow_mL_Per_s += -f->GetValue(VolumePerTimeUnit::mL_Per_s);
225
226 }
227 if (flow_mL_Per_s < 0)
228 flow_mL_Per_s = 0;// This number is something like x.e-12, which we treat as 0
229 return flow_mL_Per_s;
230}
231
232template<FLUID_COMPARTMENT_TEMPLATE>
234{
235 double flow_mL_Per_s = 0;
236
238 for (auto* link : m_IncomingLinks)
239 {
240 // Negative flow on an incoming path, is flow out of the compartment
241 f = &link->GetFlow();
242 if (f->IsNegative() || f->IsZero())
243 flow_mL_Per_s += -f->GetValue(VolumePerTimeUnit::mL_Per_s);
244 }
245 for (auto* link : m_OutgoingLinks)
246 {// Positive flow on an outgoing path, is flow out of the compartment
247 f = &link->GetFlow();
248 if (f->IsPositive() || f->IsZero())
249 flow_mL_Per_s += f->GetValue(VolumePerTimeUnit::mL_Per_s);
250 }
251 if (flow_mL_Per_s < 0)
252 flow_mL_Per_s = 0;// This number is something like x.e-12, which we treat as 0
253 return flow_mL_Per_s;
254}
255
256template<FLUID_COMPARTMENT_TEMPLATE>
258{
259 if (m_Nodes.HasMapping())
260 return m_Nodes.HasPotential();
261 if (!m_FluidChildren.empty())
262 {
263 for (auto* child : m_FluidChildren)
264 if (child->HasPressure())
265 return true;
266 return false;
267 }
268 return m_Pressure == nullptr ? false : m_Pressure->IsValid();
269}
270template<FLUID_COMPARTMENT_TEMPLATE>
272{
273 if (m_Nodes.HasMapping())
274 return m_Nodes.GetPotential();
275 if (m_Pressure == nullptr)
276 m_Pressure = new SEScalarPressure();
277 if (!m_FluidChildren.empty())
278 {
279 m_Pressure->SetReadOnly(false);
280 m_Pressure->Invalidate();
281 const PressureUnit* pUnit = nullptr;
282 for (SEFluidCompartment* child : m_FluidChildren)
283 {
284 if (child->HasPressure())
285 {
286 pUnit = child->GetPressure().GetUnit();
287 break;
288 }
289 }
290 if(pUnit!=nullptr)
291 m_Pressure->SetValue(GetPressure(*pUnit),*pUnit);
292 m_Pressure->SetReadOnly(true);
293 }
294 return *m_Pressure;
295}
296template<FLUID_COMPARTMENT_TEMPLATE>
298{
299 if (!HasPressure())
300 return SEScalar::dNaN();
301 if (m_Nodes.HasMapping())
302 return m_Nodes.GetPotential(unit);
303 if (!m_FluidChildren.empty())
304 {
305 double Pressure = 0;
306 if (HasVolume())
307 {
308 double totalVolume_mL = GetVolume(VolumeUnit::mL);
309 for (SEFluidCompartment* child : m_FluidChildren)
310 {
311 if (child->HasPressure() && child->HasVolume())
312 {
313 Pressure += child->GetPressure(unit) * (child->GetVolume(VolumeUnit::mL) / totalVolume_mL);
314 }
315 }
316 return Pressure;
317 }
318 else
319 {
320 int numHas = 0;
321 for (SEFluidCompartment* child : m_FluidChildren)
322 {
323 if (child->HasPressure())
324 {
325 numHas++;
326 Pressure += child->GetPressure(unit);
327 }
328 Pressure /= numHas;
329 }
330 return Pressure;
331 }
332 }
333 if (m_Pressure == nullptr)
334 return SEScalar::dNaN();
335 return m_Pressure->GetValue(unit);
336}
337
338template<FLUID_COMPARTMENT_TEMPLATE>
340{
341 if (m_Nodes.HasMapping())
342 return m_Nodes.HasQuantity();
343 if (!m_FluidChildren.empty())
344 {
345 for (auto* child : m_FluidChildren)
346 if (child->HasVolume())
347 return true;
348 return false;
349 }
350 return m_Volume == nullptr ? false : m_Volume->IsValid();
351}
352template<FLUID_COMPARTMENT_TEMPLATE>
354{
355 if (m_Nodes.HasMapping())
356 return m_Nodes.GetQuantity();
357 if (m_Volume == nullptr)
358 m_Volume = new SEScalarVolume();
359 if (!m_FluidChildren.empty())
360 {
361 m_Volume->SetReadOnly(false);
362 m_Volume->Invalidate();
363 for (SEFluidCompartment* child : m_FluidChildren)
364 if (child->HasVolume())
365 m_Volume->Increment(child->GetVolume());
366 m_Volume->SetReadOnly(true);
367 }
368 return *m_Volume;
369}
370template<FLUID_COMPARTMENT_TEMPLATE>
372{
373 if (m_Nodes.HasMapping())
374 return m_Nodes.GetQuantity(unit);
375 if (!m_FluidChildren.empty())
376 {
377 double volume = 0;
378 for (SEFluidCompartment* child : m_FluidChildren)
379 if (child->HasVolume())
380 volume += child->GetVolume(unit);
381 return volume;
382 }
383 if (m_Volume == nullptr)
384 return SEScalar::dNaN();
385 return m_Volume->GetValue(unit);
386}
387
388template<FLUID_COMPARTMENT_TEMPLATE>
390{
391 return !m_SubstanceQuantities.empty();
392}
393template<FLUID_COMPARTMENT_TEMPLATE>
395{
396 for (SubstanceQuantityType* sq : m_SubstanceQuantities)
397 {
398 if (&sq->GetSubstance() == &substance)
399 return true;
400 }
401 return false;
402}
403
404template<FLUID_COMPARTMENT_TEMPLATE>
405SubstanceQuantityType* SEFluidCompartment<FLUID_COMPARTMENT_TYPES>::GetSubstanceQuantity(const SESubstance& substance) const
406{
407 for (SubstanceQuantityType* sq : m_SubstanceQuantities)
408 {
409 if (&sq->GetSubstance() == &substance)
410 return sq;
411 }
412 return nullptr;
413}
414template<FLUID_COMPARTMENT_TEMPLATE>
415const std::vector<SubstanceQuantityType*>& SEFluidCompartment<FLUID_COMPARTMENT_TYPES>::GetSubstanceQuantities() const
416{
417 return m_SubstanceQuantities;
418}
419template<FLUID_COMPARTMENT_TEMPLATE>
421{
422 for (size_t i = 0; i < m_SubstanceQuantities.size(); i++)
423 {
424 if (&m_SubstanceQuantities[i]->GetSubstance() == &substance)
425 {
426 SAFE_DELETE(m_SubstanceQuantities[i]);
427 SAFE_DELETE(m_TransportSubstances[i]);// Assumes these are in sync
428 m_SubstanceQuantities.erase(m_SubstanceQuantities.begin()+i);
429 m_TransportSubstances.erase(m_TransportSubstances.begin()+i);
430
431 }
432 }
433}
434template<FLUID_COMPARTMENT_TEMPLATE>
436{
437 for (SubstanceQuantityType* sq : m_SubstanceQuantities)
438 {
439 sq->SetToZero();
440 }
441}
442
443template<FLUID_COMPARTMENT_TEMPLATE>
445{
446 if (!Contains(m_Links, link))
447 {
448 m_Links.push_back(&link);
449 if (HasChildren())
450 {
451 SEFluidCompartment& src = link.GetSourceCompartment();
452 SEFluidCompartment& tgt = link.GetTargetCompartment();
453
454 if(this!= &src && !HasChild(src))
455 m_IncomingLinks.push_back(&link);
456 else if (this!=&tgt && !HasChild(tgt))
457 m_OutgoingLinks.push_back(&link);
458 }
459 else
460 {
461 // Is it incoming or out going?
462 if (this == &link.GetSourceCompartment())
463 m_OutgoingLinks.push_back(&link);
464 else if (this == &link.GetTargetCompartment())
465 m_IncomingLinks.push_back(&link);
466 }
467 }
468}
469template<FLUID_COMPARTMENT_TEMPLATE>
471{
472 Remove(m_Links, &link);
473 Remove(m_IncomingLinks, &link);
474 Remove(m_OutgoingLinks, &link);
475}
476template<FLUID_COMPARTMENT_TEMPLATE>
478{
479 m_Links.clear();
480}
481template<FLUID_COMPARTMENT_TEMPLATE>
482const std::vector<LinkType*>& SEFluidCompartment<FLUID_COMPARTMENT_TYPES>::GetLinks()
483{
484 return m_Links;
485}
486
487template<FLUID_COMPARTMENT_TEMPLATE>
489{
490 for (SEFluidCompartment* child : m_FluidChildren)
491 {
492 if (&cmpt == child)
493 return true;
494 if (child->HasChild(cmpt))
495 return true;
496 }
497 return false;
498}
Definition: Logger.h:71
Definition: SEScalarPressure.h:8
Definition: SECompartment.h:14
virtual void Clear()
Definition: SECompartment.cpp:18
Definition: SEFluidCircuitNode.h:10
Definition: SEFluidCompartment.h:19
virtual double CalculateOutFlow_mL_Per_s() const
Definition: SEFluidCompartment.cpp:236
virtual bool HasVolume() const
Definition: SEFluidCompartment.cpp:342
virtual void ZeroSubstanceQuantities()
Definition: SEFluidCompartment.cpp:438
virtual void RemoveSubstanceQuantity(const SESubstance &substance)
Definition: SEFluidCompartment.cpp:423
virtual ~SEFluidCompartment()
Definition: SEFluidCompartment.cpp:26
virtual SEScalarPressure & GetPressure()
Definition: SEFluidCompartment.cpp:274
virtual void RemoveLink(LinkType &link)
Definition: SEFluidCompartment.cpp:473
virtual bool HasAverageOutFlow() const
Definition: SEFluidCompartment.cpp:188
virtual bool HasInFlow() const
Definition: SEFluidCompartment.cpp:103
virtual void AddLink(LinkType &link)
Definition: SEFluidCompartment.cpp:447
virtual const std::vector< SubstanceQuantityType * > & GetSubstanceQuantities() const
Definition: SEFluidCompartment.cpp:418
virtual bool HasSubstanceQuantity(const SESubstance &substance) const
Definition: SEFluidCompartment.cpp:397
virtual bool HasAverageInFlow() const
Definition: SEFluidCompartment.cpp:134
virtual void RemoveLinks()
Definition: SEFluidCompartment.cpp:480
virtual bool HasSubstanceQuantities() const
Definition: SEFluidCompartment.cpp:392
virtual const SEScalarVolumePerTime & GetAverageInFlow() const
Definition: SEFluidCompartment.cpp:139
virtual void MapNode(SEFluidCircuitNode &node)
Definition: SEFluidCompartment.cpp:69
virtual const SEScalarVolumePerTime & GetInFlow() const
Definition: SEFluidCompartment.cpp:113
virtual const SEScalarVolumePerTime & GetAverageOutFlow() const
Definition: SEFluidCompartment.cpp:193
virtual bool HasPressure() const
Definition: SEFluidCompartment.cpp:260
virtual bool HasChild(const SEFluidCompartment &cmpt)
Definition: SEFluidCompartment.cpp:491
virtual SEScalarVolume & GetVolume()
Definition: SEFluidCompartment.cpp:356
void Clear() override
Definition: SEFluidCompartment.cpp:32
SEFluidCompartment(const std::string &name, Logger *logger)
Definition: SEFluidCompartment.cpp:13
virtual const std::vector< LinkType * > & GetLinks()
Definition: SEFluidCompartment.cpp:485
virtual SubstanceQuantityType * GetSubstanceQuantity(const SESubstance &substance) const
Definition: SEFluidCompartment.cpp:408
virtual void SampleFlow()
Definition: SEFluidCompartment.cpp:95
virtual const SEScalarVolumePerTime & GetOutFlow() const
Definition: SEFluidCompartment.cpp:167
virtual void Sample(bool CycleStart)
Definition: SEFluidCompartment.cpp:78
const SEScalar * GetScalar(const std::string &name) override
Definition: SEFluidCompartment.cpp:51
virtual double CalculateInFlow_mL_Per_s() const
Definition: SEFluidCompartment.cpp:211
virtual bool HasOutFlow() const
Definition: SEFluidCompartment.cpp:157
Definition: SERunningAverage.h:8
Definition: SEScalar.h:19
static double dNaN()
Definition: SEScalar.cpp:10
bool IsPositive() const
Definition: SEScalar.cpp:115
bool IsZero(double limit=ZERO_APPROX) const
Definition: SEScalar.cpp:108
bool IsNegative() const
Definition: SEScalar.cpp:122
Definition: SEScalarPressure.h:29
double GetValue(const CCompoundUnit &unit) const override
Definition: SEScalar.hxx:125
Definition: SEScalarVolume.h:28
Definition: SEScalarVolumePerTime.h:32
Definition: SESubstance.h:15
Definition: SEScalarVolumePerTime.h:8
static const VolumePerTimeUnit mL_Per_s
Definition: SEScalarVolumePerTime.h:23
Definition: SEScalarVolume.h:8
static const VolumeUnit mL
Definition: SEScalarVolume.h:22

Distributed under the Apache License, Version 2.0.

See accompanying NOTICE file for details.