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 "PottsBasedCellPopulation.hpp" 00037 #include "RandomNumberGenerator.hpp" 00038 #include "Warnings.hpp" 00039 00040 // Needed to convert mesh in order to write nodes to VTK (visualize as glyphs) 00041 #include "VtkMeshWriter.hpp" 00042 #include "NodesOnlyMesh.hpp" 00043 #include "Exception.hpp" 00044 00045 template<unsigned DIM> 00046 void PottsBasedCellPopulation<DIM>::Validate() 00047 { 00048 // Check each element has only one cell associated with it 00049 std::vector<unsigned> validated_element = std::vector<unsigned>(this->GetNumElements(), 0); 00050 00051 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin(); 00052 cell_iter != this->End(); 00053 ++cell_iter) 00054 { 00055 unsigned elem_index = this->GetLocationIndexUsingCell(*cell_iter); 00056 validated_element[elem_index]++; 00057 } 00058 00059 for (unsigned i=0; i<validated_element.size(); i++) 00060 { 00061 if (validated_element[i] == 0) 00062 { 00063 EXCEPTION("Element " << i << " does not appear to have a cell associated with it"); 00064 } 00065 00066 if (validated_element[i] > 1) 00067 { 00068 EXCEPTION("Element " << i << " appears to have " << validated_element[i] << " cells associated with it"); 00069 } 00070 } 00071 } 00072 00073 template<unsigned DIM> 00074 PottsBasedCellPopulation<DIM>::PottsBasedCellPopulation(PottsMesh<DIM>& rMesh, 00075 std::vector<CellPtr>& rCells, 00076 bool deleteMesh, 00077 bool validate, 00078 const std::vector<unsigned> locationIndices) 00079 : AbstractOnLatticeCellPopulation<DIM>(rMesh, rCells, locationIndices, deleteMesh), 00080 mpElementTessellation(NULL), 00081 mpMutableMesh(NULL), 00082 mTemperature(0.1), 00083 mNumSweepsPerTimestep(1) 00084 { 00085 mpPottsMesh = static_cast<PottsMesh<DIM>* >(&(this->mrMesh)); 00086 // Check each element has only one cell associated with it 00087 if (validate) 00088 { 00089 Validate(); 00090 } 00091 } 00092 00093 template<unsigned DIM> 00094 PottsBasedCellPopulation<DIM>::PottsBasedCellPopulation(PottsMesh<DIM>& rMesh) 00095 : AbstractOnLatticeCellPopulation<DIM>(rMesh), 00096 mpElementTessellation(NULL), 00097 mpMutableMesh(NULL), 00098 mTemperature(0.1), 00099 mNumSweepsPerTimestep(1) 00100 { 00101 mpPottsMesh = static_cast<PottsMesh<DIM>* >(&(this->mrMesh)); 00102 } 00103 00104 template<unsigned DIM> 00105 PottsBasedCellPopulation<DIM>::~PottsBasedCellPopulation() 00106 { 00107 delete mpElementTessellation; 00108 00109 delete mpMutableMesh; 00110 00111 if (this->mDeleteMesh) 00112 { 00113 delete &this->mrMesh; 00114 } 00115 } 00116 00117 template<unsigned DIM> 00118 PottsMesh<DIM>& PottsBasedCellPopulation<DIM>::rGetMesh() 00119 { 00120 return *mpPottsMesh; 00121 } 00122 00123 template<unsigned DIM> 00124 const PottsMesh<DIM>& PottsBasedCellPopulation<DIM>::rGetMesh() const 00125 { 00126 return *mpPottsMesh; 00127 } 00128 00129 template<unsigned DIM> 00130 PottsElement<DIM>* PottsBasedCellPopulation<DIM>::GetElement(unsigned elementIndex) 00131 { 00132 return mpPottsMesh->GetElement(elementIndex); 00133 } 00134 00135 template<unsigned DIM> 00136 unsigned PottsBasedCellPopulation<DIM>::GetNumElements() 00137 { 00138 return mpPottsMesh->GetNumElements(); 00139 } 00140 00141 template<unsigned DIM> 00142 Node<DIM>* PottsBasedCellPopulation<DIM>::GetNode(unsigned index) 00143 { 00144 return this->mrMesh.GetNode(index); 00145 } 00146 00147 template<unsigned DIM> 00148 unsigned PottsBasedCellPopulation<DIM>::GetNumNodes() 00149 { 00150 return this->mrMesh.GetNumNodes(); 00151 } 00152 00153 template<unsigned DIM> 00154 c_vector<double, DIM> PottsBasedCellPopulation<DIM>::GetLocationOfCellCentre(CellPtr pCell) 00155 { 00156 return mpPottsMesh->GetCentroidOfElement(this->GetLocationIndexUsingCell(pCell)); 00157 } 00158 00159 template<unsigned DIM> 00160 PottsElement<DIM>* PottsBasedCellPopulation<DIM>::GetElementCorrespondingToCell(CellPtr pCell) 00161 { 00162 return mpPottsMesh->GetElement(this->GetLocationIndexUsingCell(pCell)); 00163 } 00164 00165 template<unsigned DIM> 00166 CellPtr PottsBasedCellPopulation<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell) 00167 { 00168 // Get the element associated with this cell 00169 PottsElement<DIM>* p_element = GetElementCorrespondingToCell(pParentCell); 00170 00171 // Divide the element 00172 unsigned new_element_index = mpPottsMesh->DivideElement(p_element, true); // new element will be below the existing element 00173 00174 // Associate the new cell with the element 00175 this->mCells.push_back(pNewCell); 00176 00177 // Update location cell map 00178 CellPtr p_created_cell = this->mCells.back(); 00179 this->SetCellUsingLocationIndex(new_element_index,p_created_cell); 00180 return p_created_cell; 00181 } 00182 00183 template<unsigned DIM> 00184 unsigned PottsBasedCellPopulation<DIM>::RemoveDeadCells() 00185 { 00186 unsigned num_removed = 0; 00187 00188 for (std::list<CellPtr>::iterator it = this->mCells.begin(); 00189 it != this->mCells.end(); 00190 ++it) 00191 { 00192 if ((*it)->IsDead()) 00193 { 00194 // Remove the element from the mesh 00195 num_removed++; 00196 mpPottsMesh->DeleteElement(this->GetLocationIndexUsingCell((*it))); 00197 it = this->mCells.erase(it); 00198 --it; 00199 } 00200 } 00201 return num_removed; 00202 } 00203 template<unsigned DIM> 00204 void PottsBasedCellPopulation<DIM>::UpdateCellLocations(double dt) 00205 { 00206 /* 00207 * This method implements a Monte Carlo method to update the cell population. 00208 * We sample randomly from all nodes in the mesh. Once we have selected a target 00209 * node we randomly select a neighbour. The Hamiltonian is evaluated in the 00210 * current configuration (H_0) and with the target node added to the same 00211 * element as the neighbour (H_1). Based on the vale of deltaH = H_1 - H_0, 00212 * the switch is either made or not. 00213 * 00214 * For each time step (i.e. each time this method is called) we sample 00215 * mrMesh.GetNumNodes() nodes. This is known as a Monte Carlo Step (MCS). 00216 */ 00217 00218 RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance(); 00219 unsigned num_nodes = this->mrMesh.GetNumNodes(); 00220 00221 // Randomly permute mUpdateRuleCollection if specified 00222 if (this->mIterateRandomlyOverUpdateRuleCollection) 00223 { 00224 // Randomly permute mUpdateRuleCollection 00225 p_gen->Shuffle(mUpdateRuleCollection); 00226 } 00227 00228 for (unsigned i=0; i<num_nodes*mNumSweepsPerTimestep; i++) 00229 { 00230 unsigned node_index; 00231 00232 if (this->mUpdateNodesInRandomOrder) 00233 { 00234 node_index = p_gen->randMod(num_nodes); 00235 } 00236 else 00237 { 00238 // Loop over nodes in index order. 00239 node_index = i%num_nodes; 00240 } 00241 00242 Node<DIM>* p_node = this->mrMesh.GetNode(node_index); 00243 00244 // Each node in the mesh must be in at most one element 00245 assert(p_node->GetNumContainingElements() <= 1); 00246 00247 // Find a random available neighbouring node to overwrite current site 00248 std::set<unsigned> neighbouring_node_indices = mpPottsMesh->GetMooreNeighbouringNodeIndices(node_index); 00249 unsigned neighbour_location_index; 00250 00251 if (!neighbouring_node_indices.empty()) 00252 { 00253 unsigned num_neighbours = neighbouring_node_indices.size(); 00254 unsigned chosen_neighbour = p_gen->randMod(num_neighbours); 00255 00256 std::set<unsigned>::iterator neighbour_iter = neighbouring_node_indices.begin(); 00257 for (unsigned j=0; j<chosen_neighbour; j++) 00258 { 00259 neighbour_iter++; 00260 } 00261 00262 neighbour_location_index = *neighbour_iter; 00263 } 00264 else 00265 { 00266 // Each node in the mesh must have at least one neighbour 00267 NEVER_REACHED; 00268 } 00269 00270 std::set<unsigned> containing_elements = p_node->rGetContainingElementIndices(); 00271 std::set<unsigned> neighbour_containing_elements = GetNode(neighbour_location_index)->rGetContainingElementIndices(); 00272 // Only calculate Hamiltonian and update elements if the nodes are from different elements, or one is from the medium 00273 if ( ( *containing_elements.begin() != *neighbour_containing_elements.begin() && !containing_elements.empty() && !neighbour_containing_elements.empty() ) 00274 || ( !containing_elements.empty() && neighbour_containing_elements.empty() ) 00275 || ( containing_elements.empty() && !neighbour_containing_elements.empty() ) ) 00276 { 00277 double delta_H = 0.0; // This is H_1-H_0. 00278 00279 // Now add contributions to the Hamiltonian from each AbstractPottsUpdateRule 00280 for (typename std::vector<boost::shared_ptr<AbstractPottsUpdateRule<DIM> > >::iterator iter = mUpdateRuleCollection.begin(); 00281 iter != mUpdateRuleCollection.end(); 00282 ++iter) 00283 { 00284 delta_H += (*iter)->EvaluateHamiltonianContribution(neighbour_location_index, p_node->GetIndex(), *this); 00285 } 00286 00287 // Generate a uniform random number to do the random motion 00288 double random_number = p_gen->ranf(); 00289 double p = exp(-delta_H/mTemperature); 00290 if (delta_H <= 0 || random_number < p) 00291 { 00292 // Do swap 00293 00294 // Remove the current node from any elements containing it (there should be at most one such element) 00295 for (std::set<unsigned>::iterator iter = containing_elements.begin(); 00296 iter != containing_elements.end(); 00297 ++iter) 00298 { 00299 GetElement(*iter)->DeleteNode(GetElement(*iter)->GetNodeLocalIndex(node_index)); 00300 00302 } 00303 00304 // Next add the current node to any elements containing the neighbouring node (there should be at most one such element) 00305 for (std::set<unsigned>::iterator iter = neighbour_containing_elements.begin(); 00306 iter != neighbour_containing_elements.end(); 00307 ++iter) 00308 { 00309 GetElement(*iter)->AddNode(this->mrMesh.GetNode(node_index)); 00310 } 00311 } 00312 } 00313 } 00314 } 00315 00316 template<unsigned DIM> 00317 bool PottsBasedCellPopulation<DIM>::IsCellAssociatedWithADeletedLocation(CellPtr pCell) 00318 { 00319 return GetElementCorrespondingToCell(pCell)->IsDeleted(); 00320 } 00321 00322 template<unsigned DIM> 00323 void PottsBasedCellPopulation<DIM>::Update(bool hasHadBirthsOrDeaths) 00324 { 00325 } 00326 00327 template<unsigned DIM> 00328 void PottsBasedCellPopulation<DIM>::CreateOutputFiles(const std::string& rDirectory, bool cleanOutputDirectory) 00329 { 00330 AbstractCellPopulation<DIM>::CreateOutputFiles(rDirectory, cleanOutputDirectory); 00331 00332 OutputFileHandler output_file_handler(rDirectory, cleanOutputDirectory); 00333 mpVizElementsFile = output_file_handler.OpenOutputFile("results.vizelements"); 00334 } 00335 00336 template<unsigned DIM> 00337 void PottsBasedCellPopulation<DIM>::CloseOutputFiles() 00338 { 00339 AbstractCellPopulation<DIM>::CloseOutputFiles(); 00340 mpVizElementsFile->close(); 00341 } 00342 00343 template<unsigned DIM> 00344 void PottsBasedCellPopulation<DIM>::WriteResultsToFiles() 00345 { 00346 AbstractCellPopulation<DIM>::WriteResultsToFiles(); 00347 00348 CreateElementTessellation(); // To be used to output to the visualizer 00349 00350 SimulationTime* p_time = SimulationTime::Instance(); 00351 00352 // Write element data to file 00353 *mpVizElementsFile << p_time->GetTime() << "\t"; 00354 00355 // Loop over cells and find associated elements so in the same order as the cells in output files 00356 for (std::list<CellPtr>::iterator cell_iter = this->mCells.begin(); 00357 cell_iter != this->mCells.end(); 00358 ++cell_iter) 00359 { 00360 unsigned elem_index = this->GetLocationIndexUsingCell(*cell_iter); 00361 00362 // Hack that covers the case where the element is associated with a cell that has just been killed (#1129) 00363 bool elem_corresponds_to_dead_cell = false; 00364 00365 if (this->IsCellAttachedToLocationIndex(elem_index)) 00366 { 00367 elem_corresponds_to_dead_cell = this->GetCellUsingLocationIndex(elem_index)->IsDead(); 00368 } 00369 00370 // Write node data to file 00371 if (!(GetElement(elem_index)->IsDeleted()) && !elem_corresponds_to_dead_cell) 00372 { 00373 PottsElement<DIM>* p_element = mpPottsMesh->GetElement(elem_index); 00374 00375 unsigned num_nodes_in_element = p_element->GetNumNodes(); 00376 00377 // First write the number of Nodes belonging to this PottsElement 00378 *mpVizElementsFile << num_nodes_in_element << " "; 00379 00380 // Then write the global index of each Node in this element 00381 for (unsigned i=0; i<num_nodes_in_element; i++) 00382 { 00383 *mpVizElementsFile << p_element->GetNodeGlobalIndex(i) << " "; 00384 } 00385 } 00386 } 00387 *mpVizElementsFile << "\n"; 00388 } 00389 00390 template<unsigned DIM> 00391 double PottsBasedCellPopulation<DIM>::GetVolumeOfCell(CellPtr pCell) 00392 { 00393 // Get element index corresponding to this cell 00394 unsigned elem_index = this->GetLocationIndexUsingCell(pCell); 00395 00396 // Get volume of this element in the Potts mesh 00397 double cell_volume = mpPottsMesh->GetVolumeOfElement(elem_index); 00398 00399 return cell_volume; 00400 } 00401 00402 template<unsigned DIM> 00403 void PottsBasedCellPopulation<DIM>::WriteCellVolumeResultsToFile() 00404 { 00405 // Write time to file 00406 *(this->mpCellVolumesFile) << SimulationTime::Instance()->GetTime() << " "; 00407 00408 // Loop over cells and find associated elements so in the same order as the cells in output files 00409 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin(); 00410 cell_iter != this->End(); 00411 ++cell_iter) 00412 { 00413 unsigned elem_index = this->GetLocationIndexUsingCell(*cell_iter); 00414 00415 // Hack that covers the case where the element is associated with a cell that has just been killed (#1129) 00416 bool elem_corresponds_to_dead_cell = false; 00417 00418 if (this->IsCellAttachedToLocationIndex(elem_index)) 00419 { 00420 elem_corresponds_to_dead_cell = this->GetCellUsingLocationIndex(elem_index)->IsDead(); 00421 } 00422 00423 // Write node data to file 00424 if (!(GetElement(elem_index)->IsDeleted()) && !elem_corresponds_to_dead_cell) 00425 { 00426 // Write element index to file 00427 *(this->mpCellVolumesFile) << elem_index << " "; 00428 00429 // Write cell ID to file 00430 unsigned cell_index = cell_iter->GetCellId(); 00431 *(this->mpCellVolumesFile) << cell_index << " "; 00432 00433 // Write centroid location to file 00434 c_vector<double, DIM> centroid_location = mpPottsMesh->GetCentroidOfElement(elem_index); 00435 00436 *(this->mpCellVolumesFile) << centroid_location[0] << " "; 00437 *(this->mpCellVolumesFile) << centroid_location[1] << " "; 00438 00439 // Write cell volume (in 3D) or area (in 2D) to file 00440 double cell_volume = this->GetVolumeOfCell(*cell_iter); 00441 *(this->mpCellVolumesFile) << cell_volume << " "; 00442 } 00443 } 00444 *(this->mpCellVolumesFile) << "\n"; 00445 } 00446 00447 template<unsigned DIM> 00448 void PottsBasedCellPopulation<DIM>::GenerateCellResultsAndWriteToFiles() 00449 { 00450 // Set up cell type counter 00451 unsigned num_cell_types = this->mCellProliferativeTypeCount.size(); 00452 std::vector<unsigned> cell_type_counter(num_cell_types); 00453 for (unsigned i=0; i<num_cell_types; i++) 00454 { 00455 cell_type_counter[i] = 0; 00456 } 00457 00458 // Set up cell cycle phase counter 00459 unsigned num_cell_cycle_phases = this->mCellCyclePhaseCount.size(); 00460 std::vector<unsigned> cell_cycle_phase_counter(num_cell_cycle_phases); 00461 for (unsigned i=0; i<num_cell_cycle_phases; i++) 00462 { 00463 cell_cycle_phase_counter[i] = 0; 00464 } 00465 00466 for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin(); 00467 cell_iter != this->End(); 00468 ++cell_iter) 00469 { 00470 this->GenerateCellResults(*cell_iter, cell_type_counter, cell_cycle_phase_counter); 00471 } 00472 00473 this->WriteCellResultsToFiles(cell_type_counter, cell_cycle_phase_counter); 00474 } 00475 00476 template<unsigned DIM> 00477 double PottsBasedCellPopulation<DIM>::GetWidth(const unsigned& rDimension) 00478 { 00479 // Call GetWidth() on the mesh 00480 double width = this->mrMesh.GetWidth(rDimension); 00481 00482 return width; 00483 } 00484 00485 template<unsigned DIM> 00486 void PottsBasedCellPopulation<DIM>::AddUpdateRule(boost::shared_ptr<AbstractPottsUpdateRule<DIM> > pUpdateRule) 00487 { 00488 mUpdateRuleCollection.push_back(pUpdateRule); 00489 } 00490 00491 template<unsigned DIM> 00492 void PottsBasedCellPopulation<DIM>::RemoveAllUpdateRules() 00493 { 00494 mUpdateRuleCollection.clear(); 00495 } 00496 00497 template<unsigned DIM> 00498 const std::vector<boost::shared_ptr<AbstractPottsUpdateRule<DIM> > >& PottsBasedCellPopulation<DIM>::rGetUpdateRuleCollection() const 00499 { 00500 return mUpdateRuleCollection; 00501 } 00502 00503 template<unsigned DIM> 00504 void PottsBasedCellPopulation<DIM>::CreateElementTessellation() 00505 { 00507 // delete mpElementTessellation; 00508 // 00509 // ///\todo this code would need to be extended if the domain were required to be periodic 00510 // 00511 // std::vector<Node<2>*> nodes; 00512 // for (unsigned node_index=0; node_index<mrMesh.GetNumNodes(); node_index++) 00513 // { 00514 // Node<2>* p_temp_node = mrMesh.GetNode(node_index); 00515 // nodes.push_back(p_temp_node); 00516 // } 00517 // MutableMesh<2,2> mesh(nodes); 00518 // mpElementTessellation = new VertexMesh<2,2>(mesh); 00519 } 00520 00521 template<unsigned DIM> 00522 VertexMesh<DIM,DIM>* PottsBasedCellPopulation<DIM>::GetElementTessellation() 00523 { 00524 // assert(mpElementTessellation != NULL); 00525 return mpElementTessellation; 00526 } 00527 00528 template<unsigned DIM> 00529 void PottsBasedCellPopulation<DIM>::CreateMutableMesh() 00530 { 00531 delete mpMutableMesh; 00532 00533 // Get the nodes of the PottsMesh 00534 std::vector<Node<DIM>*> nodes; 00535 for (unsigned node_index=0; node_index<this->mrMesh.GetNumNodes(); node_index++) 00536 { 00537 c_vector<double, DIM> location = this->mrMesh.GetNode(node_index)->rGetLocation(); 00538 nodes.push_back(new Node<DIM>(node_index, location)); 00539 } 00540 00541 mpMutableMesh = new MutableMesh<DIM,DIM>(nodes); 00542 } 00543 00544 template<unsigned DIM> 00545 MutableMesh<DIM,DIM>* PottsBasedCellPopulation<DIM>::GetMutableMesh() 00546 { 00547 assert(mpMutableMesh); 00548 return mpMutableMesh; 00549 } 00550 00551 template<unsigned DIM> 00552 void PottsBasedCellPopulation<DIM>::OutputCellPopulationParameters(out_stream& rParamsFile) 00553 { 00554 *rParamsFile << "\t\t<Temperature>" << mTemperature << "</Temperature>\n"; 00555 *rParamsFile << "\t\t<NumSweepsPerTimestep>" << mNumSweepsPerTimestep << "</NumSweepsPerTimestep>\n"; 00556 00557 // Call method on direct parent class 00558 AbstractOnLatticeCellPopulation<DIM>::OutputCellPopulationParameters(rParamsFile); 00559 } 00560 00561 template<unsigned DIM> 00562 std::set<unsigned> PottsBasedCellPopulation<DIM>::GetNeighbouringNodeIndices(unsigned index) 00563 { 00564 EXCEPTION("Cannot call GetNeighbouringNodeIndices() on a PottsBasedCellPopulation, need to go through the PottsMesh instead"); 00565 std::set<unsigned> neighbouring_node_indices; 00566 return neighbouring_node_indices; 00567 } 00568 00569 template<unsigned DIM> 00570 void PottsBasedCellPopulation<DIM>::SetTemperature(double temperature) 00571 { 00572 mTemperature = temperature; 00573 } 00574 00575 template<unsigned DIM> 00576 double PottsBasedCellPopulation<DIM>::GetTemperature() 00577 { 00578 return mTemperature; 00579 } 00580 00581 template<unsigned DIM> 00582 void PottsBasedCellPopulation<DIM>::SetNumSweepsPerTimestep(unsigned numSweepsPerTimestep) 00583 { 00584 mNumSweepsPerTimestep = numSweepsPerTimestep; 00585 } 00586 00587 template<unsigned DIM> 00588 unsigned PottsBasedCellPopulation<DIM>::GetNumSweepsPerTimestep() 00589 { 00590 return mNumSweepsPerTimestep; 00591 } 00592 00593 template<unsigned DIM> 00594 void PottsBasedCellPopulation<DIM>::WriteVtkResultsToFile() 00595 { 00596 #ifdef CHASTE_VTK 00597 std::stringstream time; 00598 time << SimulationTime::Instance()->GetTimeStepsElapsed(); 00599 VtkMeshWriter<DIM, DIM> mesh_writer(this->mDirPath, "results_"+time.str(), false); 00600 00601 unsigned num_nodes = GetNumNodes(); 00602 std::vector<double> cell_types; 00603 std::vector<double> cell_mutation_states; 00604 std::vector<double> cell_labels; 00605 std::vector<double> elem_ids; 00606 cell_types.reserve(num_nodes); 00607 cell_mutation_states.reserve(num_nodes); 00608 cell_labels.reserve(num_nodes); 00609 elem_ids.reserve(num_nodes); 00610 std::vector<std::vector<double> > cellwise_data; 00611 00612 unsigned num_cell_data_items = 0; 00613 std::vector<std::string> cell_data_names; 00614 //We assume that the first cell is representative of all cells 00615 num_cell_data_items = this->Begin()->GetCellData()->GetNumItems(); 00616 cell_data_names = this->Begin()->GetCellData()->GetKeys(); 00617 00618 for (unsigned var=0; var<num_cell_data_items; var++) 00619 { 00620 std::vector<double> cellwise_data_var(num_nodes); 00621 cellwise_data.push_back(cellwise_data_var); 00622 } 00623 for (typename AbstractMesh<DIM,DIM>::NodeIterator iter = mpPottsMesh->GetNodeIteratorBegin(); 00624 iter != mpPottsMesh->GetNodeIteratorEnd(); 00625 ++iter) 00626 { 00627 std::set<unsigned> element_indices = iter->rGetContainingElementIndices(); 00628 00629 if (element_indices.empty()) 00630 { 00631 // No elements associated with this gridpoint 00632 cell_types.push_back(-1.0); 00633 elem_ids.push_back(-1.0); 00634 if (this->mOutputCellMutationStates) 00635 { 00636 cell_mutation_states.push_back(-1.0); 00637 cell_labels.push_back(-1.0); 00638 } 00639 } 00640 else 00641 { 00642 // The number of elements should be zero or one 00643 assert(element_indices.size() == 1); 00644 00645 unsigned element_index = *(element_indices.begin()); 00646 elem_ids.push_back((double)element_index); 00647 00648 CellPtr p_cell = this->GetCellUsingLocationIndex(element_index); 00649 double cell_type = p_cell->GetCellProliferativeType(); 00650 cell_types.push_back(cell_type); 00651 00652 if (this->mOutputCellMutationStates) 00653 { 00654 double cell_mutation_state = p_cell->GetMutationState()->GetColour(); 00655 cell_mutation_states.push_back(cell_mutation_state); 00656 00657 double cell_label = 0.0; 00658 if (p_cell->HasCellProperty<CellLabel>()) 00659 { 00660 CellPropertyCollection collection = p_cell->rGetCellPropertyCollection().GetProperties<CellLabel>(); 00661 boost::shared_ptr<CellLabel> p_label = boost::static_pointer_cast<CellLabel>(collection.GetProperty()); 00662 cell_label = p_label->GetColour(); 00663 } 00664 cell_labels.push_back(cell_label); 00665 } 00666 for (unsigned var=0; var<num_cell_data_items; var++) 00667 { 00668 cellwise_data[var][iter->GetIndex()] = p_cell->GetCellData()->GetItem(cell_data_names[var]); 00669 } 00670 } 00671 } 00672 00673 assert(cell_types.size() == num_nodes); 00674 assert(elem_ids.size() == num_nodes); 00675 00676 mesh_writer.AddPointData("Element index", elem_ids); 00677 mesh_writer.AddPointData("Cell types", cell_types); 00678 00679 if (this->mOutputCellMutationStates) 00680 { 00681 assert(cell_mutation_states.size() == num_nodes); 00682 mesh_writer.AddPointData("Mutation states", cell_mutation_states); 00683 assert(cell_labels.size() == num_nodes); 00684 mesh_writer.AddPointData("Cell labels", cell_labels); 00685 } 00686 00687 if (num_cell_data_items > 0) 00688 { 00689 for (unsigned var=0; var<cellwise_data.size(); var++) 00690 { 00691 mesh_writer.AddPointData(cell_data_names[var], cellwise_data[var]); 00692 } 00693 } 00694 00695 /* 00696 * The current VTK writer can only write things which inherit from AbstractTetrahedralMeshWriter. 00697 * For now, we do an explicit conversion to NodesOnlyMesh. This can be written to VTK then visualized as glyphs. 00698 */ 00699 NodesOnlyMesh<DIM> temp_mesh; 00700 temp_mesh.ConstructNodesWithoutMesh(*mpPottsMesh); 00701 mesh_writer.WriteFilesUsingMesh(temp_mesh); 00702 00703 *(this->mpVtkMetaFile) << " <DataSet timestep=\""; 00704 *(this->mpVtkMetaFile) << time.str(); 00705 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_"; 00706 *(this->mpVtkMetaFile) << time.str(); 00707 *(this->mpVtkMetaFile) << ".vtu\"/>\n"; 00708 #endif //CHASTE_VTK 00709 } 00710 00712 // Explicit instantiation 00714 00715 template class PottsBasedCellPopulation<1>; 00716 template class PottsBasedCellPopulation<2>; 00717 template class PottsBasedCellPopulation<3>; 00718 00719 // Serialization for Boost >= 1.36 00720 #include "SerializationExportWrapperForCpp.hpp" 00721 EXPORT_TEMPLATE_CLASS_SAME_DIMS(PottsBasedCellPopulation)