LinearParabolicPdeSystemWithCoupledOdeSystemSolver.hpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 #ifndef LINEARPARABOLICPDESYSTEMWITHCOUPLEDODESYSTEMSOLVER_HPP_
00036 #define LINEARPARABOLICPDESYSTEMWITHCOUPLEDODESYSTEMSOLVER_HPP_
00037 
00038 #include "AbstractAssemblerSolverHybrid.hpp"
00039 #include "AbstractDynamicLinearPdeSolver.hpp"
00040 #include "AbstractLinearParabolicPdeSystemForCoupledOdeSystem.hpp"
00041 #include "TetrahedralMesh.hpp"
00042 #include "BoundaryConditionsContainer.hpp"
00043 #include "AbstractOdeSystemForCoupledPdeSystem.hpp"
00044 #include "CvodeAdaptor.hpp"
00045 #include "BackwardEulerIvpOdeSolver.hpp"
00046 #include "Warnings.hpp"
00047 #include "VtkMeshWriter.hpp"
00048 
00049 #include <boost/shared_ptr.hpp>
00050 
00060 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM=ELEMENT_DIM, unsigned PROBLEM_DIM=1>
00061 class LinearParabolicPdeSystemWithCoupledOdeSystemSolver
00062     : public AbstractAssemblerSolverHybrid<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, NORMAL>,
00063       public AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>
00064 {
00065 private:
00066 
00068     AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>* mpMesh;
00069 
00071     AbstractLinearParabolicPdeSystemForCoupledOdeSystem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* mpPdeSystem;
00072 
00074     std::vector<AbstractOdeSystemForCoupledPdeSystem*> mOdeSystemsAtNodes;
00075 
00077     std::vector<double> mInterpolatedOdeStateVariables;
00078 
00080     boost::shared_ptr<AbstractIvpOdeSolver> mpOdeSolver;
00081 
00087     double mSamplingTimeStep;
00088 
00090     bool mOdeSystemsPresent;
00091 
00093     out_stream mpVtkMetaFile;
00094 
00099     bool mClearOutputDirectory;
00100 
00104     void WriteVtkResultsToFile();
00105 
00116     c_matrix<double, PROBLEM_DIM*(ELEMENT_DIM+1), PROBLEM_DIM*(ELEMENT_DIM+1)> ComputeMatrixTerm(
00117         c_vector<double, ELEMENT_DIM+1>& rPhi,
00118         c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rGradPhi,
00119         ChastePoint<SPACE_DIM>& rX,
00120         c_vector<double,PROBLEM_DIM>& rU,
00121         c_matrix<double, PROBLEM_DIM, SPACE_DIM>& rGradU,
00122         Element<ELEMENT_DIM, SPACE_DIM>* pElement);
00123 
00134     c_vector<double, PROBLEM_DIM*(ELEMENT_DIM+1)> ComputeVectorTerm(
00135         c_vector<double, ELEMENT_DIM+1>& rPhi,
00136         c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rGradPhi,
00137         ChastePoint<SPACE_DIM>& rX,
00138         c_vector<double,PROBLEM_DIM>& rU,
00139         c_matrix<double,PROBLEM_DIM,SPACE_DIM>& rGradU,
00140         Element<ELEMENT_DIM, SPACE_DIM>* pElement);
00141 
00145     void ResetInterpolatedQuantities();
00146 
00154     void IncrementInterpolatedQuantities(double phiI, const Node<SPACE_DIM>* pNode);
00155 
00164     void InitialiseForSolve(Vec initialSolution=NULL);
00165 
00174     void SetupLinearSystem(Vec currentSolution, bool computeMatrix);
00175 
00176 public:
00177 
00187     LinearParabolicPdeSystemWithCoupledOdeSystemSolver(TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>* pMesh,
00188                                                        AbstractLinearParabolicPdeSystemForCoupledOdeSystem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* pPdeSystem,
00189                                                        BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* pBoundaryConditions,
00190                                                        std::vector<AbstractOdeSystemForCoupledPdeSystem*> odeSystemsAtNodes=std::vector<AbstractOdeSystemForCoupledPdeSystem*>(),
00191                                                        boost::shared_ptr<AbstractIvpOdeSolver> pOdeSolver=boost::shared_ptr<AbstractIvpOdeSolver>());
00192 
00197     ~LinearParabolicPdeSystemWithCoupledOdeSystemSolver();
00198 
00205     void PrepareForSetupLinearSystem(Vec currentPdeSolution);
00206 
00214     void SetOutputDirectory(std::string outputDirectory, bool clearDirectory=false);
00215 
00221     void SetSamplingTimeStep(double samplingTimeStep);
00222 
00227     void SolveAndWriteResultsToFile();
00228 
00235     void WriteVtkResultsToFile(Vec solution, unsigned numTimeStepsElapsed);
00236 
00243     AbstractOdeSystemForCoupledPdeSystem* GetOdeSystemAtNode(unsigned index);
00244 };
00245 
00247 // Implementation
00249 
00250 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00251 c_matrix<double, PROBLEM_DIM*(ELEMENT_DIM+1), PROBLEM_DIM*(ELEMENT_DIM+1)> LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::ComputeMatrixTerm(
00252     c_vector<double, ELEMENT_DIM+1>& rPhi,
00253     c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rGradPhi,
00254     ChastePoint<SPACE_DIM>& rX,
00255     c_vector<double,PROBLEM_DIM>& rU,
00256     c_matrix<double, PROBLEM_DIM, SPACE_DIM>& rGradU,
00257     Element<ELEMENT_DIM, SPACE_DIM>* pElement)
00258 {
00259     double timestep_inverse = PdeSimulationTime::GetPdeTimeStepInverse();
00260     c_matrix<double, PROBLEM_DIM*(ELEMENT_DIM+1), PROBLEM_DIM*(ELEMENT_DIM+1)> matrix_term = zero_matrix<double>(PROBLEM_DIM*(ELEMENT_DIM+1), PROBLEM_DIM*(ELEMENT_DIM+1));
00261 
00262     // Loop over PDEs and populate matrix_term
00263     for (unsigned pde_index=0; pde_index<PROBLEM_DIM; pde_index++)
00264     {
00265         double this_dudt_coefficient = mpPdeSystem->ComputeDuDtCoefficientFunction(rX, pde_index);
00266         c_matrix<double, SPACE_DIM, SPACE_DIM> this_pde_diffusion_term = mpPdeSystem->ComputeDiffusionTerm(rX, pde_index, pElement);
00267         c_matrix<double, 1*(ELEMENT_DIM+1), 1*(ELEMENT_DIM+1)> this_stiffness_matrix =
00268             prod(trans(rGradPhi), c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>(prod(this_pde_diffusion_term, rGradPhi)) )
00269                 + timestep_inverse * this_dudt_coefficient * outer_prod(rPhi, rPhi);
00270 
00271         for (unsigned i=0; i<ELEMENT_DIM+1; i++)
00272         {
00273             for (unsigned j=0; j<ELEMENT_DIM+1; j++)
00274             {
00275                 matrix_term(i*PROBLEM_DIM + pde_index, j*PROBLEM_DIM + pde_index) = this_stiffness_matrix(i,j);
00276             }
00277         }
00278     }
00279     return matrix_term;
00280 }
00281 
00282 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00283 c_vector<double, PROBLEM_DIM*(ELEMENT_DIM+1)> LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::ComputeVectorTerm(
00284     c_vector<double, ELEMENT_DIM+1>& rPhi,
00285     c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rGradPhi,
00286     ChastePoint<SPACE_DIM>& rX,
00287     c_vector<double,PROBLEM_DIM>& rU,
00288     c_matrix<double,PROBLEM_DIM,SPACE_DIM>& rGradU,
00289     Element<ELEMENT_DIM, SPACE_DIM>* pElement)
00290 {
00291     double timestep_inverse = PdeSimulationTime::GetPdeTimeStepInverse();
00292     c_vector<double, PROBLEM_DIM*(ELEMENT_DIM+1)> vector_term = zero_vector<double>(PROBLEM_DIM*(ELEMENT_DIM+1));
00293 
00294     // Loop over PDEs and populate vector_term
00295     for (unsigned pde_index=0; pde_index<PROBLEM_DIM; pde_index++)
00296     {
00297         double this_dudt_coefficient = mpPdeSystem->ComputeDuDtCoefficientFunction(rX, pde_index);
00298         double this_source_term = mpPdeSystem->ComputeSourceTerm(rX, rU, mInterpolatedOdeStateVariables, pde_index);
00299         c_vector<double, ELEMENT_DIM+1> this_vector_term = (this_source_term + timestep_inverse*this_dudt_coefficient*rU(pde_index))* rPhi;
00300 
00301         for (unsigned i=0; i<ELEMENT_DIM+1; i++)
00302         {
00303             vector_term(i*PROBLEM_DIM + pde_index) = this_vector_term(i);
00304         }
00305     }
00306 
00307     return vector_term;
00308 }
00309 
00310 
00311 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00312 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::ResetInterpolatedQuantities()
00313 {
00314     mInterpolatedOdeStateVariables.clear();
00315 
00316     if (mOdeSystemsPresent)
00317     {
00318         unsigned num_state_variables = mOdeSystemsAtNodes[0]->GetNumberOfStateVariables();
00319         mInterpolatedOdeStateVariables.resize(num_state_variables, 0.0);
00320     }
00321 }
00322 
00323 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00324 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::IncrementInterpolatedQuantities(double phiI, const Node<SPACE_DIM>* pNode)
00325 {
00326     if (mOdeSystemsPresent)
00327     {
00328         unsigned num_state_variables = mOdeSystemsAtNodes[0]->GetNumberOfStateVariables();
00329 
00330         for (unsigned i=0; i<num_state_variables; i++)
00331         {
00332             mInterpolatedOdeStateVariables[i] += phiI * mOdeSystemsAtNodes[pNode->GetIndex()]->rGetStateVariables()[i];
00333         }
00334     }
00335 }
00336 
00337 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00338 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::InitialiseForSolve(Vec initialSolution)
00339 {
00340     if (this->mpLinearSystem == NULL)
00341     {
00342         unsigned preallocation = mpMesh->CalculateMaximumContainingElementsPerProcess() + ELEMENT_DIM;
00343         if (ELEMENT_DIM > 1)
00344         {
00345             // Highest connectivity is closed
00346             preallocation--;
00347         }
00348         preallocation *= PROBLEM_DIM;
00349 
00350         /*
00351          * Use the current solution (ie the initial solution) as the
00352          * template in the alternative constructor of LinearSystem.
00353          * This is to avoid problems with VecScatter.
00354          */
00355         this->mpLinearSystem = new LinearSystem(initialSolution, preallocation);
00356     }
00357 
00358     assert(this->mpLinearSystem);
00359     this->mpLinearSystem->SetMatrixIsSymmetric(true);
00360     this->mpLinearSystem->SetKspType("cg");
00361 }
00362 
00363 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00364 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetupLinearSystem(Vec currentSolution, bool computeMatrix)
00365 {
00366     this->SetupGivenLinearSystem(currentSolution, computeMatrix, this->mpLinearSystem);
00367 }
00368 
00369 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00370 LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::LinearParabolicPdeSystemWithCoupledOdeSystemSolver(
00371         TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>* pMesh,
00372         AbstractLinearParabolicPdeSystemForCoupledOdeSystem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* pPdeSystem,
00373         BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* pBoundaryConditions,
00374         std::vector<AbstractOdeSystemForCoupledPdeSystem*> odeSystemsAtNodes,
00375         boost::shared_ptr<AbstractIvpOdeSolver> pOdeSolver)
00376     : AbstractAssemblerSolverHybrid<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, NORMAL>(pMesh, pBoundaryConditions),
00377       AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>(pMesh),
00378       mpMesh(pMesh),
00379       mpPdeSystem(pPdeSystem),
00380       mOdeSystemsAtNodes(odeSystemsAtNodes),
00381       mpOdeSolver(pOdeSolver),
00382       mSamplingTimeStep(DOUBLE_UNSET),
00383       mOdeSystemsPresent(false),
00384       mClearOutputDirectory(false)
00385 {
00386     this->mpBoundaryConditions = pBoundaryConditions;
00387 
00388     /*
00389      * If any ODE systems are passed in to the constructor, then we aren't just
00390      * solving a coupled PDE system, in which case the number of ODE system objects
00391      * must match the number of nodes in the finite element mesh.
00392      */
00393     if (!mOdeSystemsAtNodes.empty())
00394     {
00395         mOdeSystemsPresent = true;
00396         assert(mOdeSystemsAtNodes.size() == mpMesh->GetNumNodes());
00397 
00398         /*
00399          * In this case, if an ODE solver is not explicitly passed into the
00400          * constructor, then we create a default solver.
00401          */
00402         if (!mpOdeSolver)
00403         {
00404 #ifdef CHASTE_CVODE
00405             mpOdeSolver.reset(new CvodeAdaptor);
00406 #else
00407             mpOdeSolver.reset(new BackwardEulerIvpOdeSolver(mOdeSystemsAtNodes[0]->GetNumberOfStateVariables()));
00408 #endif //CHASTE_CVODE
00409         }
00410     }
00411 }
00412 
00413 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00414 LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::~LinearParabolicPdeSystemWithCoupledOdeSystemSolver()
00415 {
00416     if (mOdeSystemsPresent)
00417     {
00418         for (unsigned i=0; i<mOdeSystemsAtNodes.size(); i++)
00419         {
00420             delete mOdeSystemsAtNodes[i];
00421         }
00422     }
00423 }
00424 
00425 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00426 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::PrepareForSetupLinearSystem(Vec currentPdeSolution)
00427 {
00428     if (mOdeSystemsPresent)
00429     {
00430         double time = PdeSimulationTime::GetTime();
00431         double next_time = PdeSimulationTime::GetNextTime();
00432         double dt = PdeSimulationTime::GetPdeTimeStep();
00433 
00434         ReplicatableVector soln_repl(currentPdeSolution);
00435         std::vector<double> current_soln_this_node(PROBLEM_DIM);
00436 
00437         // Loop over nodes
00438         for (unsigned node_index=0; node_index<mpMesh->GetNumNodes(); node_index++)
00439         {
00440             // Store the current solution to the PDE system at this node
00441             for (unsigned pde_index=0; pde_index<PROBLEM_DIM; pde_index++)
00442             {
00443                 double current_soln_this_pde_this_node = soln_repl[PROBLEM_DIM*node_index + pde_index];
00444                 current_soln_this_node[pde_index] = current_soln_this_pde_this_node;
00445             }
00446 
00447             // Pass it into the ODE system at this node
00448             mOdeSystemsAtNodes[node_index]->SetPdeSolution(current_soln_this_node);
00449 
00450             // Solve ODE system at this node
00451             mpOdeSolver->SolveAndUpdateStateVariable(mOdeSystemsAtNodes[node_index], time, next_time, dt);
00452         }
00453     }
00454 }
00455 
00456 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00457 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetOutputDirectory(std::string outputDirectory, bool clearDirectory)
00458 {
00459     mClearOutputDirectory = clearDirectory;
00460     this->mOutputDirectory = outputDirectory;
00461 }
00462 
00463 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00464 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetSamplingTimeStep(double samplingTimeStep)
00465 {
00466     assert(samplingTimeStep >= this->mIdealTimeStep);
00467     mSamplingTimeStep = samplingTimeStep;
00468 }
00469 
00470 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00471 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SolveAndWriteResultsToFile()
00472 {
00473     // A number of methods must have been called prior to this method
00474     if (this->mOutputDirectory == "")
00475     {
00476         EXCEPTION("SetOutputDirectory() must be called prior to SolveAndWriteResultsToFile()");
00477     }
00478     if (this->mTimesSet == false)
00479     {
00480         EXCEPTION("SetTimes() must be called prior to SolveAndWriteResultsToFile()");
00481     }
00482     if (this->mIdealTimeStep <= 0.0)
00483     {
00484         EXCEPTION("SetTimeStep() must be called prior to SolveAndWriteResultsToFile()");
00485     }
00486     if (mSamplingTimeStep == DOUBLE_UNSET)
00487     {
00488         EXCEPTION("SetSamplingTimeStep() must be called prior to SolveAndWriteResultsToFile()");
00489     }
00490     if (!this->mInitialCondition)
00491     {
00492         EXCEPTION("SetInitialCondition() must be called prior to SolveAndWriteResultsToFile()");
00493     }
00494 
00495 #ifdef CHASTE_VTK
00496     // Create a .pvd output file
00497     OutputFileHandler output_file_handler(this->mOutputDirectory, mClearOutputDirectory);
00498     mpVtkMetaFile = output_file_handler.OpenOutputFile("results.pvd");
00499     *mpVtkMetaFile << "<?xml version=\"1.0\"?>\n";
00500     *mpVtkMetaFile << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\" compressor=\"vtkZLibDataCompressor\">\n";
00501     *mpVtkMetaFile << "    <Collection>\n";
00502 
00503     // Write initial condition to VTK
00504     Vec initial_condition = this->mInitialCondition;
00505     WriteVtkResultsToFile(initial_condition, 0);
00506 
00507     // The helper class TimeStepper deals with issues such as small final timesteps so we don't have to
00508     TimeStepper stepper(this->mTstart, this->mTend, mSamplingTimeStep);
00509 
00510     // Main time loop
00511     while (!stepper.IsTimeAtEnd())
00512     {
00513         // Reset start and end times
00514         this->SetTimes(stepper.GetTime(), stepper.GetNextTime());
00515 
00516         // Solve the system up to the new end time
00517         Vec soln = this->Solve();
00518 
00519         // Reset the initial condition for the next timestep
00520         if (this->mInitialCondition != initial_condition)
00521         {
00522             PetscTools::Destroy(this->mInitialCondition);
00523         }
00524         this->mInitialCondition = soln;
00525 
00526         // Move forward in time
00527         stepper.AdvanceOneTimeStep();
00528 
00529         // Write solution to VTK
00530         WriteVtkResultsToFile(soln, stepper.GetTotalTimeStepsTaken());
00531     }
00532 
00533     // Restore saved initial condition to avoid user confusion!
00534     if (this->mInitialCondition != initial_condition)
00535     {
00536         PetscTools::Destroy(this->mInitialCondition);
00537     }
00538     this->mInitialCondition = initial_condition;
00539 
00540     // Close .pvd output file
00541     *mpVtkMetaFile << "    </Collection>\n";
00542     *mpVtkMetaFile << "</VTKFile>\n";
00543     mpVtkMetaFile->close();
00544 #else //CHASTE_VTK
00545 #define COVERAGE_IGNORE // We only test this in weekly builds
00546     WARNING("VTK is not installed and is required for this functionality");
00547 #undef COVERAGE_IGNORE
00548 #endif //CHASTE_VTK
00549 }
00550 
00551 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00552 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::WriteVtkResultsToFile(Vec solution, unsigned numTimeStepsElapsed)
00553 {
00554 #ifdef CHASTE_VTK
00555 
00556     // Create a new VTK file for this time step
00557     std::stringstream time;
00558     time << numTimeStepsElapsed;
00559     VtkMeshWriter<ELEMENT_DIM, SPACE_DIM> mesh_writer(this->mOutputDirectory, "results_"+time.str(), false);
00560 
00561     /*
00562      * We first loop over PDEs. For each PDE we store the solution
00563      * at each node in a vector, then pass this vector to the mesh
00564      * writer.
00565      */
00566     ReplicatableVector solution_repl(solution);
00567     unsigned num_nodes = mpMesh->GetNumNodes();
00568     for (unsigned pde_index=0; pde_index<PROBLEM_DIM; pde_index++)
00569     {
00570         // Store the solution of this PDE at each node
00571         std::vector<double> pde_index_data;
00572         pde_index_data.resize(num_nodes, 0.0);
00573         for (unsigned node_index=0; node_index<num_nodes; node_index++)
00574         {
00575             pde_index_data[node_index] = solution_repl[PROBLEM_DIM*node_index + pde_index];
00576         }
00577 
00578         // Add this data to the mesh writer
00579         std::stringstream data_name;
00580         data_name << "PDE variable " << pde_index;
00581         mesh_writer.AddPointData(data_name.str(), pde_index_data);
00582     }
00583 
00584     if (mOdeSystemsPresent)
00585     {
00586         /*
00587          * We cannot loop over ODEs like PDEs, since the solutions are not
00588          * stored in one place. Therefore we build up a large 'vector of
00589          * vectors', then pass each component of this vector to the mesh
00590          * writer.
00591          */
00592         std::vector<std::vector<double> > ode_data;
00593         unsigned num_odes = mOdeSystemsAtNodes[0]->rGetStateVariables().size();
00594         ode_data.resize(num_odes);
00595         for (unsigned ode_index=0; ode_index<num_odes; ode_index++)
00596         {
00597             ode_data[ode_index].resize(num_nodes, 0.0);
00598         }
00599 
00600         for (unsigned node_index=0; node_index<num_nodes; node_index++)
00601         {
00602             std::vector<double> all_odes_this_node = mOdeSystemsAtNodes[node_index]->rGetStateVariables();
00603             for (unsigned i=0; i<num_odes; i++)
00604             {
00605                 ode_data[i][node_index] = all_odes_this_node[i];
00606             }
00607         }
00608 
00609         for (unsigned ode_index=0; ode_index<num_odes; ode_index++)
00610         {
00611             std::vector<double> ode_index_data = ode_data[ode_index];
00612 
00613             // Add this data to the mesh writer
00614             std::stringstream data_name;
00615             data_name << "ODE variable " << ode_index;
00616             mesh_writer.AddPointData(data_name.str(), ode_index_data);
00617         }
00618     }
00619 
00620     mesh_writer.WriteFilesUsingMesh(*mpMesh);
00621     *mpVtkMetaFile << "        <DataSet timestep=\"";
00622     *mpVtkMetaFile << numTimeStepsElapsed;
00623     *mpVtkMetaFile << "\" group=\"\" part=\"0\" file=\"results_";
00624     *mpVtkMetaFile << numTimeStepsElapsed;
00625     *mpVtkMetaFile << ".vtu\"/>\n";
00626 #endif // CHASTE_VTK
00627 }
00628 
00629 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00630 AbstractOdeSystemForCoupledPdeSystem* LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::GetOdeSystemAtNode(unsigned index)
00631 {
00632     return mOdeSystemsAtNodes[index];
00633 }
00634 
00635 #endif /*LINEARPARABOLICPDESYSTEMWITHCOUPLEDODESYSTEMSOLVER_HPP_*/

Generated by  doxygen 1.6.2