void AbstractContinuumMechanicsSolver<DIM>::RemovePressureDummyValuesThroughLinearInterpolation() { assert(mProblemDimension==DIM+1); // For quadratic triangles, node 3 is between nodes 1 and 2, node 4 is between 0 and 2, etc unsigned internal_nodes_2d[3] = {3,4,5}; unsigned neighbouring_vertices_2d[3][2] = { {1,2}, {2,0}, {0,1} }; // ordering for quadratic tetrahedra unsigned internal_nodes_3d[6] = {4,5,6,7,8,9}; unsigned neighbouring_vertices_3d[6][2] = { {0,1}, {1,2}, {0,2}, {0,3}, {1,3}, {2,3} }; unsigned num_internal_nodes_per_element = DIM==2 ? 3 : 6; // loop over elements, then loop over edges. for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = mrQuadMesh.GetElementIteratorBegin(); iter != mrQuadMesh.GetElementIteratorEnd(); ++iter) { for(unsigned i=0; i<num_internal_nodes_per_element; i++) { unsigned global_index; double left_val; double right_val; if(DIM==2) { global_index = iter->GetNodeGlobalIndex( internal_nodes_2d[i] ); unsigned vertex_0_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_2d[i][0] ); unsigned vertex_1_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_2d[i][1] ); left_val = mCurrentSolution[mProblemDimension*vertex_0_global_index + DIM]; right_val = mCurrentSolution[mProblemDimension*vertex_1_global_index + DIM]; } else { global_index = iter->GetNodeGlobalIndex( internal_nodes_3d[i] ); unsigned vertex_0_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_3d[i][0] ); unsigned vertex_1_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_3d[i][1] ); left_val = mCurrentSolution[mProblemDimension*vertex_0_global_index + DIM]; right_val = mCurrentSolution[mProblemDimension*vertex_1_global_index + DIM]; } // this line assumes the internal node is midway between the two vertices mCurrentSolution[mProblemDimension*global_index + DIM] = 0.5 * (left_val + right_val); } } }
void VtkNonlinearElasticitySolutionWriter<DIM>::Write() { if (mpSolver->mOutputDirectory=="") { EXCEPTION("No output directory was given to the mechanics solver"); } #ifdef CHASTE_VTK VtkMeshWriter<DIM, DIM> mesh_writer(mpSolver->mOutputDirectory + "/vtk", "solution", true); // write the displacement std::vector<c_vector<double,DIM> > displacement(mpSolver->mrQuadMesh.GetNumNodes()); std::vector<c_vector<double,DIM> >& r_spatial_solution = mpSolver->rGetSpatialSolution(); for(unsigned i=0; i<mpSolver->mrQuadMesh.GetNumNodes(); i++) { for(unsigned j=0; j<DIM; j++) { displacement[i](j) = r_spatial_solution[i](j)- mpSolver->mrQuadMesh.GetNode(i)->rGetLocation()[j]; } } mesh_writer.AddPointData("Displacement", displacement); // write pressures if (mpSolver->mCompressibilityType==INCOMPRESSIBLE) { mesh_writer.AddPointData("Pressure", mpSolver->rGetPressures()); } // write the element attribute as cell data. std::vector<double> element_attribute; for(typename QuadraticMesh<DIM>::ElementIterator iter = mpSolver->mrQuadMesh.GetElementIteratorBegin(); iter != mpSolver->mrQuadMesh.GetElementIteratorEnd(); ++iter) { element_attribute.push_back(iter->GetAttribute()); } mesh_writer.AddCellData("Attribute", element_attribute); // write strains if requested if (mWriteElementWiseStrains) { mTensorData.clear(); mTensorData.resize(mpSolver->mrQuadMesh.GetNumElements()); std::string name; switch(mElementWiseStrainType) { case DEFORMATION_GRADIENT_F: { name = "deformation_gradient_F"; break; } case DEFORMATION_TENSOR_C: { name = "deformation_tensor_C"; break; } case LAGRANGE_STRAIN_E: { name = "Lagrange_strain_E"; break; } default: { NEVER_REACHED; } } for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = mpSolver->mrQuadMesh.GetElementIteratorBegin(); iter != mpSolver->mrQuadMesh.GetElementIteratorEnd(); ++iter) { mpSolver->GetElementCentroidStrain(mElementWiseStrainType, *iter, mTensorData[iter->GetIndex()]); } mesh_writer.AddTensorCellData(name, mTensorData); } //// Future.. // if (mWriteNodeWiseStresses) // { // std::vector<c_matrix<double,DIM,DIM> > tensor_data; // // use recoverer // mesh_writer.AddTensorCellData("Stress_NAME_ME", tensor_data); // } // final write mesh_writer.WriteFilesUsingMesh(mpSolver->mrQuadMesh); #endif // CHASTE_VTK }
void ExtendedBidomainTissue<SPACE_DIM>::CreateExtracellularConductivityTensors() { if (this->mpConfig->IsMeshProvided() && this->mpConfig->GetLoadMesh()) { assert(this->mFibreFilePathNoExtension != ""); switch (this->mpConfig->GetConductivityMedia()) { case cp::media_type::Orthotropic: { mpExtracellularConductivityTensors = new OrthotropicConductivityTensors<SPACE_DIM,SPACE_DIM>; FileFinder ortho_file(this->mFibreFilePathNoExtension + ".ortho", RelativeTo::AbsoluteOrCwd); assert(ortho_file.Exists()); mpExtracellularConductivityTensors->SetFibreOrientationFile(ortho_file); break; } case cp::media_type::Axisymmetric: { mpExtracellularConductivityTensors = new AxisymmetricConductivityTensors<SPACE_DIM,SPACE_DIM>; FileFinder axi_file(this->mFibreFilePathNoExtension + ".axi", RelativeTo::AbsoluteOrCwd); assert(axi_file.Exists()); mpExtracellularConductivityTensors->SetFibreOrientationFile(axi_file); break; } case cp::media_type::NoFibreOrientation: mpExtracellularConductivityTensors = new OrthotropicConductivityTensors<SPACE_DIM,SPACE_DIM>; break; default : NEVER_REACHED; } } else // no fibre orientation assumed { mpExtracellularConductivityTensors = new OrthotropicConductivityTensors<SPACE_DIM,SPACE_DIM>; } c_vector<double, SPACE_DIM> extra_conductivities; this->mpConfig->GetExtracellularConductivities(extra_conductivities); // this definition must be here (and not inside the if statement) because SetNonConstantConductivities() will keep // a pointer to it and we don't want it to go out of scope before Init() is called unsigned num_elements = this->mpMesh->GetNumElements(); std::vector<c_vector<double, SPACE_DIM> > hetero_extra_conductivities; if (this->mpConfig->GetConductivityHeterogeneitiesProvided()) { try { assert(hetero_extra_conductivities.size()==0); //initialise with the values of teh default conductivity tensor hetero_extra_conductivities.resize(num_elements, extra_conductivities); } catch(std::bad_alloc &badAlloc) { #define COVERAGE_IGNORE std::cout << "Failed to allocate std::vector of size " << num_elements << std::endl; PetscTools::ReplicateException(true); throw badAlloc; #undef COVERAGE_IGNORE } PetscTools::ReplicateException(false); std::vector<boost::shared_ptr<AbstractChasteRegion<SPACE_DIM> > > conductivities_heterogeneity_areas; std::vector< c_vector<double,3> > intra_h_conductivities; std::vector< c_vector<double,3> > extra_h_conductivities; HeartConfig::Instance()->GetConductivityHeterogeneities(conductivities_heterogeneity_areas, intra_h_conductivities, extra_h_conductivities); unsigned local_element_index = 0; for (typename AbstractTetrahedralMesh<SPACE_DIM,SPACE_DIM>::ElementIterator iter = (this->mpMesh)->GetElementIteratorBegin(); iter != (this->mpMesh)->GetElementIteratorEnd(); ++iter) { //unsigned element_index = iter->GetIndex(); // if element centroid is contained in the region ChastePoint<SPACE_DIM> element_centroid(iter->CalculateCentroid()); for (unsigned region_index=0; region_index< conductivities_heterogeneity_areas.size(); region_index++) { // if element centroid is contained in the region if ( conductivities_heterogeneity_areas[region_index]->DoesContain( element_centroid ) ) { //We don't use ublas vector assignment here, because we might be getting a subvector of a 3-vector for (unsigned i=0; i<SPACE_DIM; i++) { hetero_extra_conductivities[local_element_index][i] = extra_h_conductivities[region_index][i]; } } } local_element_index++; } mpExtracellularConductivityTensors->SetNonConstantConductivities(&hetero_extra_conductivities); } else { mpExtracellularConductivityTensors->SetConstantConductivities(extra_conductivities); } mpExtracellularConductivityTensors->Init(this->mpMesh); }
void ExtendedBidomainTissue<SPACE_DIM>::CreateIntracellularConductivityTensorSecondCell() { HeartEventHandler::BeginEvent(HeartEventHandler::READ_MESH); this->mpConfig = HeartConfig::Instance(); mpIntracellularConductivityTensorsSecondCell = new OrthotropicConductivityTensors<SPACE_DIM,SPACE_DIM>; // this definition must be here (and not inside the if statement) because SetNonConstantConductivities() will keep // a pointer to it and we don't want it to go out of scope before Init() is called unsigned num_elements = this->mpMesh->GetNumElements(); std::vector<c_vector<double, SPACE_DIM> > hetero_intra_conductivities; c_vector<double, SPACE_DIM> intra_conductivities; this->mpConfig->GetIntracellularConductivities(intra_conductivities);//this one is used just for resizing if (this->mpConfig->GetConductivityHeterogeneitiesProvided()) { try { assert(hetero_intra_conductivities.size()==0); hetero_intra_conductivities.resize(num_elements, intra_conductivities); } catch(std::bad_alloc &badAlloc) { #define COVERAGE_IGNORE std::cout << "Failed to allocate std::vector of size " << num_elements << std::endl; PetscTools::ReplicateException(true); throw badAlloc; #undef COVERAGE_IGNORE } PetscTools::ReplicateException(false); std::vector<boost::shared_ptr<AbstractChasteRegion<SPACE_DIM> > > conductivities_heterogeneity_areas; std::vector< c_vector<double,3> > intra_h_conductivities; std::vector< c_vector<double,3> > extra_h_conductivities; HeartConfig::Instance()->GetConductivityHeterogeneities(conductivities_heterogeneity_areas, intra_h_conductivities, extra_h_conductivities); unsigned local_element_index = 0; for (typename AbstractTetrahedralMesh<SPACE_DIM,SPACE_DIM>::ElementIterator it = this->mpMesh->GetElementIteratorBegin(); it != this->mpMesh->GetElementIteratorEnd(); ++it) { //unsigned element_index = it->GetIndex(); // if element centroid is contained in the region ChastePoint<SPACE_DIM> element_centroid(it->CalculateCentroid()); for (unsigned region_index=0; region_index< conductivities_heterogeneity_areas.size(); region_index++) { if ( conductivities_heterogeneity_areas[region_index]->DoesContain(element_centroid) ) { //We don't use ublas vector assignment here, because we might be getting a subvector of a 3-vector for (unsigned i=0; i<SPACE_DIM; i++) { hetero_intra_conductivities[local_element_index][i] = intra_h_conductivities[region_index][i]; } } } local_element_index++; } mpIntracellularConductivityTensorsSecondCell->SetNonConstantConductivities(&hetero_intra_conductivities); } else { mpIntracellularConductivityTensorsSecondCell->SetConstantConductivities(mIntracellularConductivitiesSecondCell); } mpIntracellularConductivityTensorsSecondCell->Init(this->mpMesh); HeartEventHandler::EndEvent(HeartEventHandler::READ_MESH); }
std::vector<c_vector<unsigned, 5> > MutableMesh<ELEMENT_DIM, SPACE_DIM>::SplitLongEdges(double cutoffLength) { assert(ELEMENT_DIM == 2); assert(SPACE_DIM == 3); std::vector<c_vector<unsigned, 5> > history; bool long_edge_exists = true; while(long_edge_exists) { std::set<std::pair<unsigned, unsigned> > long_edges; // Loop over elements to check for Long edges for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator elem_iter = this->GetElementIteratorBegin(); elem_iter != this->GetElementIteratorEnd(); ++elem_iter) { unsigned num_nodes = ELEMENT_DIM+1; // Loop over element vertices for (unsigned local_index=0; local_index<num_nodes; local_index++) { // Find locations of current node (node a) and anticlockwise node (node b) Node<SPACE_DIM>* p_node_a = elem_iter->GetNode(local_index); unsigned local_index_plus_one = (local_index+1)%num_nodes; /// \todo use iterators to tidy this up Node<SPACE_DIM>* p_node_b = elem_iter->GetNode(local_index_plus_one); // Find distance between nodes double distance_between_nodes = this->GetDistanceBetweenNodes(p_node_a->GetIndex(), p_node_b->GetIndex()); if (distance_between_nodes > cutoffLength) { if (p_node_a->GetIndex() < p_node_b->GetIndex()) { std::pair<unsigned, unsigned> long_edge(p_node_a->GetIndex(),p_node_b->GetIndex()); long_edges.insert(long_edge); } else { std::pair<unsigned, unsigned> long_edge(p_node_b->GetIndex(),p_node_a->GetIndex()); long_edges.insert(long_edge); } } } } if (long_edges.size() > 0) //Split the edges in decreasing order. { while (long_edges.size() > 0) { double longest_edge = 0.0; std::set<std::pair<unsigned, unsigned> >::iterator longest_edge_iter; //Find the longest edge in the set and split it for (std::set<std::pair<unsigned, unsigned> >::iterator edge_iter = long_edges.begin(); edge_iter != long_edges.end(); ++edge_iter) { unsigned node_a_global_index = edge_iter->first; unsigned node_b_global_index = edge_iter->second; double distance_between_nodes = this->GetDistanceBetweenNodes(node_a_global_index, node_b_global_index); if (distance_between_nodes > longest_edge) { longest_edge = distance_between_nodes; longest_edge_iter = edge_iter; } } assert(longest_edge >0); c_vector<unsigned, 3> new_node_index = SplitEdge(this->GetNode(longest_edge_iter->first), this->GetNode(longest_edge_iter->second)); c_vector<unsigned, 5> node_set; node_set(0) = new_node_index[0]; node_set(1) = longest_edge_iter->first; node_set(2) = longest_edge_iter->second; node_set(3) = new_node_index[1]; node_set(4) = new_node_index[2]; history.push_back(node_set); // Delete pair from set long_edges.erase(*longest_edge_iter); } } else { long_edge_exists = false; } } return history; }
double ElectrodesStimulusFactory<DIM>::ComputeElectrodeTotalFlux(AbstractChasteRegion<DIM>* pRegion, double stimulusMagnitude) { GaussianQuadratureRule<DIM>* pQuadRule = new GaussianQuadratureRule<DIM>(2); //the basis functions c_vector<double, DIM+1> phi; double total_electrode_flux = 0.0; double ret; for (typename AbstractTetrahedralMesh<DIM,DIM>::NodeIterator node_iter=this->mpMesh->GetNodeIteratorBegin(); node_iter != this->mpMesh->GetNodeIteratorEnd(); ++node_iter) { if ( pRegion->DoesContain( (*node_iter).GetPoint() ) ) { unsigned node_index = node_iter->GetIndex(); assert(node_index < this->mpMesh->GetNumNodes()); double contribution_of_this_node = 0.0; //loop over the elements where this node is contained for(std::set<unsigned>::iterator iter = this->mpMesh->GetNode(node_index)->rGetContainingElementIndices().begin(); iter != this->mpMesh->GetNode(node_index)->rGetContainingElementIndices().end(); ++iter) { Element<DIM,DIM>* p_element = this->mpMesh->GetElement(*iter); /*Determine jacobian for this element*/ c_matrix<double, DIM, DIM> jacobian; c_matrix<double, DIM, DIM> inverse_jacobian;//unused here, but needed for the function below double jacobian_determinant; this->mpMesh->GetInverseJacobianForElement(p_element->GetIndex(), jacobian, jacobian_determinant, inverse_jacobian); double contribution_of_this_element = 0.0;//...to this node // loop over Gauss points for (unsigned quad_index=0; quad_index < pQuadRule->GetNumQuadPoints(); quad_index++) { const ChastePoint<DIM>& quad_point = pQuadRule->rGetQuadPoint(quad_index); BasisFunction::ComputeBasisFunctions(quad_point, phi); double interpolated_stimulus = 0.0; //loop over nodes in this element for (unsigned node_index_in_element = 0; node_index_in_element < p_element->GetNumNodes(); node_index_in_element++) { //const Node<DIM>* p_node = p_element->GetNode(node_index_in_element); assert(p_element->GetNumNodes() == DIM+1); interpolated_stimulus += stimulusMagnitude*phi(node_index_in_element); contribution_of_this_element += interpolated_stimulus * phi(node_index_in_element) * jacobian_determinant * pQuadRule->GetWeight(quad_index); } }/*end of loop over gauss points*/ contribution_of_this_node += contribution_of_this_element; }/*end of loop over elements where the node is contained*/ total_electrode_flux += contribution_of_this_node; }/* end of if that checks if node is in the electrode*/ }/* end of loop over nodes in the mesh*/ #ifndef NDEBUG int mpi_ret = MPI_Allreduce(&total_electrode_flux, &ret, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD); assert(mpi_ret == MPI_SUCCESS); #else MPI_Allreduce(&total_electrode_flux, &ret, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD); #endif //clear up memory delete pQuadRule; assert(ret < DBL_MAX); return ret; }