VentilationProblem.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2014, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #include "VentilationProblem.hpp"
00037 #include "TrianglesMeshReader.hpp"
00038 #include "Warnings.hpp"
00039 //#include "Debug.hpp"
00040 
00041 VentilationProblem::VentilationProblem(const std::string& rMeshDirFilePath, unsigned rootIndex)
00042     : mOutletNodeIndex(rootIndex),
00043       mDynamicResistance(false),
00044       mRadiusOnEdge(false),
00045       mViscosity(1.92e-5),
00046       mDensity(1.51e-6),
00047       mFluxGivenAtInflow(false),
00048       mTerminalInteractionMatrix(NULL),
00049       mTerminalFluxChangeVector(NULL),
00050       mTerminalPressureChangeVector(NULL),
00051       mTerminalKspSolver(NULL)
00052 {
00053     TrianglesMeshReader<1,3> mesh_reader(rMeshDirFilePath);
00054     mMesh.ConstructFromMeshReader(mesh_reader);
00055 
00056     if (mMesh.GetNode(mOutletNodeIndex)->IsBoundaryNode() == false)
00057     {
00058         EXCEPTION("Outlet node is not a boundary node");
00059     }
00060 
00061     /*
00062      * Set up the Acinar units at the terminals
00063      *
00064      * \todo Currently this is hard coded using a Swan acinar unit
00065      * (with functional residual capacity appropriate initial values). Long term this
00066      * should be factored out into a factory to allow setup of other acinar units and
00067      * other initial conditions
00068      */
00069     //unsigned num_acinar = mMesh.GetNumBoundaryNodes() - 1;
00070     double acinus_volume = 1.2e6/31000; //Assumes a residual capacity of 1.2l (x10^6 in mm^3)
00071 
00072     for (AbstractTetrahedralMesh<1,3>::BoundaryNodeIterator iter = mMesh.GetBoundaryNodeIteratorBegin();
00073           iter != mMesh.GetBoundaryNodeIteratorEnd();
00074           ++iter)
00075     {
00076         if ((*iter)->GetIndex() != mOutletNodeIndex)
00077         {
00079             Swan2012AcinarUnit* p_acinus = new Swan2012AcinarUnit;
00080 
00081             p_acinus->SetStretchRatio(1.26); //Stretch ratio appropriate for a lung at functional residual capacity
00082             p_acinus->SetUndeformedVolume(acinus_volume);
00083             p_acinus->SetPleuralPressure(-0.49); //Pleural pressure at FRC in kPa
00084             p_acinus->SetAirwayPressure(0.0);
00085 
00086             //Calculates the resistance of the terminal bronchiole.
00087             //This should be updated dynamically during the simulation
00088             c_vector<double, 3> dummy;
00089             double length;
00090             unsigned edge_index = *( (*iter)->ContainingElementsBegin() );
00091             mMesh.GetWeightedDirectionForElement(edge_index, dummy, length);
00092 
00093             double radius = (*iter)->rGetNodeAttributes()[0];
00094 
00095             double resistance = 8.0*mViscosity*length/(M_PI*SmallPow(radius, 4));
00096             p_acinus->SetTerminalBronchioleResistance(resistance);
00097 
00098             mAcinarUnits[(*iter)->GetIndex()] = p_acinus;
00099         }
00100     }
00101 
00102     mFlux.resize(mMesh.GetNumElements());
00103     mPressure.resize(mMesh.GetNumNodes());
00104 }
00105 
00106 VentilationProblem::~VentilationProblem()
00107 {
00108     for (unsigned i=0; i<mAcinarUnits.size(); i++)
00109     {
00110         delete mAcinarUnits[i];
00111     }
00112 
00113     /* Remove the PETSc context used in the iterative solver */
00114     if (mTerminalInteractionMatrix)
00115     {
00116         PetscTools::Destroy(mTerminalInteractionMatrix);
00117         PetscTools::Destroy(mTerminalFluxChangeVector);
00118         PetscTools::Destroy(mTerminalPressureChangeVector);
00119         KSPDestroy(PETSC_DESTROY_PARAM(mTerminalKspSolver));
00120     }
00121 }
00122 void VentilationProblem::SolveDirectFromFlux()
00123 {
00124     /* Work back through the node iterator looking for internal nodes: bifurcations or joints
00125      *
00126      * Each parent flux is equal to the sum of it's children
00127      * Note that we can't iterate all the way back to the root node, but that's okay
00128      * because the root is not a bifurcation.  Also note that we can't use a NodeIterator
00129      * because it does not have operator--
00130      */
00131     for (unsigned node_index = mMesh.GetNumNodes() - 1; node_index > 0; --node_index)
00132     {
00133         Node<3>* p_node = mMesh.GetNode(node_index);
00134         if (p_node->IsBoundaryNode() == false)
00135         {
00136             Node<3>::ContainingElementIterator element_iterator = p_node->ContainingElementsBegin();
00137             unsigned parent_index = *element_iterator;
00138             ++element_iterator;
00139 
00140             for (mFlux[parent_index]=0.0; element_iterator != p_node->ContainingElementsEnd(); ++element_iterator)
00141             {
00142                 mFlux[parent_index] += mFlux[*element_iterator];
00143             }
00144         }
00145     }
00146     // Poiseuille flow at each edge
00147     for (AbstractTetrahedralMesh<1,3>::ElementIterator iter = mMesh.GetElementIteratorBegin();
00148          iter != mMesh.GetElementIteratorEnd();
00149          ++iter)
00150     {
00151         /* Poiseuille flow gives:
00152          *  pressure_node_1 - pressure_node_2 - resistance * flux = 0
00153          */
00154         double flux = mFlux[iter->GetIndex()];
00155         double resistance = CalculateResistance(*iter, mDynamicResistance, flux);
00156         unsigned pressure_index_parent =  iter->GetNodeGlobalIndex(0);
00157         unsigned pressure_index_child  =  iter->GetNodeGlobalIndex(1);
00158         mPressure[pressure_index_child] = mPressure[pressure_index_parent] - resistance*flux;
00159     }
00160 }
00161 
00162 void VentilationProblem::SetupIterativeSolver()
00163 {
00164     const unsigned num_non_zeroes = 100;
00165 
00166     MatCreateSeqAIJ(PETSC_COMM_SELF, mMesh.GetNumBoundaryNodes()-1, mMesh.GetNumBoundaryNodes()-1, num_non_zeroes, NULL, &mTerminalInteractionMatrix);
00167     PetscMatTools::SetOption(mTerminalInteractionMatrix, MAT_SYMMETRIC);
00168     PetscMatTools::SetOption(mTerminalInteractionMatrix, MAT_SYMMETRY_ETERNAL);
00169 
00170     /* Map each edge to its terminal descendants so that we can keep track
00171      * of which terminals can affect each other via a particular edge.
00172      */
00173     std::vector<std::set<unsigned> > descendant_nodes(mMesh.GetNumElements());
00174     unsigned terminal_index=0;
00175     //First set up all the boundary nodes
00176     for (AbstractTetrahedralMesh<1,3>::BoundaryNodeIterator iter = mMesh.GetBoundaryNodeIteratorBegin();
00177               iter != mMesh.GetBoundaryNodeIteratorEnd();
00178               ++iter)
00179     {
00180         unsigned node_index = (*iter)->GetIndex();
00181         if (node_index != mOutletNodeIndex)
00182         {
00183             unsigned parent_index =  *((*iter)->ContainingElementsBegin());
00184             mTerminalToNodeIndex[terminal_index] = node_index;
00185             mTerminalToEdgeIndex[terminal_index] = parent_index;
00186             descendant_nodes[parent_index].insert(terminal_index++);
00187         }
00188     }
00189     // The outer loop here is for special cases where we find an internal node before its descendants
00190     // In this case we need to scan the tree more than once (up to log(N)) before the sets are correctly propagated
00191     while (descendant_nodes[mOutletNodeIndex].size() != terminal_index)
00192     {
00193         //Work back up the tree making the unions of the sets of descendants
00194         for (unsigned node_index = mMesh.GetNumNodes() - 1; node_index > 0; --node_index)
00195         {
00196             Node<3>* p_node = mMesh.GetNode(node_index);
00197             if (p_node->IsBoundaryNode() == false)
00198             {
00199                 Node<3>::ContainingElementIterator element_iterator = p_node->ContainingElementsBegin();
00200                 unsigned parent_index = *element_iterator;
00201                 ++element_iterator;
00202                 for (;element_iterator != p_node->ContainingElementsEnd(); ++element_iterator)
00203                 {
00204                     descendant_nodes[parent_index].insert(descendant_nodes[*element_iterator].begin(),descendant_nodes[*element_iterator].end());
00205                 }
00206             }
00207         }
00208     }
00209     // Use the descendant sets to build the mTerminalInteractionMatrix structure of resistances
00210     for (AbstractTetrahedralMesh<1,3>::ElementIterator iter = mMesh.GetElementIteratorBegin();
00211             iter != mMesh.GetElementIteratorEnd();
00212             ++iter)
00213     {
00214         unsigned parent_index = iter->GetIndex();
00215         double parent_resistance = CalculateResistance(*iter);
00216         if (descendant_nodes[parent_index].size() <= num_non_zeroes)
00217         {
00218             std::vector<PetscInt> indices( descendant_nodes[parent_index].begin(), descendant_nodes[parent_index].end() );
00219             std::vector<double> resistance_to_add(indices.size()*indices.size(), parent_resistance);
00220 
00221             MatSetValues(mTerminalInteractionMatrix,
00222                          indices.size(), (PetscInt*) &indices[0],
00223                          indices.size(), (PetscInt*) &indices[0], &resistance_to_add[0], ADD_VALUES);
00224         }
00226     }
00227     PetscMatTools::Finalise(mTerminalInteractionMatrix);
00228     assert( terminal_index == mMesh.GetNumBoundaryNodes()-1);
00229     VecCreateSeq(PETSC_COMM_SELF, terminal_index, &mTerminalFluxChangeVector);
00230     VecCreateSeq(PETSC_COMM_SELF, terminal_index, &mTerminalPressureChangeVector);
00231 
00232     KSPCreate(PETSC_COMM_SELF, &mTerminalKspSolver);
00233     KSPSetOperators(mTerminalKspSolver, mTerminalInteractionMatrix, mTerminalInteractionMatrix, SAME_PRECONDITIONER);
00234     KSPSetFromOptions(mTerminalKspSolver);
00235     KSPSetUp(mTerminalKspSolver);
00236 }
00237 void VentilationProblem::SolveIterativelyFromPressure()
00238 {
00239     if (mTerminalInteractionMatrix == NULL)
00240     {
00241         SetupIterativeSolver();
00242     }
00243     /* Now use the pressure boundary conditions to determine suitable flux boundary conditions
00244      * and iteratively update them until we are done
00245      */
00246     assert(mPressure[mOutletNodeIndex] == mPressureCondition[mOutletNodeIndex]);
00247 
00248     unsigned max_iterations=1000;
00249     unsigned num_terminals = mMesh.GetNumBoundaryNodes()-1u;
00250     double pressure_tolerance = 1e-4;
00251     bool converged=false;
00252     double terminal_flux_correction = 0.0;
00253     double last_max_pressure_change;
00254     double last_norm_pressure_change;
00255     for (unsigned iteration = 0; iteration < max_iterations && converged==false; iteration++)
00256     {
00257         for (unsigned terminal=0; terminal<num_terminals; terminal++)
00258         {
00259             unsigned node_index = mTerminalToNodeIndex[terminal];
00260             // How far we are away from matching this boundary condition.
00261             double delta_pressure = mPressure[node_index] - mPressureCondition[node_index];
00262             // Offset the first iteration
00263             if (iteration == 0)
00264             {
00265                 delta_pressure += mPressureCondition[mOutletNodeIndex];
00266             }
00267             VecSetValue(mTerminalPressureChangeVector, terminal, delta_pressure, INSERT_VALUES);
00268         }
00269         double max_pressure_change, norm_pressure_change;
00270         PetscInt temp_index;
00271         VecMax(mTerminalPressureChangeVector, &temp_index, &last_max_pressure_change);
00272         VecNorm(mTerminalPressureChangeVector, NORM_2, &last_norm_pressure_change);
00273 
00274         if (last_norm_pressure_change < pressure_tolerance)
00275         {
00276             converged = true;
00277             break;
00278         }
00279 
00280         KSPSolve(mTerminalKspSolver, mTerminalPressureChangeVector, mTerminalFluxChangeVector);
00281         double* p_mTerminalFluxChangeVector;
00282         VecGetArray(mTerminalFluxChangeVector, &p_mTerminalFluxChangeVector);
00283 
00284 
00285 
00286         for (unsigned terminal=0; terminal<num_terminals; terminal++)
00287         {
00288             double estimated_mTerminalFluxChangeVector=p_mTerminalFluxChangeVector[terminal];
00289             unsigned edge_index = mTerminalToEdgeIndex[terminal];
00290             mFlux[edge_index] +=  estimated_mTerminalFluxChangeVector;
00291         }
00292         SolveDirectFromFlux();
00293         /* Look at the magnitude of the response */
00294 
00295         for (unsigned terminal=0; terminal<num_terminals; terminal++)
00296         {
00297             unsigned node_index = mTerminalToNodeIndex[terminal];
00298             // How far we are away from matching this boundary condition.
00299             double delta_pressure = mPressure[node_index] - mPressureCondition[node_index];
00300             // Offset the first iteration
00301             if (iteration == 0)
00302             {
00303                 delta_pressure += mPressureCondition[mOutletNodeIndex];
00304             }
00305             VecSetValue(mTerminalPressureChangeVector, terminal, delta_pressure, INSERT_VALUES);
00306         }
00307         VecMax(mTerminalPressureChangeVector, &temp_index, &max_pressure_change);
00308         VecNorm(mTerminalPressureChangeVector, NORM_2, &norm_pressure_change);
00309         if (norm_pressure_change < pressure_tolerance)
00310         {
00311             converged = true;
00312             break;
00313         }
00314         bool rescale = true;
00315         if (max_pressure_change*last_max_pressure_change < 0.0)
00316         {
00317             /* The pressure correction has changed sign
00318              *  * so we have overshot the root
00319              *  * back up by setting a correction factor
00320              */
00321             terminal_flux_correction =  last_norm_pressure_change / (last_norm_pressure_change + norm_pressure_change) - 1.0;
00322         }
00323         else if (last_norm_pressure_change > norm_pressure_change)
00324         {
00325             /* We have a better solution without rescaling. */
00326             rescale = false;
00327         }
00328         else
00329         {
00330             //use the previous scaling factor based on the last overshoot
00331             //assert(terminal_flux_correction != 0.0);
00332         }
00333 
00334         if (rescale)
00335         {
00336             for (unsigned terminal=0; terminal<num_terminals; terminal++)
00337             {
00338                 double estimated_mTerminalFluxChangeVector=p_mTerminalFluxChangeVector[terminal];
00339                 unsigned edge_index = mTerminalToEdgeIndex[terminal];
00340                 mFlux[edge_index] +=  terminal_flux_correction*estimated_mTerminalFluxChangeVector;
00341             }
00342             SolveDirectFromFlux();
00343         }
00344     }
00345     if(!converged)
00346     {
00347         NEVER_REACHED;
00348     }
00349 }
00350 
00351 double VentilationProblem::CalculateResistance(Element<1,3>& rElement, bool usePedley, double flux)
00352 {
00353     //Resistance is based on radius, length and viscosity
00354     double radius = 0.0;
00355     if (mRadiusOnEdge)
00356     {
00357         radius = rElement.GetAttribute();
00358     }
00359     else
00360     {
00361         radius = ( rElement.GetNode(0)->rGetNodeAttributes()[0] + rElement.GetNode(1)->rGetNodeAttributes()[0]) / 2.0;
00362     }
00363 
00364     c_vector<double, 3> dummy;
00365     double length;
00366     mMesh.GetWeightedDirectionForElement(rElement.GetIndex(), dummy, length);
00367 
00368     double resistance = 8.0*mViscosity*length/(M_PI*SmallPow(radius, 4));
00369     if ( usePedley )
00370     {
00371         /* Pedley et al. 1970
00372          * http://dx.doi.org/10.1016/0034-5687(70)90094-0
00373          * also Swan et al. 2012. 10.1016/j.jtbi.2012.01.042 (page 224)
00374          * Standard Poiseuille equation is similar to Pedley's modified Eq1. and matches Swan Eq5.
00375          * R_p = 128*mu*L/(pi*d^4) = 8*mu*L/(pi*r^4)
00376          *
00377          * Pedley Eq 2 and Swan Eq4:
00378          *  Z = C/(4*sqrt(2)) * sqrt(Re*d/l) = (C/4)*sqrt(Re*r/l)
00379          * Pedley suggests that C = 1.85
00380          * R_r = Z*R_p
00381          *
00382          * Reynold's number in a pipe is
00383          * Re = rho*v*d/mu (where d is a characteristic length scale - diameter of pipe)
00384          * since flux = v*area
00385          * Re = Q * d/(mu*area) = 2*rho*Q/(mu*pi*r) ... (see Swan p 224)
00386          *
00387          *
00388          * The upshot of this calculation is that the resistance is scaled with sqrt(Q)
00389          */
00390         double reynolds_number = fabs( 2.0 * mDensity * flux / (mViscosity * M_PI * radius) );
00391         double c = 1.85;
00392         double z = (c/4.0) * sqrt(reynolds_number * radius / length);
00393         // Pedley's method will only increase the resistance
00394         if (z > 1.0)
00395         {
00396             resistance *= z;
00397         }
00398     }
00399     return resistance;
00400 }
00401 
00402 void VentilationProblem::SetOutflowPressure(double pressure)
00403 {
00404     SetPressureAtBoundaryNode(*(mMesh.GetNode(mOutletNodeIndex)), pressure);
00405     mPressure[mOutletNodeIndex] = pressure;
00406 }
00407 
00408 void VentilationProblem::SetConstantInflowPressures(double pressure)
00409 {
00410     for (AbstractTetrahedralMesh<1,3>::BoundaryNodeIterator iter =mMesh.GetBoundaryNodeIteratorBegin();
00411           iter != mMesh.GetBoundaryNodeIteratorEnd();
00412           ++iter)
00413      {
00414          if ((*iter)->GetIndex() != mOutletNodeIndex)
00415          {
00416              //Boundary conditions at each boundary/leaf node
00417              SetPressureAtBoundaryNode(*(*iter), pressure);
00418          }
00419      }
00420 }
00421 
00422 void VentilationProblem::SetConstantInflowFluxes(double flux)
00423 {
00424     for (AbstractTetrahedralMesh<1,3>::BoundaryNodeIterator iter =mMesh.GetBoundaryNodeIteratorBegin();
00425           iter != mMesh.GetBoundaryNodeIteratorEnd();
00426           ++iter)
00427      {
00428          if ((*iter)->GetIndex() != mOutletNodeIndex)
00429          {
00430              SetFluxAtBoundaryNode(*(*iter), flux);
00431          }
00432      }
00433 }
00434 
00435 void VentilationProblem::SetPressureAtBoundaryNode(const Node<3>& rNode, double pressure)
00436 {
00437     if (rNode.IsBoundaryNode() == false)
00438     {
00439         EXCEPTION("Boundary conditions cannot be set at internal nodes");
00440     }
00441     assert(mFluxGivenAtInflow == false);
00442 
00443     // Store the requirement in a map for the direct solver
00444     mPressureCondition[rNode.GetIndex()] = pressure;
00445 }
00446 
00447 double VentilationProblem::GetPressureAtBoundaryNode(const Node<3>& rNode)
00448 {
00449 // //This doesn't actually present any problems -- we could call it GetPressureAtNode
00450 //    if (rNode.IsBoundaryNode() == false)
00451 //    {
00452 //        EXCEPTION("Boundary conditions cannot be got at internal nodes");
00453 //    }
00454     return mPressure[rNode.GetIndex()];
00455 }
00456 
00457 double VentilationProblem::GetFluxAtOutflow()
00458 {
00459     return mFlux[mOutletNodeIndex];
00460 }
00461 
00462 void VentilationProblem::SetFluxAtBoundaryNode(const Node<3>& rNode, double flux)
00463 {
00464     if (rNode.IsBoundaryNode() == false)
00465     {
00466         EXCEPTION("Boundary conditions cannot be set at internal nodes");
00467     }
00468     mFluxGivenAtInflow = true;
00469 
00470     // In a <1,3> mesh a boundary node will be associated with exactly one edge.
00471     unsigned edge_index = *( rNode.ContainingElementsBegin() );
00472 
00473     // Seed the information for a direct solver
00474     mFlux[edge_index] = flux;
00475 }
00476 
00477 
00478 
00479 void VentilationProblem::Solve()
00480 {
00481     if (mFluxGivenAtInflow)
00482     {
00483         SolveDirectFromFlux();
00484     }
00485     else
00486     {
00487         SolveIterativelyFromPressure();
00488     }
00489 
00490 }
00491 
00492 
00493 void VentilationProblem::GetSolutionAsFluxesAndPressures(std::vector<double>& rFluxesOnEdges,
00494                                                          std::vector<double>& rPressuresOnNodes)
00495 {
00496     rFluxesOnEdges = mFlux;
00497     rPressuresOnNodes = mPressure;
00498 }
00499 
00500 
00501 void VentilationProblem::SetRadiusOnEdge(bool isOnEdges)
00502 {
00503     mRadiusOnEdge = isOnEdges;
00504 }
00505 
00506 TetrahedralMesh<1, 3>& VentilationProblem::rGetMesh()
00507 {
00508     return mMesh;
00509 }
00510 
00511 
00512 #ifdef CHASTE_VTK
00513 
00514 void VentilationProblem::WriteVtk(const std::string& rDirName, const std::string& rFileBaseName)
00515 {
00516     VtkMeshWriter<1, 3> vtk_writer(rDirName, rFileBaseName, false);
00517     AddDataToVtk(vtk_writer, "");
00518     vtk_writer.WriteFilesUsingMesh(mMesh);
00519 
00520 }
00521 
00522 void VentilationProblem::AddDataToVtk(VtkMeshWriter<1, 3>& rVtkWriter,
00523                                       const std::string& rSuffix)
00524 {
00525     std::vector<double> pressures;
00526     std::vector<double> fluxes;
00527     GetSolutionAsFluxesAndPressures(fluxes, pressures);
00528     rVtkWriter.AddCellData("Flux"+rSuffix, fluxes);
00529     rVtkWriter.AddPointData("Pressure"+rSuffix, pressures);
00530 
00531     std::vector<double> volumes(mMesh.GetNumNodes());
00532     std::vector<double> stretch_ratios(mMesh.GetNumNodes());
00533     for (AbstractTetrahedralMesh<1,3>::BoundaryNodeIterator iter = mMesh.GetBoundaryNodeIteratorBegin();
00534              iter != mMesh.GetBoundaryNodeIteratorEnd();
00535              ++iter)
00536     {
00537         if( (*iter)->GetIndex() != mOutletNodeIndex)
00538         {
00539             volumes[(*iter)->GetIndex()] = mAcinarUnits[(*iter)->GetIndex()]->GetVolume();
00540             stretch_ratios[(*iter)->GetIndex()] = mAcinarUnits[(*iter)->GetIndex()]->GetStretchRatio();
00541         }
00542     }
00543     rVtkWriter.AddPointData("Volume"+rSuffix, volumes);
00544     rVtkWriter.AddPointData("Stretch"+rSuffix, stretch_ratios);
00545 }
00546 
00547 #endif // CHASTE_VTK
00548 
00549 
00550 void VentilationProblem::Solve(TimeStepper& rTimeStepper,
00551         void (*pBoundaryConditionFunction)(VentilationProblem*, TimeStepper& rTimeStepper, const Node<3>&),
00552         const std::string& rDirName, const std::string& rFileBaseName)
00553 {
00554 #ifdef CHASTE_VTK
00555     VtkMeshWriter<1, 3> vtk_writer(rDirName, rFileBaseName, false);
00556 #endif
00557 
00558     bool first_step=true;
00559     while (!rTimeStepper.IsTimeAtEnd())
00560     {
00561         if (first_step)
00562         {
00563             // Do a solve at t=0 before advancing time.
00564             first_step = false;
00565         }
00566         else
00567         {
00568             rTimeStepper.AdvanceOneTimeStep();
00569         }
00570         for (AbstractTetrahedralMesh<1,3>::BoundaryNodeIterator iter = mMesh.GetBoundaryNodeIteratorBegin();
00571                  iter != mMesh.GetBoundaryNodeIteratorEnd();
00572                  ++iter )
00573         {
00574             if ((*iter)->GetIndex() != mOutletNodeIndex)
00575             {
00576                 //Boundary conditions at each boundary/leaf node
00577                 pBoundaryConditionFunction(this, rTimeStepper, *(*iter));
00578             }
00579         }
00580 
00581         // Regular solve
00582         Solve();
00583 
00584         std::ostringstream suffix_name;
00585         suffix_name <<  "_" << std::setw(6) << std::setfill('0') << rTimeStepper.GetTotalTimeStepsTaken();
00586 #ifdef CHASTE_VTK
00587         AddDataToVtk(vtk_writer, suffix_name.str());
00588 #endif
00589     }
00590 
00591 #ifdef CHASTE_VTK
00592     vtk_writer.WriteFilesUsingMesh(mMesh);
00593 #endif
00594 }
00595 
00596 void VentilationProblem::SolveProblemFromFile(const std::string& rInFilePath, const std::string& rOutFileDir, const std::string& rOutFileName)
00597 {
00598     std::ifstream file(FileFinder(rInFilePath).GetAbsolutePath().c_str(), std::ios::binary);
00599     if (!file.is_open())
00600     {
00601         EXCEPTION("Could not open file "+rInFilePath);
00602     }
00603     std::string key, unit;
00604     double value;
00605     while (!file.eof())
00606     {
00607         file >> key >> value >> unit;
00608         if (file.fail())
00609         {
00610             break;
00611         }
00612         if (key == "RHO_AIR")
00613         {
00614             SetDensity(value);
00615         }
00616         else if (key == "MU_AIR")
00617         {
00618             SetViscosity(value);
00619         }
00620         else if (key == "PRESSURE_OUT")
00621         {
00622             SetOutflowPressure(value);
00623         }
00624         else if (key == "PRESSURE_IN")
00625         {
00626             SetConstantInflowPressures(value);
00627         }
00628         else
00629         {
00630             WARNING("The key "+ key+ " is not recognised yet");
00631         }
00632     }
00633     Solve();
00634 #ifdef CHASTE_VTK
00635     WriteVtk(rOutFileDir, rOutFileName);
00636 #endif
00637 }
00638 
00639 
00640 
00641 
00642 
00643 

Generated by  doxygen 1.6.2