diff --git a/src/pmpo_MPMesh.cpp b/src/pmpo_MPMesh.cpp index 45319be..a5f709a 100644 --- a/src/pmpo_MPMesh.cpp +++ b/src/pmpo_MPMesh.cpp @@ -301,6 +301,7 @@ void MPMesh::reconstructSlices() { if (reconstructSlice.size() == 0) return; Kokkos::Timer timer; calcBasis(); + resetPreComputeFlag(); for (auto const& [index, reconstruct] : reconstructSlice) { if (reconstruct) reconstruct(); } diff --git a/src/pmpo_MPMesh.hpp b/src/pmpo_MPMesh.hpp index 5a63ef9..33f0599 100644 --- a/src/pmpo_MPMesh.hpp +++ b/src/pmpo_MPMesh.hpp @@ -16,7 +16,17 @@ template <> const MaterialPointSlice meshFieldIndexToMPSlice < MeshF_RotLatLonIn #define maxMPsPerElm 8 class MPMesh{ + private: + + bool isPreComputed; + public: + + MPMesh() : isPreComputed(false){}; + void computeMatricesAndSolve(); + void resetPreComputeFlag(); + Kokkos::View precomputedVtxCoeffs; + Mesh* p_mesh; MaterialPoints* p_MPs; @@ -49,7 +59,7 @@ class MPMesh{ void assemblyElm0(); template void assemblyVtx1(); - + template void setReconstructSlice(int order, MeshFieldType type); void reconstructSlices(); diff --git a/src/pmpo_MPMesh_assembly.hpp b/src/pmpo_MPMesh_assembly.hpp index e5dedb5..25899b9 100644 --- a/src/pmpo_MPMesh_assembly.hpp +++ b/src/pmpo_MPMesh_assembly.hpp @@ -98,35 +98,36 @@ void MPMesh::assemblyElm0() { pumipic::RecordTime("PolyMPO_Reconstruct_Elm0", timer.seconds()); } -template -void MPMesh::assemblyVtx1() { + +void MPMesh::resetPreComputeFlag(){ + isPreComputed = false; +} + +void MPMesh::computeMatricesAndSolve(){ + //Mesh Information auto elm2VtxConn = p_mesh->getElm2VtxConn(); int numVtx = p_mesh->getNumVertices(); auto vtxCoords = p_mesh->getMeshField(); - //Mesh Field - constexpr MaterialPointSlice mpfIndex = meshFieldIndexToMPSlice; - const int numEntries = mpSliceToNumEntries(); - p_mesh->fillMeshField(numVtx, numEntries, 0.0); - auto meshField = p_mesh->getMeshField(); + //Dual Element Area for Regularization + auto dual_triangle_area=p_mesh->getMeshField(); //Material Points - auto mpData = p_MPs->getData(); auto weight = p_MPs->getData(); auto mpPositions = p_MPs->getData(); //Matrix for each vertex Kokkos::View VtxMatrices("VtxMatrices", p_mesh->getNumVertices()); - //Reconstructed values - Kokkos::View reconVals("meshField", p_mesh->getNumVertices(), numEntries); - //Earth Radius double radius = 1.0; if(p_mesh->getGeomType() == geom_spherical_surf) radius=p_mesh->getSphereRadius(); + bool scaling=true; + int reg_method = 2; + //Assemble matrix for each vertex auto assemble = PS_LAMBDA(const int& elm, const int& mp, const int& mask) { if(mask) { //if material point is 'active'/'enabled' @@ -134,37 +135,112 @@ void MPMesh::assemblyVtx1() { for(int i=0; iparallel_for(assemble, "assembly"); - //Solve Ax=b for each vertex + //Assemble matrix for each vertex and apply regularization Kokkos::View VtxCoeffs("VtxCoeffs", p_mesh->getNumVertices()); + Kokkos::parallel_for("solving Ax=b", numVtx, KOKKOS_LAMBDA(const int vtx){ Vec4d v0 = {VtxMatrices(vtx,0,0), VtxMatrices(vtx,0,1), VtxMatrices(vtx,0,2), VtxMatrices(vtx,0,3)}; Vec4d v1 = {VtxMatrices(vtx,1,0), VtxMatrices(vtx,1,1), VtxMatrices(vtx,1,2), VtxMatrices(vtx,1,3)}; Vec4d v2 = {VtxMatrices(vtx,2,0), VtxMatrices(vtx,2,1), VtxMatrices(vtx,2,2), VtxMatrices(vtx,2,3)}; Vec4d v3 = {VtxMatrices(vtx,3,0), VtxMatrices(vtx,3,1), VtxMatrices(vtx,3,2), VtxMatrices(vtx,3,3)}; - - Matrix4d A = {v0,v1,v2,v3}; - double A_trace = A.trace(); + //Define the matrices + Matrix4d A = {v0,v1,v2,v3}; Matrix4d A_regularized = {v0, v1, v2, v3}; - A_regularized.addToDiag(A_trace*1e-8); - + //Regularization + switch(reg_method){ + case 0:{ + break; + } + case 1:{ + double A_trace = A.trace(); + A_regularized.addToDiag(A_trace*1e-8); + break; + } + case 2:{ + double regParam=sqrt(EPSILON)*(VtxMatrices(vtx,0,0)+VtxMatrices(vtx,1,1)+ + VtxMatrices(vtx,2,2)+VtxMatrices(vtx,3,3)); + A_regularized.addToDiag(regParam); + break; + } + default:{ + printf("Invalid regularization method \n"); + break; + } + } + //Solve Ax=b double coeff[vec4d_nEntries]={0.0, 0.0, 0.0, 0.0}; CholeskySolve4d_UnitRHS(A_regularized, coeff); + // Undo scaling + double mScale=1; + if(scaling) + mScale=sqrt(dual_triangle_area(vtx,0))/radius; + + coeff[0]=coeff[0]*mScale*mScale; + coeff[1]=coeff[1]*mScale; + coeff[2]=coeff[2]*mScale; + coeff[3]=coeff[3]*mScale; for (int i=0; iprecomputedVtxCoeffs = VtxCoeffs; +} + +template +void MPMesh::assemblyVtx1() { + + //If no reconstruction till now calculate the coeffs + if (!isPreComputed) { + computeMatricesAndSolve(); + isPreComputed=true; + } + auto VtxCoeffs=this->precomputedVtxCoeffs; + //Mesh Information + auto elm2VtxConn = p_mesh->getElm2VtxConn(); + int numVtx = p_mesh->getNumVertices(); + auto vtxCoords = p_mesh->getMeshField(); + + //Mesh Field + constexpr MaterialPointSlice mpfIndex = meshFieldIndexToMPSlice; + const int numEntries = mpSliceToNumEntries(); + p_mesh->fillMeshField(numVtx, numEntries, 0.0); + auto meshField = p_mesh->getMeshField(); + + //Material Points + auto mpData = p_MPs->getData(); + auto weight = p_MPs->getData(); + auto mpPositions = p_MPs->getData(); + + //Earth Radius + double radius = 1.0; + if(p_mesh->getGeomType() == geom_spherical_surf) + radius=p_mesh->getSphereRadius(); + + //Reconstructed values + Kokkos::View reconVals("meshField", p_mesh->getNumVertices(), numEntries); + //Reconstruct auto reconstruct = PS_LAMBDA(const int& elm, const int& mp, const int& mask) { if(mask) { //if material point is 'active'/'enabled' @@ -175,7 +251,7 @@ void MPMesh::assemblyVtx1() { double CoordDiffs[vec4d_nEntries] = {1, (vtxCoords(vID,0) - mpPositions(mp,0))/radius, (vtxCoords(vID,1) - mpPositions(mp,1))/radius, (vtxCoords(vID,2) - mpPositions(mp,2))/radius}; - + auto factor = w_vtx*(VtxCoeffs(vID,0) + VtxCoeffs(vID,1)*CoordDiffs[1] + VtxCoeffs(vID,2)*CoordDiffs[2] + VtxCoeffs(vID,3)*CoordDiffs[3]); @@ -188,7 +264,8 @@ void MPMesh::assemblyVtx1() { } }; p_MPs->parallel_for(reconstruct, "reconstruct"); - + + //Assign as a field Kokkos::parallel_for("assigning", numVtx, KOKKOS_LAMBDA(const int vtx){ for(int k=0; kp_mesh; + + //check the size + PMT_ALWAYS_ASSERT(p_mesh->getNumVertices()==nVertices); + + //copy the host array to the device + auto dualArea = p_mesh->getMeshField(); + auto h_dualArea = Kokkos::create_mirror_view(dualArea); + for(int i=0; ip_mesh; + + //check the size + PMT_ALWAYS_ASSERT(p_mesh->getNumVertices()==nVertices); + + //copy the device to host + auto dualArea = p_mesh->getMeshField(); + auto h_dualArea = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), dualArea); + for(int i=0; i @brief set the polympo dual mesh triangle area + !> @param mpmesh(in/out) MPMesh object + !> @param nVertices(in) length of array in, use for assertion + !> @param Array(in) 1D array of area of dual triangle elements + !--------------------------------------------------------------------------- + subroutine polympo_setMeshDualTriangleArea(mpMesh, nVertices, areaTriangle) & + bind(C, NAME='polympo_setMeshDualTriangleArea_f') + use :: iso_c_binding + type(c_ptr), value :: mpMesh + integer(c_int), value :: nVertices + type(c_ptr), intent(in), value :: areaTriangle + end subroutine + !--------------------------------------------------------------------------- + !> @brief get the polympo mesh dual mesh triangle area + !> @param mpmesh(in/out) MPMesh object + !> @param nVetices(in) length of array in, use for assertion + !> @param Array(in/out) 1D array of area of dual triangle elements + !--------------------------------------------------------------------------- + subroutine polympo_getMeshDualTriangleArea(mpMesh, nVertices, areaTriangle) & + bind(C, NAME='polympo_getMeshDualTriangleArea_f') + use :: iso_c_binding + type(c_ptr), value :: mpMesh + integer(c_int), value :: nVertices + type(c_ptr), value :: areaTriangle + end subroutine + !--------------------------------------------------------------------------- !> @brief set the vertices velocity from a host array !> @param mpmesh(in/out) MPMesh object diff --git a/src/pmpo_mesh.cpp b/src/pmpo_mesh.cpp index cdf9b28..9232ad1 100644 --- a/src/pmpo_mesh.cpp +++ b/src/pmpo_mesh.cpp @@ -41,6 +41,10 @@ namespace polyMPO{ auto vtxRotLatLonIncrMapEntry = meshFields2TypeAndString.at(MeshF_RotLatLonIncr); PMT_ALWAYS_ASSERT(vtxRotLatLonIncrMapEntry.first == MeshFType_VtxBased); vtxRotLatLonIncr_ = MeshFView(vtxRotLatLonIncrMapEntry.second,numVtxs_); + + auto dualTriangleAreaEntry = meshFields2TypeAndString.at(MeshF_DualTriangleArea); + PMT_ALWAYS_ASSERT(dualTriangleAreaEntry.first == MeshFType_VtxBased); + dualTriangleArea_ = MeshFView(dualTriangleAreaEntry.second,numVtxs_); } void Mesh::setMeshElmBasedFieldSize(){ diff --git a/src/pmpo_mesh.hpp b/src/pmpo_mesh.hpp index 3b91dc3..2058e13 100644 --- a/src/pmpo_mesh.hpp +++ b/src/pmpo_mesh.hpp @@ -20,6 +20,7 @@ enum MeshFieldIndex{ MeshF_VtxCoords, MeshF_VtxRotLat, MeshF_ElmCenterXYZ, + MeshF_DualTriangleArea, MeshF_Vel, MeshF_VtxMass, MeshF_ElmMass, @@ -38,6 +39,7 @@ template struct meshFieldToType; template <> struct meshFieldToType < MeshF_VtxCoords > { using type = Kokkos::View; }; template <> struct meshFieldToType < MeshF_VtxRotLat > { using type = DoubleView; }; template <> struct meshFieldToType < MeshF_ElmCenterXYZ > { using type = Kokkos::View; }; +template <> struct meshFieldToType < MeshF_DualTriangleArea > { using type = Kokkos::View; }; template <> struct meshFieldToType < MeshF_Vel > { using type = Kokkos::View; }; template <> struct meshFieldToType < MeshF_VtxMass > { using type = Kokkos::View; }; template <> struct meshFieldToType < MeshF_ElmMass > { using type = Kokkos::View; }; @@ -55,6 +57,7 @@ const std::map vtxCoords_; MeshFView vtxRotLat_; MeshFView elmCenterXYZ_; + MeshFView dualTriangleArea_; MeshFView vtxVel_; MeshFView vtxMass_; MeshFView elmMass_; @@ -181,6 +185,9 @@ auto Mesh::getMeshField(){ else if constexpr (index==MeshF_ElmCenterXYZ){ return elmCenterXYZ_; } + else if constexpr (index==MeshF_DualTriangleArea){ + return dualTriangleArea_; + } else if constexpr (index==MeshF_Vel){ return vtxVel_; } diff --git a/src/pmpo_utils.hpp b/src/pmpo_utils.hpp index b9d5f7d..7a2fdcd 100644 --- a/src/pmpo_utils.hpp +++ b/src/pmpo_utils.hpp @@ -274,6 +274,18 @@ class Matrix4d { data_[i][i]=data_[i][i]+eps; } } + + KOKKOS_INLINE_FUNCTION + void scaleFirstRowAndColumn(double factor) { + // Scale the first row + for (int j = 0; j < 4; j++) { + data_[0][j] *= factor; + } + // Scale the first column + for (int i = 0; i < 4; i++) { + data_[i][0] *= factor; + } + } }; @@ -358,27 +370,24 @@ void QRDecomp4d(Matrix4d& A, Matrix4d& Q, Matrix4d& R){ Vec4d u_column; for (int l=0; l TEST_VAL-TOLERANCE, "Error: wrong vtx mass") + !write(*, *) 'The value of LRV is:', meshVtxMass(i) end do !Test vtx order 1 reconstruction call polympo_setReconstructionOfMass(mpMesh,1,polympo_getMeshFVtxType()) + call polympo_setReconstructionOfVel(mpMesh, 1, polympo_getMeshFVtxType()) call polympo_applyReconstruction(mpMesh) call polympo_getMeshVtxMass(mpMesh,nVertices,c_loc(meshVtxMass1)) + call polympo_getMeshVtxVel(mpMesh, nVertices, c_loc(meshVtxVelu), c_loc(meshVtxVelv)) do i = 1, nVertices - call assert(meshVtxMass1(i) < TEST_VAL+TOLERANCE1 .and. meshVtxMass1(i) > TEST_VAL-TOLERANCE1, "Error: wrong vtx mass LINEAR") + call assert(meshVtxMass1(i) < TEST_VAL+TOLERANCE1 .and. meshVtxMass1(i) > TEST_VAL-TOLERANCE1, "Error: wrong vtx mass order 1") + call assert(meshVtxVelu(i) < TEST_VAL+TOLERANCE1 .and. meshVtxVelu(i) > TEST_VAL-TOLERANCE1, "Error: wrong vtx velU order 1") + call assert(meshVtxVelv(i) < TEST_VAL+TOLERANCE1 .and. meshVtxVelv(i) > TEST_VAL-TOLERANCE1, "Error: wrong vtx velV order 1") + write(*, *) 'The value of LRV is:', meshVtxVelu(i)-TEST_VAL, meshVtxVelv(i)-TEST_VAL end do @@ -143,7 +154,7 @@ program main do i = 1, numMPs vID = verticesOnCell(1,mp2Elm(i)) - call assert(meshVtxMass(vID) < TEST_VAL+TOLERANCE .and. meshVtxMass(vID) > TEST_VAL-TOLERANCE, "Error: wrong vtx mass") + call assert(meshVtxMass(vID) < TEST_VAL+TOLERANCE1 .and. meshVtxMass(vID) > TEST_VAL-TOLERANCE1, "Error: wrong vtx mass push") call assert(meshElmMass(mp2Elm(i)) < TEST_VAL+TOLERANCE & .and. meshElmMass(mp2Elm(i)) > TEST_VAL-TOLERANCE, "Error: wrong elm mass") @@ -175,6 +186,8 @@ program main deallocate(meshVtxMass) deallocate(meshVtxMass1) deallocate(meshElmMass) + deallocate(meshVtxVelu) + deallocate(meshVtxVelv) stop