Chaste Commit::f2ff7ee04e70ac9d06c57344df8d017dbb12b97b
MeshBasedCellPopulation.cpp
1/*
2
3Copyright (c) 2005-2024, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, 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
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36#include "MeshBasedCellPopulation.hpp"
37#include "VtkMeshWriter.hpp"
38#include "CellBasedEventHandler.hpp"
39#include "Cylindrical2dMesh.hpp"
40#include "Cylindrical2dVertexMesh.hpp"
41#include "Toroidal2dMesh.hpp"
42#include "Toroidal2dVertexMesh.hpp"
43#include "NodesOnlyMesh.hpp"
44#include "CellId.hpp"
45#include "CellVolumesWriter.hpp"
46#include "CellPopulationElementWriter.hpp"
47#include "VoronoiDataWriter.hpp"
48#include "NodeVelocityWriter.hpp"
49#include "CellPopulationAreaWriter.hpp"
50
51template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
53 std::vector<CellPtr>& rCells,
54 const std::vector<unsigned> locationIndices,
55 bool deleteMesh,
56 bool validate)
57 : AbstractCentreBasedCellPopulation<ELEMENT_DIM, SPACE_DIM>(rMesh, rCells, locationIndices),
58 mpVoronoiTessellation(nullptr),
59 mDeleteMesh(deleteMesh),
60 mUseAreaBasedDampingConstant(false),
61 mAreaBasedDampingConstantParameter(0.1),
62 mWriteVtkAsPoints(false),
63 mBoundVoronoiTessellation(false),
64 mHasVariableRestLength(false)
65{
67
68 assert(this->mCells.size() <= this->mrMesh.GetNumNodes());
69
70 if (validate)
71 {
72 Validate();
73 }
74
75 // Initialise the applied force at each node to zero
76 for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->rGetMesh().GetNodeIteratorBegin();
77 node_iter != this->rGetMesh().GetNodeIteratorEnd();
78 ++node_iter)
79 {
80 node_iter->ClearAppliedForce();
81 }
82}
83
84template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
92
93template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
95{
96 delete mpVoronoiTessellation;
97
98 if (mDeleteMesh)
99 {
100 delete &this->mrMesh;
101 }
102}
103
104template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
106{
107 return mUseAreaBasedDampingConstant;
108}
109
110template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
112 [[maybe_unused]] bool useAreaBasedDampingConstant) // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
113{
114 if constexpr (SPACE_DIM == 2)
115 {
116 mUseAreaBasedDampingConstant = useAreaBasedDampingConstant;
117 }
118 else
119 {
121 }
122}
123
124template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
126{
127 return mpMutableMesh->AddNode(pNewNode);
128}
129
130template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
132{
133 static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).SetNode(nodeIndex, rNewLocation, false);
134}
135
136template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
138{
140
141 /*
142 * The next code block computes the area-dependent damping constant as given by equation
143 * (5) in the following reference: van Leeuwen et al. 2009. An integrative computational model
144 * for intestinal tissue renewal. Cell Prolif. 42(5):617-636. doi:10.1111/j.1365-2184.2009.00627.x
145 */
146 if (mUseAreaBasedDampingConstant)
147 {
156 if constexpr (SPACE_DIM == 2)
157 {
158 double rest_length = 1.0;
159 double d0 = mAreaBasedDampingConstantParameter;
160
166 double d1 = 2.0*(1.0 - d0)/(sqrt(3.0)*rest_length*rest_length);
167
168 double area_cell = GetVolumeOfVoronoiElement(nodeIndex);
169
175 assert(area_cell < 1000);
176
177 damping_multiplier = d0 + area_cell*d1;
179 else
180 {
182 }
183 }
184
185 return damping_multiplier;
186}
187
188template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
190{
191 std::vector<bool> validated_node = std::vector<bool>(this->GetNumNodes(), false);
192
193 for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter)
195 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
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("At time " << SimulationTime::Instance()->GetTime() << ", Node " << i << " does not appear to have a cell associated with it");
205 }
206}
207
208template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
214template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
217 return *mpMutableMesh;
218}
219
220template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
225
226template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
228{
229 unsigned num_removed = 0;
230 for (std::list<CellPtr>::iterator it = this->mCells.begin();
231 it != this->mCells.end();
232 )
233 {
234 if ((*it)->IsDead())
235 {
236 // Check if this cell is in a marked spring
237 std::vector<const std::pair<CellPtr,CellPtr>*> pairs_to_remove; // Pairs that must be purged
238 for (std::set<std::pair<CellPtr,CellPtr> >::iterator it1 = this->mMarkedSprings.begin();
239 it1 != this->mMarkedSprings.end();
240 ++it1)
241 {
242 const std::pair<CellPtr,CellPtr>& r_pair = *it1;
243
244 for (unsigned i=0; i<2; i++)
246 CellPtr p_cell = (i==0 ? r_pair.first : r_pair.second);
247
248 if (p_cell == *it)
249 {
250 // Remember to purge this spring
251 pairs_to_remove.push_back(&r_pair);
252 break;
253 }
254 }
255 }
256
257 // Purge any marked springs that contained this cell
258 for (std::vector<const std::pair<CellPtr,CellPtr>* >::iterator pair_it = pairs_to_remove.begin();
259 pair_it != pairs_to_remove.end();
260 ++pair_it)
262 this->mMarkedSprings.erase(**pair_it);
263 }
264
265 // Remove the node from the mesh
266 num_removed++;
267 static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).DeleteNodePriorToReMesh(this->GetLocationIndexUsingCell((*it)));
268
269 // Update mappings between cells and location indices
270 unsigned location_index_of_removed_node = this->GetLocationIndexUsingCell((*it));
271 this->RemoveCellUsingLocationIndex(location_index_of_removed_node, (*it));
272
273 // Update vector of cells
274 it = this->mCells.erase(it);
276 else
277 {
278 ++it;
279 }
280 }
281
282 return num_removed;
283}
284
285template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
287{
289 bool output_node_velocities = (this-> template HasWriter<NodeVelocityWriter>());
290
301 std::map<unsigned, double> old_node_radius_map;
302 old_node_radius_map.clear();
303 if (this->mrMesh.GetNodeIteratorBegin()->HasNodeAttributes())
304 {
305 if (this->mrMesh.GetNodeIteratorBegin()->GetRadius() > 0.0)
306 {
307 for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
308 node_iter != this->mrMesh.GetNodeIteratorEnd();
309 ++node_iter)
310 {
311 unsigned node_index = node_iter->GetIndex();
312 old_node_radius_map[node_index] = node_iter->GetRadius();
313 }
314 }
315 }
316
317 std::map<unsigned, c_vector<double, SPACE_DIM> > old_node_applied_force_map;
318 old_node_applied_force_map.clear();
319 if (output_node_velocities)
320 {
321 /*
322 * If outputting node velocities, we must keep a record of the applied force at each
323 * node, since this will be cleared during the remeshing process. We then restore
324 * these attributes to the nodes after calling ReMesh().
325 */
326 for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
327 node_iter != this->mrMesh.GetNodeIteratorEnd();
328 ++node_iter)
329 {
330 unsigned node_index = node_iter->GetIndex();
331 old_node_applied_force_map[node_index] = node_iter->rGetAppliedForce();
332 }
333 }
334
335 NodeMap node_map(this->mrMesh.GetNumAllNodes());
336
337 // We must use a static_cast to call ReMesh() as this method is not defined in parent mesh classes
338 static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).ReMesh(node_map);
339
340 if (!node_map.IsIdentityMap())
341 {
342 UpdateGhostNodesAfterReMesh(node_map);
343
344 // Update the mappings between cells and location indices
345 std::map<Cell*, unsigned> old_cell_location_map = this->mCellLocationMap;
346
347 // Remove any dead pointers from the maps (needed to avoid archiving errors)
348 this->mLocationCellMap.clear();
349 this->mCellLocationMap.clear();
350
351 for (std::list<CellPtr>::iterator it = this->mCells.begin(); it != this->mCells.end(); ++it)
353 unsigned old_node_index = old_cell_location_map[(*it).get()];
354
355 // This shouldn't ever happen, as the cell vector only contains living cells
356 assert(!node_map.IsDeleted(old_node_index));
357
358 unsigned new_node_index = node_map.GetNewIndex(old_node_index);
359 this->SetCellUsingLocationIndex(new_node_index,*it);
360
361 if (old_node_radius_map[old_node_index] > 0.0)
362 {
363 this->GetNode(new_node_index)->SetRadius(old_node_radius_map[old_node_index]);
364 }
365 if (output_node_velocities)
366 {
367 this->GetNode(new_node_index)->AddAppliedForceContribution(old_node_applied_force_map[old_node_index]);
369 }
370
371 this->Validate();
372 }
373 else
374 {
375 if (old_node_radius_map[this->mCellLocationMap[(*(this->mCells.begin())).get()]] > 0.0)
376 {
377 for (std::list<CellPtr>::iterator it = this->mCells.begin(); it != this->mCells.end(); ++it)
378 {
379 unsigned node_index = this->mCellLocationMap[(*it).get()];
380 this->GetNode(node_index)->SetRadius(old_node_radius_map[node_index]);
381 }
382 }
383 if (output_node_velocities)
384 {
385 for (std::list<CellPtr>::iterator it = this->mCells.begin(); it != this->mCells.end(); ++it)
386 {
387 unsigned node_index = this->mCellLocationMap[(*it).get()];
388 this->GetNode(node_index)->AddAppliedForceContribution(old_node_applied_force_map[node_index]);
389 }
390 }
391 }
392
393 // Purge any marked springs that are no longer springs
394 std::vector<const std::pair<CellPtr,CellPtr>*> springs_to_remove;
395 for (std::set<std::pair<CellPtr,CellPtr> >::iterator spring_it = this->mMarkedSprings.begin();
396 spring_it != this->mMarkedSprings.end();
397 ++spring_it)
398 {
399 CellPtr p_cell_1 = spring_it->first;
400 CellPtr p_cell_2 = spring_it->second;
401 Node<SPACE_DIM>* p_node_1 = this->GetNodeCorrespondingToCell(p_cell_1);
402 Node<SPACE_DIM>* p_node_2 = this->GetNodeCorrespondingToCell(p_cell_2);
403
404 bool joined = false;
405
406 // For each element containing node1, if it also contains node2 then the cells are joined
407 std::set<unsigned> node2_elements = p_node_2->rGetContainingElementIndices();
408 for (typename Node<SPACE_DIM>::ContainingElementIterator elem_iter = p_node_1->ContainingElementsBegin();
409 elem_iter != p_node_1->ContainingElementsEnd();
410 ++elem_iter)
411 {
412 if (node2_elements.find(*elem_iter) != node2_elements.end())
413 {
414 joined = true;
415 break;
416 }
417 }
418
419 // If no longer joined, remove this spring from the set
420 if (!joined)
421 {
422 springs_to_remove.push_back(&(*spring_it));
423 }
424 }
425
426 // Remove any springs necessary
427 for (std::vector<const std::pair<CellPtr,CellPtr>* >::iterator spring_it = springs_to_remove.begin();
428 spring_it != springs_to_remove.end();
429 ++spring_it)
430 {
431 this->mMarkedSprings.erase(**spring_it);
433
434 // Tessellate if needed
435 TessellateIfNeeded();
436
438}
439
440template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
442{
443 if ((SPACE_DIM==2 || SPACE_DIM==3)&&(ELEMENT_DIM==SPACE_DIM))
444 {
445 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::TESSELLATION);
446 if (mUseAreaBasedDampingConstant ||
447 this-> template HasWriter<VoronoiDataWriter>() ||
448 this-> template HasWriter<CellPopulationAreaWriter>() ||
449 this-> template HasWriter<CellVolumesWriter>())
450 {
451 CreateVoronoiTessellation();
453 CellBasedEventHandler::EndEvent(CellBasedEventHandler::TESSELLATION);
454 }
455}
456
457template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
458void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::DivideLongSprings([[maybe_unused]] double springDivisionThreshold) // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
459{
460 // Only implemented for 2D elements
461 if constexpr (ELEMENT_DIM == 2)
462 {
463 std::vector<c_vector<unsigned, 5> > new_nodes;
464 new_nodes = rGetMesh().SplitLongEdges(springDivisionThreshold);
465
466 // Add new cells onto new nodes
467 for (unsigned index=0; index<new_nodes.size(); index++)
468 {
469 // Copy the cell attached to one of the neighbouring nodes onto the new node
470 unsigned new_node_index = new_nodes[index][0];
471 unsigned node_a_index = new_nodes[index][1];
472 unsigned node_b_index = new_nodes[index][2];
473
474 CellPtr p_neighbour_cell = this->GetCellUsingLocationIndex(node_a_index);
475
476 // Create copy of cell property collection to modify for daughter cell
477 CellPropertyCollection daughter_property_collection = p_neighbour_cell->rGetCellPropertyCollection();
478
479 // Remove the CellId from the daughter cell a new one will be assigned in the constructor
480 daughter_property_collection.RemoveProperty<CellId>();
482 CellPtr p_new_cell(new Cell(p_neighbour_cell->GetMutationState(),
483 p_neighbour_cell->GetCellCycleModel()->CreateCellCycleModel(),
484 p_neighbour_cell->GetSrnModel()->CreateSrnModel(),
485 false,
486 daughter_property_collection));
487
488 // Add new cell to cell population
489 this->mCells.push_back(p_new_cell);
490 this->AddCellUsingLocationIndex(new_node_index,p_new_cell);
491
492 // Update rest lengths
493
494 // Remove old node pair // note node_a_index < node_b_index
495 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(node_a_index, node_b_index);
496 double old_rest_length = mSpringRestLengths[node_pair];
497
498 std::map<std::pair<unsigned,unsigned>, double>::iterator iter = mSpringRestLengths.find(node_pair);
499 mSpringRestLengths.erase(iter);
500
501 // Add new pairs
502 node_pair = this->CreateOrderedPair(node_a_index, new_node_index);
503 mSpringRestLengths[node_pair] = 0.5*old_rest_length;
504
505 node_pair = this->CreateOrderedPair(node_b_index, new_node_index);
506 mSpringRestLengths[node_pair] = 0.5*old_rest_length;
507
508 // If necessary add other new spring rest lengths
509 for (unsigned pair_index=3; pair_index<5; pair_index++)
510 {
511 unsigned other_node_index = new_nodes[index][pair_index];
512
513 if (other_node_index != UNSIGNED_UNSET)
514 {
515 node_pair = this->CreateOrderedPair(other_node_index, new_node_index);
516 double new_rest_length = rGetMesh().GetDistanceBetweenNodes(new_node_index, other_node_index);
517 mSpringRestLengths[node_pair] = new_rest_length;
518 }
519 }
521 }
522 else
523 {
526}
527
528template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
531 return this->mrMesh.GetNode(index);
532}
533
534template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
536{
537 return this->mrMesh.GetNumAllNodes();
538}
539
540template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
543}
544
545template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
546CellPtr MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::AddCell(CellPtr pNewCell, CellPtr pParentCell)
547{
548 assert(pNewCell);
549 assert(pParentCell);
550
551 // Add new cell to population
552 CellPtr p_created_cell = AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::AddCell(pNewCell, pParentCell);
553 assert(p_created_cell == pNewCell);
554
555 // Mark spring between parent cell and new cell
556 std::pair<CellPtr,CellPtr> cell_pair = this->CreateCellPair(pParentCell, p_created_cell);
557 this->MarkSpring(cell_pair);
558
559 // Return pointer to new cell
560 return p_created_cell;
561}
562
564// Output methods //
566
567template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
569{
570 if (this->mOutputResultsForChasteVisualizer)
571 {
572 if (!this-> template HasWriter<CellPopulationElementWriter>())
573 {
574 this-> template AddPopulationWriter<CellPopulationElementWriter>();
576 }
577
579}
581template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
583{
584 if (SimulationTime::Instance()->GetTimeStepsElapsed() == 0 && this->mpVoronoiTessellation == nullptr)
585 {
586 TessellateIfNeeded(); // Update isn't run on time-step zero
587 }
590}
591
592template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
594{
595 pPopulationWriter->Visit(this);
596}
597
598template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
600{
601 pPopulationCountWriter->Visit(this);
602}
603
604template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
606{
607 pPopulationEventWriter->Visit(this);
608}
609
610template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
612{
613 pCellWriter->VisitCell(pCell, this);
614}
615
616template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
618{
619#ifdef CHASTE_VTK
620 // Store the present time as a string
621 unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
622 std::stringstream time;
623 time << num_timesteps;
624
625 // Store the number of cells for which to output data to VTK
626 unsigned num_cells_from_mesh = GetNumNodes();
627
628 // When outputting any CellData, we assume that the first cell is representative of all cells
629 unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
630 std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
631
632 std::vector<std::vector<double> > cell_data;
633 for (unsigned var=0; var<num_cell_data_items; var++)
634 {
635 std::vector<double> cell_data_var(num_cells_from_mesh);
636 cell_data.push_back(cell_data_var);
637 }
638
639 if (mWriteVtkAsPoints)
640 {
641 // Create mesh writer for VTK output
642 VtkMeshWriter<ELEMENT_DIM, SPACE_DIM> cells_writer(rDirectory, "mesh_results_"+time.str(), false);
643
644 // Iterate over any cell writers that are present
645 unsigned num_cells = this->GetNumAllCells();
646 for (typename std::vector<boost::shared_ptr<AbstractCellWriter<ELEMENT_DIM, SPACE_DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
647 cell_writer_iter != this->mCellWriters.end();
648 ++cell_writer_iter)
649 {
650 // Create vector to store VTK cell data
651 std::vector<double> vtk_cell_data(num_cells);
652
653 // Loop over cells
654 for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = this->Begin();
655 cell_iter != this->End();
656 ++cell_iter)
657 {
658 // Get the node index corresponding to this cell
659 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
660
661 // Populate the vector of VTK cell data
662 vtk_cell_data[node_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(*cell_iter, this);
663 }
664
665 cells_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
666 }
667
668 // Loop over cells
669 for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = this->Begin();
670 cell_iter != this->End();
671 ++cell_iter)
672 {
673 // Get the node index corresponding to this cell
674 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
675
676 for (unsigned var=0; var<num_cell_data_items; var++)
677 {
678 cell_data[var][node_index] = cell_iter->GetCellData()->GetItem(cell_data_names[var]);
679 }
680 }
681 for (unsigned var=0; var<num_cell_data_items; var++)
682 {
683 cells_writer.AddPointData(cell_data_names[var], cell_data[var]);
684 }
685
686 // Write data using the mesh
687 cells_writer.WriteFilesUsingMesh(rGetMesh());
688 *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
689 *(this->mpVtkMetaFile) << num_timesteps;
690 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"mesh_results_";
691 *(this->mpVtkMetaFile) << num_timesteps;
692 *(this->mpVtkMetaFile) << ".vtu\"/>\n";
693 }
694 if (mpVoronoiTessellation != nullptr)
695 {
696 // Create mesh writer for VTK output
697 VertexMeshWriter<ELEMENT_DIM, SPACE_DIM> mesh_writer(rDirectory, "voronoi_results", false);
698 std::vector<double> cell_volumes(num_cells_from_mesh);
699
700 // Iterate over any cell writers that are present
701 unsigned num_cells = this->GetNumAllCells();
702 for (typename std::vector<boost::shared_ptr<AbstractCellWriter<ELEMENT_DIM, SPACE_DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
703 cell_writer_iter != this->mCellWriters.end();
704 ++cell_writer_iter)
705 {
706 // Create vector to store VTK cell data
707 std::vector<double> vtk_cell_data(num_cells);
708
709 // Loop over elements of mpVoronoiTessellation
710 for (typename VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexElementIterator elem_iter = mpVoronoiTessellation->GetElementIteratorBegin();
711 elem_iter != mpVoronoiTessellation->GetElementIteratorEnd();
712 ++elem_iter)
713 {
714 // Get index of this element in mpVoronoiTessellation
715 unsigned elem_index = elem_iter->GetIndex();
716
717 // Get the cell corresponding to this element, via the index of the corresponding node in mrMesh
718 unsigned node_index = mpVoronoiTessellation->GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(elem_index);
719 CellPtr p_cell = this->GetCellUsingLocationIndex(node_index);
720
721 // Populate the vector of VTK cell data
722 vtk_cell_data[elem_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(p_cell, this);
723 }
724
725 mesh_writer.AddCellData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
726 }
727
728 // Loop over elements of mpVoronoiTessellation
729 for (typename VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexElementIterator elem_iter = mpVoronoiTessellation->GetElementIteratorBegin();
730 elem_iter != mpVoronoiTessellation->GetElementIteratorEnd();
731 ++elem_iter)
732 {
733 // Get index of this element in mpVoronoiTessellation
734 unsigned elem_index = elem_iter->GetIndex();
735
736 // Get the cell corresponding to this element, via the index of the corresponding node in mrMesh
737 unsigned node_index = mpVoronoiTessellation->GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(elem_index);
738 CellPtr p_cell = this->GetCellUsingLocationIndex(node_index);
739
740 for (unsigned var=0; var<num_cell_data_items; var++)
741 {
742 cell_data[var][elem_index] = p_cell->GetCellData()->GetItem(cell_data_names[var]);
743 }
744 }
745
746 for (unsigned var=0; var<cell_data.size(); var++)
747 {
748 mesh_writer.AddCellData(cell_data_names[var], cell_data[var]);
749 }
750
751 mesh_writer.WriteVtkUsingMesh(*mpVoronoiTessellation, time.str());
752 *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
753 *(this->mpVtkMetaFile) << num_timesteps;
754 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"voronoi_results_";
755 *(this->mpVtkMetaFile) << num_timesteps;
756 *(this->mpVtkMetaFile) << ".vtu\"/>\n";
757 }
758#endif //CHASTE_VTK
759}
760
761template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
763{
764 double cell_volume = 0;
765
766 if (ELEMENT_DIM == SPACE_DIM)
767 {
768 // Ensure that the Voronoi tessellation exists
769 if (mpVoronoiTessellation == nullptr)
770 {
771 CreateVoronoiTessellation();
772 }
773
774 // Get the node index corresponding to this cell
775 unsigned node_index = this->GetLocationIndexUsingCell(pCell);
776
777 // Try to get the element index of the Voronoi tessellation corresponding to this node index
778 try
779 {
780 unsigned element_index = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(node_index);
781
782 // Get the cell's volume from the Voronoi tessellation
783 cell_volume = mpVoronoiTessellation->GetVolumeOfElement(element_index);
784 }
785 catch (Exception&)
786 {
787 // If it doesn't exist this must be a boundary cell, so return infinite volume
788 cell_volume = DBL_MAX;
789 }
790 }
791 else if (SPACE_DIM==3 && ELEMENT_DIM==2)
792 {
793 unsigned node_index = this->GetLocationIndexUsingCell(pCell);
794
795 Node<SPACE_DIM>* p_node = rGetMesh().GetNode(node_index);
796
797 assert(!(p_node->rGetContainingElementIndices().empty()));
798
800 elem_iter != p_node->ContainingElementsEnd();
801 ++elem_iter)
802 {
803 Element<ELEMENT_DIM,SPACE_DIM>* p_element = rGetMesh().GetElement(*elem_iter);
804
805 c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacob;
806 double det;
807
808 p_element->CalculateJacobian(jacob, det);
809
810 cell_volume += fabs(p_element->GetVolume(det));
811 }
812
813 // This calculation adds a third of each element to the total area
814 cell_volume /= 3.0;
815 }
816 else
817 {
818 // Not implemented for other dimensions
820 }
821
822 return cell_volume;
823}
824
825template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
827{
828 mWriteVtkAsPoints = writeVtkAsPoints;
829}
830
831template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
833{
834 return mWriteVtkAsPoints;
835}
836
837template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
839{
840 mBoundVoronoiTessellation = boundVoronoiTessellation;
841}
842
843template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
845{
846 return mBoundVoronoiTessellation;
847}
848
849template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
851{
852 if (bool(dynamic_cast<Cylindrical2dMesh*>(&(this->mrMesh))))
853 {
854 *pVizSetupFile << "MeshWidth\t" << this->GetWidth(0) << "\n";
855 }
856 if (bool(dynamic_cast<Toroidal2dMesh*>(&(this->mrMesh))))
857 {
858 *pVizSetupFile << "MeshWidth\t" << this->GetWidth(0) << "\n";
859 *pVizSetupFile << "MeshHeight\t" << this->GetWidth(1) << "\n";
860 }
861}
862
863template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
865{
866 if constexpr (ELEMENT_DIM == 1)
867 {
868 // The VoronoiTessellation class is only defined in 2D or 3D
870 }
871 else if constexpr (ELEMENT_DIM == 2 && SPACE_DIM == 2)
872 {
873 delete mpVoronoiTessellation;
874
875 // Check if the mesh associated with this cell population is periodic
876 bool is_mesh_periodic = false;
877 if (dynamic_cast<Cylindrical2dMesh*>(&(this->mrMesh)))
878 {
879 is_mesh_periodic = true;
880 mpVoronoiTessellation = new Cylindrical2dVertexMesh(static_cast<Cylindrical2dMesh&>(this->mrMesh), mBoundVoronoiTessellation);
881 }
882 else if (dynamic_cast<Toroidal2dMesh*>(&(this->mrMesh)))
883 {
884 is_mesh_periodic = true;
885 mpVoronoiTessellation = new Toroidal2dVertexMesh(static_cast<Toroidal2dMesh&>(this->mrMesh), mBoundVoronoiTessellation);
886 }
887 else
888 {
889 mpVoronoiTessellation = new VertexMesh<2, 2>(static_cast<MutableMesh<2, 2>&>((this->mrMesh)), is_mesh_periodic, mBoundVoronoiTessellation);
890 }
891 }
892 else if constexpr (ELEMENT_DIM == 3)
893 {
894 // The cylindrical mesh is only defined in 2D, hence there is
895 // a separate definition for this method in 3D, which doesn't have the capability
896 // of dealing with periodic boundaries in 3D. This is \todo #1374.
897 delete mpVoronoiTessellation;
898 mpVoronoiTessellation = new VertexMesh<3, 3>(static_cast<MutableMesh<3, 3>&>(this->mrMesh));
899 }
900 else // ELEMENT_DIM == 2 && SPACE_DIM != 2
901 {
903 }
904}
905
907// Spring iterator class //
909
910template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
915
916template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
921
922template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
924{
925 assert((*this) != mrCellPopulation.SpringsEnd());
926 return mrCellPopulation.GetCellUsingLocationIndex(mEdgeIter.GetNodeA()->GetIndex());
927}
928
929template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
931{
932 assert((*this) != mrCellPopulation.SpringsEnd());
933 return mrCellPopulation.GetCellUsingLocationIndex(mEdgeIter.GetNodeB()->GetIndex());
934}
935
936template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
941
942template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
944{
945 bool edge_is_ghost = false;
946
947 do
948 {
949 ++mEdgeIter;
950 if (*this != mrCellPopulation.SpringsEnd())
951 {
952 bool a_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeA()->GetIndex());
953 bool b_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeB()->GetIndex());
954
955 edge_is_ghost = (a_is_ghost || b_is_ghost);
956 }
957 }
958 while (*this!=mrCellPopulation.SpringsEnd() && edge_is_ghost);
959
960 return (*this);
961}
962
963template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
967 : mrCellPopulation(rCellPopulation),
968 mEdgeIter(edgeIter)
969{
970 if (mEdgeIter!=static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation.mrMesh))->EdgesEnd())
971 {
972 bool a_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeA()->GetIndex());
973 bool b_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeB()->GetIndex());
974
975 if (a_is_ghost || b_is_ghost)
976 {
977 ++(*this);
978 }
979 }
980}
981
982template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
987
988template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
993
994template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1000
1001template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1003{
1004 unsigned element_index = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index);
1005 double volume = mpVoronoiTessellation->GetVolumeOfElement(element_index);
1006 return volume;
1007}
1008
1009template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1011{
1012 unsigned element_index = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index);
1013 double surface_area = mpVoronoiTessellation->GetSurfaceAreaOfElement(element_index);
1014 return surface_area;
1015}
1016
1017template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1019{
1020 unsigned element_index1 = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index1);
1021 unsigned element_index2 = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index2);
1022 try
1023 {
1024 double edge_length = mpVoronoiTessellation->GetEdgeLength(element_index1, element_index2);
1025 return edge_length;
1026 }
1027 catch (Exception&)
1028 {
1029 // The edge was between two (potentially infinite) cells on the boundary of the mesh
1030 EXCEPTION("Spring iterator tried to calculate interaction between degenerate cells on the boundary of the mesh. Have you set ghost layers correctly?");
1031 }
1032}
1033
1034template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1036{
1037 bool res = true;
1038 for (std::list<CellPtr>::iterator it=this->mCells.begin();
1039 it!=this->mCells.end();
1040 ++it)
1041 {
1042 CellPtr p_cell = *it;
1043 assert(p_cell);
1044 AbstractCellCycleModel* p_model = p_cell->GetCellCycleModel();
1045 assert(p_model);
1046
1047 // Check cell exists in cell population
1048 unsigned node_index = this->GetLocationIndexUsingCell(p_cell);
1049 std::cout << "Cell at node " << node_index << " addr " << p_cell << std::endl << std::flush;
1050 CellPtr p_cell_in_cell_population = this->GetCellUsingLocationIndex(node_index);
1051// LCOV_EXCL_START //Debugging code. Shouldn't fail under normal conditions
1052 if (p_cell_in_cell_population != p_cell)
1053 {
1054 std::cout << " Mismatch with cell population" << std::endl << std::flush;
1055 res = false;
1056 }
1057
1058 // Check model links back to cell
1059 if (p_model->GetCell() != p_cell)
1060 {
1061 std::cout << " Mismatch with cycle model" << std::endl << std::flush;
1062 res = false;
1063 }
1064 }
1065 UNUSED_OPT(res);
1066 assert(res);
1067// LCOV_EXCL_STOP
1068
1069 res = true;
1070 for (std::set<std::pair<CellPtr,CellPtr> >::iterator it1 = this->mMarkedSprings.begin();
1071 it1 != this->mMarkedSprings.end();
1072 ++it1)
1073 {
1074 const std::pair<CellPtr,CellPtr>& r_pair = *it1;
1075
1076 for (unsigned i=0; i<2; i++)
1077 {
1078 CellPtr p_cell = (i==0 ? r_pair.first : r_pair.second);
1079
1080 assert(p_cell);
1081 AbstractCellCycleModel* p_model = p_cell->GetCellCycleModel();
1082 assert(p_model);
1083 unsigned node_index = this->GetLocationIndexUsingCell(p_cell);
1084 std::cout << "Cell at node " << node_index << " addr " << p_cell << std::endl << std::flush;
1085
1086// LCOV_EXCL_START //Debugging code. Shouldn't fail under normal conditions
1087 // Check cell is alive
1088 if (p_cell->IsDead())
1089 {
1090 std::cout << " Cell is dead" << std::endl << std::flush;
1091 res = false;
1092 }
1093
1094 // Check cell exists in cell population
1095 CellPtr p_cell_in_cell_population = this->GetCellUsingLocationIndex(node_index);
1096 if (p_cell_in_cell_population != p_cell)
1097 {
1098 std::cout << " Mismatch with cell population" << std::endl << std::flush;
1099 res = false;
1100 }
1101
1102 // Check model links back to cell
1103 if (p_model->GetCell() != p_cell)
1104 {
1105 std::cout << " Mismatch with cycle model" << std::endl << std::flush;
1106 res = false;
1107 }
1108 }
1109// LCOV_EXCL_STOP
1110 }
1111 assert(res);
1112}
1113
1114template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1119
1120template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1122{
1123 assert(areaBasedDampingConstantParameter >= 0.0);
1124 mAreaBasedDampingConstantParameter = areaBasedDampingConstantParameter;
1125}
1126
1127// LCOV_EXCL_START
1128template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1130{
1131 //mNodePairs.Clear();
1133 return mNodePairs;
1134}
1135// LCOV_EXCL_STOP
1136
1137template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1139{
1140 *rParamsFile << "\t\t<UseAreaBasedDampingConstant>" << mUseAreaBasedDampingConstant << "</UseAreaBasedDampingConstant>\n";
1141 *rParamsFile << "\t\t<AreaBasedDampingConstantParameter>" << mAreaBasedDampingConstantParameter << "</AreaBasedDampingConstantParameter>\n";
1142 *rParamsFile << "\t\t<WriteVtkAsPoints>" << mWriteVtkAsPoints << "</WriteVtkAsPoints>\n";
1143 *rParamsFile << "\t\t<BoundVoronoiTessellation>" << mBoundVoronoiTessellation << "</BoundVoronoiTessellation>\n";
1144 *rParamsFile << "\t\t<HasVariableRestLength>" << mHasVariableRestLength << "</HasVariableRestLength>\n";
1145
1146 // Call method on direct parent class
1148}
1149
1150template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1152{
1153 // Call GetWidth() on the mesh
1154 double width = this->mrMesh.GetWidth(rDimension);
1155 return width;
1156}
1157
1158template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1160{
1161 // Get pointer to this node
1162 Node<SPACE_DIM>* p_node = this->mrMesh.GetNode(index);
1163
1164 // Loop over containing elements
1165 std::set<unsigned> neighbouring_node_indices;
1166 for (typename Node<SPACE_DIM>::ContainingElementIterator elem_iter = p_node->ContainingElementsBegin();
1167 elem_iter != p_node->ContainingElementsEnd();
1168 ++elem_iter)
1169 {
1170 // Get pointer to this containing element
1171 Element<ELEMENT_DIM,SPACE_DIM>* p_element = static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).GetElement(*elem_iter);
1172
1173 // Loop over nodes contained in this element
1174 for (unsigned i=0; i<p_element->GetNumNodes(); i++)
1175 {
1176 // Get index of this node and add its index to the set if not the original node
1177 unsigned node_index = p_element->GetNodeGlobalIndex(i);
1178 if (node_index != index)
1179 {
1180 neighbouring_node_indices.insert(node_index);
1181 }
1182 }
1183 }
1184 return neighbouring_node_indices;
1185}
1186
1187template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1189{
1190 mSpringRestLengths.clear();
1191
1192 // Iterate over all springs and add calculate separation of adjacent node pairs
1193 for (SpringIterator spring_iterator = SpringsBegin();
1194 spring_iterator != SpringsEnd();
1195 ++spring_iterator)
1196 {
1197 // Note that nodeA_global_index is always less than nodeB_global_index
1198 Node<SPACE_DIM>* p_nodeA = spring_iterator.GetNodeA();
1199 Node<SPACE_DIM>* p_nodeB = spring_iterator.GetNodeB();
1200
1201 unsigned nodeA_global_index = p_nodeA->GetIndex();
1202 unsigned nodeB_global_index = p_nodeB->GetIndex();
1203
1204 // Calculate the distance between nodes
1205 double separation = rGetMesh().GetDistanceBetweenNodes(nodeA_global_index, nodeB_global_index);
1206
1207 // Order node indices
1208 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(nodeA_global_index, nodeB_global_index);
1209
1210 mSpringRestLengths[node_pair] = separation;
1211 }
1213}
1214
1215template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1217{
1219 {
1220 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(indexA, indexB);
1221 std::map<std::pair<unsigned,unsigned>, double>::const_iterator iter = mSpringRestLengths.find(node_pair);
1222
1223 if (iter != mSpringRestLengths.end())
1224 {
1225 // Return the stored rest length
1226 return iter->second;
1227 }
1228 else
1229 {
1230 EXCEPTION("Tried to get a rest length of an edge that doesn't exist. You can only use variable rest lengths if SetUpdateCellPopulationRule is set on the simulation.");
1231 }
1232 }
1233 else
1234 {
1235 return 1.0;
1236 }
1237}
1238
1239template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1240void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SetRestLength(unsigned indexA, unsigned indexB, double restLength)
1241{
1243 {
1244 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(indexA, indexB);
1245 std::map<std::pair<unsigned,unsigned>, double>::iterator iter = mSpringRestLengths.find(node_pair);
1246
1247 if (iter != mSpringRestLengths.end())
1248 {
1249 // modify the stored rest length
1250 iter->second = restLength;
1251 }
1252 else
1253 {
1254 EXCEPTION("Tried to set the rest length of an edge not in the mesh.");
1255 }
1256 }
1257 else
1258 {
1259 EXCEPTION("Tried to set a rest length in a simulation with fixed rest length. You can only use variable rest lengths if SetUpdateCellPopulationRule is set on the simulation.");
1260 }
1261}
1262
1263// Explicit instantiation
1264template class MeshBasedCellPopulation<1,1>;
1265template class MeshBasedCellPopulation<1,2>;
1266template class MeshBasedCellPopulation<2,2>;
1267template class MeshBasedCellPopulation<1,3>;
1268template class MeshBasedCellPopulation<2,3>;
1269template class MeshBasedCellPopulation<3,3>;
1270
1271// Serialization for Boost >= 1.36
#define EXCEPTION(message)
#define UNUSED_OPT(var)
#define NEVER_REACHED
const unsigned UNSIGNED_UNSET
Definition Exception.hpp:53
#define EXPORT_TEMPLATE_CLASS_ALL_DIMS(CLASS)
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
AbstractMesh< ELEMENT_DIM, SPACE_DIM > & mrMesh
unsigned GetLocationIndexUsingCell(CellPtr pCell)
virtual void WriteResultsToFiles(const std::string &rDirectory)
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
std::pair< unsigned, unsigned > CreateOrderedPair(unsigned index1, unsigned index2)
std::set< std::pair< CellPtr, CellPtr > > mMarkedSprings
virtual void OutputCellPopulationParameters(out_stream &rParamsFile)
virtual double GetDampingConstant(unsigned nodeIndex)
CellPtr AddCell(CellPtr pNewCell, CellPtr pParentCell=CellPtr())
unsigned GetNumNodes() const
unsigned GetNodeGlobalIndex(unsigned localIndex) const
void SetMeshHasChangedSinceLoading()
double GetVolume(double determinant) const
void CalculateJacobian(c_matrix< double, SPACE_DIM, ELEMENT_DIM > &rJacobian, double &rJacobianDeterminant)
Element< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
Definition Cell.hpp:92
MutableMesh< ELEMENT_DIM, SPACE_DIM >::EdgeIterator mEdgeIter
MeshBasedCellPopulation< ELEMENT_DIM, SPACE_DIM > & mrCellPopulation
bool operator!=(const typename MeshBasedCellPopulation< ELEMENT_DIM, SPACE_DIM >::SpringIterator &rOther)
SpringIterator(MeshBasedCellPopulation< ELEMENT_DIM, SPACE_DIM > &rCellPopulation, typename MutableMesh< ELEMENT_DIM, SPACE_DIM >::EdgeIterator edgeIter)
virtual void OpenWritersFiles(OutputFileHandler &rOutputFileHandler)
std::vector< std::pair< Node< SPACE_DIM > *, Node< SPACE_DIM > * > > mNodePairs
std::vector< std::pair< Node< SPACE_DIM > *, Node< SPACE_DIM > * > > & rGetNodePairs()
std::map< std::pair< unsigned, unsigned >, double > mSpringRestLengths
void OutputCellPopulationParameters(out_stream &rParamsFile)
virtual void WriteResultsToFiles(const std::string &rDirectory)
virtual void Update(bool hasHadBirthsOrDeaths=true)
double GetVoronoiEdgeLength(unsigned index1, unsigned index2)
virtual void AcceptPopulationWriter(boost::shared_ptr< AbstractCellPopulationWriter< ELEMENT_DIM, SPACE_DIM > > pPopulationWriter)
double GetDampingConstant(unsigned nodeIndex)
virtual void AcceptCellWriter(boost::shared_ptr< AbstractCellWriter< ELEMENT_DIM, SPACE_DIM > > pCellWriter, CellPtr pCell)
void SetWriteVtkAsPoints(bool writeVtkAsPoints)
double GetWidth(const unsigned &rDimension)
MeshBasedCellPopulation(MutableMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, std::vector< CellPtr > &rCells, const std::vector< unsigned > locationIndices={}, bool deleteMesh=false, bool validate=true)
void SetNode(unsigned nodeIndex, ChastePoint< SPACE_DIM > &rNewLocation)
virtual void AcceptPopulationEventWriter(boost::shared_ptr< AbstractCellPopulationEventWriter< ELEMENT_DIM, SPACE_DIM > > pPopulationEventWriter)
void SetAreaBasedDampingConstant(bool useAreaBasedDampingConstant)
virtual void WriteVtkResultsToFile(const std::string &rDirectory)
virtual TetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * GetTetrahedralMeshForPdeModifier()
VertexMesh< ELEMENT_DIM, SPACE_DIM > * mpVoronoiTessellation
virtual CellPtr AddCell(CellPtr pNewCell, CellPtr pParentCell)
unsigned AddNode(Node< SPACE_DIM > *pNewNode)
double GetSurfaceAreaOfVoronoiElement(unsigned index)
std::set< unsigned > GetNeighbouringNodeIndices(unsigned index)
Node< SPACE_DIM > * GetNode(unsigned index)
virtual void UpdateGhostNodesAfterReMesh(NodeMap &rMap)
void SetBoundVoronoiTessellation(bool boundVoronoiTessellation)
virtual void AcceptPopulationCountWriter(boost::shared_ptr< AbstractCellPopulationCountWriter< ELEMENT_DIM, SPACE_DIM > > pPopulationCountWriter)
double GetVolumeOfVoronoiElement(unsigned index)
void SetRestLength(unsigned indexA, unsigned indexB, double restLength)
virtual void WriteDataToVisualizerSetupFile(out_stream &pVizSetupFile)
VertexMesh< ELEMENT_DIM, SPACE_DIM > * GetVoronoiTessellation()
MutableMesh< ELEMENT_DIM, SPACE_DIM > * mpMutableMesh
void SetAreaBasedDampingConstantParameter(double areaBasedDampingConstantParameter)
void DivideLongSprings(double springDivisionThreshold)
double GetRestLength(unsigned indexA, unsigned indexB)
double GetVolumeOfCell(CellPtr pCell)
MutableMesh< ELEMENT_DIM, SPACE_DIM > & rGetMesh()
virtual void ReMesh(NodeMap &map)
void DeleteNodePriorToReMesh(unsigned index)
virtual void SetNode(unsigned index, ChastePoint< SPACE_DIM > point, bool concreteMove=true)
Definition Node.hpp:59
ContainingElementIterator ContainingElementsEnd() const
Definition Node.hpp:493
std::set< unsigned > & rGetContainingElementIndices()
Definition Node.cpp:300
ContainingElementIterator ContainingElementsBegin() const
Definition Node.hpp:485
unsigned GetIndex() const
Definition Node.cpp:158
static SimulationTime * Instance()
unsigned GetTimeStepsElapsed() const
EdgeIterator EdgesEnd()
void WriteVtkUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, std::string stamp="")
void AddCellData(std::string dataName, std::vector< double > dataPayload)
void AddPointData(std::string name, std::vector< double > data)
void WriteFilesUsingMesh(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, bool keepOriginalElementIndexing=true)