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