コード例 #1
0
unsigned VertexBasedCellPopulation<DIM>::RemoveDeadCells()
{
    unsigned num_removed = 0;

    for (std::list<CellPtr>::iterator it = this->mCells.begin();
         it != this->mCells.end();
         )
    {
        if ((*it)->IsDead())
        {
            // Count the cell as dead
            num_removed++;

            // Remove the element from the mesh if it is not deleted yet
            ///\todo (#2489) this should cause an error - we should fix this!
            if (!(this->GetElement(this->GetLocationIndexUsingCell((*it)))->IsDeleted()))
            {
                // This warning relies on the fact that there is only one other possibility for
                // vertex elements to be marked as deleted: a T2 swap
                WARN_ONCE_ONLY("A Cell is removed without performing a T2 swap. This could leave a void in the mesh.");
                mpMutableVertexMesh->DeleteElementPriorToReMesh(this->GetLocationIndexUsingCell((*it)));
            }

            // Delete the cell
            it = this->mCells.erase(it);
        }
        else
        {
            ++it;
        }
    }
    return num_removed;
}
コード例 #2
0
void MeshBasedCellPopulationWithGhostNodes<DIM>::UpdateNodeLocations(double dt)
{
    WARN_ONCE_ONLY("UpdateNodeLocations is deprecated for MeshBasedCellPopulations. Position updates are now handled by the numerical method.");
}
コード例 #3
0
DynamicCellModelLoaderPtr CellMLToSharedLibraryConverter::Convert(const FileFinder& rFilePath,
                                                                  bool isCollective)
{
    DynamicCellModelLoaderPtr p_loader;
    std::string absolute_path = rFilePath.GetAbsolutePath();
    // Find out whether rFilePath is a .cellml or .so
    size_t dot_position = absolute_path.find_last_of(".");
    if (dot_position == std::string::npos)
    {
        EXCEPTION("File does not have an extension: " + absolute_path);
    }
    std::string extension = absolute_path.substr(dot_position+1);
    // We make a modifiable version of the const FileFinder just incase we feel like
    // amending the suffix
    FileFinder file_path_copy(rFilePath);
#ifdef __APPLE__
    if (extension == "so")
    {
        WARN_ONCE_ONLY("CellMLToSharedLibraryConverter asked to load a \".so\" file.  On this architecture it should be \".dylib\"");
        extension = "dylib";
        absolute_path.replace(dot_position+1, 5, extension);
        file_path_copy.SetPath(absolute_path,  RelativeTo::Absolute);
    }
#endif
    // Check the file exists
    if (!file_path_copy.Exists())
    {
        EXCEPTION("Dynamically loadable cell model '" + absolute_path + "' does not exist.");
    }
    if (extension == "cellml")
    {
        // Split the path into folder and leaf
        size_t slash_position = absolute_path.find_last_of("/\\");
        assert(slash_position != std::string::npos);
        std::string folder = absolute_path.substr(0, slash_position+1); // Include trailing slash
        std::string leaf = absolute_path.substr(slash_position+1, dot_position-slash_position); // Include dot
        std::string so_path = folder + "lib" + leaf + msSoSuffix;
        // Does the .so file already exist (and was it modified after the .cellml?)
        FileFinder so_file(so_path, RelativeTo::Absolute);
        if (!so_file.Exists() || rFilePath.IsNewerThan(so_file))
        {
            if (!isCollective)
            {
                EXCEPTION("Unable to convert .cellml to .so unless called collectively, due to possible race conditions.");
            }
            ConvertCellmlToSo(absolute_path, folder);
        }
        // Load the .so
        p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(so_file);
    }
    else if (extension == msSoSuffix)
    {
        // Just load the .so
        // Note that this may have been modified to .dylib
        p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(file_path_copy);
    }
    else
    {
        EXCEPTION("Unsupported extension '." + extension + "' of file '" + absolute_path + "'; must be .so, .dylib or .cellml");
    }

    return p_loader;
}
コード例 #4
0
    /**
     * Use Newton's method to solve the given cell for the next timestep.
     *
     * @param rCell  the cell to solve
     * @param time  the current time
     * @param rCurrentGuess  the current guess at a solution.  Will be updated on exit.
     */
    void Solve(CELLTYPE &rCell,
               double time,
               double rCurrentGuess[SIZE])
    {
        unsigned counter = 0;
        const double eps = 1e-6; // JonW tolerance

        // check that the initial guess that was given gives a valid residual
        rCell.ComputeResidual(time, rCurrentGuess, mResidual.data());
        double norm_of_residual = norm_inf(mResidual);
        assert(!std::isnan(norm_of_residual));
        double norm_of_update = 0.0; //Properly initialised in the loop
        do
        {
            // Calculate Jacobian for current guess
            rCell.ComputeJacobian(time, rCurrentGuess, mJacobian);

            // Solve Newton linear system for mUpdate, given mJacobian and mResidual
            SolveLinearSystem();

            // Update norm (JonW style)
            norm_of_update = norm_inf(mUpdate);

            // Update current guess and recalculate residual
            for (unsigned i=0; i<SIZE; i++)
            {
                rCurrentGuess[i] -= mUpdate[i];
            }
            double norm_of_previous_residual = norm_of_residual;
            rCell.ComputeResidual(time, rCurrentGuess, mResidual.data());
            norm_of_residual = norm_inf(mResidual);
            if (norm_of_residual > norm_of_previous_residual && norm_of_update > eps)
            {
                //Second part of guard:
                //Note that if norm_of_update < eps (converged) then it's
                //likely that both the residual and the previous residual were
                //close to the root.

                //Work out where the biggest change in the guess has happened.
                double relative_change_max = 0.0;
                unsigned relative_change_direction = 0;
                for (unsigned i=0; i<SIZE; i++)
                {
                    double relative_change = fabs(mUpdate[i]/rCurrentGuess[i]);
                    if (relative_change > relative_change_max)
                    {
                        relative_change_max = relative_change;
                        relative_change_direction = i;
                    }
                }

                if (relative_change_max > 1.0)
                {
                    //Only walk 0.2 of the way in that direction (put back 0.8)
                    rCurrentGuess[relative_change_direction] += 0.8*mUpdate[relative_change_direction];
                    rCell.ComputeResidual(time, rCurrentGuess, mResidual.data());
                    norm_of_residual = norm_inf(mResidual);
                    WARNING("Residual increasing and one direction changing radically - back tracking in that direction");
                }
            }
            counter++;

            // avoid infinite loops
            if (counter > 15)
            {
#define COVERAGE_IGNORE
                EXCEPTION("Newton method diverged in CardiacNewtonSolver::Solve()");
#undef COVERAGE_IGNORE
            }
        }
        while (norm_of_update > eps);

#define COVERAGE_IGNORE
#ifndef NDEBUG
        if (norm_of_residual > 2e-10)
        { //This line is for correlation - in case we use norm_of_residual as convergence criterion
            WARN_ONCE_ONLY("Newton iteration terminated because update vector norm is small, but residual norm is not small.");
        }
#endif // NDEBUG
#undef COVERAGE_IGNORE
    }
