MeshBasedCellPopulationWithGhostNodes.cpp

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 
00029 #include "MeshBasedCellPopulationWithGhostNodes.hpp"
00030 #include "CellwiseData.hpp"
00031 
00032 template<unsigned DIM>
00033 MeshBasedCellPopulationWithGhostNodes<DIM>::MeshBasedCellPopulationWithGhostNodes(
00034      MutableMesh<DIM, DIM>& rMesh,
00035      std::vector<CellPtr>& rCells,
00036      const std::vector<unsigned> locationIndices,
00037      bool deleteMesh,
00038      double ghostSpringStiffness)
00039              : MeshBasedCellPopulation<DIM>(rMesh, rCells, locationIndices, deleteMesh, false), // do not call the base class Validate()
00040                mGhostSpringStiffness(ghostSpringStiffness)
00041 {
00042     if (!locationIndices.empty())
00043     {
00044         // Create a set of node indices corresponding to ghost nodes
00045         std::set<unsigned> node_indices;
00046         std::set<unsigned> location_indices;
00047         std::set<unsigned> ghost_node_indices;
00048 
00049         for (unsigned i=0; i<this->GetNumNodes(); i++)
00050         {
00051             node_indices.insert(this->GetNode(i)->GetIndex());
00052         }
00053         for (unsigned i=0; i<locationIndices.size(); i++)
00054         {
00055             location_indices.insert(locationIndices[i]);
00056         }
00057 
00058         std::set_difference(node_indices.begin(), node_indices.end(),
00059                             location_indices.begin(), location_indices.end(),
00060                             std::inserter(ghost_node_indices, ghost_node_indices.begin()));
00061 
00062         // This method finishes and then calls Validate()
00063         SetGhostNodes(ghost_node_indices);
00064     }
00065     else
00066     {
00067         this->mIsGhostNode = std::vector<bool>(this->GetNumNodes(), false);
00068         Validate();
00069     }
00070 }
00071 
00072 template<unsigned DIM>
00073 MeshBasedCellPopulationWithGhostNodes<DIM>::MeshBasedCellPopulationWithGhostNodes(MutableMesh<DIM, DIM>& rMesh,
00074                                                                   double ghostSpringStiffness)
00075              : MeshBasedCellPopulation<DIM>(rMesh),
00076                mGhostSpringStiffness(ghostSpringStiffness)
00077 {
00078 }
00079 
00080 template<unsigned DIM>
00081 std::vector<bool>& MeshBasedCellPopulationWithGhostNodes<DIM>::rGetGhostNodes()
00082 {
00083     return this->mIsGhostNode;
00084 }
00085 
00086 template<unsigned DIM>
00087 bool MeshBasedCellPopulationWithGhostNodes<DIM>::IsGhostNode(unsigned index)
00088 {
00089     return this->mIsGhostNode[index];
00090 }
00091 
00092 template<unsigned DIM>
00093 std::set<unsigned> MeshBasedCellPopulationWithGhostNodes<DIM>::GetGhostNodeIndices()
00094 {
00095     std::set<unsigned> ghost_node_indices;
00096     for (unsigned i=0; i<this->mIsGhostNode.size(); i++)
00097     {
00098         if (this->mIsGhostNode[i])
00099         {
00100             ghost_node_indices.insert(i);
00101         }
00102     }
00103     return ghost_node_indices;
00104 }
00105 
00106 template<unsigned DIM>
00107 void MeshBasedCellPopulationWithGhostNodes<DIM>::SetGhostNodes(const std::set<unsigned>& rGhostNodeIndices)
00108 {
00109     // Reinitialise all entries of mIsGhostNode to false
00110     this->mIsGhostNode = std::vector<bool>(this->mrMesh.GetNumNodes(), false);
00111 
00112     // Update mIsGhostNode
00113     for (std::set<unsigned>::iterator iter=rGhostNodeIndices.begin(); iter!=rGhostNodeIndices.end(); ++iter)
00114     {
00115         this->mIsGhostNode[*iter] = true;
00116     }
00117 
00118     Validate();
00119 }
00120 
00121 template<unsigned DIM>
00122 void MeshBasedCellPopulationWithGhostNodes<DIM>::UpdateGhostPositions(double dt)
00123 {
00124     // Initialise vector of forces on ghost nodes
00125     std::vector<c_vector<double, DIM> > drdt(this->GetNumNodes());
00126     for (unsigned i=0; i<drdt.size(); i++)
00127     {
00128         drdt[i] = zero_vector<double>(DIM);
00129     }
00130 
00131     // Calculate forces on ghost nodes
00132     for (typename MutableMesh<DIM, DIM>::EdgeIterator edge_iterator = this->mrMesh.EdgesBegin();
00133         edge_iterator != this->mrMesh.EdgesEnd();
00134         ++edge_iterator)
00135     {
00136         unsigned nodeA_global_index = edge_iterator.GetNodeA()->GetIndex();
00137         unsigned nodeB_global_index = edge_iterator.GetNodeB()->GetIndex();
00138 
00139         c_vector<double, DIM> force = CalculateForceBetweenGhostNodes(nodeA_global_index, nodeB_global_index);
00140 
00141         double damping_constant = this->GetDampingConstantNormal();
00142 
00143         if (!this->mIsGhostNode[nodeA_global_index])
00144         {
00145             drdt[nodeB_global_index] -= force / damping_constant;
00146         }
00147         else
00148         {
00149             drdt[nodeA_global_index] += force / damping_constant;
00150 
00151             if (this->mIsGhostNode[nodeB_global_index])
00152             {
00153                 drdt[nodeB_global_index] -= force / damping_constant;
00154             }
00155         }
00156     }
00157 
00158     for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
00159          node_iter != this->mrMesh.GetNodeIteratorEnd();
00160          ++node_iter)
00161     {
00162         unsigned node_index = node_iter->GetIndex();
00163         if (this->mIsGhostNode[node_index])
00164         {
00165             ChastePoint<DIM> new_point(node_iter->rGetLocation() + dt*drdt[node_index]);
00166             this->mrMesh.SetNode(node_index, new_point, false);
00167         }
00168     }
00169 }
00170 
00171 template<unsigned DIM>
00172 c_vector<double, DIM> MeshBasedCellPopulationWithGhostNodes<DIM>::CalculateForceBetweenGhostNodes(const unsigned& rNodeAGlobalIndex, const unsigned& rNodeBGlobalIndex)
00173 {
00174     assert(rNodeAGlobalIndex != rNodeBGlobalIndex);
00175     c_vector<double, DIM> unit_difference;
00176     c_vector<double, DIM> node_a_location = this->GetNode(rNodeAGlobalIndex)->rGetLocation();
00177     c_vector<double, DIM> node_b_location = this->GetNode(rNodeBGlobalIndex)->rGetLocation();
00178 
00179     // There is reason not to subtract one position from the other (cylindrical meshes)
00180     unit_difference = this->mrMesh.GetVectorFromAtoB(node_a_location, node_b_location);
00181 
00182     double distance_between_nodes = norm_2(unit_difference);
00183 
00184     unit_difference /= distance_between_nodes;
00185 
00186     double rest_length = 1.0;
00187 
00188     return mGhostSpringStiffness * unit_difference * (distance_between_nodes - rest_length);
00189 }
00190 
00191 template<unsigned DIM>
00192 CellPtr MeshBasedCellPopulationWithGhostNodes<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
00193 {
00194     // Add new cell to cell population
00195     CellPtr p_created_cell = MeshBasedCellPopulation<DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell);
00196     assert(p_created_cell == pNewCell);
00197 
00198     // Update size of mIsGhostNode if necessary
00199     unsigned new_node_index = this->mCellLocationMap[p_created_cell.get()];
00200 
00201     if (this->GetNumNodes() > this->mIsGhostNode.size())
00202     {
00203         this->mIsGhostNode.resize(this->GetNumNodes());
00204         this->mIsGhostNode[new_node_index] = false;
00205     }
00206 
00207     // Return pointer to new cell
00208     return p_created_cell;
00209 }
00210 
00211 template<unsigned DIM>
00212 void MeshBasedCellPopulationWithGhostNodes<DIM>::Validate()
00213 {
00214     // Get a list of all the nodes that are ghosts
00215     std::vector<bool> validated_node = mIsGhostNode;
00216     assert(mIsGhostNode.size()==this->GetNumNodes());
00217 
00218     // Look through all of the cells and record what node they are associated with.
00219     for (typename AbstractCellPopulation<DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter)
00220     {
00221         unsigned node_index = this->mCellLocationMap[(*cell_iter).get()];
00222 
00223         // If the node attached to this cell is labelled as a ghost node, then throw an error
00224         if (mIsGhostNode[node_index])
00225         {
00226             EXCEPTION("Node " << node_index << " is labelled as a ghost node and has a cell attached");
00227         }
00228         validated_node[node_index] = true;
00229     }
00230 
00231     for (unsigned i=0; i<validated_node.size(); i++)
00232     {
00233         if (!validated_node[i])
00234         {
00235             EXCEPTION("Node " << i << " does not appear to be a ghost node or have a cell associated with it");
00236         }
00237     }
00238 }
00239 
00240 template<unsigned DIM>
00241 void MeshBasedCellPopulationWithGhostNodes<DIM>::UpdateGhostNodesAfterReMesh(NodeMap& rMap)
00242 {
00243     // Copy mIsGhostNode to a temporary vector
00244     std::vector<bool> ghost_nodes_before_remesh = mIsGhostNode;
00245 
00246     // Reinitialise mIsGhostNode
00247     mIsGhostNode.clear();
00248     mIsGhostNode.resize(this->GetNumNodes());
00249 
00250     // Update mIsGhostNode using the node map
00251     for (unsigned old_index=0; old_index<rMap.Size(); old_index++)
00252     {
00253         if (!rMap.IsDeleted(old_index))
00254         {
00255             unsigned new_index = rMap.GetNewIndex(old_index);
00256             mIsGhostNode[new_index] = ghost_nodes_before_remesh[old_index];
00257         }
00258     }
00259 }
00260 
00261 template<unsigned DIM>
00262 void MeshBasedCellPopulationWithGhostNodes<DIM>::UpdateNodeLocations(const std::vector< c_vector<double, DIM> >& rNodeForces, double dt)
00263 {
00264     // First update ghost positions first because they do not affect the real cells
00265     UpdateGhostPositions(dt);
00266 
00267     // Then call the base class method
00268     AbstractCentreBasedCellPopulation<DIM>::UpdateNodeLocations(rNodeForces, dt);
00269 }
00270 
00271 template<unsigned DIM>
00272 void MeshBasedCellPopulationWithGhostNodes<DIM>::WriteVtkResultsToFile()
00273 {
00274 #ifdef CHASTE_VTK
00275     if (this->mpVoronoiTessellation != NULL)
00276     {
00277         VertexMeshWriter<DIM, DIM> mesh_writer(this->mDirPath, "results", false);
00278         std::stringstream time;
00279         time << SimulationTime::Instance()->GetTimeStepsElapsed();
00280 
00281         unsigned num_elements = this->mpVoronoiTessellation->GetNumElements();
00282         std::vector<double> ghosts(num_elements);
00283         std::vector<double> cell_types(num_elements);
00284         std::vector<double> cell_ancestors(num_elements);
00285         std::vector<double> cell_mutation_states(num_elements);
00286         std::vector<double> cell_ages(num_elements);
00287         std::vector<double> cell_cycle_phases(num_elements);
00288         std::vector<double> cell_volumes(num_elements);
00289         std::vector<std::vector<double> > cellwise_data;
00290 
00291         // This code is commented code is because Cellwise Data can't deal with ghost nodes see #1975
00292         assert(!CellwiseData<DIM>::Instance()->IsSetUp());
00293         //if (CellwiseData<DIM>::Instance()->IsSetUp())
00294         //{
00295         //    CellwiseData<DIM>* p_data = CellwiseData<DIM>::Instance();
00296         //    unsigned num_variables = p_data->GetNumVariables();
00297         //    for (unsigned var=0; var<num_variables; var++)
00298         //    {
00299         //        std::vector<double> cellwise_data_var(num_elements);
00300         //        cellwise_data.push_back(cellwise_data_var);
00301         //    }
00302         //}
00303 
00304         // Loop over Voronoi elements
00305         for (typename VertexMesh<DIM,DIM>::VertexElementIterator elem_iter = this->mpVoronoiTessellation->GetElementIteratorBegin();
00306              elem_iter != this->mpVoronoiTessellation->GetElementIteratorEnd();
00307              ++elem_iter)
00308         {
00309             // Get index of this element in the Voronoi tessellation mesh
00310             unsigned elem_index = elem_iter->GetIndex();
00311 
00312             unsigned node_index = this->mpVoronoiTessellation->GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(elem_index);
00313 
00314             ghosts[elem_index] = (double)(this->IsGhostNode(node_index));
00315 
00316             if (!this->IsGhostNode(node_index))
00317             {
00318                 // Get the cell corresponding to this element
00319                 CellPtr p_cell = this->mLocationCellMap[node_index];
00320 
00321                 if (this->mOutputCellAncestors)
00322                 {
00323                     double ancestor_index = (p_cell->GetAncestor() == UNSIGNED_UNSET) ? (-1.0) : (double)p_cell->GetAncestor();
00324                     cell_ancestors[elem_index] = ancestor_index;
00325                 }
00326                 if (this->mOutputCellProliferativeTypes)
00327                 {
00328                     double cell_type = p_cell->GetCellCycleModel()->GetCellProliferativeType();
00329                     cell_types[elem_index] = cell_type;
00330                 }
00331                 if (this->mOutputCellMutationStates)
00332                 {
00333                     double mutation_state = p_cell->GetMutationState()->GetColour();
00334                     cell_mutation_states[elem_index] = mutation_state;
00335                 }
00336                 if (this->mOutputCellAges)
00337                 {
00338                     double age = p_cell->GetAge();
00339                     cell_ages[elem_index] = age;
00340                 }
00341                 if (this->mOutputCellCyclePhases)
00342                 {
00343                     double cycle_phase = p_cell->GetCellCycleModel()->GetCurrentCellCyclePhase();
00344                     cell_cycle_phases[elem_index] = cycle_phase;
00345                 }
00346                 if (this->mOutputCellVolumes)
00347                 {
00348                     double cell_volume = this->mpVoronoiTessellation->GetVolumeOfElement(elem_index);
00349                     cell_volumes[elem_index] = cell_volume;
00350                 }
00351                 // This code is commented  because Cellwise Data can't deal with ghost nodes see #1975
00352                 assert(!CellwiseData<DIM>::Instance()->IsSetUp());
00353                 //if (CellwiseData<DIM>::Instance()->IsSetUp())
00354                 //{
00355                 //    CellwiseData<DIM>* p_data = CellwiseData<DIM>::Instance();
00356                 //    unsigned num_variables = p_data->GetNumVariables();
00357                 //    for (unsigned var=0; var<num_variables; var++)
00358                 //    {
00359                 //        cellwise_data[var][elem_index] = p_data->GetValue(p_cell, var);
00360                 //    }
00361                 //}
00362             }
00363             else
00364             {
00365                 if (this->mOutputCellAncestors)
00366                 {
00367                     cell_ancestors[elem_index] = -1.0;
00368                 }
00369                 if (this->mOutputCellProliferativeTypes)
00370                 {
00371                     cell_types[elem_index] = -1.0;
00372                 }
00373                 if (this->mOutputCellMutationStates)
00374                 {
00375                     cell_mutation_states[elem_index] = -1.0;
00376                 }
00377                 if (this->mOutputCellAges)
00378                 {
00379                     cell_ages[elem_index] = -1.0;
00380                 }
00381                 if (this->mOutputCellCyclePhases)
00382                 {
00383                     cell_cycle_phases[elem_index] = -1.0;
00384                 }
00385                 if (this->mOutputCellVolumes)
00386                 {
00387                     cell_volumes[elem_index] = -1.0;
00388                 }
00389             }
00390         }
00391 
00392         mesh_writer.AddCellData("Non-ghosts", ghosts);
00393         if (this->mOutputCellProliferativeTypes)
00394         {
00395             mesh_writer.AddCellData("Cell types", cell_types);
00396         }
00397         if (this->mOutputCellAncestors)
00398         {
00399             mesh_writer.AddCellData("Ancestors", cell_ancestors);
00400         }
00401         if (this->mOutputCellMutationStates)
00402         {
00403             mesh_writer.AddCellData("Mutation states", cell_mutation_states);
00404         }
00405         if (this->mOutputCellAges)
00406         {
00407             mesh_writer.AddCellData("Ages", cell_ages);
00408         }
00409         if (this->mOutputCellCyclePhases)
00410         {
00411             mesh_writer.AddCellData("Cycle phases", cell_cycle_phases);
00412         }
00413         if (this->mOutputCellVolumes)
00414         {
00415             mesh_writer.AddCellData("Cell volumes", cell_volumes);
00416         }
00417         // This code is commented code is because Cellwise Data can't deal with ghost nodes see #1975
00418         assert(!CellwiseData<DIM>::Instance()->IsSetUp());
00419 //if (CellwiseData<DIM>::Instance()->IsSetUp())
00420 //{
00421 //  for (unsigned var=0; var<cellwise_data.size(); var++)
00422 //  {
00423 //      std::stringstream data_name;
00424 //      data_name << "Cellwise data " << var;
00425 //      std::vector<double> cellwise_data_var = cellwise_data[var];
00426 //      mesh_writer.AddCellData(data_name.str(), cellwise_data_var);
00427 //  }
00428 //}
00429 
00430         mesh_writer.WriteVtkUsingMesh(*(this->mpVoronoiTessellation), time.str());
00431         *(this->mpVtkMetaFile) << "        <DataSet timestep=\"";
00432         *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00433         *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
00434         *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
00435         *(this->mpVtkMetaFile) << ".vtu\"/>\n";
00436     }
00437 #endif //CHASTE_VTK
00438 }
00439 
00440 template<unsigned DIM>
00441 void MeshBasedCellPopulationWithGhostNodes<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile)
00442 {
00443     *rParamsFile << "\t\t<GhostSpringStiffness>" << mGhostSpringStiffness << "</GhostSpringStiffness>\n";
00444 
00445     // Call method on direct parent class
00446     MeshBasedCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile);
00447 }
00448 
00450 // Explicit instantiation
00452 
00453 template class MeshBasedCellPopulationWithGhostNodes<1>;
00454 template class MeshBasedCellPopulationWithGhostNodes<2>;
00455 template class MeshBasedCellPopulationWithGhostNodes<3>;
00456 
00457 // Serialization for Boost >= 1.36
00458 #include "SerializationExportWrapperForCpp.hpp"
00459 EXPORT_TEMPLATE_CLASS_SAME_DIMS(MeshBasedCellPopulationWithGhostNodes)
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3