Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, 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 "MeshBasedCellPopulationWithGhostNodes.hpp" 00037 00038 template<unsigned DIM> 00039 MeshBasedCellPopulationWithGhostNodes<DIM>::MeshBasedCellPopulationWithGhostNodes( 00040 MutableMesh<DIM, DIM>& rMesh, 00041 std::vector<CellPtr>& rCells, 00042 const std::vector<unsigned> locationIndices, 00043 bool deleteMesh, 00044 double ghostSpringStiffness) 00045 : MeshBasedCellPopulation<DIM>(rMesh, rCells, locationIndices, deleteMesh, false), // do not call the base class Validate() 00046 mGhostSpringStiffness(ghostSpringStiffness) 00047 { 00048 if (!locationIndices.empty()) 00049 { 00050 // Create a set of node indices corresponding to ghost nodes 00051 std::set<unsigned> node_indices; 00052 std::set<unsigned> location_indices; 00053 std::set<unsigned> ghost_node_indices; 00054 00055 for (unsigned i=0; i<this->GetNumNodes(); i++) 00056 { 00057 node_indices.insert(this->GetNode(i)->GetIndex()); 00058 } 00059 for (unsigned i=0; i<locationIndices.size(); i++) 00060 { 00061 location_indices.insert(locationIndices[i]); 00062 } 00063 00064 std::set_difference(node_indices.begin(), node_indices.end(), 00065 location_indices.begin(), location_indices.end(), 00066 std::inserter(ghost_node_indices, ghost_node_indices.begin())); 00067 00068 // This method finishes and then calls Validate() 00069 SetGhostNodes(ghost_node_indices); 00070 } 00071 else 00072 { 00073 this->mIsGhostNode = std::vector<bool>(this->GetNumNodes(), false); 00074 Validate(); 00075 } 00076 } 00077 00078 template<unsigned DIM> 00079 MeshBasedCellPopulationWithGhostNodes<DIM>::MeshBasedCellPopulationWithGhostNodes(MutableMesh<DIM, DIM>& rMesh, 00080 double ghostSpringStiffness) 00081 : MeshBasedCellPopulation<DIM>(rMesh), 00082 mGhostSpringStiffness(ghostSpringStiffness) 00083 { 00084 } 00085 00086 template<unsigned DIM> 00087 std::vector<bool>& MeshBasedCellPopulationWithGhostNodes<DIM>::rGetGhostNodes() 00088 { 00089 return this->mIsGhostNode; 00090 } 00091 00092 template<unsigned DIM> 00093 bool MeshBasedCellPopulationWithGhostNodes<DIM>::IsGhostNode(unsigned index) 00094 { 00095 return this->mIsGhostNode[index]; 00096 } 00097 00098 template<unsigned DIM> 00099 std::set<unsigned> MeshBasedCellPopulationWithGhostNodes<DIM>::GetGhostNodeIndices() 00100 { 00101 std::set<unsigned> ghost_node_indices; 00102 for (unsigned i=0; i<this->mIsGhostNode.size(); i++) 00103 { 00104 if (this->mIsGhostNode[i]) 00105 { 00106 ghost_node_indices.insert(i); 00107 } 00108 } 00109 return ghost_node_indices; 00110 } 00111 00112 template<unsigned DIM> 00113 void MeshBasedCellPopulationWithGhostNodes<DIM>::SetGhostNodes(const std::set<unsigned>& rGhostNodeIndices) 00114 { 00115 // Reinitialise all entries of mIsGhostNode to false 00116 this->mIsGhostNode = std::vector<bool>(this->mrMesh.GetNumNodes(), false); 00117 00118 // Update mIsGhostNode 00119 for (std::set<unsigned>::iterator iter=rGhostNodeIndices.begin(); iter!=rGhostNodeIndices.end(); ++iter) 00120 { 00121 this->mIsGhostNode[*iter] = true; 00122 } 00123 00124 Validate(); 00125 } 00126 00127 template<unsigned DIM> 00128 void MeshBasedCellPopulationWithGhostNodes<DIM>::UpdateGhostPositions(double dt) 00129 { 00130 // Initialise vector of forces on ghost nodes 00131 std::vector<c_vector<double, DIM> > drdt(this->GetNumNodes()); 00132 for (unsigned i=0; i<drdt.size(); i++) 00133 { 00134 drdt[i] = zero_vector<double>(DIM); 00135 } 00136 00137 // Calculate forces on ghost nodes 00138 for (typename MutableMesh<DIM, DIM>::EdgeIterator edge_iterator = static_cast<MutableMesh<DIM, DIM>&>((this->mrMesh)).EdgesBegin(); 00139 edge_iterator != static_cast<MutableMesh<DIM, DIM>&>((this->mrMesh)).EdgesEnd(); 00140 ++edge_iterator) 00141 { 00142 unsigned nodeA_global_index = edge_iterator.GetNodeA()->GetIndex(); 00143 unsigned nodeB_global_index = edge_iterator.GetNodeB()->GetIndex(); 00144 00145 c_vector<double, DIM> force = CalculateForceBetweenGhostNodes(nodeA_global_index, nodeB_global_index); 00146 00147 double damping_constant = this->GetDampingConstantNormal(); 00148 00149 if (!this->mIsGhostNode[nodeA_global_index]) 00150 { 00151 drdt[nodeB_global_index] -= force / damping_constant; 00152 } 00153 else 00154 { 00155 drdt[nodeA_global_index] += force / damping_constant; 00156 00157 if (this->mIsGhostNode[nodeB_global_index]) 00158 { 00159 drdt[nodeB_global_index] -= force / damping_constant; 00160 } 00161 } 00162 } 00163 00164 for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin(); 00165 node_iter != this->mrMesh.GetNodeIteratorEnd(); 00166 ++node_iter) 00167 { 00168 unsigned node_index = node_iter->GetIndex(); 00169 if (this->mIsGhostNode[node_index]) 00170 { 00171 ChastePoint<DIM> new_point(node_iter->rGetLocation() + dt*drdt[node_index]); 00172 static_cast<MutableMesh<DIM, DIM>&>((this->mrMesh)).SetNode(node_index, new_point, false); 00173 } 00174 } 00175 } 00176 00177 template<unsigned DIM> 00178 c_vector<double, DIM> MeshBasedCellPopulationWithGhostNodes<DIM>::CalculateForceBetweenGhostNodes(const unsigned& rNodeAGlobalIndex, const unsigned& rNodeBGlobalIndex) 00179 { 00180 assert(rNodeAGlobalIndex != rNodeBGlobalIndex); 00181 c_vector<double, DIM> unit_difference; 00182 c_vector<double, DIM> node_a_location = this->GetNode(rNodeAGlobalIndex)->rGetLocation(); 00183 c_vector<double, DIM> node_b_location = this->GetNode(rNodeBGlobalIndex)->rGetLocation(); 00184 00185 // There is reason not to subtract one position from the other (cylindrical meshes) 00186 unit_difference = this->mrMesh.GetVectorFromAtoB(node_a_location, node_b_location); 00187 00188 double distance_between_nodes = norm_2(unit_difference); 00189 00190 unit_difference /= distance_between_nodes; 00191 00192 double rest_length = 1.0; 00193 00194 return mGhostSpringStiffness * unit_difference * (distance_between_nodes - rest_length); 00195 } 00196 00197 template<unsigned DIM> 00198 CellPtr MeshBasedCellPopulationWithGhostNodes<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell) 00199 { 00200 // Add new cell to cell population 00201 CellPtr p_created_cell = MeshBasedCellPopulation<DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell); 00202 assert(p_created_cell == pNewCell); 00203 00204 // Update size of mIsGhostNode if necessary 00205 unsigned new_node_index = this->GetLocationIndexUsingCell(p_created_cell); 00206 00207 if (this->GetNumNodes() > this->mIsGhostNode.size()) 00208 { 00209 this->mIsGhostNode.resize(this->GetNumNodes()); 00210 this->mIsGhostNode[new_node_index] = false; 00211 } 00212 00213 // Return pointer to new cell 00214 return p_created_cell; 00215 } 00216 00217 template<unsigned DIM> 00218 void MeshBasedCellPopulationWithGhostNodes<DIM>::Validate() 00219 { 00220 // Get a list of all the nodes that are ghosts 00221 std::vector<bool> validated_node = mIsGhostNode; 00222 assert(mIsGhostNode.size()==this->GetNumNodes()); 00223 00224 // Look through all of the cells and record what node they are associated with. 00225 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter) 00226 { 00227 unsigned node_index = this->GetLocationIndexUsingCell((*cell_iter)); 00228 00229 // If the node attached to this cell is labelled as a ghost node, then throw an error 00230 if (mIsGhostNode[node_index]) 00231 { 00232 EXCEPTION("Node " << node_index << " is labelled as a ghost node and has a cell attached"); 00233 } 00234 validated_node[node_index] = true; 00235 } 00236 00237 for (unsigned i=0; i<validated_node.size(); i++) 00238 { 00239 if (!validated_node[i]) 00240 { 00241 EXCEPTION("Node " << i << " does not appear to be a ghost node or have a cell associated with it"); 00242 } 00243 } 00244 } 00245 00246 template<unsigned DIM> 00247 void MeshBasedCellPopulationWithGhostNodes<DIM>::UpdateGhostNodesAfterReMesh(NodeMap& rMap) 00248 { 00249 // Copy mIsGhostNode to a temporary vector 00250 std::vector<bool> ghost_nodes_before_remesh = mIsGhostNode; 00251 00252 // Reinitialise mIsGhostNode 00253 mIsGhostNode.clear(); 00254 mIsGhostNode.resize(this->GetNumNodes()); 00255 00256 // Update mIsGhostNode using the node map 00257 for (unsigned old_index=0; old_index<rMap.Size(); old_index++) 00258 { 00259 if (!rMap.IsDeleted(old_index)) 00260 { 00261 unsigned new_index = rMap.GetNewIndex(old_index); 00262 mIsGhostNode[new_index] = ghost_nodes_before_remesh[old_index]; 00263 } 00264 } 00265 } 00266 00267 template<unsigned DIM> 00268 void MeshBasedCellPopulationWithGhostNodes<DIM>::UpdateNodeLocations(const std::vector< c_vector<double, DIM> >& rNodeForces, double dt) 00269 { 00270 // First update ghost positions first because they do not affect the real cells 00271 UpdateGhostPositions(dt); 00272 00273 // Then call the base class method 00274 AbstractCentreBasedCellPopulation<DIM>::UpdateNodeLocations(rNodeForces, dt); 00275 } 00276 00277 template<unsigned DIM> 00278 void MeshBasedCellPopulationWithGhostNodes<DIM>::WriteVtkResultsToFile() 00279 { 00280 #ifdef CHASTE_VTK 00281 if (this->mpVoronoiTessellation != NULL) 00282 { 00283 VertexMeshWriter<DIM, DIM> mesh_writer(this->mDirPath, "results", false); 00284 std::stringstream time; 00285 time << SimulationTime::Instance()->GetTimeStepsElapsed(); 00286 00287 unsigned num_elements = this->mpVoronoiTessellation->GetNumElements(); 00288 std::vector<double> ghosts(num_elements); 00289 std::vector<double> cell_types(num_elements); 00290 std::vector<double> cell_ancestors(num_elements); 00291 std::vector<double> cell_mutation_states(num_elements); 00292 std::vector<double> cell_ages(num_elements); 00293 std::vector<double> cell_cycle_phases(num_elements); 00294 std::vector<double> cell_volumes(num_elements); 00295 std::vector<std::vector<double> > cellwise_data; 00296 00297 unsigned num_cell_data_items = 0; 00298 // This code is commented because CellData can't deal with ghost nodes see #1975 00299 // //We assume that the first cell is representative of all cells 00300 // num_cell_data_items = this->Begin()->GetCellData()->GetNumItems(); 00301 00302 for (unsigned var=0; var<num_cell_data_items; var++) 00303 { 00304 // This code is commented code is because CellData can't deal with ghost nodes see #1975 00305 //std::vector<double> cellwise_data_var(num_elements); 00306 //cellwise_data.push_back(cellwise_data_var); 00307 } 00308 00309 // Loop over Voronoi elements 00310 for (typename VertexMesh<DIM,DIM>::VertexElementIterator elem_iter = this->mpVoronoiTessellation->GetElementIteratorBegin(); 00311 elem_iter != this->mpVoronoiTessellation->GetElementIteratorEnd(); 00312 ++elem_iter) 00313 { 00314 // Get index of this element in the Voronoi tessellation mesh 00315 unsigned elem_index = elem_iter->GetIndex(); 00316 00317 unsigned node_index = this->mpVoronoiTessellation->GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(elem_index); 00318 00319 ghosts[elem_index] = (double)(this->IsGhostNode(node_index)); 00320 00321 if (!this->IsGhostNode(node_index)) 00322 { 00323 // Get the cell corresponding to this element 00324 CellPtr p_cell = this->GetCellUsingLocationIndex(node_index); 00325 00326 if (this->mOutputCellAncestors) 00327 { 00328 double ancestor_index = (p_cell->GetAncestor() == UNSIGNED_UNSET) ? (-1.0) : (double)p_cell->GetAncestor(); 00329 cell_ancestors[elem_index] = ancestor_index; 00330 } 00331 if (this->mOutputCellProliferativeTypes) 00332 { 00333 double cell_type = p_cell->GetCellProliferativeType(); 00334 cell_types[elem_index] = cell_type; 00335 } 00336 if (this->mOutputCellMutationStates) 00337 { 00338 double mutation_state = p_cell->GetMutationState()->GetColour(); 00339 cell_mutation_states[elem_index] = mutation_state; 00340 } 00341 if (this->mOutputCellAges) 00342 { 00343 double age = p_cell->GetAge(); 00344 cell_ages[elem_index] = age; 00345 } 00346 if (this->mOutputCellCyclePhases) 00347 { 00348 double cycle_phase = p_cell->GetCellCycleModel()->GetCurrentCellCyclePhase(); 00349 cell_cycle_phases[elem_index] = cycle_phase; 00350 } 00351 if (this->mOutputCellVolumes) 00352 { 00353 double cell_volume = this->mpVoronoiTessellation->GetVolumeOfElement(elem_index); 00354 cell_volumes[elem_index] = cell_volume; 00355 } 00356 00357 for (unsigned var=0; var<num_cell_data_items; var++) 00358 { 00359 // This code is commented because CellData can't deal with ghost nodes see #1975 00360 //cellwise_data[var][elem_index] = cell_iter->GetCellData()->GetItem(var); 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 } 00418 // This code is commented code is because Cellwise Data can't deal with ghost nodes see #1975 00419 if (num_cell_data_items > 0) 00420 { 00421 // for (unsigned var=0; var<cellwise_data.size(); var++) 00422 // { 00423 // // This code is commented because Cellwise Data can't deal with ghost nodes see #1975 00424 // std::stringstream data_name; 00425 // data_name << "Cellwise data " << var; 00426 // std::vector<double> cellwise_data_var = cellwise_data[var]; 00427 // mesh_writer.AddCellData(data_name.str(), cellwise_data_var); 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)