コード例 #5
0
void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::Initialise()
{
    // compute total num quad points
    unsigned num_quad_pts_per_element = this->mpQuadratureRule->GetNumQuadPoints();
    mTotalQuadPoints = this->mrQuadMesh.GetNumElements()*num_quad_pts_per_element;

    std::vector<ElementAndWeights<DIM> > fine_elements = mpMeshPair->rGetElementsAndWeights();
    assert(fine_elements.size()==mTotalQuadPoints);
    assert(mpMeshPair!=NULL);

    AbstractContractionCellFactory<DIM>* p_factory = mrElectroMechanicsProblemDefinition.GetContractionCellFactory();

    for (typename AbstractTetrahedralMesh<DIM, DIM>::ElementIterator iter = this->mrQuadMesh.GetElementIteratorBegin();
         iter != this->mrQuadMesh.GetElementIteratorEnd();
         ++iter)
    {
        Element<DIM, DIM>& element = *iter;

        if (element.GetOwnership() == true)
        {
            for(unsigned j=0; j<num_quad_pts_per_element; j++)
            {
                unsigned quad_pt_global_index = element.GetIndex()*num_quad_pts_per_element + j;

                // We construct a set of data to be assigned to each quadrature point
                // this includes a contraction cell model set as bath or by the contraction
                // cell factory.
                DataAtQuadraturePoint data_at_quad_point;
                data_at_quad_point.Stretch = 1.0;
                data_at_quad_point.StretchLastTimeStep = 1.0;

                if ( mpMeshPair->GetFineMesh().GetElement(fine_elements[quad_pt_global_index].ElementNum)
                        ->GetUnsignedAttribute() == HeartRegionCode::GetValidBathId() )
                {
                    // Bath
                    data_at_quad_point.ContractionModel = new FakeBathContractionModel;
                }
                else
                {
                    // Tissue
                    data_at_quad_point.ContractionModel = p_factory->CreateContractionCellForElement( &element );
                }
                mQuadPointToDataAtQuadPointMap[quad_pt_global_index] = data_at_quad_point;
            }
        }
    }

    // initialise the iterator to point at the beginning
    mMapIterator = mQuadPointToDataAtQuadPointMap.begin();

    // initialise fibre/sheet direction matrix to be the identity, fibres in X-direction, and sheet in XY-plane
    mConstantFibreSheetDirections = zero_matrix<double>(DIM,DIM);
    for(unsigned i=0; i<DIM; i++)
    {
        mConstantFibreSheetDirections(i,i) = 1.0;
    }

    mpVariableFibreSheetDirections = NULL;

    // Check that we are using the right kind of solver.
    for(std::map<unsigned,DataAtQuadraturePoint>::iterator iter = this->mQuadPointToDataAtQuadPointMap.begin();
            iter != this->mQuadPointToDataAtQuadPointMap.end();
            iter++)
    {
        if (!IsImplicitSolver() && (*iter).second.ContractionModel->IsStretchRateDependent())
        {
            EXCEPTION("stretch-rate-dependent contraction model requires an IMPLICIT cardiac mechanics solver.");
        }

        if (!IsImplicitSolver() && (*iter).second.ContractionModel->IsStretchDependent())
        {
            WARN_ONCE_ONLY("stretch-dependent contraction model may require an IMPLICIT cardiac mechanics solver.");
        }
    }
}
コード例 #6
0
void VertexBasedCellPopulation<DIM>::UpdateNodeLocations(double dt)
{
    WARN_ONCE_ONLY("UpdateNodeLocations is deprecated for VertexBasedCellPopulations. Position updates are now handled by the numerical method.");
}