void TestRefreshMeshByScaling() { TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/cube_136_elements"); TetrahedralMesh<3,3> mesh; mesh.ConstructFromMeshReader(mesh_reader); TS_ASSERT_DELTA(mesh.GetVolume(), 1.0, 1e-6); TS_ASSERT_DELTA(mesh.GetSurfaceArea(), 6.0, 1e-6); // Change coordinates for (unsigned i=0; i<mesh.GetNumNodes(); i++) { Node<3>* p_node = mesh.GetNode(i); ChastePoint<3> point = p_node->GetPoint(); point.SetCoordinate(0, point[0]*2.0); point.SetCoordinate(1, point[1]*2.0); point.SetCoordinate(2, point[2]*2.0); p_node->SetPoint(point); } mesh.RefreshMesh(); TS_ASSERT_DELTA(mesh.GetVolume(), 8.0, 1e-6); TS_ASSERT_DELTA(mesh.GetSurfaceArea(), 24.0, 1e-6); }
void TestXaxisRotation3DWithHomogeneousUblas() { TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/cube_136_elements"); TetrahedralMesh<3,3> mesh; mesh.ConstructFromMeshReader(mesh_reader); TS_ASSERT_DELTA(mesh.GetVolume(), 1.0, 1e-6); TS_ASSERT_DELTA(mesh.GetSurfaceArea(), 6.0, 1e-6); // Change coordinates c_matrix<double, 4, 4> x_rotation_matrix = identity_matrix<double>(4); double theta = M_PI/2; x_rotation_matrix(1,1) = cos(theta); x_rotation_matrix(1,2) = sin(theta); x_rotation_matrix(2,1) = -sin(theta); x_rotation_matrix(2,2) = cos(theta); ChastePoint<3> corner_before = mesh.GetNode(6)->GetPoint(); TS_ASSERT_EQUALS(corner_before[0], 1.0); TS_ASSERT_EQUALS(corner_before[1], 1.0); TS_ASSERT_EQUALS(corner_before[2], 1.0); for (unsigned i=0; i<mesh.GetNumNodes(); i++) { Node<3>* p_node = mesh.GetNode(i); ChastePoint<3> point = p_node->GetPoint(); c_vector<double, 4> point_location; point_location[0] = point[0]; point_location[1] = point[1]; point_location[2] = point[2]; point_location[3] = 1.0; c_vector<double, 4> new_point_location = prod(x_rotation_matrix, point_location); TS_ASSERT_EQUALS(new_point_location[3], 1.0); point.SetCoordinate(0, new_point_location[0]); point.SetCoordinate(1, new_point_location[1]); point.SetCoordinate(2, new_point_location[2]); p_node->SetPoint(point); } ChastePoint<3> corner_after = mesh.GetNode(6)->GetPoint(); TS_ASSERT_EQUALS(corner_after[0], 1.0); TS_ASSERT_EQUALS(corner_after[1], 1.0); TS_ASSERT_DELTA(corner_after[2], -1.0, 1e-7); mesh.RefreshMesh(); TS_ASSERT_DELTA(mesh.GetVolume(), 1.0, 1e-6); TS_ASSERT_DELTA(mesh.GetSurfaceArea(), 6.0, 1e-6); }
void TestAddNode() throw (Exception) { EXIT_IF_PARALLEL; // HoneycombMeshGenerator doesn't work in parallel // Create generating mesh HoneycombMeshGenerator generator(4, 4); TetrahedralMesh<2,2>* p_generating_mesh = generator.GetMesh(); // Convert this to a Cylindrical2dNodesOnlyMesh double periodic_width = 4.0; Cylindrical2dNodesOnlyMesh* p_mesh = new Cylindrical2dNodesOnlyMesh(periodic_width); p_mesh->ConstructNodesWithoutMesh(*p_generating_mesh, periodic_width); // ReMesh to make the box collection big enough to accommodate new nodes. p_mesh->ResizeBoxCollection(); // Choose a node on the left boundary ChastePoint<2> point = p_mesh->GetNode(4)->GetPoint(); TS_ASSERT_DELTA(point[0], 0.5, 1e-4); TS_ASSERT_DELTA(point[1], 0.5*sqrt(3.0), 1e-4); // Create a new node close to this node point.SetCoordinate(0, -0.01); Node<2>* p_node = new Node<2>(p_mesh->GetNumNodes(), point); unsigned old_num_nodes = p_mesh->GetNumNodes(); // Add this new node to the mesh unsigned new_index = p_mesh->AddNode(p_node); TS_ASSERT_EQUALS(new_index, old_num_nodes); // Check that the mesh is updated TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 17u); TS_ASSERT_DELTA(p_mesh->GetNode(new_index)->rGetLocation()[0], 3.99, 1e-4); TS_ASSERT_DELTA(p_mesh->GetNode(new_index)->rGetLocation()[1], 0.5*sqrt(3.0), 1e-4); // Now test AddNode() when mDeletedNodeIndices is populated // Label node 14 as deleted p_mesh->mDeletedNodeIndices.push_back(14); // Create a new node ChastePoint<2> point2; point2.SetCoordinate(0, 2.0); point2.SetCoordinate(1, 2.1); Node<2>* p_node2 = new Node<2>(p_mesh->GetNumNodes(), point); // Add this new node to the mesh new_index = p_mesh->AddNode(p_node2); TS_ASSERT_EQUALS(p_mesh->SolveNodeMapping(new_index), 14u); // Avoid memory leak delete p_mesh; }
void TestAddNodeAndReMesh() throw (Exception) { // Create mesh CylindricalHoneycombVertexMeshGenerator generator(6, 6); Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh(); TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 84u); TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 36u); // Choose a node on the left boundary ChastePoint<2> point = p_mesh->GetNode(18)->GetPoint(); TS_ASSERT_DELTA(point[0], 0.5, 1e-4); TS_ASSERT_DELTA(point[1], 4.0*0.5/sqrt(3.0), 1e-4); // Create a new node close to this node point.SetCoordinate(0, -0.01); point.SetCoordinate(1, 4.5); Node<2>* p_node = new Node<2>(p_mesh->GetNumNodes(), point); unsigned old_num_nodes = p_mesh->GetNumNodes(); // Add this new node to the mesh unsigned new_index = p_mesh->AddNode(p_node); TS_ASSERT_EQUALS(new_index, old_num_nodes); // Remesh to update correspondences VertexElementMap map(p_mesh->GetNumElements()); p_mesh->ReMesh(map); TS_ASSERT_EQUALS(map.Size(), p_mesh->GetNumElements()); TS_ASSERT_EQUALS(map.IsIdentityMap(), true); // Check that the mesh is updated TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 85u); TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 36u); TS_ASSERT_DELTA(p_mesh->GetNode(new_index)->rGetLocation()[0], 5.99, 1e-4); TS_ASSERT_DELTA(p_mesh->GetNode(new_index)->rGetLocation()[1], 4.5000, 1e-4); // Now test AddNode() when mDeletedNodeIndices is populated // Label node 29 as deleted p_mesh->mDeletedNodeIndices.push_back(29); // Create a new node close to this node ChastePoint<2> point2; point2.SetCoordinate(0, 2.0); point2.SetCoordinate(1, 2.1); Node<2>* p_node2 = new Node<2>(p_mesh->GetNumNodes(), point); // Add this new node to the mesh new_index = p_mesh->AddNode(p_node2); TS_ASSERT_EQUALS(new_index, 29u); }
unsigned MutableMesh<ELEMENT_DIM, SPACE_DIM>::RefineElement( Element<ELEMENT_DIM,SPACE_DIM>* pElement, ChastePoint<SPACE_DIM> point) { //Check that the point is in the element if (pElement->IncludesPoint(point, true) == false) { EXCEPTION("RefineElement could not be started (point is not in element)"); } // Add a new node from the point that is passed to RefineElement unsigned new_node_index = AddNode(new Node<SPACE_DIM>(0, point.rGetLocation())); // Note: the first argument is the index of the node, which is going to be // overridden by AddNode, so it can safely be ignored // This loop constructs the extra elements which are going to fill the space for (unsigned i = 0; i < ELEMENT_DIM; i++) { // First, make a copy of the current element making sure we update its index unsigned new_elt_index; if (mDeletedElementIndices.empty()) { new_elt_index = this->mElements.size(); } else { new_elt_index = mDeletedElementIndices.back(); mDeletedElementIndices.pop_back(); } Element<ELEMENT_DIM,SPACE_DIM>* p_new_element= new Element<ELEMENT_DIM,SPACE_DIM>(*pElement, new_elt_index); // Second, update the node in the element with the new one p_new_element->UpdateNode(ELEMENT_DIM-1-i, this->mNodes[new_node_index]); // Third, add the new element to the set if ((unsigned) new_elt_index == this->mElements.size()) { this->mElements.push_back(p_new_element); } else { delete this->mElements[new_elt_index]; this->mElements[new_elt_index] = p_new_element; } } // Lastly, update the last node in the element to be refined pElement->UpdateNode(ELEMENT_DIM, this->mNodes[new_node_index]); return new_node_index; }
c_vector<double, SPACE_DIM> Element<ELEMENT_DIM, SPACE_DIM>::CalculateXi(const ChastePoint<SPACE_DIM>& rTestPoint) { //Can only test if it's a tetrahedral mesh in 3d, triangles in 2d... assert(ELEMENT_DIM == SPACE_DIM); // Find the location with respect to node 0 ///\todo: #1361 ComputeContainingElements and related methods, and methods called by that down to /// here, should really take in const c_vector& rather than ChastePoints. c_vector<double, SPACE_DIM> test_location=rTestPoint.rGetLocation()-this->GetNodeLocation(0); //Multiply by inverse Jacobian c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian; c_matrix<double, ELEMENT_DIM, SPACE_DIM> inverse_jacobian; double jacobian_determinant; ///\todo #1326 This method shouldn't need a new Jacobian inverse for every Xi this->CalculateInverseJacobian(jacobian, jacobian_determinant, inverse_jacobian); return prod(inverse_jacobian, test_location); }
void Cylindrical2dMesh::SetNode(unsigned index, ChastePoint<2> point, bool concreteMove) { // Perform a periodic movement if necessary if (point.rGetLocation()[0] >= mWidth) { // Move point to the left point.SetCoordinate(0, point.rGetLocation()[0] - mWidth); } else if (point.rGetLocation()[0] < 0.0) { // Move point to the right point.SetCoordinate(0, point.rGetLocation()[0] + mWidth); } // Update the node's location MutableMesh<2,2>::SetNode(index, point, concreteMove); }
void TestGeneralConvolution3DWithHomogeneousUblas() { TrianglesMeshReader<3,3> mesh_reader("mesh/test/data/cube_136_elements"); TetrahedralMesh<3,3> mesh; mesh.ConstructFromMeshReader(mesh_reader); TS_ASSERT_DELTA(mesh.GetVolume(), 1.0, 1e-6); TS_ASSERT_DELTA(mesh.GetSurfaceArea(), 6.0, 1e-6); // Change coordinates c_matrix<double, 4, 4> x_rotation_matrix = identity_matrix<double>(4); c_matrix<double, 4, 4> y_rotation_matrix = identity_matrix<double>(4); c_matrix<double, 4, 4> z_rotation_matrix = identity_matrix<double>(4); c_matrix<double, 4, 4> translation_matrix = identity_matrix<double>(4); double theta = 0.7; double phi = 0.3; double psi = 1.4; x_rotation_matrix(1,1) = cos(theta); x_rotation_matrix(1,2) = sin(theta); x_rotation_matrix(2,1) = -sin(theta); x_rotation_matrix(2,2) = cos(theta); y_rotation_matrix(0,0) = cos(phi); y_rotation_matrix(0,2) = -sin(phi); y_rotation_matrix(2,0) = sin(phi); y_rotation_matrix(2,2) = cos(phi); z_rotation_matrix(0,0) = cos(psi); z_rotation_matrix(0,1) = sin(psi); z_rotation_matrix(1,0) = -sin(psi); z_rotation_matrix(1,1) = cos(psi); translation_matrix(0,3) = 2.3; translation_matrix(1,3) = 3.1; translation_matrix(2,3) = 1.7; /* Note: because we are using column-major vectors this tranformation: RotX(theta) . RotY(phi) . RotZ(psi) . Trans(...) is actually being applied right-to-left See test below. */ c_matrix<double, 4, 4> transformation_matrix = prod (x_rotation_matrix, y_rotation_matrix); transformation_matrix = prod (transformation_matrix, z_rotation_matrix); transformation_matrix = prod (transformation_matrix, translation_matrix); for (unsigned i=0; i<mesh.GetNumNodes(); i++) { Node<3>* p_node = mesh.GetNode(i); ChastePoint<3> point = p_node->GetPoint(); c_vector<double, 4> point_location; point_location[0] = point[0]; point_location[1] = point[1]; point_location[2] = point[2]; point_location[3] = 1.0; c_vector<double, 4> new_point_location = prod(transformation_matrix, point_location); TS_ASSERT_EQUALS(new_point_location[3], 1.0); point.SetCoordinate(0,new_point_location[0]); point.SetCoordinate(1,new_point_location[1]); point.SetCoordinate(2,new_point_location[2]); p_node->SetPoint(point); } mesh.RefreshMesh(); TS_ASSERT_DELTA(mesh.GetVolume(), 1.0, 1e-6); TS_ASSERT_DELTA(mesh.GetSurfaceArea(), 6.0, 1e-6); ChastePoint<3> corner_after = mesh.GetNode(6)->GetPoint(); TS_ASSERT_DELTA(corner_after[0], 3.59782, 5e-5); TS_ASSERT_DELTA(corner_after[1], 0.583418, 5e-5); TS_ASSERT_DELTA(corner_after[2], 4.65889, 5e-5); // Write to file TrianglesMeshWriter<3,3> mesh_writer("","TransformedMesh"); mesh_writer.WriteFilesUsingMesh(mesh); /* * Now try tetview /tmp/chaste/testoutput/TransformedMesh */ }
void CellBasedPdeHandler<DIM>::UseCoarsePdeMesh(double stepSize, ChasteCuboid<DIM> meshCuboid, bool centreOnCellPopulation) { if (mPdeAndBcCollection.empty()) { EXCEPTION("mPdeAndBcCollection should be populated prior to calling UseCoarsePdeMesh()."); } // If solving PDEs on a coarse mesh, each PDE must have an averaged source term for (unsigned pde_index=0; pde_index<mPdeAndBcCollection.size(); pde_index++) { if (mPdeAndBcCollection[pde_index]->HasAveragedSourcePde() == false && !dynamic_cast<MultipleCaBasedCellPopulation<DIM>*>(mpCellPopulation)) { EXCEPTION("UseCoarsePdeMesh() should only be called if averaged-source PDEs are specified."); } } // Create a regular coarse tetrahedral mesh mpCoarsePdeMesh = new TetrahedralMesh<DIM,DIM>; switch (DIM) { case 1: mpCoarsePdeMesh->ConstructRegularSlabMesh(stepSize, meshCuboid.GetWidth(0)); break; case 2: mpCoarsePdeMesh->ConstructRegularSlabMesh(stepSize, meshCuboid.GetWidth(0), meshCuboid.GetWidth(1)); break; case 3: mpCoarsePdeMesh->ConstructRegularSlabMesh(stepSize, meshCuboid.GetWidth(0), meshCuboid.GetWidth(1), meshCuboid.GetWidth(2)); break; default: NEVER_REACHED; } if (centreOnCellPopulation) { // Find the centre of the coarse PDE mesh c_vector<double,DIM> centre_of_coarse_mesh = zero_vector<double>(DIM); for (unsigned i=0; i<mpCoarsePdeMesh->GetNumNodes(); i++) { centre_of_coarse_mesh += mpCoarsePdeMesh->GetNode(i)->rGetLocation(); } centre_of_coarse_mesh /= mpCoarsePdeMesh->GetNumNodes(); // Translate the centre of coarse PDE mesh to the centre of the cell population c_vector<double,DIM> centre_of_cell_population = mpCellPopulation->GetCentroidOfCellPopulation(); mpCoarsePdeMesh->Translate(centre_of_cell_population - centre_of_coarse_mesh); } else { // Get centroid of meshCuboid ChastePoint<DIM> upper = meshCuboid.rGetUpperCorner(); ChastePoint<DIM> lower = meshCuboid.rGetLowerCorner(); c_vector<double,DIM> centre_of_cuboid = 0.5*(upper.rGetLocation() + lower.rGetLocation()); // Find the centre of the coarse PDE mesh c_vector<double,DIM> centre_of_coarse_mesh = zero_vector<double>(DIM); for (unsigned i=0; i<mpCoarsePdeMesh->GetNumNodes(); i++) { centre_of_coarse_mesh += mpCoarsePdeMesh->GetNode(i)->rGetLocation(); } centre_of_coarse_mesh /= mpCoarsePdeMesh->GetNumNodes(); mpCoarsePdeMesh->Translate(centre_of_cuboid - centre_of_coarse_mesh); } }