What’s New in the Pulse Physiology Engine 4.4.0
×
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;
19 m_Pressure = nullptr;
20 m_Volume = nullptr;
21}
22template<FLUID_COMPARTMENT_TEMPLATE>
24{
25 Clear();
26}
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}
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;
65template<FLUID_COMPARTMENT_TEMPLATE>
68 if (HasChildren())
69 Fatal("You cannot map nodes to compartments with children.");
70 else
71 m_Nodes.MapNode(node);
72}
74template<FLUID_COMPARTMENT_TEMPLATE>
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>
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 SubstanceQuantityType* SEFluidCompartment<FLUID_COMPARTMENT_TYPES>::GetSubstanceQuantity(const SESubstance& substance) const
416{
417 for (SubstanceQuantityType* sq : m_SubstanceQuantities)
418 {
419 if (&sq->GetSubstance() == &substance)
420 return sq;
421 }
422 return nullptr;
423}
424template<FLUID_COMPARTMENT_TEMPLATE>
425const std::vector<SubstanceQuantityType*>& SEFluidCompartment<FLUID_COMPARTMENT_TYPES>::GetSubstanceQuantities() const
426{
427 return m_SubstanceQuantities;
428}
429template<FLUID_COMPARTMENT_TEMPLATE>
431{
432 for (size_t i = 0; i < m_SubstanceQuantities.size(); i++)
433 {
434 if (&m_SubstanceQuantities[i]->GetSubstance() == &substance)
435 {
436 SAFE_DELETE(m_SubstanceQuantities[i]);
437 SAFE_DELETE(m_TransportSubstances[i]);// Assumes these are in sync
438 m_SubstanceQuantities.erase(m_SubstanceQuantities.begin()+i);
439 m_TransportSubstances.erase(m_TransportSubstances.begin()+i);
440
441 }
442 }
443}
444template<FLUID_COMPARTMENT_TEMPLATE>
446{
447 for (SubstanceQuantityType* sq : m_SubstanceQuantities)
448 {
449 sq->SetToZero();
450 }
451}
452
453template<FLUID_COMPARTMENT_TEMPLATE>
455{
456 if (!Contains(m_Links, link))
457 {
458 m_Links.push_back(&link);
459 if (HasChildren())
460 {
461 SEFluidCompartment& src = link.GetSourceCompartment();
462 SEFluidCompartment& tgt = link.GetTargetCompartment();
463
464 if(this!= &src && !HasChild(src))
465 m_IncomingLinks.push_back(&link);
466 else if (this!=&tgt && !HasChild(tgt))
467 m_OutgoingLinks.push_back(&link);
468 }
469 else
470 {
471 // Is it incoming or out going?
472 if (this == &link.GetSourceCompartment())
473 m_OutgoingLinks.push_back(&link);
474 else if (this == &link.GetTargetCompartment())
475 m_IncomingLinks.push_back(&link);
476 }
477 }
478}
479template<FLUID_COMPARTMENT_TEMPLATE>
481{
482 Remove(m_Links, &link);
483 Remove(m_IncomingLinks, &link);
484 Remove(m_OutgoingLinks, &link);
485}
486template<FLUID_COMPARTMENT_TEMPLATE>
488{
489 m_Links.clear();
490}
491template<FLUID_COMPARTMENT_TEMPLATE>
493{
494 return m_Links;
495}
496
497template<FLUID_COMPARTMENT_TEMPLATE>
499{
500 for (SEFluidCompartment* child : m_FluidChildren)
501 {
502 if (&cmpt == child)
503 return true;
504 if (child->HasChild(cmpt))
505 return true;
506 }
507 return false;
508}
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 bool HasVolume() const
Definition: SEFluidCompartment.hxx:339
virtual void ZeroSubstanceQuantities()
Definition: SEFluidCompartment.hxx:445
virtual void RemoveSubstanceQuantity(const SESubstance &substance)
Definition: SEFluidCompartment.hxx:430
virtual ~SEFluidCompartment()
Definition: SEFluidCompartment.hxx:23
SEScalarVolumePerTime * m_AverageOutflow
Definition: SEFluidCompartment.h:95
virtual SEScalarPressure & GetPressure()
Definition: SEFluidCompartment.hxx:271
virtual void RemoveLink(LinkType &link)
Definition: SEFluidCompartment.hxx:480
SEScalarVolumePerTime * m_AverageInflow
Definition: SEFluidCompartment.h:94
virtual void AddLink(LinkType &link)
Definition: SEFluidCompartment.hxx:454
virtual double CalculateInflow_mL_Per_s() const
Definition: SEFluidCompartment.hxx:208
virtual bool HasOutflow() const
Definition: SEFluidCompartment.hxx:154
virtual const std::vector< SubstanceQuantityType * > & GetSubstanceQuantities() const
Definition: SEFluidCompartment.hxx:425
virtual const SEScalarVolumePerTime & GetOutflow() const
Definition: SEFluidCompartment.hxx:164
SERunningAverage * m_AverageOutflow_mL_Per_s
Definition: SEFluidCompartment.h:97
virtual bool HasAverageOutflow() const
Definition: SEFluidCompartment.hxx:185
virtual bool HasSubstanceQuantity(const SESubstance &substance) const
Definition: SEFluidCompartment.hxx:394
virtual void RemoveLinks()
Definition: SEFluidCompartment.hxx:487
virtual SubstanceQuantityType * GetSubstanceQuantity(const SESubstance &substance)
Definition: SEFluidCompartment.hxx:405
virtual bool HasSubstanceQuantities() const
Definition: SEFluidCompartment.hxx:389
virtual const SEScalarVolumePerTime & GetAverageInflow() const
Definition: SEFluidCompartment.hxx:136
virtual void MapNode(SEFluidCircuitNode &node)
Definition: SEFluidCompartment.hxx:66
virtual bool HasInflow() const
Definition: SEFluidCompartment.hxx:100
SEScalarVolumePerTime * m_Inflow
Definition: SEFluidCompartment.h:91
virtual bool HasPressure() const
Definition: SEFluidCompartment.hxx:257
SEScalarVolumePerTime * m_Outflow
Definition: SEFluidCompartment.h:92
bool m_SampleFlow
Definition: SEFluidCompartment.h:93
virtual bool HasChild(const SEFluidCompartment &cmpt)
Definition: SEFluidCompartment.hxx:498
virtual SEScalarVolume & GetVolume()
Definition: SEFluidCompartment.hxx:353
void Clear() override
Definition: SEFluidCompartment.hxx:29
SERunningAverage * m_AverageInflow_mL_Per_s
Definition: SEFluidCompartment.h:96
SEFluidCompartment(const std::string &name, Logger *logger)
Definition: SEFluidCompartment.hxx:10
virtual const std::vector< LinkType * > & GetLinks()
Definition: SEFluidCompartment.hxx:492
virtual void SampleFlow()
Definition: SEFluidCompartment.hxx:92
virtual bool HasAverageInflow() const
Definition: SEFluidCompartment.hxx:131
SEScalarVolume * m_Volume
Definition: SEFluidCompartment.h:100
SEScalarPressure * m_Pressure
Definition: SEFluidCompartment.h:99
virtual void Sample(bool CycleStart)
Definition: SEFluidCompartment.hxx:75
const SEScalar * GetScalar(const std::string &name) override
Definition: SEFluidCompartment.hxx:48
virtual const SEScalarVolumePerTime & GetAverageOutflow() const
Definition: SEFluidCompartment.hxx:190
virtual double CalculateOutflow_mL_Per_s() const
Definition: SEFluidCompartment.hxx:233
virtual const SEScalarVolumePerTime & GetInflow() const
Definition: SEFluidCompartment.hxx:110
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:16
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.