Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/Chaste/OpenVT
Browse files Browse the repository at this point in the history
jmosborne committed Aug 30, 2024
2 parents b67a7d8 + 7d695fe commit f11fb01
Showing 12 changed files with 1,694 additions and 0 deletions.
106 changes: 106 additions & 0 deletions src/Test02aMonolayerGrowth/FixedDurationCellCycleModel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
Copyright (c) 2005-2022, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "AbstractSimplePhaseBasedCellCycleModel.hpp"
#include "DifferentiatedCellProliferativeType.hpp"

#include "FixedDurationCellCycleModel.hpp"

template<class Archive>
void FixedDurationCellCycleModel::serialize(Archive & archive, const unsigned int version)
{
// Archive cell-cycle model using serialization code from AbstractSimplePhaseBasedCellCycleModel
archive & boost::serialization::base_object<AbstractSimplePhaseBasedCellCycleModel>(*this);
}

FixedDurationCellCycleModel::FixedDurationCellCycleModel()
: AbstractSimplePhaseBasedCellCycleModel()
{
SetPhaseDurations();
}

void FixedDurationCellCycleModel::SetPhaseDurations()
{
SetStemCellG1Duration(7.0);
SetTransitCellG1Duration(7.0);
SetSDuration(6.0);
SetG2Duration(3.0);
SetMDuration(2.0);
SetMinimumGapDuration(3.0);
}

void FixedDurationCellCycleModel::SetG1Duration()
{
assert(mpCell != NULL); // Make sure cell exists

mG1Duration = 7.0;
}

AbstractCellCycleModel* FixedDurationCellCycleModel::CreateCellCycleModel()
{
// Create a new cell-cycle model
FixedDurationCellCycleModel* pCellCycleModel = new FixedDurationCellCycleModel();
return pCellCycleModel;
}

void FixedDurationCellCycleModel::UpdateCellCyclePhase()
{
double timeSinceBirth = GetAge();
assert(timeSinceBirth >= 0);

if (mpCell->GetCellProliferativeType()->IsType<DifferentiatedCellProliferativeType>())
{
mCurrentCellCyclePhase = G_ZERO_PHASE;
}
else if (timeSinceBirth < GetG1Duration())
{
mCurrentCellCyclePhase = G_ONE_PHASE;
}
else if (timeSinceBirth < GetG1Duration() + GetSDuration())
{
mCurrentCellCyclePhase = S_PHASE;
}
else if (timeSinceBirth < GetG1Duration() + GetSDuration() + GetG2Duration())
{
mCurrentCellCyclePhase = G_TWO_PHASE;
}
else if (timeSinceBirth < GetG1Duration() + GetSDuration() + GetG2Duration() + GetMDuration())
{
mCurrentCellCyclePhase = M_PHASE;
}
}

#include "SerializationExportWrapperForCpp.hpp"
CHASTE_CLASS_EXPORT(FixedDurationCellCycleModel)
69 changes: 69 additions & 0 deletions src/Test02aMonolayerGrowth/FixedDurationCellCycleModel.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
Copyright (c) 2005-2022, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef FIXEDDURATIONCELLCYCLEMODEL_HPP_
#define FIXEDDURATIONCELLCYCLEMODEL_HPP_

#include "AbstractSimplePhaseBasedCellCycleModel.hpp"

// "Simple" cell-cycle model: phase durations are set when the model is created.
class FixedDurationCellCycleModel : public AbstractSimplePhaseBasedCellCycleModel
{
private:
// For archiving (saving or loading) the cell-cycle model object in a cell-based simulation.
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & archive, const unsigned int version);

void SetPhaseDurations();
void SetG1Duration() override;

public:
FixedDurationCellCycleModel();

// Override builder method for new copies of the cell-cycle model.
AbstractCellCycleModel* CreateCellCycleModel() override;

// Override to start phase from G1
void UpdateCellCyclePhase() override;
};

// Provides a unique identifier for the custom cell-cycle model.
// Needed for archiving and for writing out parameters file.
// Simulations will throw errors if missing.
#include "SerializationExportWrapper.hpp"
CHASTE_CLASS_EXPORT(FixedDurationCellCycleModel)

#endif // FIXEDDURATIONCELLCYCLEMODEL_HPP_
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
Copyright (c) 2005-2022, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "AbstractSimplePhaseBasedCellCycleModel.hpp"
#include "DifferentiatedCellProliferativeType.hpp"

#include "FixedDurationCellCycleModelWithGrowthInhibition.hpp"

#include <iostream>

#include "RandomNumberGenerator.hpp"

template<class Archive>
void FixedDurationCellCycleModelWithGrowthInhibition::serialize(Archive & archive, const unsigned int version)
{
// Archive cell-cycle model using serialization code from AbstractSimplePhaseBasedCellCycleModel
archive & boost::serialization::base_object<AbstractSimplePhaseBasedCellCycleModel>(*this);
}

FixedDurationCellCycleModelWithGrowthInhibition::FixedDurationCellCycleModelWithGrowthInhibition()
: AbstractSimplePhaseBasedCellCycleModel()
{
SetPhaseDurations();
mPhaseTimer = 0.0;
mLastCellAge = 0.0;
}

void FixedDurationCellCycleModelWithGrowthInhibition::ResetForDivision()
{
AbstractCellCycleModel::ResetForDivision();
mCurrentCellCyclePhase = G_ONE_PHASE;
mPhaseTimer = 0.0;
mLastCellAge = 0.0;
}

void FixedDurationCellCycleModelWithGrowthInhibition::SetPhaseDurations()
{
SetStemCellG1Duration(7.0);
SetTransitCellG1Duration(7.0);
SetSDuration(6.0);
SetG2Duration(3.0);
SetMDuration(2.0);
SetMinimumGapDuration(3.0);
}

void FixedDurationCellCycleModelWithGrowthInhibition::SetG1Duration()
{
assert(mpCell != NULL); // Make sure cell exists

mG1Duration = 7.0;
}

AbstractCellCycleModel* FixedDurationCellCycleModelWithGrowthInhibition::CreateCellCycleModel()
{
// Create a new cell-cycle model
FixedDurationCellCycleModelWithGrowthInhibition* pCellCycleModel = new FixedDurationCellCycleModelWithGrowthInhibition();
return pCellCycleModel;
}


