Chaste Commit::1fd4e48e3990e67db148bc1bc4cf6991a0049d0c
FarhadifarForce.cpp
1/*
2
3Copyright (c) 2005-2024, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, are permitted provided that the following conditions are met:
14 * Redistributions of source code must retain the above copyright notice,
15 this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 * Neither the name of the University of Oxford nor the names of its
20 contributors may be used to endorse or promote products derived from this
21 software without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36#include "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 =
137 p_cell_population->rGetMesh().GetAreaGradientOfElementAtNode(p_element, local_index);
138 area_elasticity_contribution -= GetAreaElasticityParameter()*(element_areas[elem_index] -
139 target_areas[elem_index])*element_area_gradient;
140
141 // Get the previous and next nodes in this element
142 unsigned previous_node_local_index = (num_nodes_elem+local_index-1)%num_nodes_elem;
143 Node<DIM>* p_previous_node = p_element->GetNode(previous_node_local_index);
144
145 unsigned next_node_local_index = (local_index+1)%num_nodes_elem;
146 Node<DIM>* p_next_node = p_element->GetNode(next_node_local_index);
147
148 // Compute the line tension parameter for each of these edges - be aware that this is half of the actual
149 // value for internal edges since we are looping over each of the internal edges twice
150 double previous_edge_line_tension_parameter = GetLineTensionParameter(p_previous_node, p_this_node, *p_cell_population);
151 double next_edge_line_tension_parameter = GetLineTensionParameter(p_this_node, p_next_node, *p_cell_population);
152
153 // Compute the gradient of each these edges, computed at the present node
154 c_vector<double, DIM> previous_edge_gradient =
155 -p_cell_population->rGetMesh().GetNextEdgeGradientOfElementAtNode(p_element, previous_node_local_index);
156 c_vector<double, DIM> next_edge_gradient = p_cell_population->rGetMesh().GetNextEdgeGradientOfElementAtNode(p_element, local_index);
157
158 // Add the force contribution from cell-cell and cell-boundary line tension (note the minus sign)
159 line_tension_contribution -= previous_edge_line_tension_parameter*previous_edge_gradient +
160 next_edge_line_tension_parameter*next_edge_gradient;
161
162 // Add the force contribution from this cell's perimeter contractility (note the minus sign)
163 c_vector<double, DIM> element_perimeter_gradient;
164 element_perimeter_gradient = previous_edge_gradient + next_edge_gradient;
165 perimeter_contractility_contribution -= GetPerimeterContractilityParameter()* element_perimeters[elem_index]*
166 element_perimeter_gradient;
167 }
168
169 c_vector<double, DIM> force_on_node = area_elasticity_contribution + perimeter_contractility_contribution + line_tension_contribution;
170 p_cell_population->GetNode(node_index)->AddAppliedForceContribution(force_on_node);
171 }
172}
173
174template<unsigned DIM>
176{
177 // Find the indices of the elements owned by each node
178 std::set<unsigned> elements_containing_nodeA = pNodeA->rGetContainingElementIndices();
179 std::set<unsigned> elements_containing_nodeB = pNodeB->rGetContainingElementIndices();
180
181 // Find common elements
182 std::set<unsigned> shared_elements;
183 std::set_intersection(elements_containing_nodeA.begin(),
184 elements_containing_nodeA.end(),
185 elements_containing_nodeB.begin(),
186 elements_containing_nodeB.end(),
187 std::inserter(shared_elements, shared_elements.begin()));
188
189 // Check that the nodes have a common edge
190 assert(!shared_elements.empty());
191
192 // Since each internal edge is visited twice in the loop above, we have to use half the line tension parameter
193 // for each visit.
194 double line_tension_parameter_in_calculation = GetLineTensionParameter()/2.0;
195
196 // If the edge corresponds to a single element, then the cell is on the boundary
197 if (shared_elements.size() == 1)
198 {
199 line_tension_parameter_in_calculation = GetBoundaryLineTensionParameter();
200 }
201
202 return line_tension_parameter_in_calculation;
203}
204
205template<unsigned DIM>
207{
208 return mAreaElasticityParameter;
209}
210
211template<unsigned DIM>
213{
214 return mPerimeterContractilityParameter;
215}
216
217template<unsigned DIM>
219{
220 return mLineTensionParameter;
221}
222
223template<unsigned DIM>
225{
226 return mBoundaryLineTensionParameter;
227}
228
229template<unsigned DIM>
231{
232 return mTargetAreaParameter;
233}
234
235template<unsigned DIM>
236void FarhadifarForce<DIM>::SetAreaElasticityParameter(double areaElasticityParameter)
237{
238 mAreaElasticityParameter = areaElasticityParameter;
239}
240
241template<unsigned DIM>
242void FarhadifarForce<DIM>::SetPerimeterContractilityParameter(double perimeterContractilityParameter)
243{
244 mPerimeterContractilityParameter = perimeterContractilityParameter;
245}
246
247template<unsigned DIM>
248void FarhadifarForce<DIM>::SetLineTensionParameter(double lineTensionParameter)
249{
250 mLineTensionParameter = lineTensionParameter;
251}
252
253template<unsigned DIM>
254void FarhadifarForce<DIM>::SetBoundaryLineTensionParameter(double boundaryLineTensionParameter)
255{
256 mBoundaryLineTensionParameter = boundaryLineTensionParameter;
257}
258
259template<unsigned DIM>
260void FarhadifarForce<DIM>::SetTargetAreaParameter(double targetAreaParameter)
261{
262 mTargetAreaParameter = targetAreaParameter;
263}
264
265template<unsigned DIM>
267{
268 *rParamsFile << "\t\t\t<AreaElasticityParameter>" << mAreaElasticityParameter << "</AreaElasticityParameter>\n";
269 *rParamsFile << "\t\t\t<PerimeterContractilityParameter>" << mPerimeterContractilityParameter << "</PerimeterContractilityParameter>\n";
270 *rParamsFile << "\t\t\t<LineTensionParameter>" << mLineTensionParameter << "</LineTensionParameter>\n";
271 *rParamsFile << "\t\t\t<BoundaryLineTensionParameter>" << mBoundaryLineTensionParameter << "</BoundaryLineTensionParameter>\n";
272 *rParamsFile << "\t\t\t<TargetAreaParameter>" << mTargetAreaParameter << "</TargetAreaParameter>\n";
273
274 // Call method on direct parent class
276}
277
278// Explicit instantiation
279template class FarhadifarForce<1>;
280template class FarhadifarForce<2>;
281template class FarhadifarForce<3>;
282
283// 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)