Chaste Commit::675f9facbe008c5eacb9006feaeb6423206579ea
MeshBasedCellPopulation.cpp
1/*
2
3Copyright (c) 2005-2025, 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 mScaleBoundByEdgeLength(false),
65 mBoundedVoroniTesselationLengthCutoff(DBL_MAX),
66 mOffsetNewBoundaryNodes(false),
67 mHasVariableRestLength(false)
68{
70
71 assert(this->mCells.size() <= this->mrMesh.GetNumNodes());
72
73 if (validate)
74 {
75 Validate();
76 }
77
79
80 // Initialise the applied force at each node to zero
81 for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->rGetMesh().GetNodeIteratorBegin();
82 node_iter != this->rGetMesh().GetNodeIteratorEnd();
83 ++node_iter)
84 {
85 node_iter->ClearAppliedForce();
86 }
87}
88
89template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
98
99template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
101{
102 delete mpVoronoiTessellation;
103
104 if (mDeleteMesh)
105 {
106 delete &this->mrMesh;
107 }
108}
109
110template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
112{
113 return mUseAreaBasedDampingConstant;
114}
115
116template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
118 [[maybe_unused]] bool useAreaBasedDampingConstant) // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
119{
120 if constexpr (SPACE_DIM == 2)
121 {
122 mUseAreaBasedDampingConstant = useAreaBasedDampingConstant;
123 }
124 else
125 {
127 }
128}
129
130template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
132{
133 return mpMutableMesh->AddNode(pNewNode);
134}
135
136template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
138{
139 static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).SetNode(nodeIndex, rNewLocation, false);
140}
141
142template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
144{
146
147 /*
148 * The next code block computes the area-dependent damping constant as given by equation
149 * (5) in the following reference: van Leeuwen et al. 2009. An integrative computational model
150 * for intestinal tissue renewal. Cell Prolif. 42(5):617-636. doi:10.1111/j.1365-2184.2009.00627.x
151 */
152 if (mUseAreaBasedDampingConstant)
153 {
162 if constexpr (SPACE_DIM == 2)
164 double rest_length = 1.0;
165 double d0 = mAreaBasedDampingConstantParameter;
166
172 double d1 = 2.0*(1.0 - d0)/(sqrt(3.0)*rest_length*rest_length);
173
174 double area_cell = GetVolumeOfVoronoiElement(nodeIndex);
175
181 assert(area_cell < 1000);
182
183 damping_multiplier = d0 + area_cell*d1;
184 }
185 else
186 {
188 }
189 }
191 return damping_multiplier;
192}
193
194template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
196{
197 std::vector<bool> validated_node = std::vector<bool>(this->GetNumNodes(), false);
198
199 for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter=this->Begin(); cell_iter!=this->End(); ++cell_iter)
200 {
201 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
202 validated_node[node_index] = true;
203 }
204
205 for (unsigned i=0; i<validated_node.size(); i++)
207 if (!validated_node[i])
208 {
209 EXCEPTION("At time " << SimulationTime::Instance()->GetTime() << ", Node " << i << " does not appear to have a cell associated with it");
210 }
212}
213
214template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
217 return *mpMutableMesh;
218}
219
220template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
226template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
229 return mpMutableMesh;
230}
231
232template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
234{
235 unsigned num_removed = 0;
236 for (std::list<CellPtr>::iterator it = this->mCells.begin();
237 it != this->mCells.end();
239 {
240 if ((*it)->IsDead())
241 {
242 // Check if this cell is in a marked spring
243 std::vector<const std::pair<CellPtr,CellPtr>*> pairs_to_remove; // Pairs that must be purged
244 for (std::set<std::pair<CellPtr,CellPtr> >::iterator it1 = this->mMarkedSprings.begin();
245 it1 != this->mMarkedSprings.end();
246 ++it1)
247 {
248 const std::pair<CellPtr,CellPtr>& r_pair = *it1;
249
250 for (unsigned i=0; i<2; i++)
251 {
252 CellPtr p_cell = (i==0 ? r_pair.first : r_pair.second);
253
254 if (p_cell == *it)
255 {
256 // Remember to purge this spring
257 pairs_to_remove.push_back(&r_pair);
258 break;
259 }
260 }
261 }
262
263 // Purge any marked springs that contained this cell
264 for (std::vector<const std::pair<CellPtr,CellPtr>* >::iterator pair_it = pairs_to_remove.begin();
265 pair_it != pairs_to_remove.end();
266 ++pair_it)
267 {
268 this->mMarkedSprings.erase(**pair_it);
269 }
270
271 // Remove the node from the mesh
272 num_removed++;
273 static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).DeleteNodePriorToReMesh(this->GetLocationIndexUsingCell((*it)));
274
275 // Update mappings between cells and location indices
276 unsigned location_index_of_removed_node = this->GetLocationIndexUsingCell((*it));
277 this->RemoveCellUsingLocationIndex(location_index_of_removed_node, (*it));
278
279 // Update vector of cells
280 it = this->mCells.erase(it);
281 }
282 else
283 {
284 ++it;
285 }
286 }
288 return num_removed;
289}
290
291template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
293{
294 this->mNodePairs.clear();
295 for (SpringIterator spring_it = SpringsBegin(); spring_it != SpringsEnd(); ++spring_it)
296 {
297 this->mNodePairs.emplace_back(spring_it.GetNodeA(), spring_it.GetNodeB());
298 }
299}
301template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
303{
305 bool output_node_velocities = (this-> template HasWriter<NodeVelocityWriter>());
306
317 std::map<unsigned, double> old_node_radius_map;
318 old_node_radius_map.clear();
319 if (this->mrMesh.GetNodeIteratorBegin()->HasNodeAttributes())
320 {
321 if (this->mrMesh.GetNodeIteratorBegin()->GetRadius() > 0.0)
322 {
323 for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
324 node_iter != this->mrMesh.GetNodeIteratorEnd();
325 ++node_iter)
326 {
327 unsigned node_index = node_iter->GetIndex();
328 old_node_radius_map[node_index] = node_iter->GetRadius();
329 }
330 }
332
333 std::map<unsigned, c_vector<double, SPACE_DIM> > old_node_applied_force_map;
334 old_node_applied_force_map.clear();
335 if (output_node_velocities)
336 {
337 /*
338 * If outputting node velocities, we must keep a record of the applied force at each
339 * node, since this will be cleared during the remeshing process. We then restore
340 * these attributes to the nodes after calling ReMesh().
341 */
342 for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = this->mrMesh.GetNodeIteratorBegin();
343 node_iter != this->mrMesh.GetNodeIteratorEnd();
344 ++node_iter)
345 {
346 unsigned node_index = node_iter->GetIndex();
347 old_node_applied_force_map[node_index] = node_iter->rGetAppliedForce();
348 }
350
351 NodeMap node_map(this->mrMesh.GetNumAllNodes());
352
353 // We must use a static_cast to call ReMesh() as this method is not defined in parent mesh classes
354 static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).ReMesh(node_map);
355
356 if (!node_map.IsIdentityMap())
358 UpdateGhostNodesAfterReMesh(node_map);
359
360 // Update the mappings between cells and location indices
361 std::map<Cell*, unsigned> old_cell_location_map = this->mCellLocationMap;
362
363 // Remove any dead pointers from the maps (needed to avoid archiving errors)
364 this->mLocationCellMap.clear();
365 this->mCellLocationMap.clear();
366
367 for (std::list<CellPtr>::iterator it = this->mCells.begin(); it != this->mCells.end(); ++it)
368 {
369 unsigned old_node_index = old_cell_location_map[(*it).get()];
370
371 // This shouldn't ever happen, as the cell vector only contains living cells
372 assert(!node_map.IsDeleted(old_node_index));
374 unsigned new_node_index = node_map.GetNewIndex(old_node_index);
375 this->SetCellUsingLocationIndex(new_node_index,*it);
376
377 if (old_node_radius_map[old_node_index] > 0.0)
378 {
379 this->GetNode(new_node_index)->SetRadius(old_node_radius_map[old_node_index]);
381 if (output_node_velocities)
382 {
383 this->GetNode(new_node_index)->AddAppliedForceContribution(old_node_applied_force_map[old_node_index]);
384 }
385 }
386
387 this->Validate();
388 }
389 else
390 {
391 if (old_node_radius_map[this->mCellLocationMap[(*(this->mCells.begin())).get()]] > 0.0)
392 {
393 for (std::list<CellPtr>::iterator it = this->mCells.begin(); it != this->mCells.end(); ++it)
394 {
395 unsigned node_index = this->mCellLocationMap[(*it).get()];
396 this->GetNode(node_index)->SetRadius(old_node_radius_map[node_index]);
397 }
398 }
399 if (output_node_velocities)
401 for (std::list<CellPtr>::iterator it = this->mCells.begin(); it != this->mCells.end(); ++it)
402 {
403 unsigned node_index = this->mCellLocationMap[(*it).get()];
404 this->GetNode(node_index)->AddAppliedForceContribution(old_node_applied_force_map[node_index]);
406 }
407 }
408
409 // Purge any marked springs that are no longer springs
410 std::vector<const std::pair<CellPtr,CellPtr>*> springs_to_remove;
411 for (std::set<std::pair<CellPtr,CellPtr> >::iterator spring_it = this->mMarkedSprings.begin();
412 spring_it != this->mMarkedSprings.end();
413 ++spring_it)
414 {
415 CellPtr p_cell_1 = spring_it->first;
416 CellPtr p_cell_2 = spring_it->second;
417 Node<SPACE_DIM>* p_node_1 = this->GetNodeCorrespondingToCell(p_cell_1);
418 Node<SPACE_DIM>* p_node_2 = this->GetNodeCorrespondingToCell(p_cell_2);
420 bool joined = false;
421
422 // For each element containing node1, if it also contains node2 then the cells are joined
423 std::set<unsigned> node2_elements = p_node_2->rGetContainingElementIndices();
424 for (typename Node<SPACE_DIM>::ContainingElementIterator elem_iter = p_node_1->ContainingElementsBegin();
425 elem_iter != p_node_1->ContainingElementsEnd();
426 ++elem_iter)
427 {
428 if (node2_elements.find(*elem_iter) != node2_elements.end())
429 {
430 joined = true;
431 break;
432 }
433 }
434
435 // If no longer joined, remove this spring from the set
436 if (!joined)
437 {
438 springs_to_remove.push_back(&(*spring_it));
439 }
440 }
441
442 // Remove any springs necessary
443 for (std::vector<const std::pair<CellPtr,CellPtr>* >::iterator spring_it = springs_to_remove.begin();
444 spring_it != springs_to_remove.end();
445 ++spring_it)
446 {
447 this->mMarkedSprings.erase(**spring_it);
448 }
449
450 // Update node pairs. Note, this must happen after remeshing.
451 UpdateNodePairs();
452
453 // Tessellate if needed
454 TessellateIfNeeded();
457}
458
459template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
461{
462 if ((SPACE_DIM==2 || SPACE_DIM==3)&&(ELEMENT_DIM==SPACE_DIM))
463 {
464 CellBasedEventHandler::BeginEvent(CellBasedEventHandler::TESSELLATION);
465 if (mUseAreaBasedDampingConstant ||
466 this-> template HasWriter<VoronoiDataWriter>() ||
467 this-> template HasWriter<CellPopulationAreaWriter>() ||
468 this-> template HasWriter<CellVolumesWriter>())
469 {
470 CreateVoronoiTessellation();
471 }
472 CellBasedEventHandler::EndEvent(CellBasedEventHandler::TESSELLATION);
473 }
474}
475
476template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
477void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::DivideLongSprings([[maybe_unused]] double springDivisionThreshold) // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
479 // Only implemented for 2D elements
480 if constexpr (ELEMENT_DIM == 2)
481 {
482 std::vector<c_vector<unsigned, 5> > new_nodes;
483 new_nodes = rGetMesh().SplitLongEdges(springDivisionThreshold);
484
485 // Add new cells onto new nodes
486 for (unsigned index=0; index<new_nodes.size(); index++)
487 {
488 // Copy the cell attached to one of the neighbouring nodes onto the new node
489 unsigned new_node_index = new_nodes[index][0];
490 unsigned node_a_index = new_nodes[index][1];
491 unsigned node_b_index = new_nodes[index][2];
492
493 CellPtr p_neighbour_cell = this->GetCellUsingLocationIndex(node_a_index);
494
495 // Create copy of cell property collection to modify for daughter cell
496 CellPropertyCollection daughter_property_collection = p_neighbour_cell->rGetCellPropertyCollection();
497
498 // Remove the CellId from the daughter cell a new one will be assigned in the constructor
499 daughter_property_collection.RemoveProperty<CellId>();
500
501 CellPtr p_new_cell(new Cell(p_neighbour_cell->GetMutationState(),
502 p_neighbour_cell->GetCellCycleModel()->CreateCellCycleModel(),
503 p_neighbour_cell->GetSrnModel()->CreateSrnModel(),
504 false,
505 daughter_property_collection));
506
507 // Add new cell to cell population
508 this->mCells.push_back(p_new_cell);
509 this->AddCellUsingLocationIndex(new_node_index,p_new_cell);
510
511 // Update rest lengths
512
513 // Remove old node pair // note node_a_index < node_b_index
514 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(node_a_index, node_b_index);
515 double old_rest_length = mSpringRestLengths[node_pair];
516
517 std::map<std::pair<unsigned,unsigned>, double>::iterator iter = mSpringRestLengths.find(node_pair);
518 mSpringRestLengths.erase(iter);
519
520 // Add new pairs
521 node_pair = this->CreateOrderedPair(node_a_index, new_node_index);
522 mSpringRestLengths[node_pair] = 0.5*old_rest_length;
523
524 node_pair = this->CreateOrderedPair(node_b_index, new_node_index);
525 mSpringRestLengths[node_pair] = 0.5*old_rest_length;
526
527 // If necessary add other new spring rest lengths
528 for (unsigned pair_index=3; pair_index<5; pair_index++)
529 {
530 unsigned other_node_index = new_nodes[index][pair_index];
531
532 if (other_node_index != UNSIGNED_UNSET)
533 {
534 node_pair = this->CreateOrderedPair(other_node_index, new_node_index);
535 double new_rest_length = rGetMesh().GetDistanceBetweenNodes(new_node_index, other_node_index);
536 mSpringRestLengths[node_pair] = new_rest_length;
538 }
539 }
540 }
541 else
544 }
545}
546
547template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
549{
550 return this->mrMesh.GetNode(index);
551}
552
553template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
555{
556 return this->mrMesh.GetNumAllNodes();
557}
558
559template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
562}
563
564template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
565CellPtr MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::AddCell(CellPtr pNewCell, CellPtr pParentCell)
566{
567 assert(pNewCell);
568 assert(pParentCell);
569
570 // Add new cell to population
571 CellPtr p_created_cell = AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::AddCell(pNewCell, pParentCell);
572 assert(p_created_cell == pNewCell);
574 // Mark spring between parent cell and new cell
575 std::pair<CellPtr,CellPtr> cell_pair = this->CreateCellPair(pParentCell, p_created_cell);
576 this->MarkSpring(cell_pair);
577
578 // Return pointer to new cell
579 return p_created_cell;
581
583// Output methods //
586template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
588{
589 if (this->mOutputResultsForChasteVisualizer)
590 {
591 if (!this-> template HasWriter<CellPopulationElementWriter>())
593 this-> template AddPopulationWriter<CellPopulationElementWriter>();
594 }
595 }
596
598}
599
600template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
602{
603 if (SimulationTime::Instance()->GetTimeStepsElapsed() == 0 && this->mpVoronoiTessellation == nullptr)
605 TessellateIfNeeded(); // Update isn't run on time-step zero
606 }
607
610
611template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
613{
614 pPopulationWriter->Visit(this);
615}
617template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
619{
620 pPopulationCountWriter->Visit(this);
622
623template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
625{
626 pPopulationEventWriter->Visit(this);
627}
628
629template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
631{
632 pCellWriter->VisitCell(pCell, this);
633}
635template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
637{
638#ifdef CHASTE_VTK
639 // Store the present time as a string
640 unsigned num_timesteps = SimulationTime::Instance()->GetTimeStepsElapsed();
641 std::stringstream time;
642 time << num_timesteps;
643
644 // Store the number of cells for which to output data to VTK
645 unsigned num_cells_from_mesh = GetNumNodes();
646
647 // When outputting any CellData, we assume that the first cell is representative of all cells
648 unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
649 std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
650
651 std::vector<std::vector<double> > cell_data;
652 for (unsigned var=0; var<num_cell_data_items; var++)
653 {
654 std::vector<double> cell_data_var(num_cells_from_mesh);
655 cell_data.push_back(cell_data_var);
656 }
657
658 if (mWriteVtkAsPoints)
659 {
660 // Create mesh writer for VTK output
661 VtkMeshWriter<ELEMENT_DIM, SPACE_DIM> cells_writer(rDirectory, "mesh_results_"+time.str(), false);
662
663 // Iterate over any cell writers that are present
664 unsigned num_cells = this->GetNumAllCells();
665 for (typename std::vector<boost::shared_ptr<AbstractCellWriter<ELEMENT_DIM, SPACE_DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
666 cell_writer_iter != this->mCellWriters.end();
667 ++cell_writer_iter)
668 {
669 // Create vector to store VTK cell data
670 std::vector<double> vtk_cell_data(num_cells);
671
672 // Loop over cells
673 for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = this->Begin();
674 cell_iter != this->End();
675 ++cell_iter)
676 {
677 // Get the node index corresponding to this cell
678 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
679
680 // Populate the vector of VTK cell data
681 vtk_cell_data[node_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(*cell_iter, this);
682 }
683
684 cells_writer.AddPointData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
685 }
686
687 // Loop over cells
688 for (typename AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>::Iterator cell_iter = this->Begin();
689 cell_iter != this->End();
690 ++cell_iter)
691 {
692 // Get the node index corresponding to this cell
693 unsigned node_index = this->GetLocationIndexUsingCell(*cell_iter);
694
695 for (unsigned var=0; var<num_cell_data_items; var++)
696 {
697 cell_data[var][node_index] = cell_iter->GetCellData()->GetItem(cell_data_names[var]);
698 }
699 }
700 for (unsigned var=0; var<num_cell_data_items; var++)
701 {
702 cells_writer.AddPointData(cell_data_names[var], cell_data[var]);
703 }
704
705 // Write data using the mesh
706 cells_writer.WriteFilesUsingMesh(rGetMesh());
707 *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
708 *(this->mpVtkMetaFile) << num_timesteps;
709 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"mesh_results_";
710 *(this->mpVtkMetaFile) << num_timesteps;
711 *(this->mpVtkMetaFile) << ".vtu\"/>\n";
712 }
713 if (mpVoronoiTessellation != nullptr)
714 {
715 // Create mesh writer for VTK output
716 VertexMeshWriter<ELEMENT_DIM, SPACE_DIM> mesh_writer(rDirectory, "voronoi_results", false);
717 std::vector<double> cell_volumes(num_cells_from_mesh);
718
719 // Iterate over any cell writers that are present
720 unsigned num_cells = this->GetNumAllCells();
721 for (typename std::vector<boost::shared_ptr<AbstractCellWriter<ELEMENT_DIM, SPACE_DIM> > >::iterator cell_writer_iter = this->mCellWriters.begin();
722 cell_writer_iter != this->mCellWriters.end();
723 ++cell_writer_iter)
724 {
725 // Create vector to store VTK cell data
726 std::vector<double> vtk_cell_data(num_cells);
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 // Populate the vector of VTK cell data
741 vtk_cell_data[elem_index] = (*cell_writer_iter)->GetCellDataForVtkOutput(p_cell, this);
742 }
743
744 mesh_writer.AddCellData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
745 }
746
747 // Loop over elements of mpVoronoiTessellation
748 for (typename VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexElementIterator elem_iter = mpVoronoiTessellation->GetElementIteratorBegin();
749 elem_iter != mpVoronoiTessellation->GetElementIteratorEnd();
750 ++elem_iter)
751 {
752 // Get index of this element in mpVoronoiTessellation
753 unsigned elem_index = elem_iter->GetIndex();
754
755 // Get the cell corresponding to this element, via the index of the corresponding node in mrMesh
756 unsigned node_index = mpVoronoiTessellation->GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(elem_index);
757 CellPtr p_cell = this->GetCellUsingLocationIndex(node_index);
758
759 for (unsigned var=0; var<num_cell_data_items; var++)
760 {
761 cell_data[var][elem_index] = p_cell->GetCellData()->GetItem(cell_data_names[var]);
762 }
763 }
764
765 for (unsigned var=0; var<cell_data.size(); var++)
766 {
767 mesh_writer.AddCellData(cell_data_names[var], cell_data[var]);
768 }
769
770 mesh_writer.WriteVtkUsingMesh(*mpVoronoiTessellation, time.str());
771 *(this->mpVtkMetaFile) << " <DataSet timestep=\"";
772 *(this->mpVtkMetaFile) << num_timesteps;
773 *(this->mpVtkMetaFile) << "\" group=\"\" part=\"0\" file=\"voronoi_results_";
774 *(this->mpVtkMetaFile) << num_timesteps;
775 *(this->mpVtkMetaFile) << ".vtu\"/>\n";
776 }
777#endif //CHASTE_VTK
778}
779
780template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
782{
783 double cell_volume = 0;
784
785 if (ELEMENT_DIM == SPACE_DIM)
786 {
787 // Ensure that the Voronoi tessellation exists
788 if (mpVoronoiTessellation == nullptr)
789 {
790 CreateVoronoiTessellation();
791 }
792
793 // Get the node index corresponding to this cell
794 unsigned node_index = this->GetLocationIndexUsingCell(pCell);
795
796 // Try to get the element index of the Voronoi tessellation corresponding to this node index
797 try
798 {
799 unsigned element_index = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(node_index);
800
801 // Get the cell's volume from the Voronoi tessellation
802 cell_volume = mpVoronoiTessellation->GetVolumeOfElement(element_index);
803 }
804 catch (Exception&)
805 {
806 // If it doesn't exist this must be a boundary cell, so return infinite volume
807 cell_volume = DBL_MAX;
808 }
809 }
810 else if (SPACE_DIM==3 && ELEMENT_DIM==2)
811 {
812 unsigned node_index = this->GetLocationIndexUsingCell(pCell);
813
814 Node<SPACE_DIM>* p_node = rGetMesh().GetNode(node_index);
815
816 assert(!(p_node->rGetContainingElementIndices().empty()));
817
819 elem_iter != p_node->ContainingElementsEnd();
820 ++elem_iter)
821 {
822 Element<ELEMENT_DIM,SPACE_DIM>* p_element = rGetMesh().GetElement(*elem_iter);
823
824 c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacob;
825 double det;
826
827 p_element->CalculateJacobian(jacob, det);
828
829 cell_volume += fabs(p_element->GetVolume(det));
830 }
831
832 // This calculation adds a third of each element to the total area
833 cell_volume /= 3.0;
834 }
835 else
836 {
837 // Not implemented for other dimensions
839 }
840
841 return cell_volume;
842}
843
844template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
846{
847 mWriteVtkAsPoints = writeVtkAsPoints;
848}
849
850template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
852{
853 return mWriteVtkAsPoints;
854}
855
856template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
858{
859 mBoundVoronoiTessellation = boundVoronoiTessellation;
860}
861
862template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
864{
865 return mBoundVoronoiTessellation;
866}
867
868template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
870{
871 mScaleBoundByEdgeLength = scaleBoundByEdgeLength;
872}
873
874template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
876{
877 return mScaleBoundByEdgeLength;
878}
879
880template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
882{
883 assert(boundedVoroniTesselationLengthCutoff>0);
884 mBoundedVoroniTesselationLengthCutoff = boundedVoroniTesselationLengthCutoff;
885}
886
887template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
889{
890 return mBoundedVoroniTesselationLengthCutoff;
891}
892
893template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
895{
896 mOffsetNewBoundaryNodes = offsetNewBoundaryNodes;
897}
898
899template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
901{
902 return mOffsetNewBoundaryNodes;
903}
904
905
906
907template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
909{
910 if (bool(dynamic_cast<Cylindrical2dMesh*>(&(this->mrMesh))))
911 {
912 *pVizSetupFile << "MeshWidth\t" << this->GetWidth(0) << "\n";
913 }
914 if (bool(dynamic_cast<Toroidal2dMesh*>(&(this->mrMesh))))
915 {
916 *pVizSetupFile << "MeshWidth\t" << this->GetWidth(0) << "\n";
917 *pVizSetupFile << "MeshHeight\t" << this->GetWidth(1) << "\n";
918 }
919}
920
921template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
923{
924 if constexpr (ELEMENT_DIM == 1)
925 {
926 // The VoronoiTessellation class is only defined in 2D or 3D
928 }
929 else if constexpr (ELEMENT_DIM == 2 && SPACE_DIM == 2)
930 {
931 delete mpVoronoiTessellation;
932
933 // Check if the mesh associated with this cell population is periodic
934 bool is_mesh_periodic = false;
935 if (dynamic_cast<Cylindrical2dMesh*>(&(this->mrMesh)))
936 {
937 if(mScaleBoundByEdgeLength || mBoundedVoroniTesselationLengthCutoff<DBL_MAX || mOffsetNewBoundaryNodes)
938 {
939 // Not implemented for Cylindrical meshes yet see Issue 305
941 }
942 is_mesh_periodic = true;
943 mpVoronoiTessellation = new Cylindrical2dVertexMesh(static_cast<Cylindrical2dMesh&>(this->mrMesh), mBoundVoronoiTessellation);
944 }
945 else if (dynamic_cast<Toroidal2dMesh*>(&(this->mrMesh)))
946 {
947 if(mScaleBoundByEdgeLength || mBoundedVoroniTesselationLengthCutoff<DBL_MAX || mOffsetNewBoundaryNodes)
948 {
949 // Not implemented for Toroidal meshes yet see Issue 305
951 }
952 is_mesh_periodic = true;
953 mpVoronoiTessellation = new Toroidal2dVertexMesh(static_cast<Toroidal2dMesh&>(this->mrMesh), mBoundVoronoiTessellation);
954 }
955 else
956 {
957 mpVoronoiTessellation = new VertexMesh<2, 2>(static_cast<MutableMesh<2, 2>&>((this->mrMesh)), is_mesh_periodic, mBoundVoronoiTessellation, mScaleBoundByEdgeLength, mBoundedVoroniTesselationLengthCutoff, mOffsetNewBoundaryNodes);
958 }
959 }
960 else if constexpr (ELEMENT_DIM == 3)
961 {
962 // The cylindrical mesh is only defined in 2D, hence there is
963 // a separate definition for this method in 3D, which doesn't have the capability
964 // of dealing with periodic boundaries in 3D. This is \todo #1374.
965 delete mpVoronoiTessellation;
966 mpVoronoiTessellation = new VertexMesh<3, 3>(static_cast<MutableMesh<3, 3>&>(this->mrMesh));
967 }
968 else // ELEMENT_DIM == 2 && SPACE_DIM != 2
969 {
971 }
972}
973
975// Spring iterator class //
977
978template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
983
984template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
989
990template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
992{
993 assert((*this) != mrCellPopulation.SpringsEnd());
994 return mrCellPopulation.GetCellUsingLocationIndex(mEdgeIter.GetNodeA()->GetIndex());
995}
996
997template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
999{
1000 assert((*this) != mrCellPopulation.SpringsEnd());
1001 return mrCellPopulation.GetCellUsingLocationIndex(mEdgeIter.GetNodeB()->GetIndex());
1002}
1003
1004template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1009
1010template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1012{
1013 bool edge_is_ghost = false;
1014
1015 do
1016 {
1017 ++mEdgeIter;
1018 if (*this != mrCellPopulation.SpringsEnd())
1019 {
1020 bool a_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeA()->GetIndex());
1021 bool b_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeB()->GetIndex());
1022
1023 edge_is_ghost = (a_is_ghost || b_is_ghost);
1024 }
1025 }
1026 while (*this!=mrCellPopulation.SpringsEnd() && edge_is_ghost);
1027
1028 return (*this);
1029}
1030
1031template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1035 : mrCellPopulation(rCellPopulation),
1036 mEdgeIter(edgeIter)
1037{
1038 if (mEdgeIter!=static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>*>(&(this->mrCellPopulation.mrMesh))->EdgesEnd())
1039 {
1040 bool a_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeA()->GetIndex());
1041 bool b_is_ghost = mrCellPopulation.IsGhostNode(mEdgeIter.GetNodeB()->GetIndex());
1042
1043 if (a_is_ghost || b_is_ghost)
1044 {
1045 ++(*this);
1046 }
1047 }
1048}
1049
1050template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1055
1056template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1061
1062template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1068
1069template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1071{
1072 unsigned element_index = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index);
1073 double volume = mpVoronoiTessellation->GetVolumeOfElement(element_index);
1074 return volume;
1075}
1076
1077template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1079{
1080 unsigned element_index = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index);
1081 double surface_area = mpVoronoiTessellation->GetSurfaceAreaOfElement(element_index);
1082 return surface_area;
1083}
1084
1085template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1087{
1088 unsigned element_index1 = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index1);
1089 unsigned element_index2 = mpVoronoiTessellation->GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(index2);
1090 try
1091 {
1092 double edge_length = mpVoronoiTessellation->GetEdgeLength(element_index1, element_index2);
1093 return edge_length;
1094 }
1095 catch (Exception&)
1096 {
1097 // The edge was between two (potentially infinite) cells on the boundary of the mesh
1098 EXCEPTION("Spring iterator tried to calculate interaction between degenerate cells on the boundary of the mesh. Have you set ghost layers correctly?");
1099 }
1100}
1101
1102template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1104{
1105 bool res = true;
1106 for (std::list<CellPtr>::iterator it=this->mCells.begin();
1107 it!=this->mCells.end();
1108 ++it)
1109 {
1110 CellPtr p_cell = *it;
1111 assert(p_cell);
1112 AbstractCellCycleModel* p_model = p_cell->GetCellCycleModel();
1113 assert(p_model);
1114
1115 // Check cell exists in cell population
1116 unsigned node_index = this->GetLocationIndexUsingCell(p_cell);
1117 std::cout << "Cell at node " << node_index << " addr " << p_cell << std::endl << std::flush;
1118 CellPtr p_cell_in_cell_population = this->GetCellUsingLocationIndex(node_index);
1119// LCOV_EXCL_START //Debugging code. Shouldn't fail under normal conditions
1120 if (p_cell_in_cell_population != p_cell)
1121 {
1122 std::cout << " Mismatch with cell population" << std::endl << std::flush;
1123 res = false;
1124 }
1125
1126 // Check model links back to cell
1127 if (p_model->GetCell() != p_cell)
1128 {
1129 std::cout << " Mismatch with cycle model" << std::endl << std::flush;
1130 res = false;
1131 }
1132 }
1133 UNUSED_OPT(res);
1134 assert(res);
1135// LCOV_EXCL_STOP
1136
1137 res = true;
1138 for (std::set<std::pair<CellPtr,CellPtr> >::iterator it1 = this->mMarkedSprings.begin();
1139 it1 != this->mMarkedSprings.end();
1140 ++it1)
1141 {
1142 const std::pair<CellPtr,CellPtr>& r_pair = *it1;
1143
1144 for (unsigned i=0; i<2; i++)
1145 {
1146 CellPtr p_cell = (i==0 ? r_pair.first : r_pair.second);
1147
1148 assert(p_cell);
1149 AbstractCellCycleModel* p_model = p_cell->GetCellCycleModel();
1150 assert(p_model);
1151 unsigned node_index = this->GetLocationIndexUsingCell(p_cell);
1152 std::cout << "Cell at node " << node_index << " addr " << p_cell << std::endl << std::flush;
1153
1154// LCOV_EXCL_START //Debugging code. Shouldn't fail under normal conditions
1155 // Check cell is alive
1156 if (p_cell->IsDead())
1157 {
1158 std::cout << " Cell is dead" << std::endl << std::flush;
1159 res = false;
1160 }
1161
1162 // Check cell exists in cell population
1163 CellPtr p_cell_in_cell_population = this->GetCellUsingLocationIndex(node_index);
1164 if (p_cell_in_cell_population != p_cell)
1165 {
1166 std::cout << " Mismatch with cell population" << std::endl << std::flush;
1167 res = false;
1168 }
1169
1170 // Check model links back to cell
1171 if (p_model->GetCell() != p_cell)
1172 {
1173 std::cout << " Mismatch with cycle model" << std::endl << std::flush;
1174 res = false;
1175 }
1176 }
1177// LCOV_EXCL_STOP
1178 }
1179 assert(res);
1180}
1181
1182template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1187
1188template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1190{
1191 assert(areaBasedDampingConstantParameter >= 0.0);
1192 mAreaBasedDampingConstantParameter = areaBasedDampingConstantParameter;
1193}
1194
1195template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1197{
1198 *rParamsFile << "\t\t<UseAreaBasedDampingConstant>" << mUseAreaBasedDampingConstant << "</UseAreaBasedDampingConstant>\n";
1199 *rParamsFile << "\t\t<AreaBasedDampingConstantParameter>" << mAreaBasedDampingConstantParameter << "</AreaBasedDampingConstantParameter>\n";
1200 *rParamsFile << "\t\t<WriteVtkAsPoints>" << mWriteVtkAsPoints << "</WriteVtkAsPoints>\n";
1201 *rParamsFile << "\t\t<BoundVoronoiTessellation>" << mBoundVoronoiTessellation << "</BoundVoronoiTessellation>\n";
1202 *rParamsFile << "\t\t<HasVariableRestLength>" << mHasVariableRestLength << "</HasVariableRestLength>\n";
1203
1204 // Call method on direct parent class
1206}
1207
1208template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1210{
1211 // Call GetWidth() on the mesh
1212 double width = this->mrMesh.GetWidth(rDimension);
1213 return width;
1214}
1215
1216template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1218{
1219 // Get pointer to this node
1220 Node<SPACE_DIM>* p_node = this->mrMesh.GetNode(index);
1221
1222 // Loop over containing elements
1223 std::set<unsigned> neighbouring_node_indices;
1224 for (typename Node<SPACE_DIM>::ContainingElementIterator elem_iter = p_node->ContainingElementsBegin();
1225 elem_iter != p_node->ContainingElementsEnd();
1226 ++elem_iter)
1227 {
1228 // Get pointer to this containing element
1229 Element<ELEMENT_DIM,SPACE_DIM>* p_element = static_cast<MutableMesh<ELEMENT_DIM,SPACE_DIM>&>((this->mrMesh)).GetElement(*elem_iter);
1230
1231 // Loop over nodes contained in this element
1232 for (unsigned i=0; i<p_element->GetNumNodes(); i++)
1233 {
1234 // Get index of this node and add its index to the set if not the original node
1235 unsigned node_index = p_element->GetNodeGlobalIndex(i);
1236 if (node_index != index)
1237 {
1238 neighbouring_node_indices.insert(node_index);
1239 }
1240 }
1241 }
1242 return neighbouring_node_indices;
1243}
1244
1245template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1247{
1248 mSpringRestLengths.clear();
1249
1250 // Iterate over all springs and add calculate separation of adjacent node pairs
1251 for (SpringIterator spring_iterator = SpringsBegin();
1252 spring_iterator != SpringsEnd();
1253 ++spring_iterator)
1254 {
1255 // Note that nodeA_global_index is always less than nodeB_global_index
1256 Node<SPACE_DIM>* p_nodeA = spring_iterator.GetNodeA();
1257 Node<SPACE_DIM>* p_nodeB = spring_iterator.GetNodeB();
1258
1259 unsigned nodeA_global_index = p_nodeA->GetIndex();
1260 unsigned nodeB_global_index = p_nodeB->GetIndex();
1261
1262 // Calculate the distance between nodes
1263 double separation = rGetMesh().GetDistanceBetweenNodes(nodeA_global_index, nodeB_global_index);
1264
1265 // Order node indices
1266 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(nodeA_global_index, nodeB_global_index);
1267
1268 mSpringRestLengths[node_pair] = separation;
1269 }
1271}
1272
1273template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1275{
1277 {
1278 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(indexA, indexB);
1279 std::map<std::pair<unsigned,unsigned>, double>::const_iterator iter = mSpringRestLengths.find(node_pair);
1280
1281 if (iter != mSpringRestLengths.end())
1282 {
1283 // Return the stored rest length
1284 return iter->second;
1285 }
1286 else
1287 {
1288 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.");
1289 }
1290 }
1291 else
1292 {
1293 return 1.0;
1294 }
1295}
1296
1297template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
1298void MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>::SetRestLength(unsigned indexA, unsigned indexB, double restLength)
1299{
1301 {
1302 std::pair<unsigned,unsigned> node_pair = this->CreateOrderedPair(indexA, indexB);
1303 std::map<std::pair<unsigned,unsigned>, double>::iterator iter = mSpringRestLengths.find(node_pair);
1304
1305 if (iter != mSpringRestLengths.end())
1306 {
1307 // modify the stored rest length
1308 iter->second = restLength;
1309 }
1310 else
1311 {
1312 EXCEPTION("Tried to set the rest length of an edge not in the mesh.");
1313 }
1314 }
1315 else
1316 {
1317 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.");
1318 }
1319}
1320
1321// Explicit instantiation
1322template class MeshBasedCellPopulation<1,1>;
1323template class MeshBasedCellPopulation<1,2>;
1324template class MeshBasedCellPopulation<2,2>;
1325template class MeshBasedCellPopulation<1,3>;
1326template class MeshBasedCellPopulation<2,3>;
1327template class MeshBasedCellPopulation<3,3>;
1328
1329// 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::map< std::pair< unsigned, unsigned >, double > mSpringRestLengths
void SetBoundedVoroniTesselationLengthCutoff(double boundedVoroniTesselationLengthCutoff)
void OutputCellPopulationParameters(out_stream &rParamsFile)
virtual void WriteResultsToFiles(const std::string &rDirectory)
virtual void Update(bool hasHadBirthsOrDeaths=true)
double GetVoronoiEdgeLength(unsigned index1, unsigned index2)
void SetScaleBoundByEdgeLength(bool scaleBoundByEdgeLength)
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)
void SetOffsetNewBoundaryNodes(bool offsetNewBoundaryNodes)
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()