void FixedDurationCellCycleModelWithGrowthInhibition::SetPhaseTimer(const double value) {
mPhaseTimer = value;
}

bool FixedDurationCellCycleModelWithGrowthInhibition::ReadyToDivide() {
assert(mpCell != nullptr);

if (!mReadyToDivide)
{
UpdateCellCyclePhase();
if ((mCurrentCellCyclePhase != G_ZERO_PHASE) &&
(mPhaseTimer >= GetMDuration() + GetG1Duration() + GetSDuration() + GetG2Duration()) &&
(mCurrentCellCyclePhase == M_PHASE))
{
mReadyToDivide = true;
}
}

mpCell->GetCellData()->SetItem("growth inhibited", 0.0);
return mReadyToDivide;
}

void FixedDurationCellCycleModelWithGrowthInhibition::UpdateCellCyclePhase()
{
double timeSinceBirth = GetAge();
assert(timeSinceBirth >= 0);

// Update cell growth phase timer
double change_in_cell_age = timeSinceBirth - mLastCellAge;
mPhaseTimer += change_in_cell_age;
mLastCellAge = timeSinceBirth;

// Select the correct phase
if (mpCell->GetCellProliferativeType()->IsType<DifferentiatedCellProliferativeType>())
{
mCurrentCellCyclePhase = G_ZERO_PHASE;
}
else if (mPhaseTimer < GetG1Duration())
{
if (mpCell->GetCellData()->GetItem("growth inhibited") != 0.0) {
//std::cout << "Cell inhibited\n";
mPhaseTimer -= change_in_cell_age;
return;
}
mCurrentCellCyclePhase = G_ONE_PHASE;
}
else if (mPhaseTimer < GetG1Duration() + GetSDuration())
{
mCurrentCellCyclePhase = S_PHASE;
}
else if (mPhaseTimer < GetG1Duration() + GetSDuration() + GetG2Duration())
{
if (mpCell->GetCellData()->GetItem("growth inhibited") != 0.0) {
//std::cout << "Cell inhibited\n";
mPhaseTimer -= change_in_cell_age;
return;
}
mCurrentCellCyclePhase = G_TWO_PHASE;
}
else if (mPhaseTimer < GetG1Duration() + GetSDuration() + GetG2Duration() + GetMDuration())
{
mCurrentCellCyclePhase = M_PHASE;
}

mpCell->GetCellData()->SetItem("cell age", mPhaseTimer);
}

#include "SerializationExportWrapperForCpp.hpp"
CHASTE_CLASS_EXPORT(FixedDurationCellCycleModelWithGrowthInhibition)
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
Copyright (c) 2005-2022, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef FIXEDDURATIONCELLCYCLEMODELWITHGROWTHINHIBITION_HPP_
#define FIXEDDURATIONCELLCYCLEMODELWITHGROWTHINHIBITION_HPP_

#include "AbstractSimplePhaseBasedCellCycleModel.hpp"

// "Simple" cell-cycle model: phase durations are set when the model is created.
class FixedDurationCellCycleModelWithGrowthInhibition : public AbstractSimplePhaseBasedCellCycleModel
{
private:
// For archiving (saving or loading) the cell-cycle model object in a cell-based simulation.
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & archive, const unsigned int version);

void SetPhaseDurations();
void SetG1Duration() override;

double mPhaseTimer;
double mLastCellAge;

public:
FixedDurationCellCycleModelWithGrowthInhibition();

// Override builder method for new copies of the cell-cycle model.
AbstractCellCycleModel* CreateCellCycleModel() override;

bool ReadyToDivide() override;

void ResetForDivision() override;

// Override to start phase from G1
void UpdateCellCyclePhase() override;

void SetPhaseTimer(const double value);
};

// Provides a unique identifier for the custom cell-cycle model.
// Needed for archiving and for writing out parameters file.
// Simulations will throw errors if missing.
#include "SerializationExportWrapper.hpp"
CHASTE_CLASS_EXPORT(FixedDurationCellCycleModelWithGrowthInhibition)

#endif // FIXEDDURATIONCELLCYCLEMODELWITHGROWTHINHIBITION_HPP_
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
/*
Copyright (c) 2005-2023, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "GeneralisedLinearSpringForceWithMinDistanceItem.hpp"

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::GeneralisedLinearSpringForceWithMinDistanceItem()
: AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM>(),
mMeinekeSpringStiffness(5.0), // denoted by mu in Meineke et al, 2001 (doi:10.1046/j.0960-7722.2001.00216.x)
mMeinekeDivisionRestingSpringLength(0.5),
mMeinekeSpringGrowthDuration(1.0)
{
if (SPACE_DIM == 1)
{
mMeinekeSpringStiffness = 5.0;
}
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
double GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::VariableSpringConstantMultiplicationFactor(unsigned nodeAGlobalIndex,
unsigned nodeBGlobalIndex,
AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>& rCellPopulation,
bool isCloserThanRestLength)
{
return 1.0;
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::~GeneralisedLinearSpringForceWithMinDistanceItem()
{
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
c_vector<double, SPACE_DIM> GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::CalculateForceBetweenNodes(unsigned nodeAGlobalIndex,
unsigned nodeBGlobalIndex,
AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>& rCellPopulation)
{
// We should only ever calculate the force between two distinct nodes
assert(nodeAGlobalIndex != nodeBGlobalIndex);

Node<SPACE_DIM>* p_node_a = rCellPopulation.GetNode(nodeAGlobalIndex);
Node<SPACE_DIM>* p_node_b = rCellPopulation.GetNode(nodeBGlobalIndex);

// Get the node locations
const c_vector<double, SPACE_DIM>& r_node_a_location = p_node_a->rGetLocation();
const c_vector<double, SPACE_DIM>& r_node_b_location = p_node_b->rGetLocation();

// Get the node radii for a NodeBasedCellPopulation
double node_a_radius = 0.0;
double node_b_radius = 0.0;

// Update actual cell radius
CellPtr p_cell_A = rCellPopulation.GetCellUsingLocationIndex(nodeAGlobalIndex);
CellPtr p_cell_B = rCellPopulation.GetCellUsingLocationIndex(nodeBGlobalIndex);

double current_radius_a = p_cell_A->GetCellData()->GetItem("Current Radius");
p_node_a->SetRadius(current_radius_a);
double current_radius_b = p_cell_B->GetCellData()->GetItem("Current Radius");
p_node_b->SetRadius(current_radius_b);

if (bool(dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation)))
{
node_a_radius = p_node_a->GetRadius();
node_b_radius = p_node_b->GetRadius();
}

// Get the unit vector parallel to the line joining the two nodes
c_vector<double, SPACE_DIM> unit_difference;
/*
* We use the mesh method GetVectorFromAtoB() to compute the direction of the
* unit vector along the line joining the two nodes, rather than simply subtract
* their positions, because this method can be overloaded (e.g. to enforce a
* periodic boundary in Cylindrical2dMesh).
*/
unit_difference = rCellPopulation.rGetMesh().GetVectorFromAtoB(r_node_a_location, r_node_b_location);

