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