Chaste  Release::3.4
MeshBasedCellPopulationWithGhostNodes.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 "MeshBasedCellPopulationWithGhostNodes.hpp"
37 
38 // Cell writers
39 #include "CellAgesWriter.hpp"
40 #include "CellAncestorWriter.hpp"
41 #include "CellProliferativePhasesWriter.hpp"
42 #include "CellProliferativeTypesWriter.hpp"
43 #include "CellVolumesWriter.hpp"
44 #include "CellLocationIndexWriter.hpp"
45 
46 // Cell population writers
47 #include "CellMutationStatesCountWriter.hpp"
48 
49 template<unsigned DIM>
51  MutableMesh<DIM, DIM>& rMesh,
52  std::vector<CellPtr>& rCells,
53  const std::vector<unsigned> locationIndices,
54  bool deleteMesh,
55  double ghostSpringStiffness)
56  : MeshBasedCellPopulation<DIM,DIM>(rMesh, rCells, locationIndices, deleteMesh, false), // do not call the base class Validate()
57  mGhostSpringStiffness(ghostSpringStiffness)
58 {
59  if (!locationIndices.empty())
60  {
61  // Create a set of node indices corresponding to ghost nodes
62  std::set<unsigned> node_indices;
63  std::set<unsigned> location_indices;
64  std::set<unsigned> ghost_node_indices;
65 
66  for (unsigned i=0; i<this->GetNumNodes(); i++)
67  {
68  node_indices.insert(this->GetNode(i)->GetIndex());
69  }
70  for (unsigned i=0; i<locationIndices.size(); i++)
71  {
72  location_indices.insert(locationIndices[i]);
73  }
74 
75  std::set_difference(node_indices.begin(), node_indices.end(),
76  location_indices.begin(), location_indices.end(),
77  std::inserter(ghost_node_indices, ghost_node_indices.begin()));
78 
79  // This method finishes and then calls Validate()
80  SetGhostNodes(ghost_node_indices);
81  }
82  else
83  {
84  this->mIsGhostNode = std::vector<bool>(this->GetNumNodes(), false);
85  Validate();
86  }
87 }
88 
89 template<unsigned DIM>
91  double ghostSpringStiffness)
92  : MeshBasedCellPopulation<DIM,DIM>(rMesh),
93  mGhostSpringStiffness(ghostSpringStiffness)
94 {
95 }
96 
97 template<unsigned DIM>
99 {
100 }
101 
102 template<unsigned DIM>
104 {
105  return this->mIsGhostNode;
106 }
107 
108 template<unsigned DIM>
110 {
111  return this->mIsGhostNode[index];
112 }
113 
114 template<unsigned DIM>
116 {
117  std::set<unsigned> ghost_node_indices;
118  for (unsigned i=0; i<this->mIsGhostNode.size(); i++)
119  {
120  if (this->mIsGhostNode[i])
121  {
122  ghost_node_indices.insert(i);
123  }
124  }
125  return ghost_node_indices;
126 }
127 
128 template<unsigned DIM>
129 void MeshBasedCellPopulationWithGhostNodes<DIM>::SetGhostNodes(const std::set<unsigned>& rGhostNodeIndices)
130 {
131  // Reinitialise all entries of mIsGhostNode to false
132  this->mIsGhostNode = std::vector<bool>(this->mrMesh.GetNumNodes(), false);
133 
134  // Update mIsGhostNode
135  for (std::set<unsigned>::iterator iter=rGhostNodeIndices.begin(); iter!=rGhostNodeIndices.end(); ++iter)
136  {
137  this->mIsGhostNode[*iter] = true;
138  }
139 
140  Validate();
141 }
142 
143 template<unsigned DIM>
145 {
146  // Initialise vector of forces on ghost nodes
147  std::vector<c_vector<double, DIM> > drdt(this->GetNumNodes());
148  for (unsigned i=0; i<drdt.size(); i++)
149  {
150  drdt[i] = zero_vector<double>(DIM);
151  }
152 
153  // Calculate forces on ghost nodes
154  for (typename MutableMesh<DIM, DIM>::EdgeIterator edge_iterator = static_cast<MutableMesh<DIM, DIM>&>((this->mrMesh)).EdgesBegin();
155  edge_iterator != static_cast<MutableMesh<DIM, DIM>&>((this->mrMesh)).EdgesEnd();
156  ++edge_iterator)
157  {
158  unsigned nodeA_global_index = edge_iterator.GetNodeA()->GetIndex();
159  unsigned nodeB_global_index = edge_iterator.GetNodeB()->GetIndex();
160 
161  c_vector<double, DIM> force = CalculateForceBetweenGhostNodes(nodeA_global_index, nodeB_global_index);
162 
163  double damping_constant = this->GetDampingConstantNormal();
164 
165  if (!this->mIsGhostNode[nodeA_global_index])
166  {
167  drdt[nodeB_global_index] -= force / damping_constant;
168  }
169  else
170  {
171  drdt[nodeA_global_index] += force / damping_constant;
172 
173  if (this->mIsGhostNode[nodeB_global_index])
174  {
175  drdt[nodeB_global_index] -= force / damping_constant;
176  }
177  }
178  }
179 
180  for (typename AbstractMesh<DIM,DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
181  node_iter != this->mrMesh.GetNodeIteratorEnd();
182  ++node_iter)
183  {
184  unsigned node_index = node_iter->GetIndex();
185  if (this->mIsGhostNode[node_index])
186  {
187  ChastePoint<DIM> new_point(node_iter->rGetLocation() + dt*drdt[node_index]);
188  static_cast<MutableMesh<DIM, DIM>&>((this->mrMesh)).SetNode(node_index, new_point, false);
189  }
190  }
191 }
192 
193 template<unsigned DIM>
194 c_vector<double, DIM> MeshBasedCellPopulationWithGhostNodes<DIM>::CalculateForceBetweenGhostNodes(const unsigned& rNodeAGlobalIndex, const unsigned& rNodeBGlobalIndex)
195 {
196  assert(rNodeAGlobalIndex != rNodeBGlobalIndex);
197  c_vector<double, DIM> unit_difference;
198  c_vector<double, DIM> node_a_location = this->GetNode(rNodeAGlobalIndex)->rGetLocation();
199  c_vector<double, DIM> node_b_location = this->GetNode(rNodeBGlobalIndex)->rGetLocation();
200 
201  // There is reason not to subtract one position from the other (cylindrical meshes)
202  unit_difference = this->mrMesh.GetVectorFromAtoB(node_a_location, node_b_location);
203 
204  double distance_between_nodes = norm_2(unit_difference);
205  unit_difference /= distance_between_nodes;
206 
207  double rest_length = 1.0;
208 
209  return mGhostSpringStiffness * unit_difference * (distance_between_nodes - rest_length);
210 }
211 
212 template<unsigned DIM>
213 CellPtr MeshBasedCellPopulationWithGhostNodes<DIM>::AddCell(CellPtr pNewCell, const c_vector<double,DIM>& rCellDivisionVector, CellPtr pParentCell)
214 {
215  // Add new cell to cell population
216  CellPtr p_created_cell = MeshBasedCellPopulation<DIM,DIM>::AddCell(pNewCell, rCellDivisionVector, pParentCell);
217  assert(p_created_cell == pNewCell);
218 
219  // Update size of mIsGhostNode if necessary
220  unsigned new_node_index = this->GetLocationIndexUsingCell(p_created_cell);
221 
222  if (this->GetNumNodes() > this->mIsGhostNode.size())
223  {
224  this->mIsGhostNode.resize(this->GetNumNodes());
225  this->mIsGhostNode[new_node_index] = false;
226  }
227 
228  // Return pointer to new cell
229  return p_created_cell;
230 }
231 
232 template<unsigned DIM>
234 {
235  // Get a list of all the nodes that are ghosts
236  std::vector<bool> validated_node = mIsGhostNode;
237  assert(mIsGhostNode.size()==this->GetNumNodes());
238 
239  // Look through all of the cells and record what node they are associated with.
240  for (typename AbstractCellPopulation<DIM,DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter)
241  {
242  unsigned node_index = this->GetLocationIndexUsingCell((*cell_iter));
243 
244  // If the node attached to this cell is labelled as a ghost node, then throw an error
245  if (mIsGhostNode[node_index])
246  {
247  EXCEPTION("Node " << node_index << " is labelled as a ghost node and has a cell attached");
248  }
249  validated_node[node_index] = true;
250  }
251 
252  for (unsigned i=0; i<validated_node.size(); i++)
253  {
254  if (!validated_node[i])
255  {
256  EXCEPTION("Node " << i << " does not appear to be a ghost node or have a cell associated with it");
257  }
258  }
259 }
260 
261 template<unsigned DIM>
263 {
264  // Copy mIsGhostNode to a temporary vector
265  std::vector<bool> ghost_nodes_before_remesh = mIsGhostNode;
266 
267  // Reinitialise mIsGhostNode
268  mIsGhostNode.clear();
269  mIsGhostNode.resize(this->GetNumNodes());
270 
271  // Update mIsGhostNode using the node map
272  for (unsigned old_index=0; old_index<rMap.GetSize(); old_index++)
273  {
274  if (!rMap.IsDeleted(old_index))
275  {
276  unsigned new_index = rMap.GetNewIndex(old_index);
277  mIsGhostNode[new_index] = ghost_nodes_before_remesh[old_index];
278  }
279  }
280 }
281 
282 template<unsigned DIM>
284 {
285  unsigned node_index = this->GetLocationIndexUsingCell(pCell);
286  std::set<unsigned> neighbour_indices = this->GetNeighbouringNodeIndices(node_index);
287 
288  // Remove ghost nodes from the neighbour indices
289  for (std::set<unsigned>::iterator iter = neighbour_indices.begin();
290  iter != neighbour_indices.end();)
291  {
292  if (this->IsGhostNode(*iter))
293  {
294  neighbour_indices.erase(iter++);
295  }
296  else
297  {
298  ++iter;
299  }
300  }
301 
302  return neighbour_indices;
303 }
304 
305 template<unsigned DIM>
307 {
308  for (typename AbstractMesh<DIM, DIM>::NodeIterator node_iter = this->rGetMesh().GetNodeIteratorBegin();
309  node_iter != this->rGetMesh().GetNodeIteratorEnd();
310  ++node_iter)
311  {
312  // If it isn't a ghost node then there might be cell writers attached
313  if (! this->IsGhostNode(node_iter->GetIndex()))
314  {
315  for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
316  cell_writer_iter != this->mCellWriters.end();
317  ++cell_writer_iter)
318  {
319  CellPtr cell_from_node = this->GetCellUsingLocationIndex(node_iter->GetIndex());
320  this->AcceptCellWriter(*cell_writer_iter, cell_from_node);
321  }
322  }
323  }
324 }
325 
326 template<unsigned DIM>
328 {
329  // First update ghost positions first because they do not affect the real cells
330  UpdateGhostPositions(dt);
331 
332  // Then call the base class method
334 }
335 
336 
337 template<unsigned DIM>
339 {
340  if (this->mOutputResultsForChasteVisualizer)
341  {
342  if (!this-> template HasWriter<CellLocationIndexWriter>())
343  {
344  this-> template AddCellWriter<CellLocationIndexWriter>();
345  }
346  }
347 
349 }
350 
351 template<unsigned DIM>
353 {
354 #ifdef CHASTE_VTK
355  if (this->mpVoronoiTessellation != NULL)
356  {
357  unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
358  std::stringstream time;
359  time << num_timesteps;
360 
361  // Create mesh writer for VTK output
362  VertexMeshWriter<DIM, DIM> mesh_writer(rDirectory, "results", false);
363 
364  // Iterate over any cell writers that are present
365  unsigned num_vtk_cells = this->mpVoronoiTessellation->GetNumElements();
366  for (typename std::vector<boost::shared_ptr<AbstractCellWriter<DIM, DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
367  cell_writer_iter != this->mCellWriters.end();
368  ++cell_writer_iter)
369  {
370  // Create vector to store VTK cell data
371  std::vector<double> vtk_cell_data(num_vtk_cells);
372 
373  // Loop over elements of mpVoronoiTessellation
374  for (typename VertexMesh<DIM, DIM>::VertexElementIterator elem_iter = this->mpVoronoiTessellation->GetElementIteratorBegin();
375  elem_iter != this->mpVoronoiTessellation->GetElementIteratorEnd();
376  ++elem_iter)
377  {
378  // Get the indices of this element and the corresponding node in mrMesh
379  unsigned elem_index = elem_iter->GetIndex();
380  unsigned node_index = this->mpVoronoiTessellation->GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(elem_index);
381 
382  // If this node corresponds to a ghost node, set any "cell" data to be -1.0
383  if (this->IsGhostNode(node_index))
384  {
385  // Populate the vector of VTK cell data
386  vtk_cell_data[elem_index] = -1.0;
387  }
388  else
389  {
390  // Get the cell corresponding to this node
391  CellPtr p_cell = this->GetCellUsingLocationIndex(node_index);
392 
393  // Populate the vector of VTK cell data
394  vtk_cell_data[elem_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(p_cell, this);
395  }
396  }
397 
398  mesh_writer.AddCellData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
399  }
400 
401  // Next, record which nodes are ghost nodes
402  // Note that the cell writer hierarchy can not be used to do this as ghost nodes don't have corresponding cells.
403  std::vector<double> ghosts(num_vtk_cells);
404  for (typename VertexMesh<DIM, DIM>::VertexElementIterator elem_iter = this->mpVoronoiTessellation->GetElementIteratorBegin();
405  elem_iter != this->mpVoronoiTessellation->GetElementIteratorEnd();
406  ++elem_iter)
407  {
408  unsigned elem_index = elem_iter->GetIndex();
409  unsigned node_index = this->mpVoronoiTessellation->GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(elem_index);
410  ghosts[elem_index] = (double) (this->IsGhostNode(node_index));
411  }
412  mesh_writer.AddCellData("Non-ghosts", ghosts);
413 
415 
416  mesh_writer.WriteVtkUsingMesh(*(this->mpVoronoiTessellation), time.str());
417  *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
418  *(this->mpVtkMetaFile) << num_timesteps;
419  *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"results_";
420  *(this->mpVtkMetaFile) << num_timesteps;
421  *(this->mpVtkMetaFile) << ".vtu\"/>\n";
422  }
423 #endif //CHASTE_VTK
424 }
425 
426 template<unsigned DIM>
428 {
429  *rParamsFile << "\t\t<GhostSpringStiffness>" << mGhostSpringStiffness << "</GhostSpringStiffness>\n";
430 
431  // Call method on direct parent class
433 }
434 
435 // Explicit instantiation
439 
440 // Serialization for Boost >= 1.36
void AddCellData(std::string dataName, std::vector< double > dataPayload)
std::set< unsigned > GetNeighbouringLocationIndices(CellPtr pCell)
virtual CellPtr AddCell(CellPtr pNewCell, const c_vector< double, SPACE_DIM > &rCellDivisionVector, CellPtr pParentCell)
virtual void WriteVtkResultsToFile(const std::string &rDirectory)
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
#define EXCEPTION(message)
Definition: Exception.hpp:143
static SimulationTime * Instance()
NodeIterator GetNodeIteratorEnd()
unsigned GetTimeStepsElapsed() const
unsigned GetSize()
Definition: NodeMap.cpp:104
CellPtr AddCell(CellPtr pNewCell, const c_vector< double, DIM > &rCellDivisionVector, CellPtr pParentCell)
virtual void SetNode(unsigned index, ChastePoint< SPACE_DIM > point, bool concreteMove=true)
c_vector< double, DIM > CalculateForceBetweenGhostNodes(const unsigned &rNodeAGlobalIndex, const unsigned &rNodeBGlobalIndex)
MeshBasedCellPopulationWithGhostNodes(MutableMesh< DIM, DIM > &rMesh, std::vector< CellPtr > &rCells, const std::vector< unsigned > locationIndices=std::vector< unsigned >(), bool deleteMesh=false, double ghostSpringStiffness=15.0)
VertexElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
Definition: VertexMesh.hpp:668
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
void SetGhostNodes(const std::set< unsigned > &rGhostNodeIndices)
void WriteVtkUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, std::string stamp="")
NodeIterator GetNodeIteratorBegin(bool skipDeletedNodes=true)
Node< ELEMENT_DIM > * GetNode(unsigned index)
bool IsDeleted(unsigned index)
Definition: NodeMap.cpp:81
unsigned GetNewIndex(unsigned oldIndex) const
Definition: NodeMap.cpp:86
void OutputCellPopulationParameters(out_stream &rParamsFile)
EdgeIterator EdgesEnd()
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)