// Calculate the distance between the two nodes
double distance_between_nodes = norm_2(unit_difference);
assert(distance_between_nodes > 0);
assert(!std::isnan(distance_between_nodes));

unit_difference /= distance_between_nodes;

/*
* If mUseCutOffLength has been set, then there is zero force between
* two nodes located a distance apart greater than mMechanicsCutOffLength in AbstractTwoBodyInteractionForce.
*/
if (this->mUseCutOffLength)
{
if (distance_between_nodes >= this->GetCutOffLength())
{
return zero_vector<double>(SPACE_DIM); // c_vector<double,SPACE_DIM>() is not guaranteed to be fresh memory
}
}

/*
* Calculate the rest length of the spring connecting the two nodes with a default
* value of 1.0.
*/
double rest_length_final = 1.0;

if (bool(dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation)))
{
rest_length_final = static_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation)->GetRestLength(nodeAGlobalIndex, nodeBGlobalIndex);
}
else if (bool(dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation)))
{
assert(node_a_radius > 0 && node_b_radius > 0);
rest_length_final = node_a_radius+node_b_radius;
}

double rest_length = rest_length_final;


// Update growth inhibition
double combined_resting_cell_radius = node_a_radius + node_b_radius;
double compression = combined_resting_cell_radius - distance_between_nodes;
if (compression > 0.2 * node_a_radius) {
p_cell_A->GetCellData()->SetItem("growth inhibited", 1.0);
}


if (compression > 0.2 * node_b_radius) {
p_cell_B->GetCellData()->SetItem("growth inhibited", 1.0);
}


double ageA = p_cell_A->GetAge();
double ageB = p_cell_B->GetAge();

assert(!std::isnan(ageA));
assert(!std::isnan(ageB));

/*
* If the cells are both newly divided, then the rest length of the spring
* connecting them grows linearly with time, until 1 hour after division.
*/
if (ageA < mMeinekeSpringGrowthDuration && ageB < mMeinekeSpringGrowthDuration)
{
AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>* p_static_cast_cell_population = static_cast<AbstractCentreBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation);

std::pair<CellPtr,CellPtr> cell_pair = p_static_cast_cell_population->CreateCellPair(p_cell_A, p_cell_B);

if (p_static_cast_cell_population->IsMarkedSpring(cell_pair))
{
// Spring rest length increases from a small value to the normal rest length over 1 hour
double lambda = mMeinekeDivisionRestingSpringLength;
rest_length = lambda + (rest_length_final - lambda) * ageA/mMeinekeSpringGrowthDuration;
}
if (ageA + SimulationTime::Instance()->GetTimeStep() >= mMeinekeSpringGrowthDuration)
{
// This spring is about to go out of scope
p_static_cast_cell_population->UnmarkSpring(cell_pair);
}
}

/*
* For apoptosis, progressively reduce the radius of the cell
*/
double a_rest_length = rest_length*0.5;
double b_rest_length = a_rest_length;

if (bool(dynamic_cast<NodeBasedCellPopulation<SPACE_DIM>*>(&rCellPopulation)))
{
assert(node_a_radius > 0 && node_b_radius > 0);
a_rest_length = (node_a_radius/(node_a_radius+node_b_radius))*rest_length;
b_rest_length = (node_b_radius/(node_a_radius+node_b_radius))*rest_length;
}

/*
* If either of the cells has begun apoptosis, then the length of the spring
* connecting them decreases linearly with time.
*/
if (p_cell_A->HasApoptosisBegun())
{
double time_until_death_a = p_cell_A->GetTimeUntilDeath();
a_rest_length = a_rest_length * time_until_death_a / p_cell_A->GetApoptosisTime();
}
if (p_cell_B->HasApoptosisBegun())
{
double time_until_death_b = p_cell_B->GetTimeUntilDeath();
b_rest_length = b_rest_length * time_until_death_b / p_cell_B->GetApoptosisTime();
}

rest_length = a_rest_length + b_rest_length;
//assert(rest_length <= 1.0+1e-12); ///\todo #1884 Magic number: would "<= 1.0" do?

// Although in this class the 'spring constant' is a constant parameter, in
// subclasses it can depend on properties of each of the cells
double overlap = distance_between_nodes - rest_length;
bool is_closer_than_rest_length = (overlap <= 0);
double multiplication_factor = VariableSpringConstantMultiplicationFactor(nodeAGlobalIndex, nodeBGlobalIndex, rCellPopulation, is_closer_than_rest_length);
double spring_stiffness = mMeinekeSpringStiffness;

