Skip to content

Commit 197e8ed

Browse files
committed
Merge branch 'main' of https://github.com/Chaste/OpenVT
2 parents 0af436a + 252d399 commit 197e8ed

9 files changed

Lines changed: 792 additions & 6 deletions

src/Test02MonolayerGrowth/GeneralisedLinearSpringForceWithMinDistanceItem.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3535

3636
#include "GeneralisedLinearSpringForceWithMinDistanceItem.hpp"
3737

38+
#include "AbstractCentreBasedCellPopulation.hpp"
39+
#include "MeshBasedCellPopulation.hpp"
40+
#include "NodeBasedCellPopulation.hpp"
41+
3842
template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
3943
GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::GeneralisedLinearSpringForceWithMinDistanceItem()
4044
: AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM>(),

src/Test02MonolayerGrowth/QuadraticRepulsionForce.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3535

3636
#include "QuadraticRepulsionForce.hpp"
3737

38+
#include "AbstractCentreBasedCellPopulation.hpp"
39+
#include "MeshBasedCellPopulation.hpp"
40+
#include "NodeBasedCellPopulation.hpp"
41+
3842
template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
3943
QuadraticRepulsionForce<ELEMENT_DIM,SPACE_DIM>::QuadraticRepulsionForce()
4044
: AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM>(),
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*
2+
3+
Copyright (c) 2005-2025, University of Oxford.
4+
All rights reserved.
5+
6+
University of Oxford means the Chancellor, Masters and Scholars of the
7+
University of Oxford, having an administrative office at Wellington
8+
Square, Oxford OX1 2JD, UK.
9+
10+
This file is part of Chaste.
11+
12+
Redistribution and use in source and binary forms, with or without
13+
modification, 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+
23+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29+
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32+
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33+
34+
*/
35+
36+
#include "SimplifiedNagaiHondaForce.hpp"
37+
38+
template<unsigned DIM>
39+
SimplifiedNagaiHondaForce<DIM>::SimplifiedNagaiHondaForce()
40+
: AbstractForce<DIM>(),
41+
mNagaiHondaDeformationEnergyParameter(100.0), // This is 1.0 in the Nagai & Honda paper.
42+
mNagaiHondaMembraneSurfaceEnergyParameter(10.0), // This is 0.1 in the Nagai & Honda paper.
43+
mNagaiHondaCellCellAdhesionEnergyParameter(0.5), // This corresponds to a value of 1.0 for
44+
// the sigma parameter in the Nagai & Honda
45+
// paper. In the paper, the sigma value is
46+
// set to 0.01.
47+
mNagaiHondaCellBoundaryAdhesionEnergyParameter(1.0), // This is 0.01 in the Nagai & Honda paper
48+
mNagaiHondaTargetAreaParameter(0.5*sqrt(3.0)), // This corresponds to a regular hexagon with edge length 0.5
49+
mNagaiHondaTargetPerimeterParameter(3.0)
50+
{
51+
}
52+
53+
template<unsigned DIM>
54+
SimplifiedNagaiHondaForce<DIM>::~SimplifiedNagaiHondaForce()
55+
{
56+
}
57+
58+
template<unsigned DIM>
59+
void SimplifiedNagaiHondaForce<DIM>::AddForceContribution(AbstractCellPopulation<DIM>& rCellPopulation)
60+
{
61+
// Throw an exception message if not using a VertexBasedCellPopulation
62+
if (dynamic_cast<VertexBasedCellPopulation<DIM>*>(&rCellPopulation) == nullptr)
63+
{
64+
EXCEPTION("SimplifiedNagaiHondaForce is to be used with a VertexBasedCellPopulation only");
65+
}
66+
67+
// Define some helper variables
68+
VertexBasedCellPopulation<DIM>* p_cell_population = static_cast<VertexBasedCellPopulation<DIM>*>(&rCellPopulation);
69+
unsigned num_nodes = p_cell_population->GetNumNodes();
70+
unsigned num_elements = p_cell_population->GetNumElements();
71+
72+
/*
73+
* Check if a subclass of AbstractTargetAreaModifier is being used by
74+
* interrogating the first cell (assuming either all cells, or no cells, in
75+
* the population have the CellData item "target area").
76+
*/
77+
bool using_target_area_modifier = p_cell_population->Begin()->GetCellData()->HasItem("target area");
78+
79+
if (using_target_area_modifier)
80+
{
81+
// This simple model does not support a target area modifier
82+
NEVER_REACHED;
83+
}
84+
85+
// Begin by computing the area and perimeter of each element in the mesh, to avoid having to do this multiple times
86+
std::vector<double> element_areas(num_elements);
87+
std::vector<double> element_perimeters(num_elements);
88+
std::vector<double> target_areas(num_elements);
89+
std::vector<double> target_perimeters(num_elements);
90+
91+
for (typename VertexMesh<DIM,DIM>::VertexElementIterator elem_iter = p_cell_population->rGetMesh().GetElementIteratorBegin();
92+
elem_iter != p_cell_population->rGetMesh().GetElementIteratorEnd();
93+
++elem_iter)
94+
{
95+
unsigned elem_index = elem_iter->GetIndex();
96+
element_areas[elem_index] = p_cell_population->rGetMesh().GetVolumeOfElement(elem_index);
97+
element_perimeters[elem_index] = p_cell_population->rGetMesh().GetSurfaceAreaOfElement(elem_index);
98+
99+
target_areas[elem_index] = mNagaiHondaTargetAreaParameter;
100+
target_perimeters[elem_index] = mNagaiHondaTargetPerimeterParameter;
101+
}
102+
103+
// Iterate over vertices in the cell population
104+
for (unsigned node_index=0; node_index<num_nodes; node_index++)
105+
{
106+
Node<DIM>* p_this_node = p_cell_population->GetNode(node_index);
107+
108+
/*
109+
* The force on this Node is given by the gradient of the total free
110+
* energy of the CellPopulation, evaluated at the position of the vertex. This
111+
* free energy is the sum of the free energies of all CellPtrs in
112+
* the cell population. The free energy of each CellPtr is comprised of three
113+
* parts - a cell deformation energy, a membrane surface tension energy
114+
* and an adhesion energy.
115+
*
116+
* Note that since the movement of this Node only affects the free energy
117+
* of the CellPtrs containing it, we can just consider the contributions
118+
* to the free energy gradient from each of these CellPtrs.
119+
*/
120+
c_vector<double, DIM> deformation_contribution = zero_vector<double>(DIM);
121+
c_vector<double, DIM> membrane_surface_tension_contribution = zero_vector<double>(DIM);
122+
c_vector<double, DIM> adhesion_contribution = zero_vector<double>(DIM);
123+
124+
// Find the indices of the elements owned by this node
125+
std::set<unsigned> containing_elem_indices = p_cell_population->GetNode(node_index)->rGetContainingElementIndices();
126+
127+
// Iterate over these elements
128+
for (std::set<unsigned>::iterator iter = containing_elem_indices.begin();
129+
iter != containing_elem_indices.end();
130+
++iter)
131+
{
132+
// Get this element, its index and its number of nodes
133+
VertexElement<DIM, DIM>* p_element = p_cell_population->GetElement(*iter);
134+
unsigned elem_index = p_element->GetIndex();
135+
unsigned num_nodes_elem = p_element->GetNumNodes();
136+
137+
// Find the local index of this node in this element
138+
unsigned local_index = p_element->GetNodeLocalIndex(node_index);
139+
140+
// Add the force contribution from this cell's deformation energy (note the minus sign)
141+
c_vector<double, DIM> element_area_gradient = p_cell_population->rGetMesh().GetAreaGradientOfElementAtNode(p_element, local_index);
142+
deformation_contribution -= 2*GetNagaiHondaDeformationEnergyParameter()*(element_areas[elem_index] - target_areas[elem_index])*element_area_gradient;
143+
144+
// Get the previous and next nodes in this element
145+
unsigned previous_node_local_index = (num_nodes_elem+local_index-1)%num_nodes_elem;
146+
Node<DIM>* p_previous_node = p_element->GetNode(previous_node_local_index);
147+
148+
unsigned next_node_local_index = (local_index+1)%num_nodes_elem;
149+
Node<DIM>* p_next_node = p_element->GetNode(next_node_local_index);
150+
151+
// Compute the adhesion parameter for each of these edges
152+
double previous_edge_adhesion_parameter = GetAdhesionParameter(p_previous_node, p_this_node, *p_cell_population);
153+
double next_edge_adhesion_parameter = GetAdhesionParameter(p_this_node, p_next_node, *p_cell_population);
154+
155+
// Compute the gradient of each these edges, computed at the present node
156+
c_vector<double, DIM> previous_edge_gradient = -p_cell_population->rGetMesh().GetNextEdgeGradientOfElementAtNode(p_element, previous_node_local_index);
157+
c_vector<double, DIM> next_edge_gradient = p_cell_population->rGetMesh().GetNextEdgeGradientOfElementAtNode(p_element, local_index);
158+
159+
// Add the force contribution from cell-cell and cell-boundary adhesion (note the minus sign)
160+
adhesion_contribution -= previous_edge_adhesion_parameter*previous_edge_gradient + next_edge_adhesion_parameter*next_edge_gradient;
161+
162+
// Add the force contribution from this cell's membrane surface tension (note the minus sign)
163+
c_vector<double, DIM> element_perimeter_gradient;
164+
element_perimeter_gradient = previous_edge_gradient + next_edge_gradient;
165+
//double cell_target_perimeter = 2*sqrt(M_PI*target_areas[elem_index]);
166+
membrane_surface_tension_contribution -= 2*GetNagaiHondaMembraneSurfaceEnergyParameter()*(element_perimeters[elem_index] - target_perimeters[elem_index])*element_perimeter_gradient;
167+
}
168+
169+
c_vector<double, DIM> force_on_node = deformation_contribution + membrane_surface_tension_contribution + adhesion_contribution;
170+
p_cell_population->GetNode(node_index)->AddAppliedForceContribution(force_on_node);
171+
}
172+
}
173+
174+
template<unsigned DIM>
175+
double SimplifiedNagaiHondaForce<DIM>::GetAdhesionParameter(Node<DIM>* pNodeA, Node<DIM>* pNodeB, VertexBasedCellPopulation<DIM>& rVertexCellPopulation)
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+
double adhesion_parameter = GetNagaiHondaCellCellAdhesionEnergyParameter();
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+
adhesion_parameter = GetNagaiHondaCellBoundaryAdhesionEnergyParameter();
198+
}
199+
200+
return adhesion_parameter;
201+
}
202+
203+
template<unsigned DIM>
204+
double SimplifiedNagaiHondaForce<DIM>::GetNagaiHondaDeformationEnergyParameter()
205+
{
206+
return mNagaiHondaDeformationEnergyParameter;
207+
}
208+
209+
template<unsigned DIM>
210+
double SimplifiedNagaiHondaForce<DIM>::GetNagaiHondaMembraneSurfaceEnergyParameter()
211+
{
212+
return mNagaiHondaMembraneSurfaceEnergyParameter;
213+
}
214+
215+
template<unsigned DIM>
216+
double SimplifiedNagaiHondaForce<DIM>::GetNagaiHondaCellCellAdhesionEnergyParameter()
217+
{
218+
return mNagaiHondaCellCellAdhesionEnergyParameter;
219+
}
220+
221+
template<unsigned DIM>
222+
double SimplifiedNagaiHondaForce<DIM>::GetNagaiHondaCellBoundaryAdhesionEnergyParameter()
223+
{
224+
return mNagaiHondaCellBoundaryAdhesionEnergyParameter;
225+
}
226+
227+
template<unsigned DIM>
228+
double SimplifiedNagaiHondaForce<DIM>::GetNagaiHondaTargetAreaParameter()
229+
{
230+
return mNagaiHondaTargetAreaParameter;
231+
}
232+
233+
template<unsigned DIM>
234+
void SimplifiedNagaiHondaForce<DIM>::SetNagaiHondaDeformationEnergyParameter(double deformationEnergyParameter)
235+
{
236+
mNagaiHondaDeformationEnergyParameter = deformationEnergyParameter;
237+
}
238+
239+
template<unsigned DIM>
240+
void SimplifiedNagaiHondaForce<DIM>::SetNagaiHondaMembraneSurfaceEnergyParameter(double membraneSurfaceEnergyParameter)
241+
{
242+
mNagaiHondaMembraneSurfaceEnergyParameter = membraneSurfaceEnergyParameter;
243+
}
244+
245+
template<unsigned DIM>
246+
void SimplifiedNagaiHondaForce<DIM>::SetNagaiHondaCellCellAdhesionEnergyParameter(double cellCellAdhesionEnergyParameter)
247+
{
248+
mNagaiHondaCellCellAdhesionEnergyParameter = cellCellAdhesionEnergyParameter;
249+
}
250+
251+
template<unsigned DIM>
252+
void SimplifiedNagaiHondaForce<DIM>::SetNagaiHondaCellBoundaryAdhesionEnergyParameter(double cellBoundaryAdhesionEnergyParameter)
253+
{
254+
mNagaiHondaCellBoundaryAdhesionEnergyParameter = cellBoundaryAdhesionEnergyParameter;
255+
}
256+
257+
template<unsigned DIM>
258+
void SimplifiedNagaiHondaForce<DIM>::SetNagaiHondaTargetAreaParameter(double nagaiHondaTargetAreaParameter)
259+
{
260+
mNagaiHondaTargetAreaParameter = nagaiHondaTargetAreaParameter;
261+
}
262+
263+
template<unsigned DIM>
264+
void SimplifiedNagaiHondaForce<DIM>::SetNagaiHondaTargetPerimeterParameter(double nagaiHondaTargetPerimeterParameter)
265+
{
266+
mNagaiHondaTargetPerimeterParameter = nagaiHondaTargetPerimeterParameter;
267+
}
268+
269+
template<unsigned DIM>
270+
void SimplifiedNagaiHondaForce<DIM>::OutputForceParameters(out_stream& rParamsFile)
271+
{
272+
*rParamsFile << "\t\t\t<NagaiHondaDeformationEnergyParameter>" << mNagaiHondaDeformationEnergyParameter << "</NagaiHondaDeformationEnergyParameter>\n";
273+
*rParamsFile << "\t\t\t<NagaiHondaMembraneSurfaceEnergyParameter>" << mNagaiHondaMembraneSurfaceEnergyParameter << "</NagaiHondaMembraneSurfaceEnergyParameter>\n";
274+
*rParamsFile << "\t\t\t<NagaiHondaCellCellAdhesionEnergyParameter>" << mNagaiHondaCellCellAdhesionEnergyParameter << "</NagaiHondaCellCellAdhesionEnergyParameter>\n";
275+
*rParamsFile << "\t\t\t<NagaiHondaCellBoundaryAdhesionEnergyParameter>" << mNagaiHondaCellBoundaryAdhesionEnergyParameter << "</NagaiHondaCellBoundaryAdhesionEnergyParameter>\n";
276+
*rParamsFile << "\t\t\t<NagaiHondaTargetAreaParameter>" << mNagaiHondaTargetAreaParameter << "</NagaiHondaTargetAreaParameter>\n";
277+
*rParamsFile << "\t\t\t<NagaiHondaTargetPerimeterParameter>" << mNagaiHondaTargetPerimeterParameter << "</NagaiHondaTargetPerimeterParameter>\n";
278+
279+
// Call method on direct parent class
280+
AbstractForce<DIM>::OutputForceParameters(rParamsFile);
281+
}
282+
283+
// Explicit instantiation
284+
template class SimplifiedNagaiHondaForce<1>;
285+
template class SimplifiedNagaiHondaForce<2>;
286+
template class SimplifiedNagaiHondaForce<3>;
287+
288+
// Serialization for Boost >= 1.36
289+
#include "SerializationExportWrapperForCpp.hpp"
290+
EXPORT_TEMPLATE_CLASS_SAME_DIMS(SimplifiedNagaiHondaForce)

0 commit comments

Comments
 (0)