34 #include "BetteridgeHaematocritSolver.hpp" 35 #include "LinearSystem.hpp" 36 #include "VesselNode.hpp" 38 #include "Exception.hpp" 39 #include "ReplicatableVector.hpp" 41 template<
unsigned DIM>
50 template<
unsigned DIM>
56 template<
unsigned DIM>
62 template<
unsigned DIM>
68 template<
unsigned DIM>
74 template<
unsigned DIM>
78 std::vector<boost::shared_ptr<Vessel<DIM> > > vessels = this->
mpNetwork->GetVessels();
79 for(
unsigned idx=0; idx<vessels.size(); idx++)
81 vessels[idx]->SetId(idx);
85 PetscInt lhsVectorSize = vessels.size();
86 unsigned max_vessels_per_branch = 5;
87 if(vessels.size() < max_vessels_per_branch)
89 max_vessels_per_branch = unsigned(lhsVectorSize);
91 LinearSystem linearSystem(lhsVectorSize, max_vessels_per_branch);
94 linearSystem.SetPcType(
"lu");
95 #ifdef PETSC_HAVE_HYPRE 96 linearSystem.SetPcType(
"hypre");
97 #endif //PETSC_HAVE_HYPRE 98 linearSystem.SetKspType(
"preonly");
101 std::vector<std::vector<unsigned> > update_indices;
102 for(
unsigned idx=0; idx<vessels.size(); idx++)
105 linearSystem.SetMatrixElement(idx, idx, 1);
106 if(vessels[idx]->GetStartNode()->GetFlowProperties()->IsInputNode() or vessels[idx]->GetEndNode()->GetFlowProperties()->IsInputNode())
111 else if(vessels[idx]->GetFlowProperties()->GetFlowRate()==0.0*unit::metre_cubed_per_second)
113 linearSystem.SetRhsVectorElement(idx, 0.0);
118 boost::shared_ptr<VesselNode<DIM> > p_inflow_node;
119 units::quantity<unit::flow_rate> flow_rate= vessels[idx]->GetFlowProperties()->GetFlowRate();
120 if(flow_rate >0 * unit::metre_cubed_per_second)
122 p_inflow_node = vessels[idx]->GetStartNode();
126 p_inflow_node = vessels[idx]->GetEndNode();
130 if(p_inflow_node->GetNumberOfSegments()>1)
132 std::vector<boost::shared_ptr<Vessel<DIM> > > parent_vessels;
133 std::vector<boost::shared_ptr<Vessel<DIM> > > competitor_vessels;
134 for(
unsigned jdx=0; jdx<p_inflow_node->GetSegments().size(); jdx++)
137 if(p_inflow_node->GetSegment(jdx)->GetVessel()!=vessels[idx])
139 units::quantity<unit::flow_rate> inflow_rate = p_inflow_node->GetSegment(jdx)->GetVessel()->GetFlowProperties()->GetFlowRate();
140 if(p_inflow_node->GetSegment(jdx)->GetVessel()->GetEndNode()==p_inflow_node)
142 if(inflow_rate>0.0 * unit::metre_cubed_per_second)
144 parent_vessels.push_back(p_inflow_node->GetSegment(jdx)->GetVessel());
146 else if(inflow_rate<0.0 * unit::metre_cubed_per_second)
148 competitor_vessels.push_back(p_inflow_node->GetSegment(jdx)->GetVessel());
151 if(p_inflow_node->GetSegment(jdx)->GetVessel()->GetStartNode()==p_inflow_node)
153 if(inflow_rate>0.0 * unit::metre_cubed_per_second)
155 competitor_vessels.push_back(p_inflow_node->GetSegment(jdx)->GetVessel());
157 else if(inflow_rate<0.0 * unit::metre_cubed_per_second)
159 parent_vessels.push_back(p_inflow_node->GetSegment(jdx)->GetVessel());
166 if(competitor_vessels.size()==0 or units::fabs(competitor_vessels[0]->GetFlowProperties()->GetFlowRate()) == 0.0 * unit::metre_cubed_per_second)
168 for(
unsigned jdx=0; jdx<parent_vessels.size();jdx++)
170 linearSystem.SetMatrixElement(idx, parent_vessels[jdx]->GetId(), -fabs(parent_vessels[jdx]->GetFlowProperties()->GetFlowRate()/flow_rate));
175 if(competitor_vessels.size()>1 or parent_vessels.size()>1)
177 EXCEPTION(
"This solver can only work with branches with connectivity 3");
179 units::quantity<unit::flow_rate> competitor0_flow_rate = competitor_vessels[0]->GetFlowProperties()->GetFlowRate();
180 units::quantity<unit::flow_rate> parent0_flow_rate = parent_vessels[0]->GetFlowProperties()->GetFlowRate();
183 units::quantity<unit::length> my_radius = vessels[idx]->GetRadius();
184 units::quantity<unit::length> competitor_radius = competitor_vessels[0]->GetRadius();
185 units::quantity<unit::velocity> my_velocity = units::fabs(flow_rate)/(M_PI * my_radius * my_radius);
186 units::quantity<unit::velocity> competitor_velocity = fabs(competitor0_flow_rate)/(M_PI * competitor_radius * competitor_radius);
188 units::quantity<unit::dimensionless> alpha = 1.0 - parent_vessels[0]->GetFlowProperties()->GetHaematocrit();
189 units::quantity<unit::dimensionless> flow_ratio_pm = fabs(parent0_flow_rate)/fabs(flow_rate);
190 units::quantity<unit::dimensionless> flow_ratio_cm = fabs(competitor0_flow_rate)/fabs(flow_rate);
191 double numer = flow_ratio_pm;
194 if(my_velocity >= competitor_velocity)
196 units::quantity<unit::dimensionless> term = alpha * (my_velocity/competitor_velocity-1.0);
197 double denom = 1.0+flow_ratio_cm*(1.0/(1.0+term));
198 linearSystem.SetMatrixElement(idx, parent_vessels[0]->GetId(), -numer/denom);
202 units::quantity<unit::dimensionless> term = alpha * (competitor_velocity/my_velocity-1.0);
203 double denom = 1.0+flow_ratio_cm*(1.0+term);
204 linearSystem.SetMatrixElement(idx, parent_vessels[0]->GetId(), -numer/denom);
208 std::vector<unsigned> local_update_indics = std::vector<unsigned>(3);
209 local_update_indics[0] = idx;
210 local_update_indics[1] = parent_vessels[0]->GetId();
211 local_update_indics[2] = competitor_vessels[0]->GetId();
212 update_indices.push_back(local_update_indics);
219 double tolerance = 1e-3;
220 double max_iterations = 1000;
221 double residual = DBL_MAX;
224 while(residual > tolerance && iterations < max_iterations)
226 if(iterations>0 and update_indices.size()>0)
229 linearSystem.SwitchWriteModeLhsMatrix();
230 for(
unsigned idx=0; idx<update_indices.size();idx++)
232 units::quantity<unit::flow_rate> self_flow_rate = vessels[update_indices[idx][0]]->GetFlowProperties()->GetFlowRate();
233 units::quantity<unit::flow_rate> competitor0_flow_rate = vessels[update_indices[idx][2]]->GetFlowProperties()->GetFlowRate();
234 units::quantity<unit::flow_rate> parent0_flow_rate = vessels[update_indices[idx][1]]->GetFlowProperties()->GetFlowRate();
236 units::quantity<unit::length> my_radius = vessels[update_indices[idx][0]]->GetRadius();
237 units::quantity<unit::length> competitor_radius = vessels[update_indices[idx][2]]->GetRadius();
238 units::quantity<unit::velocity> my_velocity = fabs(self_flow_rate)/(M_PI * my_radius * my_radius);
239 units::quantity<unit::velocity> competitor_velocity = fabs(competitor0_flow_rate)/(M_PI * competitor_radius * competitor_radius);
240 units::quantity<unit::dimensionless> alpha = 1.0 - vessels[update_indices[idx][1]]->GetFlowProperties()->GetHaematocrit();
242 double flow_ratio_pm = fabs(parent0_flow_rate/self_flow_rate);
243 double flow_ratio_cm = fabs(competitor0_flow_rate/self_flow_rate);
244 double numer = flow_ratio_pm;
247 if(my_velocity >= competitor_velocity)
249 double term = alpha * (my_velocity/competitor_velocity-1.0);
250 double denom = 1.0+flow_ratio_cm*(1.0/(1.0+term));
251 linearSystem.SetMatrixElement(update_indices[idx][0], update_indices[idx][1], -numer/denom);
255 double term = alpha * (competitor_velocity/my_velocity-1.0);
256 double denom = 1.0+flow_ratio_cm*(1.0+term);
257 linearSystem.SetMatrixElement(update_indices[idx][0], update_indices[idx][1], -numer/denom);
262 Vec solution = PetscTools::CreateVec(vessels.size());
263 linearSystem.AssembleFinalLinearSystem();
264 solution = linearSystem.Solve();
265 ReplicatableVector a(solution);
269 for (
unsigned i = 0; i < vessels.size(); i++)
271 if(fabs(vessels[i]->GetFlowProperties()->GetHaematocrit() - a[i]) > residual)
273 residual = fabs(vessels[i]->GetFlowProperties()->GetHaematocrit() - a[i]);
278 for (
unsigned idx = 0; idx < vessels.size(); idx++)
280 for (
unsigned jdx = 0; jdx < vessels[idx]->GetNumberOfSegments(); jdx++)
282 vessels[idx]->GetSegments()[jdx]->GetFlowProperties()->SetHaematocrit(a[idx]);
287 if(iterations == max_iterations)
289 EXCEPTION(
"Haematocrit calculation failed to converge.");
292 PetscTools::Destroy(solution);
void SetHaematocrit(units::quantity< unit::dimensionless > haematocrit)
~BetteridgeHaematocritSolver()
boost::shared_ptr< VesselNetwork< DIM > > mpNetwork
units::quantity< unit::dimensionless > mTHR
units::quantity< unit::dimensionless > mHaematocrit
BetteridgeHaematocritSolver()
*
void SetAlpha(units::quantity< unit::dimensionless > alpha)
units::quantity< unit::dimensionless > mAlpha
void SetTHR(units::quantity< unit::dimensionless > thr)