if (bool(dynamic_cast<MeshBasedCellPopulation<ELEMENT_DIM,SPACE_DIM>*>(&rCellPopulation)))
{
return multiplication_factor * spring_stiffness * unit_difference * overlap;
}
else
{
// A reasonably stable simple force law
if (is_closer_than_rest_length) //overlap is negative
{
//log(x+1) is undefined for x<=-1
assert(overlap > -rest_length_final);
c_vector<double, SPACE_DIM> temp = multiplication_factor*spring_stiffness * unit_difference * rest_length_final* log(1.0 + overlap/rest_length_final);
return temp;
}
else
{
double alpha = 5.0;
c_vector<double, SPACE_DIM> temp = multiplication_factor*spring_stiffness * unit_difference * overlap * exp(-alpha * overlap/rest_length_final);
return temp;
}
}
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
double GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::GetMeinekeSpringStiffness()
{
return mMeinekeSpringStiffness;
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
double GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::GetMeinekeDivisionRestingSpringLength()
{
return mMeinekeDivisionRestingSpringLength;
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
double GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::GetMeinekeSpringGrowthDuration()
{
return mMeinekeSpringGrowthDuration;
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::SetMeinekeSpringStiffness(double springStiffness)
{
assert(springStiffness > 0.0);
mMeinekeSpringStiffness = springStiffness;
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::SetMeinekeDivisionRestingSpringLength(double divisionRestingSpringLength)
{
assert(divisionRestingSpringLength <= 1.0);
assert(divisionRestingSpringLength >= 0.0);

mMeinekeDivisionRestingSpringLength = divisionRestingSpringLength;
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::SetMeinekeSpringGrowthDuration(double springGrowthDuration)
{
assert(springGrowthDuration >= 0.0);

mMeinekeSpringGrowthDuration = springGrowthDuration;
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void GeneralisedLinearSpringForceWithMinDistanceItem<ELEMENT_DIM,SPACE_DIM>::OutputForceParameters(out_stream& rParamsFile)
{
*rParamsFile << "\t\t\t<MeinekeSpringStiffness>" << mMeinekeSpringStiffness << "</MeinekeSpringStiffness>\n";
*rParamsFile << "\t\t\t<MeinekeDivisionRestingSpringLength>" << mMeinekeDivisionRestingSpringLength << "</MeinekeDivisionRestingSpringLength>\n";
*rParamsFile << "\t\t\t<MeinekeSpringGrowthDuration>" << mMeinekeSpringGrowthDuration << "</MeinekeSpringGrowthDuration>\n";

// Call method on direct parent class
AbstractTwoBodyInteractionForce<ELEMENT_DIM,SPACE_DIM>::OutputForceParameters(rParamsFile);
}

// Explicit instantiation
template class GeneralisedLinearSpringForceWithMinDistanceItem<1,1>;
template class GeneralisedLinearSpringForceWithMinDistanceItem<1,2>;
template class GeneralisedLinearSpringForceWithMinDistanceItem<2,2>;
template class GeneralisedLinearSpringForceWithMinDistanceItem<1,3>;
template class GeneralisedLinearSpringForceWithMinDistanceItem<2,3>;
template class GeneralisedLinearSpringForceWithMinDistanceItem<3,3>;

// Serialization for Boost >= 1.36
#include "SerializationExportWrapperForCpp.hpp"
EXPORT_TEMPLATE_CLASS_ALL_DIMS(GeneralisedLinearSpringForceWithMinDistanceItem)
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/*
Copyright (c) 2005-2023, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef GENERALISEDLINEARSPRINGFORCEWITHMINDISTANCEITEM_HPP_
#define GENERALISEDLINEARSPRINGFORCEWITHMINDISTANCEITEM_HPP_

#include "AbstractTwoBodyInteractionForce.hpp"

#include "ChasteSerialization.hpp"
#include <boost/serialization/base_object.hpp>

/**
* A force law employed by Meineke et al (2001) in their off-lattice
* model of the intestinal crypt (doi:10.1046/j.0960-7722.2001.00216.x).
*
* Each pair of neighbouring nodes are assumed to be connected by a linear
* spring. The force of node \f$i\f$ is given
* by
*
* \f[
* \mathbf{F}_{i}(t) = \sum_{j} \mu_{i,j} ( || \mathbf{r}_{i,j} || - s_{i,j}(t) ) \hat{\mathbf{r}}_{i,j}.
* \f]
*
* Here \f$\mu_{i,j}\f$ is the spring constant for the spring between nodes
* \f$i\f$ and \f$j\f$, \f$s_{i,j}(t)\f$ is its natural length at time \f$t\f$,
* \f$\mathbf{r}_{i,j}\f$ is their relative displacement and a hat (\f$\hat{}\f$)
* denotes a unit vector.
*
* Length is scaled by natural length.
* Time is in hours.
*/
template<unsigned ELEMENT_DIM, unsigned SPACE_DIM=ELEMENT_DIM>
class GeneralisedLinearSpringForceWithMinDistanceItem : public AbstractTwoBodyInteractionForce<ELEMENT_DIM, SPACE_DIM>
{
friend class TestForces;

private:

/** Needed for serialization. */
friend class boost::serialization::access;
/**
* Archive the object and its member variables.
*
* @param archive the archive
* @param version the current version of this class
*/
template<class Archive>
void serialize(Archive & archive, const unsigned int version)
{
archive & boost::serialization::base_object<AbstractTwoBodyInteractionForce<ELEMENT_DIM, SPACE_DIM> >(*this);
archive & mMeinekeSpringStiffness;
archive & mMeinekeDivisionRestingSpringLength;
archive & mMeinekeSpringGrowthDuration;
}

protected:

/**
* Spring stiffness.
*
* Represented by the parameter mu in the model by Meineke et al (2001) in
* their off-lattice model of the intestinal crypt
* (doi:10.1046/j.0960-7722.2001.00216.x).
*/
double mMeinekeSpringStiffness;

/**
* Initial resting spring length after cell division.
* Has units of cell size at equilibrium rest length
*
* The value of this parameter should be larger than mDivisionSeparation,
* because of pressure from neighbouring springs.
*/
double mMeinekeDivisionRestingSpringLength;

/**
* The time it takes for the springs rest length to increase from
* mMeinekeDivisionRestingSpringLength to its natural length.
*
* The value of this parameter is usually the same as the M Phase of the cell cycle and defaults to 1.
*/
double mMeinekeSpringGrowthDuration;

public:

/**
* Constructor.
*/
GeneralisedLinearSpringForceWithMinDistanceItem();

/**
* Destructor.
*/
virtual ~GeneralisedLinearSpringForceWithMinDistanceItem();

/**
* Return a multiplication factor for the spring constant, which
* returns a default value of 1.
*
* This method may be overridden in subclasses.
*
* @param nodeAGlobalIndex index of one neighbouring node
* @param nodeBGlobalIndex index of the other neighbouring node
* @param rCellPopulation the cell population
* @param isCloserThanRestLength whether the neighbouring nodes lie closer than the rest length of their connecting spring
*
* @return the multiplication factor.
*/
virtual double VariableSpringConstantMultiplicationFactor(unsigned nodeAGlobalIndex,
unsigned nodeBGlobalIndex,
AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>& rCellPopulation,
bool isCloserThanRestLength);

/**
* Overridden CalculateForceBetweenNodes() method.
*
* Calculates the force between two nodes.
*
* Note that this assumes they are connected and is called by AddForceContribution()
*
* @param nodeAGlobalIndex index of one neighbouring node
* @param nodeBGlobalIndex index of the other neighbouring node
* @param rCellPopulation the cell population
* @return The force exerted on Node A by Node B.
*/
c_vector<double, SPACE_DIM> CalculateForceBetweenNodes(unsigned nodeAGlobalIndex,
unsigned nodeBGlobalIndex,
AbstractCellPopulation<ELEMENT_DIM,SPACE_DIM>& rCellPopulation);
/**
* @return mMeinekeSpringStiffness
*/
double GetMeinekeSpringStiffness();

/**
* @return mMeinekeDivisionRestingSpringLength
*/
double GetMeinekeDivisionRestingSpringLength();

/**
* @return mMeinekeSpringGrowthDuration
*/
double GetMeinekeSpringGrowthDuration();

/**
* Set mMeinekeSpringStiffness.
*
* @param springStiffness the new value of mMeinekeSpringStiffness
*/
void SetMeinekeSpringStiffness(double springStiffness);

/**
* Set mMeinekeDivisionRestingSpringLength.
*
* @param divisionRestingSpringLength the new value of mMeinekeDivisionRestingSpringLength
*/
void SetMeinekeDivisionRestingSpringLength(double divisionRestingSpringLength);

/**
* Set mMeinekeSpringGrowthDuration.
*
* @param springGrowthDuration the new value of mMeinekeSpringGrowthDuration
*/
void SetMeinekeSpringGrowthDuration(double springGrowthDuration);

/**
* Overridden OutputForceParameters() method.
*
* @param rParamsFile the file stream to which the parameters are output
*/
virtual void OutputForceParameters(out_stream& rParamsFile);
};

#include "SerializationExportWrapper.hpp"
EXPORT_TEMPLATE_CLASS_ALL_DIMS(GeneralisedLinearSpringForceWithMinDistanceItem)

#endif /*GENERALISEDLINEARSPRINGFORCEWITHMINDISTANCEITEM_HPP_*/
138 changes: 138 additions & 0 deletions src/Test02aMonolayerGrowth/GrowthInhibitionModifier.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
Copyright (c) 2005-2022, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <cmath>

#include "GrowthInhibitionModifier.hpp"
#include "FixedDurationCellCycleModel.hpp"

template<unsigned DIM>
GrowthInhibitionModifier<DIM>::GrowthInhibitionModifier()
: AbstractCellBasedSimulationModifier<DIM>()
{
}

template<unsigned DIM>
GrowthInhibitionModifier<DIM>::~GrowthInhibitionModifier()
{
}

template<unsigned DIM>
void GrowthInhibitionModifier<DIM>::UpdateAtEndOfTimeStep(AbstractCellPopulation<DIM,DIM>& rCellPopulation)
{
UpdateCellData(rCellPopulation);
}

template<unsigned DIM>
void GrowthInhibitionModifier<DIM>::SetupSolve(AbstractCellPopulation<DIM,DIM>& rCellPopulation, std::string outputDirectory)
{
/*
* We must update CellData in SetupSolve(), otherwise it will not have been
* fully initialised by the time we enter the main time loop.
*/
UpdateCellData(rCellPopulation);
}

template<unsigned DIM>
void GrowthInhibitionModifier<DIM>::UpdateCellData(AbstractCellPopulation<DIM,DIM>& rCellPopulation)
{
rCellPopulation.Update(); // Make sure the cell population is updated

// Get volume for each cell
for (typename AbstractCellPopulation<DIM>::Iterator pCell = rCellPopulation.Begin();
pCell != rCellPopulation.End();
++pCell)
{
double cellVolume = rCellPopulation.GetVolumeOfCell(*pCell);
pCell->GetCellData()->SetItem("volume", cellVolume);
}

// Set target radius for each cell
for (typename AbstractCellPopulation<DIM>::Iterator pCell = rCellPopulation.Begin();
pCell != rCellPopulation.End();
++pCell)
{
// Get current cell age in minutes
double cellAge = pCell->GetCellData()->GetItem("cell age") * 60.0;
if (cellAge < 0){
cellAge = 0;
}

// Get G1 duration in minutes
auto pCellCycleModel = static_cast<FixedDurationCellCycleModel*>(pCell->GetCellCycleModel());
double phaseG1Duration = pCellCycleModel->GetG1Duration() * 60.0;

// Compute target relative volume %
double targetRelativeVolume {0.0};

if (cellAge < phaseG1Duration)
{
targetRelativeVolume = 100.0;

} else {
double age = cellAge - phaseG1Duration;
targetRelativeVolume = 100.0 + 0.2850 * age - 0.0002 * age * age;
}

// Compute target radius
double initialRadius = 0.5; // todo: fix magic number from test setup
double initialVolume = (4.0 * M_PI * initialRadius * initialRadius * initialRadius) / 3.0;
double targetVolume = (targetRelativeVolume * initialVolume) / 100.0;
double targetRadius = std::cbrt((3.0 * targetVolume) / (4.0 * M_PI));

// Set target radius
pCell->GetCellData()->SetItem("Radius", targetRadius);
pCell->GetCellData()->SetItem("TargetVolume", targetVolume);

double cellVolume = rCellPopulation.GetVolumeOfCell(*pCell);
pCell->GetCellData()->SetItem("Current Radius", std::cbrt((3.0 * cellVolume) / (4.0 * M_PI)));
}
rCellPopulation.Update(); // Make sure the cell population is updated
}

template<unsigned DIM>
void GrowthInhibitionModifier<DIM>::OutputSimulationModifierParameters(out_stream& rParamsFile)
{
// No parameters to output, so just call method on direct parent class
AbstractCellBasedSimulationModifier<DIM>::OutputSimulationModifierParameters(rParamsFile);
}

// Explicit instantiation
template class GrowthInhibitionModifier<2>;
template class GrowthInhibitionModifier<3>;

// Serialization for Boost >= 1.36
#include "SerializationExportWrapperForCpp.hpp"
EXPORT_TEMPLATE_CLASS_SAME_DIMS(GrowthInhibitionModifier)
118 changes: 118 additions & 0 deletions src/Test02aMonolayerGrowth/GrowthInhibitionModifier.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
Copyright (c) 2005-2022, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef GROWTHINHIBITIONMODIFIER_HPP_
#define GROWTHINHIBITIONMODIFIER_HPP_

#include "ChasteSerialization.hpp"
#include <boost/serialization/base_object.hpp>

#include "AbstractCellBasedSimulationModifier.hpp"

/**
* A modifier class which at each simulation time step records the
* volume of each cell and updates is radius based on the target area.
* The values are stored in the CellData property.
* To be used together with a target area modifier.
*/
template<unsigned DIM>
class GrowthInhibitionModifier : public AbstractCellBasedSimulationModifier<DIM,DIM>
{
/** Needed for serialization. */
friend class boost::serialization::access;
/**
* Boost Serialization method for archiving/checkpointing.
* Archives the object and its member variables.
*
* @param archive The boost archive.
* @param version The current version of this class.
*/
template<class Archive>
void serialize(Archive & archive, const unsigned int version)
{
archive & boost::serialization::base_object<AbstractCellBasedSimulationModifier<DIM,DIM> >(*this);
}

public:

/**
* Default constructor.
*/
GrowthInhibitionModifier();

/**
* Destructor.
*/
virtual ~GrowthInhibitionModifier();

/**
* Overridden UpdateAtEndOfTimeStep() method.
*
* Specify what to do in the simulation at the end of each time step.
*
* @param rCellPopulation reference to the cell population
*/
virtual void UpdateAtEndOfTimeStep(AbstractCellPopulation<DIM,DIM>& rCellPopulation) override;

/**
* Overridden SetupSolve() method.
*
* Specify what to do in the simulation before the start of the time loop.
*
* @param rCellPopulation reference to the cell population
* @param outputDirectory the output directory, relative to where Chaste output is stored
*/
virtual void SetupSolve(AbstractCellPopulation<DIM,DIM>& rCellPopulation, std::string outputDirectory) override;

/**
* Helper method to compute the volume of each cell in the population and store these in the CellData.
*
* @param rCellPopulation reference to the cell population
*/
void UpdateCellData(AbstractCellPopulation<DIM,DIM>& rCellPopulation);

/**
* Overridden OutputSimulationModifierParameters() method.
* Output any simulation modifier parameters to file.
*
* @param rParamsFile the file stream to which the parameters are output
*/
void OutputSimulationModifierParameters(out_stream& rParamsFile) override;
};

#include "SerializationExportWrapper.hpp"
EXPORT_TEMPLATE_CLASS_SAME_DIMS(GrowthInhibitionModifier)

#endif // GROWTHINHIBITIONMODIFIER_HPP_
136 changes: 136 additions & 0 deletions src/Test02aMonolayerGrowth/TissueWidthWriter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
Copyright (c) 2005-2023, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "TissueWidthWriter.hpp"
#include "AbstractCellPopulation.hpp"
#include "MeshBasedCellPopulation.hpp"
#include "CaBasedCellPopulation.hpp"
#include "NodeBasedCellPopulation.hpp"
#include "PottsBasedCellPopulation.hpp"
#include "VertexBasedCellPopulation.hpp"
#include "ImmersedBoundaryCellPopulation.hpp"

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
TissueWidthWriter<ELEMENT_DIM, SPACE_DIM>::TissueWidthWriter()
: AbstractCellPopulationWriter<ELEMENT_DIM, SPACE_DIM>("tissuewidth.dat")
{
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void TissueWidthWriter<ELEMENT_DIM, SPACE_DIM>::VisitAnyPopulation(AbstractCellPopulation<SPACE_DIM, SPACE_DIM>* pCellPopulation)
{
double max_width =-2000000;
double min_width = 2000000;
for (typename AbstractMesh<SPACE_DIM, SPACE_DIM>::NodeIterator node_iter = pCellPopulation->rGetMesh().GetNodeIteratorBegin();
node_iter != pCellPopulation->rGetMesh().GetNodeIteratorEnd();
++node_iter)
{
if (!node_iter->IsDeleted())
{
const c_vector<double,SPACE_DIM>& position = node_iter->rGetLocation();
if(position[0] > max_width){
max_width = position[0];
}
if(position[0] < min_width){
min_width =position[0];
}
}
}
double tissue_width = (max_width - min_width)*20 + 10; // outputs tissue diameter in um and the number of cells
unsigned int num_cells = pCellPopulation->GetNumRealCells();
*this->mpOutStream << min_width << "," << max_width << "," << tissue_width << "," << num_cells << "\n";
std::cout << "Time: " << SimulationTime::Instance()->GetTime() << " Tissue diameter: " << tissue_width << " Number of Cells: " << num_cells << "\n";
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void TissueWidthWriter<ELEMENT_DIM, SPACE_DIM>::Visit(MeshBasedCellPopulation<ELEMENT_DIM, SPACE_DIM>* pCellPopulation)
{
for (typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::NodeIterator node_iter = pCellPopulation->rGetMesh().GetNodeIteratorBegin();
node_iter != pCellPopulation->rGetMesh().GetNodeIteratorEnd();
++node_iter)
{
if (!node_iter->IsDeleted())
{
const c_vector<double,SPACE_DIM>& position = node_iter->rGetLocation();

for (unsigned i=0; i<SPACE_DIM; i++)
{
*this->mpOutStream << position[i] << " ";
}
}
}
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void TissueWidthWriter<ELEMENT_DIM, SPACE_DIM>::Visit(CaBasedCellPopulation<SPACE_DIM>* pCellPopulation)
{
VisitAnyPopulation(pCellPopulation);
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void TissueWidthWriter<ELEMENT_DIM, SPACE_DIM>::Visit(NodeBasedCellPopulation<SPACE_DIM>* pCellPopulation)
{
VisitAnyPopulation(pCellPopulation);
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void TissueWidthWriter<ELEMENT_DIM, SPACE_DIM>::Visit(PottsBasedCellPopulation<SPACE_DIM>* pCellPopulation)
{
VisitAnyPopulation(pCellPopulation);
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void TissueWidthWriter<ELEMENT_DIM, SPACE_DIM>::Visit(VertexBasedCellPopulation<SPACE_DIM>* pCellPopulation)
{
VisitAnyPopulation(pCellPopulation);
}

template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
void TissueWidthWriter<ELEMENT_DIM, SPACE_DIM>::Visit(ImmersedBoundaryCellPopulation<SPACE_DIM>* pCellPopulation)
{
VisitAnyPopulation(pCellPopulation);
}

// Explicit instantiation
template class TissueWidthWriter<1,1>;
template class TissueWidthWriter<1,2>;
template class TissueWidthWriter<2,2>;
template class TissueWidthWriter<1,3>;
template class TissueWidthWriter<2,3>;
template class TissueWidthWriter<3,3>;

#include "SerializationExportWrapperForCpp.hpp"
// Declare identifier for the serializer
EXPORT_TEMPLATE_CLASS_ALL_DIMS(TissueWidthWriter)
181 changes: 181 additions & 0 deletions src/Test02aMonolayerGrowth/TissueWidthWriter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
Copyright (c) 2005-2023, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef TISSUEWIDTHWRITER_HPP_
#define TISSUEWIDTHWRITER_HPP_

#include "AbstractCellPopulationWriter.hpp"
#include "ChasteSerialization.hpp"
#include <boost/serialization/base_object.hpp>

/**
* A class written using the visitor pattern for writing node locations from a cell population to file.
*
* The output file is called results.viznodes by default.
*/
template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
class TissueWidthWriter : public AbstractCellPopulationWriter<ELEMENT_DIM, SPACE_DIM>
{
private:
/** Needed for serialization. */
friend class boost::serialization::access;
/**
* Serialize the object and its member variables.
*
* @param archive the archive
* @param version the current version of this class
*/
template<class Archive>
void serialize(Archive & archive, const unsigned int version)
{
archive & boost::serialization::base_object<AbstractCellPopulationWriter<ELEMENT_DIM, SPACE_DIM> >(*this);
}

public:

/**
* Default constructor.
*/
TissueWidthWriter();

/**
* Visit any population and write the data. This is the same structure for any population.
*
* @param pCellPopulation a pointer to the population to visit.
*/
void VisitAnyPopulation(AbstractCellPopulation<SPACE_DIM, SPACE_DIM>* pCellPopulation);

/**
* Visit the population and write the location of each Node.
*
* Outputs a line of space-separated values of the form:
* ... [node x-pos] [node y-pos] [node z-pos] ...
*
* where z-pos is used in 3 dimensions.
* Here the indexing of nodes is as given by the NodeIterator.
*
* This line is appended to the output written by AbstractCellBasedWriter, which is a single
* value [present simulation time], followed by a tab.
*
* @param pCellPopulation a pointer to the MeshBasedCellPopulation to visit.
*/
virtual void Visit(MeshBasedCellPopulation<ELEMENT_DIM, SPACE_DIM>* pCellPopulation);

/**
* Visit the population and write the location of each Node.
*
* Outputs a line of space-separated values of the form:
* ... [node x-pos] [node y-pos] [node z-pos] ...
*
* where z-pos is used in 3 dimensions.
* Here the indexing of nodes is as given by the NodeIterator.
*
* This line is appended to the output written by AbstractCellBasedWriter, which is a single
* value [present simulation time], followed by a tab.
*
* @param pCellPopulation a pointer to the CaBasedCellPopulation to visit.
*/
virtual void Visit(CaBasedCellPopulation<SPACE_DIM>* pCellPopulation);

/**
* Visit the population and write the location of each Node.
*
* Outputs a line of space-separated values of the form:
* ... [node x-pos] [node y-pos] [node z-pos] ...
*
* where z-pos is used in 3 dimensions.
* Here the indexing of nodes is as given by the NodeIterator.
*
* This line is appended to the output written by AbstractCellBasedWriter, which is a single
* value [present simulation time], followed by a tab.
*
* @param pCellPopulation a pointer to the NodeBasedCellPopulation to visit.
*/
virtual void Visit(NodeBasedCellPopulation<SPACE_DIM>* pCellPopulation);

/**
* Visit the population and write the location of each Node.
*
* Outputs a line of space-separated values of the form:
* ... [node x-pos] [node y-pos] [node z-pos] ...
*
* where z-pos is used in 3 dimensions.
* Here the indexing of nodes is as given by the NodeIterator.
*
* This line is appended to the output written by AbstractCellBasedWriter, which is a single
* value [present simulation time], followed by a tab.
*
* @param pCellPopulation a pointer to the PottsBasedCellPopulation to visit.
*/
virtual void Visit(PottsBasedCellPopulation<SPACE_DIM>* pCellPopulation);

/**
* Visit the population and write the location of each Node.
*
* Outputs a line of space-separated values of the form:
* ... [node x-pos] [node y-pos] [node z-pos] ...
*
* where z-pos is used in 3 dimensions.
* Here the indexing of nodes is as given by the NodeIterator.
*
* This line is appended to the output written by AbstractCellBasedWriter, which is a single
* value [present simulation time], followed by a tab.
*
* @param pCellPopulation a pointer to the VertexBasedCellPopulation to visit.
*/
virtual void Visit(VertexBasedCellPopulation<SPACE_DIM>* pCellPopulation);

/**
* Visit the population and write whether each node is a boundary node.
*
* Outputs a line of space-separated values of the form:
* [node 0 is boundary node] [node 1 is boundary node] ...
*
* where [node 0 is boundary node] is 1 if node 0 is a boundary node and 0 if it is not, and so on.
* Here the indexing of nodes is as given by the NodeIterator.
*
* This line is appended to the output written by AbstractCellBasedWriter, which is a single
* value [present simulation time], followed by a tab.
*
* @param pCellPopulation a pointer to the ImmersedBoundaryCellPopulation to visit.
*/
virtual void Visit(ImmersedBoundaryCellPopulation<SPACE_DIM>* pCellPopulation);
};

#include "SerializationExportWrapper.hpp"
// Declare identifier for the serializer
EXPORT_TEMPLATE_CLASS_ALL_DIMS(TissueWidthWriter)

#endif /* TISSUEWIDTHWRITER_HPP_ */
1 change: 1 addition & 0 deletions test/ContinuousTestPack.txt
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ Comparison/TestMorphogenMonolayerLiteratePaper.hpp
Investigation/TestCentreBasedCellSorting.hpp
Test01PersistentRandomWalk.hpp
Test02MonolayerGrowth.hpp
Test02aMonolayerGrowth.hpp
Test03WoundHealing.hpp
Test04Chemotaxis.hpp
Test05CellSorting.hpp
185 changes: 185 additions & 0 deletions test/Test02aMonolayerGrowth.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
Copyright (c) 2005-2024, University of Oxford.
All rights reserved.
University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.
This file is part of Chaste.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the University of Oxford nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef TEST02AMONOLAYERGROWTH_HPP_
#define TEST02AMONOLAYERGROWTH_HPP_

#include <cxxtest/TestSuite.h>

// Must be included before other cell_based headers
#include "CellBasedSimulationArchiver.hpp"

#include "SmartPointers.hpp"
#include "AbstractCellBasedWithTimingsTestSuite.hpp"

#include "DefaultCellProliferativeType.hpp"

#include "CellIdWriter.hpp"
#include "CellAgesWriter.hpp"
#include "VoronoiDataWriter.hpp"
#include "CellMutationStatesWriter.hpp"

#include "ParabolicGrowingDomainPdeModifier.hpp"
#include "VolumeTrackingModifier.hpp"

#include "FixedDurationCellCycleModelWithGrowthInhibition.hpp"
#include "CellDataItemWriter.hpp"
#include "CellVolumesWriter.hpp"
#include "TissueWidthWriter.hpp"
#include "OffLatticeSimulation.hpp"
#include "OnLatticeSimulation.hpp"
#include "CellsGenerator.hpp"
#include "RandomCellKiller.hpp"

#include "MeshBasedCellPopulationWithGhostNodes.hpp"
#include "HoneycombMeshGenerator.hpp"
#include "GeneralisedLinearSpringForceWithMinDistanceItem.hpp"

#include "NodeBasedCellPopulation.hpp"
#include "RepulsionForce.hpp"

#include "VertexBasedCellPopulation.hpp"
#include "HoneycombVertexMeshGenerator.hpp"
#include "NagaiHondaForce.hpp"
#include "SimpleTargetAreaModifier.hpp"
#include "GrowthInhibitionModifier.hpp"

#include "PottsBasedCellPopulation.hpp"
#include "PottsMeshGenerator.hpp"
#include "VolumeConstraintPottsUpdateRule.hpp"
#include "AdhesionPottsUpdateRule.hpp"
#include "SurfaceAreaConstraintPottsUpdateRule.hpp"

#include "CaBasedCellPopulation.hpp"
#include "DiffusionCaUpdateRule.hpp"

#include "RandomNumberGenerator.hpp"

#include "PetscSetupAndFinalize.hpp"


class Test02aMonlayerGrowth : public AbstractCellBasedWithTimingsTestSuite
{
private:

/*
* This is a helper method to generate cells and is used in all simulations.
*/
void GenerateCells(unsigned num_cells, std::vector<CellPtr>& rCells, bool randomiseBirthTime)
{
MAKE_PTR(WildTypeCellMutationState, p_state);
MAKE_PTR(TransitCellProliferativeType, p_transit_type);

for (unsigned i=0; i<num_cells; i++)
{
//UniformlyDistributedCellCycleModel* p_cycle_model = new UniformlyDistributedCellCycleModel();
FixedDurationCellCycleModelWithGrowthInhibition* p_cycle_model = new FixedDurationCellCycleModelWithGrowthInhibition();
p_cycle_model->SetDimension(2);

CellPtr p_cell(new Cell(p_state, p_cycle_model));
p_cell->SetCellProliferativeType(p_transit_type);

double birth_time = 0.0;
if (randomiseBirthTime) {
birth_time = -RandomNumberGenerator::Instance()->ranf() * 18.0;
}
p_cell->SetBirthTime(birth_time);
p_cycle_model->SetPhaseTimer(birth_time);


p_cell->InitialiseCellCycleModel();

// Set Target Area so dont need to use a growth model in vertex simulations
p_cell->GetCellData()->SetItem("target area", 1.0);
p_cell->GetCellData()->SetItem("growth inhibited", 0.0);
p_cell->GetCellData()->SetItem("Radius", 0.1);
p_cell->GetCellData()->SetItem("cell age", birth_time);
rCells.push_back(p_cell);
}
}

public:

/*
* Simulate growth of a tissue monolayer without diffusion. Starts with a single cell
*/
void Test2DMonolayerWithoutDiffusionSingleCell()
{
static const double end_time = 28*24; // 28 days first 14 days and second 14 days can be separated


NodesOnlyMesh<2>* p_mesh = new NodesOnlyMesh<2>;
std::vector<double> center = {0.0, 0.0};
double cut_off_length = 1.5; //this is the default
Node<2> node(0, center.data(), false);
p_mesh->AddNode(&node);
p_mesh->SetMaximumInteractionDistance(cut_off_length);

std::vector<CellPtr> cells;
GenerateCells(p_mesh->GetNumNodes(),cells,false);

NodeBasedCellPopulation<2> cell_population(*p_mesh, cells);
cell_population.AddCellWriter<CellIdWriter>();
cell_population.AddCellWriter<CellAgesWriter>();
cell_population.AddCellWriter<CellMutationStatesWriter>();
cell_population.AddCellWriter<CellVolumesWriter>();
cell_population.AddPopulationWriter<TissueWidthWriter>();
cell_population.SetUseVariableRadii(true);

OffLatticeSimulation<2> simulator(cell_population);
simulator.SetOutputDirectory("Test02aMonlayerGrowth");
simulator.SetDt(0.05);
simulator.SetSamplingTimestepMultiple(20); // Every hour
simulator.SetEndTime(end_time);

simulator.SetOutputDivisionLocations(true);

// Create a force law and pass it to the simulation
MAKE_PTR(GeneralisedLinearSpringForceWithMinDistanceItem<2>, p_linear_force);
p_linear_force->SetMeinekeSpringStiffness(2.70);
p_linear_force->SetCutOffLength(cut_off_length);
simulator.AddForce(p_linear_force);

MAKE_PTR(GrowthInhibitionModifier<2>, p_growth_inhibition_modifier);
simulator.AddSimulationModifier(p_growth_inhibition_modifier);


simulator.Solve();

}

};

#endif /* TEST02MONOLAYERGROWTH_HPP_ */

0 comments on commit f11fb01

Please sign in to comment.