From 7d695fe3338654260b21f70545696ed5c77552ec Mon Sep 17 00:00:00 2001 From: jmosborne Date: Fri, 23 Aug 2024 06:20:13 +0100 Subject: [PATCH] Adding simple OS monolayer Reference Model --- .../FixedDurationCellCycleModel.cpp | 106 ++++++ .../FixedDurationCellCycleModel.hpp | 69 ++++ ...tionCellCycleModelWithGrowthInhibition.cpp | 161 +++++++++ ...tionCellCycleModelWithGrowthInhibition.hpp | 78 +++++ ...edLinearSpringForceWithMinDistanceItem.cpp | 313 ++++++++++++++++++ ...edLinearSpringForceWithMinDistanceItem.hpp | 208 ++++++++++++ .../GrowthInhibitionModifier.cpp | 138 ++++++++ .../GrowthInhibitionModifier.hpp | 118 +++++++ .../TissueWidthWriter.cpp | 136 ++++++++ .../TissueWidthWriter.hpp | 181 ++++++++++ test/ContinuousTestPack.txt | 1 + test/Test02aMonolayerGrowth.hpp | 185 +++++++++++ 12 files changed, 1694 insertions(+) create mode 100644 src/Test02aMonolayerGrowth/FixedDurationCellCycleModel.cpp create mode 100644 src/Test02aMonolayerGrowth/FixedDurationCellCycleModel.hpp create mode 100644 src/Test02aMonolayerGrowth/FixedDurationCellCycleModelWithGrowthInhibition.cpp create mode 100644 src/Test02aMonolayerGrowth/FixedDurationCellCycleModelWithGrowthInhibition.hpp create mode 100644 src/Test02aMonolayerGrowth/GeneralisedLinearSpringForceWithMinDistanceItem.cpp create mode 100644 src/Test02aMonolayerGrowth/GeneralisedLinearSpringForceWithMinDistanceItem.hpp create mode 100644 src/Test02aMonolayerGrowth/GrowthInhibitionModifier.cpp create mode 100644 src/Test02aMonolayerGrowth/GrowthInhibitionModifier.hpp create mode 100644 src/Test02aMonolayerGrowth/TissueWidthWriter.cpp create mode 100644 src/Test02aMonolayerGrowth/TissueWidthWriter.hpp create mode 100644 test/Test02aMonolayerGrowth.hpp diff --git a/src/Test02aMonolayerGrowth/FixedDurationCellCycleModel.cpp b/src/Test02aMonolayerGrowth/FixedDurationCellCycleModel.cpp new file mode 100644 index 0000000..0328ab2 --- /dev/null +++ b/src/Test02aMonolayerGrowth/FixedDurationCellCycleModel.cpp @@ -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 +void FixedDurationCellCycleModel::serialize(Archive & archive, const unsigned int version) +{ + // Archive cell-cycle model using serialization code from AbstractSimplePhaseBasedCellCycleModel + archive & boost::serialization::base_object(*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()) + { + 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) diff --git a/src/Test02aMonolayerGrowth/FixedDurationCellCycleModel.hpp b/src/Test02aMonolayerGrowth/FixedDurationCellCycleModel.hpp new file mode 100644 index 0000000..a5cdc98 --- /dev/null +++ b/src/Test02aMonolayerGrowth/FixedDurationCellCycleModel.hpp @@ -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 + 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_ diff --git a/src/Test02aMonolayerGrowth/FixedDurationCellCycleModelWithGrowthInhibition.cpp b/src/Test02aMonolayerGrowth/FixedDurationCellCycleModelWithGrowthInhibition.cpp new file mode 100644 index 0000000..4272824 --- /dev/null +++ b/src/Test02aMonolayerGrowth/FixedDurationCellCycleModelWithGrowthInhibition.cpp @@ -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 + +#include "RandomNumberGenerator.hpp" + +template +void FixedDurationCellCycleModelWithGrowthInhibition::serialize(Archive & archive, const unsigned int version) +{ + // Archive cell-cycle model using serialization code from AbstractSimplePhaseBasedCellCycleModel + archive & boost::serialization::base_object(*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()) + { + 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) diff --git a/src/Test02aMonolayerGrowth/FixedDurationCellCycleModelWithGrowthInhibition.hpp b/src/Test02aMonolayerGrowth/FixedDurationCellCycleModelWithGrowthInhibition.hpp new file mode 100644 index 0000000..e5dd1b1 --- /dev/null +++ b/src/Test02aMonolayerGrowth/FixedDurationCellCycleModelWithGrowthInhibition.hpp @@ -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 + 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_ diff --git a/src/Test02aMonolayerGrowth/GeneralisedLinearSpringForceWithMinDistanceItem.cpp b/src/Test02aMonolayerGrowth/GeneralisedLinearSpringForceWithMinDistanceItem.cpp new file mode 100644 index 0000000..5a9b4ac --- /dev/null +++ b/src/Test02aMonolayerGrowth/GeneralisedLinearSpringForceWithMinDistanceItem.cpp @@ -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 +GeneralisedLinearSpringForceWithMinDistanceItem::GeneralisedLinearSpringForceWithMinDistanceItem() + : AbstractTwoBodyInteractionForce(), + 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 +double GeneralisedLinearSpringForceWithMinDistanceItem::VariableSpringConstantMultiplicationFactor(unsigned nodeAGlobalIndex, + unsigned nodeBGlobalIndex, + AbstractCellPopulation& rCellPopulation, + bool isCloserThanRestLength) +{ + return 1.0; +} + +template +GeneralisedLinearSpringForceWithMinDistanceItem::~GeneralisedLinearSpringForceWithMinDistanceItem() +{ +} + +template +c_vector GeneralisedLinearSpringForceWithMinDistanceItem::CalculateForceBetweenNodes(unsigned nodeAGlobalIndex, + unsigned nodeBGlobalIndex, + AbstractCellPopulation& rCellPopulation) +{ + // We should only ever calculate the force between two distinct nodes + assert(nodeAGlobalIndex != nodeBGlobalIndex); + + Node* p_node_a = rCellPopulation.GetNode(nodeAGlobalIndex); + Node* p_node_b = rCellPopulation.GetNode(nodeBGlobalIndex); + + // Get the node locations + const c_vector& r_node_a_location = p_node_a->rGetLocation(); + const c_vector& 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*>(&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 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(SPACE_DIM); // c_vector() 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*>(&rCellPopulation))) + { + rest_length_final = static_cast*>(&rCellPopulation)->GetRestLength(nodeAGlobalIndex, nodeBGlobalIndex); + } + else if (bool(dynamic_cast*>(&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* p_static_cast_cell_population = static_cast*>(&rCellPopulation); + + std::pair 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*>(&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*>(&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 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 temp = multiplication_factor*spring_stiffness * unit_difference * overlap * exp(-alpha * overlap/rest_length_final); + return temp; + } + } +} + +template +double GeneralisedLinearSpringForceWithMinDistanceItem::GetMeinekeSpringStiffness() +{ + return mMeinekeSpringStiffness; +} + +template +double GeneralisedLinearSpringForceWithMinDistanceItem::GetMeinekeDivisionRestingSpringLength() +{ + return mMeinekeDivisionRestingSpringLength; +} + +template +double GeneralisedLinearSpringForceWithMinDistanceItem::GetMeinekeSpringGrowthDuration() +{ + return mMeinekeSpringGrowthDuration; +} + +template +void GeneralisedLinearSpringForceWithMinDistanceItem::SetMeinekeSpringStiffness(double springStiffness) +{ + assert(springStiffness > 0.0); + mMeinekeSpringStiffness = springStiffness; +} + +template +void GeneralisedLinearSpringForceWithMinDistanceItem::SetMeinekeDivisionRestingSpringLength(double divisionRestingSpringLength) +{ + assert(divisionRestingSpringLength <= 1.0); + assert(divisionRestingSpringLength >= 0.0); + + mMeinekeDivisionRestingSpringLength = divisionRestingSpringLength; +} + +template +void GeneralisedLinearSpringForceWithMinDistanceItem::SetMeinekeSpringGrowthDuration(double springGrowthDuration) +{ + assert(springGrowthDuration >= 0.0); + + mMeinekeSpringGrowthDuration = springGrowthDuration; +} + +template +void GeneralisedLinearSpringForceWithMinDistanceItem::OutputForceParameters(out_stream& rParamsFile) +{ + *rParamsFile << "\t\t\t" << mMeinekeSpringStiffness << "\n"; + *rParamsFile << "\t\t\t" << mMeinekeDivisionRestingSpringLength << "\n"; + *rParamsFile << "\t\t\t" << mMeinekeSpringGrowthDuration << "\n"; + + // Call method on direct parent class + AbstractTwoBodyInteractionForce::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) diff --git a/src/Test02aMonolayerGrowth/GeneralisedLinearSpringForceWithMinDistanceItem.hpp b/src/Test02aMonolayerGrowth/GeneralisedLinearSpringForceWithMinDistanceItem.hpp new file mode 100644 index 0000000..57048e3 --- /dev/null +++ b/src/Test02aMonolayerGrowth/GeneralisedLinearSpringForceWithMinDistanceItem.hpp @@ -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 + +/** + * 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 +class GeneralisedLinearSpringForceWithMinDistanceItem : public AbstractTwoBodyInteractionForce +{ + 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 + void serialize(Archive & archive, const unsigned int version) + { + archive & boost::serialization::base_object >(*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& 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 CalculateForceBetweenNodes(unsigned nodeAGlobalIndex, + unsigned nodeBGlobalIndex, + AbstractCellPopulation& 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_*/ diff --git a/src/Test02aMonolayerGrowth/GrowthInhibitionModifier.cpp b/src/Test02aMonolayerGrowth/GrowthInhibitionModifier.cpp new file mode 100644 index 0000000..996b473 --- /dev/null +++ b/src/Test02aMonolayerGrowth/GrowthInhibitionModifier.cpp @@ -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 + +#include "GrowthInhibitionModifier.hpp" +#include "FixedDurationCellCycleModel.hpp" + +template +GrowthInhibitionModifier::GrowthInhibitionModifier() + : AbstractCellBasedSimulationModifier() +{ +} + +template +GrowthInhibitionModifier::~GrowthInhibitionModifier() +{ +} + +template +void GrowthInhibitionModifier::UpdateAtEndOfTimeStep(AbstractCellPopulation& rCellPopulation) +{ + UpdateCellData(rCellPopulation); +} + +template +void GrowthInhibitionModifier::SetupSolve(AbstractCellPopulation& 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 +void GrowthInhibitionModifier::UpdateCellData(AbstractCellPopulation& rCellPopulation) +{ + rCellPopulation.Update(); // Make sure the cell population is updated + + // Get volume for each cell + for (typename AbstractCellPopulation::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::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(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 +void GrowthInhibitionModifier::OutputSimulationModifierParameters(out_stream& rParamsFile) +{ + // No parameters to output, so just call method on direct parent class + AbstractCellBasedSimulationModifier::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) diff --git a/src/Test02aMonolayerGrowth/GrowthInhibitionModifier.hpp b/src/Test02aMonolayerGrowth/GrowthInhibitionModifier.hpp new file mode 100644 index 0000000..ea1a0a4 --- /dev/null +++ b/src/Test02aMonolayerGrowth/GrowthInhibitionModifier.hpp @@ -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 + +#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 +class GrowthInhibitionModifier : public AbstractCellBasedSimulationModifier +{ + /** 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 + void serialize(Archive & archive, const unsigned int version) + { + archive & boost::serialization::base_object >(*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& 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& 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& 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_ diff --git a/src/Test02aMonolayerGrowth/TissueWidthWriter.cpp b/src/Test02aMonolayerGrowth/TissueWidthWriter.cpp new file mode 100644 index 0000000..e0eed82 --- /dev/null +++ b/src/Test02aMonolayerGrowth/TissueWidthWriter.cpp @@ -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 +TissueWidthWriter::TissueWidthWriter() + : AbstractCellPopulationWriter("tissuewidth.dat") +{ +} + +template +void TissueWidthWriter::VisitAnyPopulation(AbstractCellPopulation* pCellPopulation) +{ + double max_width =-2000000; + double min_width = 2000000; + for (typename AbstractMesh::NodeIterator node_iter = pCellPopulation->rGetMesh().GetNodeIteratorBegin(); + node_iter != pCellPopulation->rGetMesh().GetNodeIteratorEnd(); + ++node_iter) + { + if (!node_iter->IsDeleted()) + { + const c_vector& 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 +void TissueWidthWriter::Visit(MeshBasedCellPopulation* pCellPopulation) +{ + for (typename AbstractMesh::NodeIterator node_iter = pCellPopulation->rGetMesh().GetNodeIteratorBegin(); + node_iter != pCellPopulation->rGetMesh().GetNodeIteratorEnd(); + ++node_iter) + { + if (!node_iter->IsDeleted()) + { + const c_vector& position = node_iter->rGetLocation(); + + for (unsigned i=0; impOutStream << position[i] << " "; + } + } + } +} + +template +void TissueWidthWriter::Visit(CaBasedCellPopulation* pCellPopulation) +{ + VisitAnyPopulation(pCellPopulation); +} + +template +void TissueWidthWriter::Visit(NodeBasedCellPopulation* pCellPopulation) +{ + VisitAnyPopulation(pCellPopulation); +} + +template +void TissueWidthWriter::Visit(PottsBasedCellPopulation* pCellPopulation) +{ + VisitAnyPopulation(pCellPopulation); +} + +template +void TissueWidthWriter::Visit(VertexBasedCellPopulation* pCellPopulation) +{ + VisitAnyPopulation(pCellPopulation); +} + +template +void TissueWidthWriter::Visit(ImmersedBoundaryCellPopulation* 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) diff --git a/src/Test02aMonolayerGrowth/TissueWidthWriter.hpp b/src/Test02aMonolayerGrowth/TissueWidthWriter.hpp new file mode 100644 index 0000000..9ea478b --- /dev/null +++ b/src/Test02aMonolayerGrowth/TissueWidthWriter.hpp @@ -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 + +/** + * 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 +class TissueWidthWriter : public AbstractCellPopulationWriter +{ +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 + void serialize(Archive & archive, const unsigned int version) + { + archive & boost::serialization::base_object >(*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* 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* 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* 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* 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* 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* 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* pCellPopulation); +}; + +#include "SerializationExportWrapper.hpp" +// Declare identifier for the serializer +EXPORT_TEMPLATE_CLASS_ALL_DIMS(TissueWidthWriter) + +#endif /* TISSUEWIDTHWRITER_HPP_ */ diff --git a/test/ContinuousTestPack.txt b/test/ContinuousTestPack.txt index 59d69dc..5975be2 100644 --- a/test/ContinuousTestPack.txt +++ b/test/ContinuousTestPack.txt @@ -5,6 +5,7 @@ Comparison/TestMorphogenMonolayerLiteratePaper.hpp Investigation/TestCentreBasedCellSorting.hpp Test01PersistentRandomWalk.hpp Test02MonolayerGrowth.hpp +Test02aMonolayerGrowth.hpp Test03WoundHealing.hpp Test04Chemotaxis.hpp Test05CellSorting.hpp diff --git a/test/Test02aMonolayerGrowth.hpp b/test/Test02aMonolayerGrowth.hpp new file mode 100644 index 0000000..3108728 --- /dev/null +++ b/test/Test02aMonolayerGrowth.hpp @@ -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 + +// 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& rCells, bool randomiseBirthTime) + { + MAKE_PTR(WildTypeCellMutationState, p_state); + MAKE_PTR(TransitCellProliferativeType, p_transit_type); + + for (unsigned i=0; iSetDimension(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 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 cells; + GenerateCells(p_mesh->GetNumNodes(),cells,false); + + NodeBasedCellPopulation<2> cell_population(*p_mesh, cells); + cell_population.AddCellWriter(); + cell_population.AddCellWriter(); + cell_population.AddCellWriter(); + cell_population.AddCellWriter(); + cell_population.AddPopulationWriter(); + 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_ */