Chaste Commit::6e4f5fe395bca70eb7641cf6e0e87f450383ca5a
FarhadifarForce.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 "FarhadifarForce.hpp"
37
38template<unsigned DIM>
40 : AbstractForce<DIM>(),
41 mAreaElasticityParameter(1.0), // These parameters are Case I in Farhadifar's paper
42 mPerimeterContractilityParameter(0.04),
43 mLineTensionParameter(0.12),
44 mBoundaryLineTensionParameter(0.12), // This parameter as such does not exist in Farhadifar's model
45 mTargetAreaParameter(1.0)
46{
47}
48
49template<unsigned DIM>
53
54template<unsigned DIM>
56{
57 // Throw an exception message if not using a VertexBasedCellPopulation
59 if (dynamic_cast<VertexBasedCellPopulation<DIM>*>(&rCellPopulation) == nullptr)
60 {
61 EXCEPTION("FarhadifarForce is to be used with a VertexBasedCellPopulation only");
62 }
63
64 // Define some helper variables
65 VertexBasedCellPopulation<DIM>* p_cell_population = static_cast<VertexBasedCellPopulation<DIM>*>(&rCellPopulation);
66 unsigned num_nodes = p_cell_population->GetNumNodes();
67 unsigned num_elements = p_cell_population->GetNumElements();
68
69 /*
70 * Check if a subclass of AbstractTargetAreaModifier is being used by
71 * interrogating the first cell (assuming either all cells, or no cells, in
72 * the population have the CellData item "target area").
73 */
74 bool using_target_area_modifier = p_cell_population->Begin()->GetCellData()->HasItem("target area");
75
76 // Begin by computing the area and perimeter of each element in the mesh, to avoid having to do this multiple times
77 std::vector<double> element_areas(num_elements);
78 std::vector<double> element_perimeters(num_elements);
79 std::vector<double> target_areas(num_elements);
80 for (typename VertexMesh<DIM,DIM>::VertexElementIterator elem_iter = p_cell_population->rGetMesh().GetElementIteratorBegin();
81 elem_iter != p_cell_population->rGetMesh().GetElementIteratorEnd();
82 ++elem_iter)
83 {
84 unsigned elem_index = elem_iter->GetIndex();
85 element_areas[elem_index] = p_cell_population->rGetMesh().GetVolumeOfElement(elem_index);
86 element_perimeters[elem_index] = p_cell_population->rGetMesh().GetSurfaceAreaOfElement(elem_index);
87
88 if (using_target_area_modifier)
89 {
90 target_areas[elem_index] = p_cell_population->GetCellUsingLocationIndex(elem_index)->GetCellData()->GetItem("target area");
91 }
92 else
93 {
94 target_areas[elem_index] = mTargetAreaParameter;
95 }
96 }
97
98 // Iterate over vertices in the cell population
99 for (unsigned node_index=0; node_index<num_nodes; node_index++)
100 {
101 Node<DIM>* p_this_node = p_cell_population->GetNode(node_index);
102
103 /*
104 * The force on this Node is given by the gradient of the total free
105 * energy of the CellPopulation, evaluated at the position of the vertex. This
106 * free energy is the sum of the free energies of all CellPtrs in
107 * the cell population. The free energy of each CellPtr is comprised of three
108 * terms - an area deformation energy, a perimeter deformation energy
109 * and line tension energy.
110 *
111 * Note that since the movement of this Node only affects the free energy
112 * of the CellPtrs containing it, we can just consider the contributions
113 * to the free energy gradient from each of these CellPtrs.
114 */
115 c_vector<double, DIM> area_elasticity_contribution = zero_vector<double>(DIM);
116 c_vector<double, DIM> perimeter_contractility_contribution = zero_vector<double>(DIM);
117 c_vector<double, DIM> line_tension_contribution = zero_vector<double>(DIM);
118
119 // Find the indices of the elements owned by this node
120 std::set<unsigned> containing_elem_indices = p_cell_population->GetNode(node_index)->rGetContainingElementIndices();
121
122 // Iterate over these elements
123 for (std::set<unsigned>::iterator iter = containing_elem_indices.begin();
124 iter != containing_elem_indices.end();
125 ++iter)
126 {
127 // Get this element, its index and its number of nodes
128 VertexElement<DIM, DIM>* p_element = p_cell_population->GetElement(*iter);
129 unsigned elem_index = p_element->GetIndex();
130 unsigned num_nodes_elem = p_element->GetNumNodes();
131
132 // Find the local index of this node in this element
133 unsigned local_index = p_element->GetNodeLocalIndex(node_index);
134
135 // Add the force contribution from this cell's area elasticity (note the minus sign)
136 c_vector<double, DIM> element_area_gradient = p_cell_population->rGetMesh().GetAreaGradientOfElementAtNode(p_element, local_index);
137 area_elasticity_contribution -= GetAreaElasticityParameter()*(element_areas[elem_index] -
138 target_areas[elem_index])*element_area_gradient;
139
140 // Get the previous and next nodes in this element
141 unsigned previous_node_local_index = (num_nodes_elem+local_index-1)%num_nodes_elem;
142 Node<DIM>* p_previous_node = p_element->GetNode(previous_node_local_index);
143
144 unsigned next_node_local_index = (local_index+1)%num_nodes_elem;
145 Node<DIM>* p_next_node = p_element->GetNode(next_node_local_index);
146
147 // Compute the line tension parameter for each of these edges - be aware that this is half of the actual
148 // value for internal edges since we are looping over each of the internal edges twice
149 double previous_edge_line_tension_parameter = GetLineTensionParameter(p_previous_node, p_this_node, *p_cell_population);
150 double next_edge_line_tension_parameter = GetLineTensionParameter(p_this_node, p_next_node, *p_cell_population);
151
152 // Compute the gradient of each these edges, computed at the present node
153 c_vector<double, DIM> previous_edge_gradient = -p_cell_population->rGetMesh().GetNextEdgeGradientOfElementAtNode(p_element, previous_node_local_index);
154 c_vector<double, DIM> next_edge_gradient = p_cell_population->rGetMesh().GetNextEdgeGradientOfElementAtNode(p_element, local_index);
155
156 // Add the force contribution from cell-cell and cell-boundary line tension (note the minus sign)
157 line_tension_contribution -= previous_edge_line_tension_parameter*previous_edge_gradient +
158 next_edge_line_tension_parameter*next_edge_gradient;
159
160 // Add the force contribution from this cell's perimeter contractility (note the minus sign)
161 c_vector<double, DIM> element_perimeter_gradient;
162 element_perimeter_gradient = previous_edge_gradient + next_edge_gradient;
163 perimeter_contractility_contribution -= GetPerimeterContractilityParameter()* element_perimeters[elem_index]*
164 element_perimeter_gradient;
165 }
166
167 c_vector<double, DIM> force_on_node = area_elasticity_contribution + perimeter_contractility_contribution + line_tension_contribution;
168 p_cell_population->GetNode(node_index)->AddAppliedForceContribution(force_on_node);
169 }
170}
171
172template<unsigned DIM>
174{
175 // Find the indices of the elements owned by each node
176 std::set<unsigned> elements_containing_nodeA = pNodeA->rGetContainingElementIndices();
177 std::set<unsigned> elements_containing_nodeB = pNodeB->rGetContainingElementIndices();
178
179 // Find common elements
180 std::set<unsigned> shared_elements;
181 std::set_intersection(elements_containing_nodeA.begin(),
182 elements_containing_nodeA.end(),
183 elements_containing_nodeB.begin(),
184 elements_containing_nodeB.end(),
185 std::inserter(shared_elements, shared_elements.begin()));
186
187 // Check that the nodes have a common edge
188 assert(!shared_elements.empty());
189
190 // Since each internal edge is visited twice in the loop above, we have to use half the line tension parameter
191 // for each visit.
192 double line_tension_parameter_in_calculation = GetLineTensionParameter()/2.0;
193
194 // If the edge corresponds to a single element, then the cell is on the boundary
195 if (shared_elements.size() == 1)
196 {
197 line_tension_parameter_in_calculation = GetBoundaryLineTensionParameter();
198 }
199
200 return line_tension_parameter_in_calculation;
201}
202
203template<unsigned DIM>
205{
206 return mAreaElasticityParameter;
207}
208
209template<unsigned DIM>
211{
212 return mPerimeterContractilityParameter;
213}
214
215template<unsigned DIM>
217{
218 return mLineTensionParameter;
219}
220
221template<unsigned DIM>
223{
224 return mBoundaryLineTensionParameter;
225}
226
227template<unsigned DIM>
229{
230 return mTargetAreaParameter;
231}
232
233template<unsigned DIM>
234void FarhadifarForce<DIM>::SetAreaElasticityParameter(double areaElasticityParameter)
235{
236 mAreaElasticityParameter = areaElasticityParameter;
237}
238
239template<unsigned DIM>
240void FarhadifarForce<DIM>::SetPerimeterContractilityParameter(double perimeterContractilityParameter)
241{
242 mPerimeterContractilityParameter = perimeterContractilityParameter;
243}
244
245template<unsigned DIM>
246void FarhadifarForce<DIM>::SetLineTensionParameter(double lineTensionParameter)
247{
248 mLineTensionParameter = lineTensionParameter;
249}
250
251template<unsigned DIM>
252void FarhadifarForce<DIM>::SetBoundaryLineTensionParameter(double boundaryLineTensionParameter)
253{
254 mBoundaryLineTensionParameter = boundaryLineTensionParameter;
255}
256
257template<unsigned DIM>
258void FarhadifarForce<DIM>::SetTargetAreaParameter(double targetAreaParameter)
259{
260 mTargetAreaParameter = targetAreaParameter;
261}
262
263template<unsigned DIM>
265{
266 *rParamsFile << "\t\t\t<AreaElasticityParameter>" << mAreaElasticityParameter << "</AreaElasticityParameter>\n";
267 *rParamsFile << "\t\t\t<PerimeterContractilityParameter>" << mPerimeterContractilityParameter << "</PerimeterContractilityParameter>\n";
268 *rParamsFile << "\t\t\t<LineTensionParameter>" << mLineTensionParameter << "</LineTensionParameter>\n";
269 *rParamsFile << "\t\t\t<BoundaryLineTensionParameter>" << mBoundaryLineTensionParameter << "</BoundaryLineTensionParameter>\n";
270 *rParamsFile << "\t\t\t<TargetAreaParameter>" << mTargetAreaParameter << "</TargetAreaParameter>\n";
271
272 // Call method on direct parent class
274}
275
276// Explicit instantiation
277template class FarhadifarForce<1>;
278template class FarhadifarForce<2>;
279template class FarhadifarForce<3>;
280
281// Serialization for Boost >= 1.36
#define EXCEPTION(message)
#define EXPORT_TEMPLATE_CLASS_SAME_DIMS(CLASS)
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
unsigned GetNumNodes() const
unsigned GetIndex() const
virtual void OutputForceParameters(out_stream &rParamsFile)=0
void SetAreaElasticityParameter(double areaElasticityParameter)
void SetBoundaryLineTensionParameter(double boundaryLineTensionParameter)
virtual void AddForceContribution(AbstractCellPopulation< DIM > &rCellPopulation)
void SetPerimeterContractilityParameter(double perimeterContractilityParameter)
double GetTargetAreaParameter()
virtual ~FarhadifarForce()
double GetBoundaryLineTensionParameter()
double GetPerimeterContractilityParameter()
void OutputForceParameters(out_stream &rParamsFile)
double GetAreaElasticityParameter()
double GetLineTensionParameter()
void SetTargetAreaParameter(double targetAreaParameter)
void SetLineTensionParameter(double lineTensionParameter)
unsigned GetNodeLocalIndex(unsigned globalIndex) const
Definition Node.hpp:59
std::set< unsigned > & rGetContainingElementIndices()
Definition Node.cpp:300
void AddAppliedForceContribution(const c_vector< double, SPACE_DIM > &rForceContribution)
Definition Node.cpp:224
VertexElement< DIM, DIM > * GetElement(unsigned elementIndex)
MutableVertexMesh< DIM, DIM > & rGetMesh()
Node< DIM > * GetNode(unsigned index)
VertexElementIterator GetElementIteratorEnd()
virtual double GetSurfaceAreaOfElement(unsigned index)
c_vector< double, SPACE_DIM > GetNextEdgeGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
c_vector< double, SPACE_DIM > GetAreaGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
VertexElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
virtual double GetVolumeOfElement(unsigned index)