LinearParabolicPdeSystemWithCoupledOdeSystemSolver.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 #ifndef LINEARPARABOLICPDESYSTEMWITHCOUPLEDODESYSTEMSOLVER_HPP_
00029 #define LINEARPARABOLICPDESYSTEMWITHCOUPLEDODESYSTEMSOLVER_HPP_
00030 
00031 #include "AbstractAssemblerSolverHybrid.hpp"
00032 #include "AbstractDynamicLinearPdeSolver.hpp"
00033 #include "AbstractLinearParabolicPdeSystemForCoupledOdeSystem.hpp"
00034 #include "TetrahedralMesh.hpp"
00035 #include "BoundaryConditionsContainer.hpp"
00036 #include "AbstractOdeSystemForCoupledPdeSystem.hpp"
00037 #include "CvodeAdaptor.hpp"
00038 #include "BackwardEulerIvpOdeSolver.hpp"
00039 #include "VtkMeshWriter.hpp"
00040 
00041 #include <boost/shared_ptr.hpp>
00042 
00052 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM=ELEMENT_DIM, unsigned PROBLEM_DIM=1>
00053 class LinearParabolicPdeSystemWithCoupledOdeSystemSolver
00054     : public AbstractAssemblerSolverHybrid<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, NORMAL>,
00055       public AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>
00056 {
00057 private:
00058 
00060     AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>* mpMesh;
00061 
00063     AbstractLinearParabolicPdeSystemForCoupledOdeSystem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* mpPdeSystem;
00064 
00066     std::vector<AbstractOdeSystemForCoupledPdeSystem*> mOdeSystemsAtNodes;
00067 
00069     std::vector<double> mInterpolatedOdeStateVariables;
00070 
00072     boost::shared_ptr<AbstractIvpOdeSolver> mpOdeSolver;
00073 
00079     double mSamplingTimeStep;
00080 
00082     bool mOdeSystemsPresent;
00083 
00085     out_stream mpVtkMetaFile;
00086 
00090     void WriteVtkResultsToFile();
00091 
00102     c_matrix<double, PROBLEM_DIM*(ELEMENT_DIM+1), PROBLEM_DIM*(ELEMENT_DIM+1)> ComputeMatrixTerm(
00103         c_vector<double, ELEMENT_DIM+1>& rPhi,
00104         c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rGradPhi,
00105         ChastePoint<SPACE_DIM>& rX,
00106         c_vector<double,PROBLEM_DIM>& rU,
00107         c_matrix<double, PROBLEM_DIM, SPACE_DIM>& rGradU,
00108         Element<ELEMENT_DIM, SPACE_DIM>* pElement);
00109 
00120     c_vector<double, PROBLEM_DIM*(ELEMENT_DIM+1)> ComputeVectorTerm(
00121         c_vector<double, ELEMENT_DIM+1>& rPhi,
00122         c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rGradPhi,
00123         ChastePoint<SPACE_DIM>& rX,
00124         c_vector<double,PROBLEM_DIM>& rU,
00125         c_matrix<double,PROBLEM_DIM,SPACE_DIM>& rGradU,
00126         Element<ELEMENT_DIM, SPACE_DIM>* pElement);
00127 
00131     void ResetInterpolatedQuantities();
00132 
00140     void IncrementInterpolatedQuantities(double phiI, const Node<SPACE_DIM>* pNode);
00141 
00150     void InitialiseForSolve(Vec initialSolution=NULL);
00151 
00160     void SetupLinearSystem(Vec currentSolution, bool computeMatrix);
00161 
00162 public:
00163 
00173     LinearParabolicPdeSystemWithCoupledOdeSystemSolver(TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>* pMesh,
00174                                                        AbstractLinearParabolicPdeSystemForCoupledOdeSystem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* pPdeSystem,
00175                                                        BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* pBoundaryConditions,
00176                                                        std::vector<AbstractOdeSystemForCoupledPdeSystem*> odeSystemsAtNodes=std::vector<AbstractOdeSystemForCoupledPdeSystem*>(),
00177                                                        boost::shared_ptr<AbstractIvpOdeSolver> pOdeSolver=boost::shared_ptr<AbstractIvpOdeSolver>());
00178 
00182     ~LinearParabolicPdeSystemWithCoupledOdeSystemSolver();
00183 
00190     void PrepareForSetupLinearSystem(Vec currentPdeSolution);
00191 
00197     void SetOutputDirectory(std::string outputDirectory);
00198 
00204     void SetSamplingTimeStep(double samplingTimeStep);
00205 
00210     void SolveAndWriteResultsToFile();
00211 
00218     void WriteVtkResultsToFile(Vec solution, unsigned numTimeStepsElapsed);
00219 };
00220 
00222 // Implementation
00224 
00225 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00226 c_matrix<double, PROBLEM_DIM*(ELEMENT_DIM+1), PROBLEM_DIM*(ELEMENT_DIM+1)> LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::ComputeMatrixTerm(
00227     c_vector<double, ELEMENT_DIM+1>& rPhi,
00228     c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rGradPhi,
00229     ChastePoint<SPACE_DIM>& rX,
00230     c_vector<double,PROBLEM_DIM>& rU,
00231     c_matrix<double, PROBLEM_DIM, SPACE_DIM>& rGradU,
00232     Element<ELEMENT_DIM, SPACE_DIM>* pElement)
00233 {
00234     double timestep_inverse = PdeSimulationTime::GetPdeTimeStepInverse();
00235     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));
00236 
00237     // Loop over PDEs and populate matrix_term
00238     for (unsigned pde_index=0; pde_index<PROBLEM_DIM; pde_index++)
00239     {
00240         double this_dudt_coefficient = mpPdeSystem->ComputeDuDtCoefficientFunction(rX, pde_index);
00241         c_matrix<double, SPACE_DIM, SPACE_DIM> this_pde_diffusion_term = mpPdeSystem->ComputeDiffusionTerm(rX, pde_index, pElement);
00242         c_matrix<double, 1*(ELEMENT_DIM+1), 1*(ELEMENT_DIM+1)> this_stiffness_matrix =
00243             prod(trans(rGradPhi), c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>(prod(this_pde_diffusion_term, rGradPhi)) )
00244                 + timestep_inverse * this_dudt_coefficient * outer_prod(rPhi, rPhi);
00245 
00246         for (unsigned i=0; i<ELEMENT_DIM+1; i++)
00247         {
00248             for (unsigned j=0; j<ELEMENT_DIM+1; j++)
00249             {
00250                 matrix_term(i*PROBLEM_DIM + pde_index, j*PROBLEM_DIM + pde_index) = this_stiffness_matrix(i,j);
00251             }
00252         }
00253     }
00254     return matrix_term;
00255 }
00256 
00257 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00258 c_vector<double, PROBLEM_DIM*(ELEMENT_DIM+1)> LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::ComputeVectorTerm(
00259     c_vector<double, ELEMENT_DIM+1>& rPhi,
00260     c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rGradPhi,
00261     ChastePoint<SPACE_DIM>& rX,
00262     c_vector<double,PROBLEM_DIM>& rU,
00263     c_matrix<double,PROBLEM_DIM,SPACE_DIM>& rGradU,
00264     Element<ELEMENT_DIM, SPACE_DIM>* pElement)
00265 {
00266     double timestep_inverse = PdeSimulationTime::GetPdeTimeStepInverse();
00267     c_vector<double, PROBLEM_DIM*(ELEMENT_DIM+1)> vector_term = zero_vector<double>(PROBLEM_DIM*(ELEMENT_DIM+1));
00268 
00269     // Loop over PDEs and populate vector_term
00270     for (unsigned pde_index=0; pde_index<PROBLEM_DIM; pde_index++)
00271     {
00272         double this_dudt_coefficient = mpPdeSystem->ComputeDuDtCoefficientFunction(rX, pde_index);
00273         double this_source_term = mpPdeSystem->ComputeSourceTerm(rX, rU, mInterpolatedOdeStateVariables, pde_index);
00274         c_vector<double, ELEMENT_DIM+1> this_vector_term = (this_source_term + timestep_inverse*this_dudt_coefficient*rU(pde_index))* rPhi;
00275 
00276         for (unsigned i=0; i<ELEMENT_DIM+1; i++)
00277         {
00278             vector_term(i*PROBLEM_DIM + pde_index) = this_vector_term(i);
00279         }
00280     }
00281 
00282     return vector_term;
00283 }
00284 
00285 
00286 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00287 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::ResetInterpolatedQuantities()
00288 {
00289     mInterpolatedOdeStateVariables.clear();
00290 
00291     if (mOdeSystemsPresent)
00292     {
00293         unsigned num_state_variables = mOdeSystemsAtNodes[0]->GetNumberOfStateVariables();
00294         mInterpolatedOdeStateVariables.resize(num_state_variables, 0.0);
00295     }
00296 }
00297 
00298 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00299 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::IncrementInterpolatedQuantities(double phiI, const Node<SPACE_DIM>* pNode)
00300 {
00301     if (mOdeSystemsPresent)
00302     {
00303         unsigned num_state_variables = mOdeSystemsAtNodes[0]->GetNumberOfStateVariables();
00304 
00305         for (unsigned i=0; i<num_state_variables; i++)
00306         {
00307             mInterpolatedOdeStateVariables[i] += phiI * mOdeSystemsAtNodes[pNode->GetIndex()]->rGetStateVariables()[i];
00308         }
00309     }
00310 }
00311 
00312 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00313 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::InitialiseForSolve(Vec initialSolution)
00314 {
00315     if (this->mpLinearSystem == NULL)
00316     {
00317         unsigned preallocation = mpMesh->CalculateMaximumContainingElementsPerProcess() + ELEMENT_DIM;
00318         if (ELEMENT_DIM > 1)
00319         {
00320             // Highest connectivity is closed
00321             preallocation--;
00322         }
00323         preallocation *= PROBLEM_DIM;
00324 
00325         /*
00326          * Use the current solution (ie the initial solution) as the
00327          * template in the alternative constructor of LinearSystem.
00328          * This is to avoid problems with VecScatter.
00329          */
00330         this->mpLinearSystem = new LinearSystem(initialSolution, preallocation);
00331     }
00332 
00333     assert(this->mpLinearSystem);
00334     this->mpLinearSystem->SetMatrixIsSymmetric(true);
00335     this->mpLinearSystem->SetKspType("cg");
00336 }
00337 
00338 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00339 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetupLinearSystem(Vec currentSolution, bool computeMatrix)
00340 {
00341     SetupGivenLinearSystem(currentSolution, computeMatrix, this->mpLinearSystem);
00342 }
00343 
00344 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00345 LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::LinearParabolicPdeSystemWithCoupledOdeSystemSolver(
00346         TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>* pMesh,
00347         AbstractLinearParabolicPdeSystemForCoupledOdeSystem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* pPdeSystem,
00348         BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* pBoundaryConditions,
00349         std::vector<AbstractOdeSystemForCoupledPdeSystem*> odeSystemsAtNodes,
00350         boost::shared_ptr<AbstractIvpOdeSolver> pOdeSolver)
00351     : AbstractAssemblerSolverHybrid<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, NORMAL>(pMesh, pBoundaryConditions),
00352       AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>(pMesh),
00353       mpMesh(pMesh),
00354       mpPdeSystem(pPdeSystem),
00355       mOdeSystemsAtNodes(odeSystemsAtNodes),
00356       mpOdeSolver(pOdeSolver),
00357       mSamplingTimeStep(DOUBLE_UNSET),
00358       mOdeSystemsPresent(false)
00359 {
00360     this->mpBoundaryConditions = pBoundaryConditions;
00361 
00362     /*
00363      * If any ODE systems are passed in to the constructor, then we aren't just
00364      * solving a coupled PDE system, in which case the number of ODE system objects
00365      * must match the number of nodes in the finite element mesh.
00366      */
00367     if (!mOdeSystemsAtNodes.empty())
00368     {
00369         mOdeSystemsPresent = true;
00370         assert(mOdeSystemsAtNodes.size() == mpMesh->GetNumNodes());
00371 
00372         /*
00373          * In this case, if an ODE solver is not explicitly passed into the
00374          * constructor, then we create a default solver.
00375          */
00376         if (!mpOdeSolver)
00377         {
00378 #ifdef CHASTE_CVODE
00379             mpOdeSolver.reset(new CvodeAdaptor);
00380 #else
00381             mpOdeSolver.reset(new BackwardEulerIvpOdeSolver(mOdeSystemsAtNodes[0]->GetNumberOfStateVariables()));
00382 #endif //CHASTE_CVODE
00383         }
00384     }
00385 }
00386 
00387 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00388 LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::~LinearParabolicPdeSystemWithCoupledOdeSystemSolver()
00389 {
00390     if (mOdeSystemsPresent)
00391     {
00392         for (unsigned i=0; i<mOdeSystemsAtNodes.size(); i++)
00393         {
00394             delete mOdeSystemsAtNodes[i];
00395         }
00396     }
00397 }
00398 
00399 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00400 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::PrepareForSetupLinearSystem(Vec currentPdeSolution)
00401 {
00402     if (mOdeSystemsPresent)
00403     {
00404         double time = PdeSimulationTime::GetTime();
00405         double dt = PdeSimulationTime::GetPdeTimeStep();
00406 
00407         ReplicatableVector soln_repl(currentPdeSolution);
00408         std::vector<double> current_soln_this_node(PROBLEM_DIM);
00409 
00410         // Loop over nodes
00411         for (unsigned node_index=0; node_index<mpMesh->GetNumNodes(); node_index++)
00412         {
00413             // Store the current solution to the PDE system at this node
00414             for (unsigned pde_index=0; pde_index<PROBLEM_DIM; pde_index++)
00415             {
00416                 double current_soln_this_pde_this_node = soln_repl[PROBLEM_DIM*node_index + pde_index];
00417                 current_soln_this_node[pde_index] = current_soln_this_pde_this_node;
00418             }
00419 
00420             // Pass it into the ODE system at this node
00421             mOdeSystemsAtNodes[node_index]->SetPdeSolution(current_soln_this_node);
00422 
00423             // Solve ODE system at this node
00424             mpOdeSolver->SolveAndUpdateStateVariable(mOdeSystemsAtNodes[node_index], time, time+dt, dt);
00425         }
00426     }
00427 }
00428 
00429 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00430 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetOutputDirectory(std::string outputDirectory)
00431 {
00432     this->mOutputDirectory = outputDirectory;
00433 }
00434 
00435 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00436 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetSamplingTimeStep(double samplingTimeStep)
00437 {
00438     assert(samplingTimeStep >= this->mIdealTimeStep);
00439     mSamplingTimeStep = samplingTimeStep;
00440 }
00441 
00442 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00443 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SolveAndWriteResultsToFile()
00444 {
00445     // A number of methods must have been called prior to this method
00446     if (this->mOutputDirectory == "")
00447     {
00448         EXCEPTION("SetOutputDirectory() must be called prior to SolveAndWriteResultsToFile()");
00449     }
00450     if (this->mTimesSet == false)
00451     {
00452         EXCEPTION("SetTimes() must be called prior to SolveAndWriteResultsToFile()");
00453     }
00454     if (this->mIdealTimeStep <= 0.0)
00455     {
00456         EXCEPTION("SetTimeStep() must be called prior to SolveAndWriteResultsToFile()");
00457     }
00458     if (mSamplingTimeStep == DOUBLE_UNSET)
00459     {
00460         EXCEPTION("SetSamplingTimeStep() must be called prior to SolveAndWriteResultsToFile()");
00461     }
00462     if (!this->mInitialCondition)
00463     {
00464         EXCEPTION("SetInitialCondition() must be called prior to SolveAndWriteResultsToFile()");
00465     }
00466 
00467 #ifdef CHASTE_VTK
00468     // Create a .pvd output file
00469     OutputFileHandler output_file_handler(this->mOutputDirectory, false);
00470     mpVtkMetaFile = output_file_handler.OpenOutputFile("results.pvd");
00471     *mpVtkMetaFile << "<?xml version=\"1.0\"?>\n";
00472     *mpVtkMetaFile << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\" compressor=\"vtkZLibDataCompressor\">\n";
00473     *mpVtkMetaFile << "    <Collection>\n";
00474 
00475     // Write initial condition to VTK
00476     Vec initial_condition = this->mInitialCondition;
00477     WriteVtkResultsToFile(initial_condition, 0);
00478 
00479     // The helper class TimeStepper deals with issues such as small final timesteps so we don't have to
00480     TimeStepper stepper(this->mTstart, this->mTend, mSamplingTimeStep);
00481 
00482     // Main time loop
00483     while (!stepper.IsTimeAtEnd())
00484     {
00485         // Reset start and end times
00486         this->SetTimes(stepper.GetTime(), stepper.GetNextTime());
00487 
00488         // Solve the system up to the new end time
00489         Vec soln = this->Solve();
00490 
00491         // Reset the initial condition for the next timestep
00492         if (this->mInitialCondition != initial_condition)
00493         {
00494             VecDestroy(this->mInitialCondition);
00495         }
00496         this->mInitialCondition = soln;
00497 
00498         // Move forward in time
00499         stepper.AdvanceOneTimeStep();
00500 
00501         // Write solution to VTK
00502         WriteVtkResultsToFile(soln, stepper.GetTotalTimeStepsTaken());
00503     }
00504 
00505     // Restore saved initial condition to avoid user confusion!
00506     if (this->mInitialCondition != initial_condition)
00507     {
00508         VecDestroy(this->mInitialCondition);
00509     }
00510     this->mInitialCondition = initial_condition;
00511 
00512     // Close .pvd output file
00513     *mpVtkMetaFile << "    </Collection>\n";
00514     *mpVtkMetaFile << "</VTKFile>\n";
00515     mpVtkMetaFile->close();
00516 #else //CHASTE_VTK
00517 #define COVERAGE_IGNORE // We can't test this in regular builds
00518     EXCEPTION("VTK is not installed and is required for this functionality");
00519 #undef COVERAGE_IGNORE
00520 #endif //CHASTE_VTK
00521 }
00522 
00523 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00524 void LinearParabolicPdeSystemWithCoupledOdeSystemSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::WriteVtkResultsToFile(Vec solution, unsigned numTimeStepsElapsed)
00525 {
00526 #ifdef CHASTE_VTK
00527 
00528     // Create a new VTK file for this time step
00529     std::stringstream time;
00530     time << numTimeStepsElapsed;
00531     VtkMeshWriter<ELEMENT_DIM, SPACE_DIM> mesh_writer(this->mOutputDirectory, "results_"+time.str(), false);
00532 
00533     /*
00534      * We first loop over PDEs. For each PDE we store the solution
00535      * at each node in a vector, then pass this vector to the mesh
00536      * writer.
00537      */
00538     ReplicatableVector solution_repl(solution);
00539     unsigned num_nodes = mpMesh->GetNumNodes();
00540     for (unsigned pde_index=0; pde_index<PROBLEM_DIM; pde_index++)
00541     {
00542         // Store the solution of this PDE at each node
00543         std::vector<double> pde_index_data;
00544         pde_index_data.resize(num_nodes, 0.0);
00545         for (unsigned node_index=0; node_index<num_nodes; node_index++)
00546         {
00547             pde_index_data[node_index] = solution_repl[PROBLEM_DIM*node_index + pde_index];
00548         }
00549 
00550         // Add this data to the mesh writer
00551         std::stringstream data_name;
00552         data_name << "PDE variable " << pde_index;
00553         mesh_writer.AddPointData(data_name.str(), pde_index_data);
00554     }
00555 
00556     if (mOdeSystemsPresent)
00557     {
00558         /*
00559          * We cannot loop over ODEs like PDEs, since the solutions are not
00560          * stored in one place. Therefore we build up a large 'vector of
00561          * vectors', then pass each component of this vector to the mesh
00562          * writer.
00563          */
00564         std::vector<std::vector<double> > ode_data;
00565         unsigned num_odes = mOdeSystemsAtNodes[0]->rGetStateVariables().size();
00566         ode_data.resize(num_odes);
00567         for (unsigned ode_index=0; ode_index<num_odes; ode_index++)
00568         {
00569             ode_data[ode_index].resize(num_nodes, 0.0);
00570         }
00571 
00572         for (unsigned node_index=0; node_index<num_nodes; node_index++)
00573         {
00574             std::vector<double> all_odes_this_node = mOdeSystemsAtNodes[node_index]->rGetStateVariables();
00575             for (unsigned i=0; i<num_odes; i++)
00576             {
00577                 ode_data[i][node_index] = all_odes_this_node[i];
00578             }
00579         }
00580 
00581         for (unsigned ode_index=0; ode_index<num_odes; ode_index++)
00582         {
00583             std::vector<double> ode_index_data = ode_data[ode_index];
00584 
00585             // Add this data to the mesh writer
00586             std::stringstream data_name;
00587             data_name << "ODE variable " << ode_index;
00588             mesh_writer.AddPointData(data_name.str(), ode_index_data);
00589         }
00590     }
00591 
00592     mesh_writer.WriteFilesUsingMesh(*mpMesh);
00593     *mpVtkMetaFile << "        <DataSet timestep=\"";
00594     *mpVtkMetaFile << numTimeStepsElapsed;
00595     *mpVtkMetaFile << "\" group=\"\" part=\"0\" file=\"results_";
00596     *mpVtkMetaFile << numTimeStepsElapsed;
00597     *mpVtkMetaFile << ".vtu\"/>\n";
00598 #endif // CHASTE_VTK
00599 }
00600 
00601 #endif /*LINEARPARABOLICPDESYSTEMWITHCOUPLEDODESYSTEMSOLVER_HPP_*/
Generated on Thu Dec 22 13:00:17 2011 for Chaste by  doxygen 1.6.3