diff --git a/src/pmpo_MPMesh_assembly.hpp b/src/pmpo_MPMesh_assembly.hpp index 2f81aa6..733fd16 100644 --- a/src/pmpo_MPMesh_assembly.hpp +++ b/src/pmpo_MPMesh_assembly.hpp @@ -83,7 +83,7 @@ void MPMesh::assemblyElm0() { if(mask) { //if material point is 'active'/'enabled' Kokkos::atomic_add(&mpsPerElm(elm),1); for(int j=0;j void MPMesh::assemblyVtx1() { - constexpr MaterialPointSlice mpfIndex = meshFieldIndexToMPSlice; + //Mesh Information auto elm2VtxConn = p_mesh->getElm2VtxConn(); - auto mpData = p_MPs->getData(); - const int numEntries = mpSliceToNumEntries(); 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(); + + //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(); + + //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' int nVtxE = elm2VtxConn(elm,0); //number of vertices bounding the element for(int i=0; iparallel_for(assemble, "assembly"); + + //Solve Ax=b for each vertex + Kokkos::View VtxCoeffs("VtxMatrices", 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 f_norm=A.frobeniusNorm(); + double A_trace = A.trace(); + Matrix4d A_regularized = {v0, v1, v2, v3}; + A_regularized.addToDiag(A_trace*1e-8); + + double coeff[vec4d_nEntries]={0.0, 0.0, 0.0, 0.0}; + CholeskySolve4d_UnitRHS(A_regularized, coeff); + for (int i=0; iparallel_for(reconstruct, "reconstruct"); + + Kokkos::parallel_for("assigning", numVtx, KOKKOS_LAMBDA(const int vtx){ + for(int k=0; k diff --git a/src/pmpo_materialPoints.hpp b/src/pmpo_materialPoints.hpp index 4c37a16..77a325c 100644 --- a/src/pmpo_materialPoints.hpp +++ b/src/pmpo_materialPoints.hpp @@ -211,25 +211,26 @@ class MaterialPoints { auto tgtPosXYZ = MPs->get(); auto rotLatLonIncr = MPs->get(); + auto is_rotated = getRotatedFlag(); auto updateRotLatLon = PS_LAMBDA(const int& elm, const int& mp, const int& mask){ if(mask){ auto rotLat = curPosRotLatLon(mp,0) + rotLatLonIncr(mp,0); // phi - auto rotLon = curPosRotLatLon(mp,1) + rotLatLonIncr(mp,1); // lambda + auto rotLon = curPosRotLatLon(mp,1) + rotLatLonIncr(mp,1); // lambda + tgtPosRotLatLon(mp,0) = rotLat; + tgtPosRotLatLon(mp,1) = rotLon; auto geoLat = rotLat; auto geoLon = rotLon; - tgtPosRotLatLon(mp,0) = geoLat; - tgtPosRotLatLon(mp,1) = geoLon; + if(is_rotated){ + auto xyz_rot = xyz_from_lat_lon(rotLat, rotLon, radius); + auto xyz_geo = grid_rotation_backward(xyz_rot); + lat_lon_from_xyz(geoLat, geoLon, xyz_geo, radius); + } // x = cosLon cosLat, y = sinLon cosLat, z = sinLat tgtPosXYZ(mp,0) = radius * std::cos(geoLon) * std::cos(geoLat); tgtPosXYZ(mp,1) = radius * std::sin(geoLon) * std::cos(geoLat); - tgtPosXYZ(mp,2) = radius * std::sin(geoLat); + tgtPosXYZ(mp,2) = radius * std::sin(geoLat); } }; - if(isRotatedFlag){ - //TODO rotation lat lon calc - fprintf(stderr, "rotational lat lon in MP is not support yet!"); - PMT_ALWAYS_ASSERT(false); - } ps::parallel_for(MPs, updateRotLatLon,"updateRotationalLatitudeLongitude"); pumipic::RecordTime("PolyMPO_updateRotLatLonAndXYZ2Tgt", timer.seconds()); } diff --git a/src/pmpo_utils.hpp b/src/pmpo_utils.hpp index af6e397..42971d7 100644 --- a/src/pmpo_utils.hpp +++ b/src/pmpo_utils.hpp @@ -21,14 +21,22 @@ void PMT_Assert_Fail(const char* msg) __attribute__ ((noreturn)); namespace polyMPO{ +const double EPSILON = std::numeric_limits::epsilon(); + #define vec2d_nEntries 2 typedef double vec2d_t[vec2d_nEntries]; #define vec3d_nEntries 3 typedef double vec3d_t[vec3d_nEntries]; +#define vec4d_nEntries 4 +typedef double vec4d_t[vec4d_nEntries]; + typedef double doubleSclr_t[1]; class Vec2d; class Vec3d; +class Vec4d; +class Matrix4d; + using Vec2dView = Kokkos::View; using Vec3dView = Kokkos::View; using DoubleView = Kokkos::View; @@ -145,6 +153,147 @@ class Vec3d{ } }; + +class Vec4d{ + + private: + vec4d_t coords_; + + public: + + //constructors + KOKKOS_INLINE_FUNCTION + Vec4d():coords_{0.0, 0.0, 0.0, 0.0}{} + ~Vec4d() = default; + + KOKKOS_INLINE_FUNCTION + Vec4d(double x1, double x2, double x3, double x4):coords_{x1,x2,x3,x4}{} + + KOKKOS_INLINE_FUNCTION + Vec4d(double x[4]):coords_{x[0], x[1], x[2], x[3]}{} + + //operators + KOKKOS_INLINE_FUNCTION + double operator[](int i) const { return coords_[i]; } + + KOKKOS_INLINE_FUNCTION + double &operator[](int i) { return coords_[i]; } + + KOKKOS_INLINE_FUNCTION + Vec4d operator+(const Vec4d& v) const { + return Vec4d(coords_[0] + v.coords_[0], coords_[1] + v.coords_[1], + coords_[2] + v.coords_[2], coords_[3] + v.coords_[3]); + } + + KOKKOS_INLINE_FUNCTION + Vec4d operator-(const Vec4d& v) const { + return Vec4d(coords_[0] - v.coords_[0], coords_[1] - v.coords_[1], + coords_[2] - v.coords_[2], coords_[3] - v.coords_[3]); + } + + KOKKOS_INLINE_FUNCTION + Vec4d operator-() { return Vec4d(-coords_[0], -coords_[1], -coords_[2], -coords_[3]); } + + KOKKOS_INLINE_FUNCTION + Vec4d operator*(double scalar) const { + return Vec4d(coords_[0] * scalar, coords_[1] * scalar, coords_[2] * scalar, coords_[3] * scalar); + } + + KOKKOS_INLINE_FUNCTION + double dot(const Vec4d& v) const { + return coords_[0] * v.coords_[0] + coords_[1] * v.coords_[1] + coords_[2] * v.coords_[2] + coords_[3] * v.coords_[3]; + } + + KOKKOS_INLINE_FUNCTION + double magnitude() const { + return std::sqrt(coords_[0] * coords_[0] + coords_[1] * coords_[1] + coords_[2] * coords_[2] + coords_[3] * coords_[3]); + } +}; + +class Matrix4d { + + private: + + double** data_; + int rows_=4; + int cols_=4; + + public: + + KOKKOS_INLINE_FUNCTION + Matrix4d(Vec4d v0, Vec4d v1, Vec4d v2, Vec4d v3){ + data_ = new double*[rows_]; + + for (int i=0; iEPSILON){ + A(1,1)=std::sqrt(diag); + A(1,2)=(A(1,2)-A(0,1)*A(0,2))/A(1,1); + A(1,3)=(A(1,3)-A(0,1)*A(0,3))/A(1,1); + } + else{ + A(1,1)=0.0; + A(1,2)=0.0; + A(1,3)=0.0; + } + + diag = A(2,2) - A(0,2)*A(0,2)-A(1,2)*A(1,2); + if(diag>EPSILON){ + A(2,2)=std::sqrt(diag); + A(2,3)=(A(2,3)-A(0,2)*A(0,3)-A(1,2)*A(1,3))/A(2,2); + } + else{ + A(2,2)=0.0; + A(2,3)=0.0; + } + + diag=A(3,3)-A(0,3)*A(0,3)-A(1,3)*A(1,3)-A(2,3)*A(2,3); + if(diag>EPSILON) + A(3,3)=std::sqrt(diag); + else + A(3,3)=0.0; + + if(abs(A(1,1)) max_push_diff ) then + max_push_diff = abs(mpLatLon_new(2,i)-mpLatLon(2,i)) + end if + end do + call assert(max_push_diff.le.TOLERANCE_PUSH , "MPs donot come back check push!") + if (testType == "API") then call runApiTest(mpMesh, numMPs, nVertices, nCells, numPush, mpLatLon, mpPosition, xVertex, yVertex, zVertex, latVertex) else if (testType == "MIGRATION") then diff --git a/test/testFortranMPReconstruction.f90 b/test/testFortranMPReconstruction.f90 index 5831291..7411af5 100644 --- a/test/testFortranMPReconstruction.f90 +++ b/test/testFortranMPReconstruction.f90 @@ -19,6 +19,7 @@ program main real(kind=MPAS_RKIND) :: pi = 4.0_MPAS_RKIND*atan(1.0_MPAS_RKIND) real(kind=MPAS_RKIND) :: TEST_VAL = 1.1_MPAS_RKIND real(kind=MPAS_RKIND) :: TOLERANCE = 0.0001_MPAS_RKIND + real(kind=MPAS_RKIND) :: TOLERANCE1 = 0.0000000001_MPAS_RKIND character (len=2048) :: filename real(kind=MPAS_RKIND), dimension(:,:), pointer :: dispIncr character (len=64) :: onSphere @@ -32,7 +33,7 @@ program main integer, dimension(:), pointer :: mpsPerElm, mp2Elm, isMPActive real(kind=MPAS_RKIND), dimension(:,:), pointer :: mpPosition, mpLatLon real(kind=MPAS_RKIND), dimension(:,:), pointer :: mpMass, mpVel - real(kind=MPAS_RKIND), dimension(:), pointer :: meshVtxMass, meshElmMass + real(kind=MPAS_RKIND), dimension(:), pointer :: meshVtxMass, meshElmMass, meshVtxMass1 logical :: inBound integer, parameter :: MP_ACTIVE = 1 integer, parameter :: MP_INACTIVE = 0 @@ -88,6 +89,7 @@ program main allocate(mpMass(1,numMPs)) allocate(mpVel(2,numMPs)) allocate(meshVtxMass(nVertices)) + allocate(meshVtxMass1(nVertices)) allocate(meshElmMass(nCells)) isMPActive = MP_ACTIVE !all active MPs and some changed below @@ -99,9 +101,9 @@ program main j = verticesOnCell(1,i) mpLatLon(1,i) = latVertex(j) mpLatLon(2,i) = lonVertex(j) - mpPosition(1,i) = xVertex(j) - mpPosition(2,i) = yVertex(j) - mpPosition(3,i) = zVertex(j) + mpPosition(1,i) = xCell(i) + mpPosition(2,i) = yCell(i) + mpPosition(3,i) = zCell(i) end do call polympo_createMPs(mpMesh,nCells,numMPs,c_loc(mpsPerElm),c_loc(mp2Elm),c_loc(isMPActive)) @@ -112,7 +114,6 @@ program main call polympo_setMPVel(mpMesh,2,numMPs,c_loc(mpVel)) ! Test vtx reconstruction - call polympo_setReconstructionOfMass(mpMesh,0,polympo_getMeshFVtxType()) call polympo_applyReconstruction(mpMesh) call polympo_getMeshVtxMass(mpMesh,nVertices,c_loc(meshVtxMass)) @@ -121,8 +122,16 @@ program main call assert(meshVtxMass(i) < TEST_VAL+TOLERANCE .and. meshVtxMass(i) > TEST_VAL-TOLERANCE, "Error: wrong vtx mass") end do - ! Test push reconstruction + !Test vtx order 1 reconstruction + call polympo_setReconstructionOfMass(mpMesh,1,polympo_getMeshFVtxType()) + call polympo_applyReconstruction(mpMesh) + call polympo_getMeshVtxMass(mpMesh,nVertices,c_loc(meshVtxMass1)) + do i = 1, nVertices + call assert(meshVtxMass1(i) < TEST_VAL+TOLERANCE1 .and. meshVtxMass1(i) > TEST_VAL-TOLERANCE1, "Error: wrong vtx mass lINEAR") + end do + + ! Test push reconstruction do j = 1, 5 call calcSurfDispIncr(mpMesh, latVertex, lonVertex, nEdgesOnCell, verticesOnCell, nVertices, sphereRadius) call polympo_setReconstructionOfMass(mpMesh,0,polympo_getMeshFElmType()) @@ -164,6 +173,7 @@ program main deallocate(mpMass) deallocate(mpVel) deallocate(meshVtxMass) + deallocate(meshVtxMass1) deallocate(meshElmMass) stop