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; }
void MeshBasedCellPopulationWithGhostNodes<DIM>::UpdateNodeLocations(double dt) { WARN_ONCE_ONLY("UpdateNodeLocations is deprecated for MeshBasedCellPopulations. Position updates are now handled by the numerical method."); }
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; }
/** * 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 }
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."); } } }
void VertexBasedCellPopulation<DIM>::UpdateNodeLocations(double dt) { WARN_ONCE_ONLY("UpdateNodeLocations is deprecated for VertexBasedCellPopulations. Position updates are now handled by the numerical method."); }