Conversation
cwsmith
left a comment
There was a problem hiding this comment.
Thank you @jvmespark .
In addition to the comments below, I have a a few requests:
- Please add a description in the PR. If you got the shape function/gradient/quadrature points from literature please reference it.
- The CMakeLists.txt file needs to be modified to add the new test.
- Please add a test to exercise
evaluate(...)(given user defined parametric coords in each element, return the field value at those locations). As with the integration test, I'd strongly prefer a test that we know the result for and can check against it (as opposed to a simpler 'it doesn't crash' test).
| const auto family = OMEGA_H_SIMPLEX; | ||
| auto len = 1.0; | ||
| return Omega_h::build_box(world, family, len, len, len, | ||
| 2, 2, (dim == 3 ? 2 : 0)); |
There was a problem hiding this comment.
I think the template dim can be removed and the third dimension hardcoded as zero.
| { | ||
| auto mesh2D = createMesh<2>(lib); | ||
| MeshField::OmegahMeshField<ExecutionSpace, 2, MeshField::KokkosController> omf2D(mesh2D); | ||
| runReducedQuinticImplicit<MeshField::KokkosController>(mesh2D, omf2D); |
There was a problem hiding this comment.
Is there an expected result from the integration? I'd much prefer a test that we know the result for.
There was a problem hiding this comment.
There is probably some test cases in M3DC1 that I can dig up and share with James.
src/MeshField_Integrate.hpp
Outdated
| 0.1167862757264 / 2.0), | ||
| IntegrationPoint(Vector3{0.249286745, 0.249286745, 0.501426509}, | ||
| 0.1167862757264 / 2.0), | ||
|
|
There was a problem hiding this comment.
I think some of the points here do not have enough precision and fail summing to 1.
There was a problem hiding this comment.
@jvmespark This looks like it is the standard Gauss-Legendre points. You can copy them from here with more precision: https://github.com/SCOREC/core/blob/6a972af6daceec626e589b4d4f63acc22e27317f/apf/apfIntegrate.cc#L216
Alternatively, it looks like we may be able to use this script in APF to calculate to machine precision: https://github.com/SCOREC/core/blob/6a972af6daceec626e589b4d4f63acc22e27317f/apf/apfPolyBasis1D.cc
| const auto [shp, map] = MeshField::Omegah::getReducedQuinticImplicitElement(mesh); | ||
| MeshField::FieldElement fes(mesh.nelems(), field, shp, map); | ||
|
|
||
| ReducedQuinticImplicitIntegrator<FieldElement> integrator(fes); |
There was a problem hiding this comment.
| ReducedQuinticImplicitIntegrator<FieldElement> integrator(fes); | |
| ReducedQuinticImplicitIntegrator integrator(fes); |
Either do not put in template or you have to include the templating of FieldElement. ie MeshField::FieldElement<templating>.
|
Can you add |
src/MeshField.hpp
Outdated
| }; | ||
|
|
||
| template <int ShapeOrder> auto getTriangleElement(Omega_h::Mesh &mesh) { | ||
| static_assert(ShapeOrder == 1 || ShapeOrder == 2); |
There was a problem hiding this comment.
| static_assert(ShapeOrder == 1 || ShapeOrder == 2); | |
| static_assert(ShapeOrder == 1 || ShapeOrder == 2 || ShapeOrder == 5); |
|
@cwsmith @Joshua-Kloepfer One thing that we noticed is that in core the integration only stores n-1 coordinates where n is the number of vertices. This is why |
|
@jacobmerson Currently in our code, we store all n coordinates so for Tets we decided to store all 4 parametric coordinates (https://github.com/SCOREC/meshFields/blob/jk/FixIntegration/src/MeshField_Integrate.hpp#L85) and in triangles we store 3 (https://github.com/SCOREC/meshFields/blob/jk/FixIntegration/src/MeshField_Integrate.hpp#L85). We felt that this was the right approach. Is there somewhere else where we are not storing all the entries? |
| auto& rqShape = element.shp; | ||
|
|
||
| MeshField::Vector3 xi = {1.0/3.0, 1.0/3.0, 1.0/3.0}; | ||
| constexpr int nn = static_cast<int>(MeshField::ReducedQuinticImplicitShape::numNodes); |
There was a problem hiding this comment.
why does this require a static cast to int?
| auto dN = rqShape.getLocalGradients(xi); | ||
| // Evaluate shape functions and local gradients at the centroid. | ||
| const auto N = rqShape.getValues(xi); | ||
| (void)rqShape.getLocalGradients(xi); // computed for coverage; not asserted here |
There was a problem hiding this comment.
? what do you mean here?
| for (int i = 0; i < nn; ++i) { | ||
| sumN += N[i]; | ||
| } | ||
| for (int i = 0; i < nn; ++i) sumN += static_cast<double>(N[i]); |
There was a problem hiding this comment.
why are you static casting to double? Since this is on CPU, you can use std::accumulate
| printf("[ReducedQuinticImplicit] Integrated Value = %.12e\n", total); | ||
| Kokkos::View<MeshField::Real *> /*dV*/) override | ||
| { | ||
| const int npts = static_cast<int>(w.extent(0)); |
There was a problem hiding this comment.
can you use const auto here? why do you need to cast to int?
| "Integrate_f_bary_to_phys", npts, | ||
| KOKKOS_LAMBDA(const int ip, double& acc) { | ||
| // Barycentric weights (l0,l1,l2) corresponding to the element's vertices (v0,v1,v2). | ||
| const double l0 = static_cast<double>(p(ip, 0)); |
There was a problem hiding this comment.
I expect the result of p to be double? why is static cast neeeded? Use const auto instead
| const double y = l0 * y0 + l1 * y1 + l2 * y2; | ||
|
|
||
| // Accumulate f(x,y) * w. We assume w already includes dV. | ||
| acc += f_analytic(x, y) * static_cast<double>(w(ip)); // w includes dV |
| Kokkos::parallel_reduce( | ||
| "Integrate_1_bary_to_phys", npts, | ||
| KOKKOS_LAMBDA(const int ip, double& acc) { | ||
| acc += static_cast<double>(w(ip)); |
src/MeshField.hpp
Outdated
| if (triNodeIdx == 0) { | ||
| osh_ent = triVerts[3*tri + 0]; | ||
| nodeInHolder = 0; | ||
| } | ||
| else if (triNodeIdx == 1) { | ||
| osh_ent = triVerts[3*tri + 1]; | ||
| nodeInHolder = 0; | ||
| } | ||
| else if (triNodeIdx == 2) { | ||
| osh_ent = triVerts[3*tri + 2]; | ||
| nodeInHolder = 0; | ||
| } |
There was a problem hiding this comment.
can't all of this be one statement? i.e., osh_ent = triVerts[3*tri + triNodeIdx]
src/MeshField.hpp
Outdated
| } | ||
| else if (triNodeIdx >= 3 && triNodeIdx <= 6) { | ||
| const MeshField::LO v0 = triVerts[3*tri + 0]; | ||
| const MeshField::LO v1 = triVerts[3*tri + 1]; |
There was a problem hiding this comment.
why is this needed in this branch of the if statement?
src/MeshField_Shape.hpp
Outdated
| auto fact = [](int n) { | ||
| double r = 1.0; | ||
| for (int i = 2; i <= n; ++i) r *= double(i); | ||
| return r; | ||
| }; | ||
| const double f5 = fact(5); |
There was a problem hiding this comment.
If you need to do this you should use an IIFE, don't bother naming the lambda.
src/MeshField_Shape.hpp
Outdated
| for (int i = 0; i <= 5; ++i) { | ||
| for (int j = 0; j <= 5 - i; ++j) { | ||
| int k = 5 - i - j; | ||
| double coeff = f5 / (fact(i) * fact(j) * fact(k)); |
There was a problem hiding this comment.
this calculation needs to be explained in the comment. One issue I see is that you are recomputing the factorials many times. Would it make more sense to have a table of the coefficients?
src/MeshField_Shape.hpp
Outdated
| auto fact = [](int n) { | ||
| double r = 1.0; | ||
| for (int i = 2; i <= n; ++i) r *= double(i); | ||
| return r; | ||
| }; | ||
| const double f5 = fact(5); |
There was a problem hiding this comment.
why have you repeated the code?
| Omega_h::Mesh mesh(&lib); | ||
| Omega_h::build_from_elems_and_coords(&mesh, OMEGA_H_SIMPLEX, 2, verts, coords); | ||
|
|
||
| runTest<MeshField::KokkosController>(mesh); |
There was a problem hiding this comment.
have run test return a bool or error code that you can use to set the return value of main. This can be used with ctest to know if the test passed/failed.
| } | ||
|
|
||
| std::cout << "[PASS] ReducedQuinticImplicit evaluator test (partition of unity)\n"; | ||
| } |
There was a problem hiding this comment.
You are missing a test case where you evaluate the shape function for example at 1/3, 1/3, 1/3 for up to a 4th order polynomial. You should be able to get an exact value.
No description provided.