Chaste  Release::3.4
NodeBasedCellPopulationWithParticles.cpp
1 /*
2 
3 Copyright (c) 2005-2016, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 #include "NodeBasedCellPopulationWithParticles.hpp"
37 #include "VtkMeshWriter.hpp"
38 #include "CellAgesWriter.hpp"
39 #include "CellAncestorWriter.hpp"
40 #include "CellProliferativePhasesWriter.hpp"
41 #include "CellProliferativeTypesWriter.hpp"
42 #include "CellVolumesWriter.hpp"
43 #include "CellMutationStatesCountWriter.hpp"
44 
45 template<unsigned DIM>
47  std::vector<CellPtr>& rCells,
48  const std::vector<unsigned> locationIndices,
49  bool deleteMesh)
50  : NodeBasedCellPopulation<DIM>(rMesh, rCells, locationIndices, deleteMesh, false)
51 {
53  if (!locationIndices.empty())
54  {
55  // Create a set of node indices corresponding to particles
56  std::set<unsigned> node_indices;
57  std::set<unsigned> location_indices;
58  std::set<unsigned> particle_indices;
59 
60  for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = rMesh.GetNodeIteratorBegin();
61  node_iter != rMesh.GetNodeIteratorEnd();
62  ++node_iter)
63  {
64  node_indices.insert(node_iter->GetIndex());
65  }
66  for (unsigned i=0; i<locationIndices.size(); i++)
67  {
68  location_indices.insert(locationIndices[i]);
69  }
70 
71  std::set_difference(node_indices.begin(), node_indices.end(),
72  location_indices.begin(), location_indices.end(),
73  std::inserter(particle_indices, particle_indices.begin()));
74 
75  // This method finishes and then calls Validate()
76  SetParticles(particle_indices);
77  }
78  else
79  {
80  for (typename NodesOnlyMesh<DIM>::NodeIterator node_iter = rMesh.GetNodeIteratorBegin();
81  node_iter != rMesh.GetNodeIteratorEnd();
82  ++node_iter)
83  {
84  (*node_iter).SetIsParticle(false);
85  }
87  }
88 }
89 
90 template<unsigned DIM>
92  : NodeBasedCellPopulation<DIM>(rMesh)
93 {
94 }
95 
96 template<unsigned DIM>
98 {
99  return this->GetNode(index)->IsParticle();
100 }
101 
102 template<unsigned DIM>
104 {
105  std::set<unsigned> particle_indices;
106 
107  for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
108  node_iter != this->mrMesh.GetNodeIteratorEnd();
109  ++node_iter)
110  {
111  if (node_iter->IsParticle())
112  {
113  particle_indices.insert(node_iter->GetIndex());
114  }
115  }
116 
117  return particle_indices;
118 }
119 
120 template<unsigned DIM>
121 void NodeBasedCellPopulationWithParticles<DIM>::SetParticles(const std::set<unsigned>& rParticleIndices)
122 {
123  for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
124  node_iter != this->mrMesh.GetNodeIteratorEnd();
125  ++node_iter)
126  {
127  if (rParticleIndices.find(node_iter->GetIndex()) != rParticleIndices.end())
128  {
129  node_iter->SetIsParticle(true);
130  }
131  }
133 }
134 
135 template<unsigned DIM>
137 {
138  // Initialise vector of forces on particles
139  std::vector<c_vector<double, DIM> > drdt(this->GetNumNodes());
140  for (unsigned i=0; i<drdt.size(); i++)
141  {
142  drdt[i] = zero_vector<double>(DIM);
143  }
144 
145  // Calculate forces on particles
146  double damping_constant = this->GetDampingConstantNormal();
147  for (unsigned i=0; i<drdt.size(); i++)
148  {
149  drdt[i] = this->GetNode(i)->rGetAppliedForce()/damping_constant;
150  }
151 
152  for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
153  node_iter != this->mrMesh.GetNodeIteratorEnd();
154  ++node_iter)
155  {
156  if (node_iter->IsParticle())
157  {
158  ChastePoint<DIM> new_point(node_iter->rGetLocation() + dt*drdt[node_iter->GetIndex()]);
159  node_iter->SetPoint(new_point);
160  }
161  }
162 }
163 
164 template<unsigned DIM>
166 {
167 }
168 
169 template<unsigned DIM>
170 CellPtr NodeBasedCellPopulationWithParticles<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
171 {
172  assert(pNewCell);
173 
174  // Add new cell to cell population
175  CellPtr p_created_cell = AbstractCentreBasedCellPopulation<DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell);
176  assert(p_created_cell == pNewCell);
177 
178  // Then set the new cell radius in the NodesOnlyMesh
179  unsigned node_index = this->GetLocationIndexUsingCell(p_created_cell);
180  this->GetNode(node_index)->SetRadius(0.5);
181  this->GetNode(node_index)->SetIsParticle(false);
182 
183  // Return pointer to new cell
184  return p_created_cell;
185 }
186 
187 template<unsigned DIM>
189 {
190  std::map<unsigned, bool> validated_nodes;
191  for (typename AbstractMesh<DIM, DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
192  node_iter != this->mrMesh.GetNodeIteratorEnd();
193  ++node_iter)
194  {
195  validated_nodes[node_iter->GetIndex()] = node_iter->IsParticle();
196  }
197 
198  // Look through all of the cells and record what node they are associated with.
199  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter)
200  {
201  unsigned node_index = this->GetLocationIndexUsingCell((*cell_iter));
202 
203  // If the node attached to this cell is labelled as a particle, then throw an error
204  if (this->GetNode(node_index)->IsParticle())
205  {
206  EXCEPTION("Node " << node_index << " is labelled as a particle and has a cell attached");
207  }
208  validated_nodes[node_index] = true;
209  }
210 
211  for (std::map<unsigned, bool>::iterator map_iter = validated_nodes.begin();
212  map_iter != validated_nodes.end();
213  map_iter++)
214  {
215  if (!map_iter->second)
216  {
217  EXCEPTION("Node " << map_iter->first << " does not appear to be a particle or has a cell associated with it");
218  }
219  }
220 }
221 
222 template<unsigned DIM>
224 {
225  // First update particle positions
226  UpdateParticlePositions(dt);
227 
228  // Then call the base class method
230 }
231 
232 template<unsigned DIM>
234 {
235  for (typename AbstractMesh<DIM, DIM>::NodeIterator node_iter = this->rGetMesh().GetNodeIteratorBegin();
236  node_iter != this->rGetMesh().GetNodeIteratorEnd();
237  ++node_iter)
238  {
239  // If it isn't a particle then there might be cell writers attached
240  if (! this->IsParticle(node_iter->GetIndex()))
241  {
242  for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
243  cell_writer_iter != this->mCellWriters.end();
244  ++cell_writer_iter)
245  {
246  CellPtr cell_from_node = this->GetCellUsingLocationIndex(node_iter->GetIndex());
247  this->AcceptCellWriter(*cell_writer_iter, cell_from_node);
248  }
249  }
250  }
251 }
252 
253 
254 template<unsigned DIM>
256 {
257 #ifdef CHASTE_VTK
258  // Store the present time as a string
259  std::stringstream time;
261 
262  // Make sure the nodes are ordered contiguously in memory
263  NodeMap map(1 + this->mpNodesOnlyMesh->GetMaximumNodeIndex());
264  this->mpNodesOnlyMesh->ReMesh(map);
265 
266  // Store the number of cells for which to output data to VTK
267  unsigned num_nodes = this->GetNumNodes();
268  std::vector<double> rank(num_nodes);
269  std::vector<double> particles(num_nodes);
270 
271  unsigned num_cell_data_items = 0;
272  std::vector<std::string> cell_data_names;
273 
274  // We assume that the first cell is representative of all cells
275  if (num_nodes > 0)
276  {
277  num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
278  cell_data_names = this->Begin()->GetCellData()->GetKeys();
279  }
280 
281  std::vector<std::vector<double> > cell_data;
282  for (unsigned var=0; var<num_cell_data_items; var++)
283  {
284  std::vector<double> cell_data_var(num_nodes);
285  cell_data.push_back(cell_data_var);
286  }
287 
288  // Create mesh writer for VTK output
289  VtkMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results_"+time.str(), false);
290  mesh_writer.SetParallelFiles(*(this->mpNodesOnlyMesh));
291 
292  // Iterate over any cell writers that are present
293  for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
294  cell_writer_iter != this->mCellWriters.end();
295  ++cell_writer_iter)
296  {
297  // Create vector to store VTK cell data
298  std::vector<double> vtk_cell_data(num_nodes);
299 
300  // Loop over nodes
301  for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
302  node_iter != this->mrMesh.GetNodeIteratorEnd();
303  ++node_iter)
304  {
305  unsigned node_index = node_iter->GetIndex();
306 
307  // If this node is a particle (not a cell), then we set the 'dummy' VTK cell data for this to be -2.0...
308  if (this->IsParticle(node_index))
309  {
310  vtk_cell_data[node_index] = -2.0;
311  }
312  else
313  {
314  // ...otherwise we populate the vector of VTK cell data as usual
315  CellPtr p_cell = this->GetCellUsingLocationIndex(node_index);
316  vtk_cell_data[node_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(p_cell, this);
317  }
318  }
319 
320  mesh_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
321  }
322 
323  // Loop over cells
324  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = this->Begin();
325  cell_iter != this->End();
326  ++cell_iter)
327  {
328  // Get the node index corresponding to this cell
329  unsigned global_index = this->GetLocationIndexUsingCell(*cell_iter);
330  unsigned node_index = this->rGetMesh().SolveNodeMapping(global_index);
331 
332  for (unsigned var=0; var<num_cell_data_items; var++)
333  {
334  cell_data[var][node_index] = cell_iter->GetCellData()->GetItem(cell_data_names[var]);
335  }
336 
337  rank[node_index] = (PetscTools::GetMyRank());
338  }
339 
340  mesh_writer.AddPointData("Process rank", rank);
341 
342  // Loop over nodes
343  for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
344  node_iter != this->mrMesh.GetNodeIteratorEnd();
345  ++node_iter)
346  {
347  unsigned node_index = node_iter->GetIndex();
348  particles[node_index] = (double) (this->IsParticle(node_index));
349  }
350 
351  mesh_writer.AddPointData("Non-particles", particles);
352 
353  if (num_cell_data_items > 0)
354  {
355  for (unsigned var=0; var<cell_data.size(); var++)
356  {
357  mesh_writer.AddPointData(cell_data_names[var], cell_data[var]);
358  }
359  }
360 
361  mesh_writer.WriteFilesUsingMesh(*(this->mpNodesOnlyMesh));
362 
363  *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
364  *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
365  *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
366  *(this->mpVtkMetaFile) << SimulationTime::Instance()->GetTimeStepsElapsed();
368  {
369  *(this->mpVtkMetaFile) << ".vtu\"/>\n";
370  }
371 /* {
372  // Parallel vtu files .vtu -> .pvtu
373  *(this->mpVtkMetaFile) << ".pvtu\"/>\n";
374  }*/
375 #endif //CHASTE_VTK
376 }
377 
378 template<unsigned DIM>
380 {
381  // Call method on direct parent class
383 }
384 
385 // Explicit instantiation
389 
390 // Serialization for Boost >= 1.36
void OutputCellPopulationParameters(out_stream &rParamsFile)
NodeBasedCellPopulationWithParticles(NodesOnlyMesh< DIM > &rMesh, std::vector< CellPtr > &rCells, const std::vector< unsigned > locationIndices=std::vector< unsigned >(), bool deleteMesh=false)
#define EXCEPTION(message)
Definition: Exception.hpp:143
static SimulationTime * Instance()
void SetParallelFiles(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
NodeIterator GetNodeIteratorEnd()
unsigned GetTimeStepsElapsed() const
static bool IsSequential()
Definition: PetscTools.cpp:91
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
#define EXCEPT_IF_NOT(test)
Definition: Exception.hpp:158
NodeIterator GetNodeIteratorBegin(bool skipDeletedNodes=true)
virtual void WriteVtkResultsToFile(const std::string &rDirectory)
CellPtr AddCell(CellPtr pNewCell, const c_vector< double, SPACE_DIM > &rCellDivisionVector, CellPtr pParentCell=CellPtr())
CellPtr AddCell(CellPtr pNewCell, const c_vector< double, DIM > &rCellDivisionVector, CellPtr pParentCell)
static unsigned GetMyRank()
Definition: PetscTools.cpp:114
void SetParticles(const std::set< unsigned > &rParticleIndices)