Skip to content

Commit 42eb98b

Browse files
committed
Merge branch 'main' into mesh-fields-tolerances
2 parents 023a43d + d36b89f commit 42eb98b

20 files changed

+716
-93
lines changed

.github/workflows/cmake.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ jobs:
2727
sudo apt-get install -yq cmake
2828
cmake --version
2929
30+
# There is a known bug using MPICH ubuntu-24.04 (ubuntu-latest as of 11/10/2025)
31+
# https://bugs.launchpad.net/ubuntu/+source/mpich/+bug/2072338
32+
- name: Install mpi
33+
run: |
34+
sudo apt-get update -yq
35+
sudo apt-get install -yq openmpi-bin libopenmpi-dev
36+
3037
## Kokkos
3138
- name: Kokkos Checkout repo
3239
uses: actions/checkout@v4
@@ -51,7 +58,7 @@ jobs:
5158
- name: Omega_h Checkout repo
5259
uses: actions/checkout@v4
5360
with:
54-
repository: sandialabs/omega_h
61+
repository: SCOREC/omega_h
5562
path: omegah
5663

5764
- name: Omega_h Configure CMake

.github/workflows/doxygen-gh-pages.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
- name: Omega_h Checkout repo
4545
uses: actions/checkout@v4
4646
with:
47-
repository: sandialabs/omega_h
47+
repository: SCOREC/omega_h
4848
path: omegah
4949

5050
- name: Omega_h Configure CMake

.github/workflows/pr_comment_trigger_self_hosted.yml

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ on:
55
issue_comment:
66
types: [created]
77

8-
# Allows you to run this workflow manually from the Actions tab
9-
workflow_dispatch:
10-
118
jobs:
129
build_and_test:
1310
permissions:
@@ -34,11 +31,11 @@ jobs:
3431
run: |
3532
set +e #avoid exiting when lua modules return non-zero on 'warning' messages
3633
source /etc/profile #provides module command
37-
module use /opt/scorec/spack/rhel9/v0201_4/lmod/linux-rhel9-x86_64/Core/
38-
module load gcc/12.3.0-iil3lno
39-
module load mpich/4.1.1-xpoyz4t
40-
module load cmake/3.26.3-2duxfcd
41-
module load cuda/12.1.1-zxa4msk
34+
module use /opt/scorec/spack/rhel9/v0222_2/lmod/linux-rhel9-x86_64/Core/
35+
module load gcc/13.2.0-4eahhas
36+
module load mpich/4.2.3-62uy3hd
37+
module load cuda/12.6.2-gqq65nw
38+
module load cmake
4239
set -e
4340
4441
echo "github.workspace ${{github.workspace}}"
@@ -93,15 +90,16 @@ jobs:
9390
-DCMAKE_CUDA_ARCHITECTURES="80" \
9491
-DKokkos_PREFIX=$kkbdir/install \
9592
-DBUILD_SHARED_LIBS=on
96-
cmake --build $ohbdir -j 4 --target install
93+
cmake --build $ohbdir -j 6 --target install
9794
9895
#meshfields
9996
mfbdir=${workDir}/build-meshfields
10097
cmake -S meshfields_${{ github.event.issue.number }} -B $mfbdir \
10198
-DMeshFields_USE_Cabana=on \
10299
-DOmega_h_ROOT=$ohbdir/install \
103100
-DKokkos_ROOT=$kkbdir/install \
104-
-DCabana_ROOT=$cabbdir/install
101+
-DCabana_ROOT=$cabbdir/install \
102+
-DMeshFields_IS_TESTING=on
105103
cmake --build $mfbdir -j4
106104
ctest --test-dir $mfbdir
107105

CMakeLists.txt

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ option(MeshFields_USE_Cabana "Build with the Cabana storage backend" OFF)
99

1010
find_package(Kokkos REQUIRED)
1111
find_package(Omega_h REQUIRED)
12-
#Clear the omegah compilation flags that it passes to cuda. Using the
13-
# kokkos target, and nvcc_wrapper, provide sufficient flags.
14-
set_property(TARGET Omega_h::omega_h PROPERTY INTERFACE_COMPILE_OPTIONS "")
12+
find_package(MPI REQUIRED)
13+
14+
# Verify Omega_h was built with Kokkos enabled
15+
if(NOT Omega_h_USE_Kokkos)
16+
message(FATAL_ERROR "Omega_h must be built with Kokkos enabled (Omega_h_USE_Kokkos=ON)")
17+
endif()
1518

1619
if(MeshFields_USE_Cabana)
1720
find_package(Cabana 0.7.0 REQUIRED)
@@ -32,6 +35,7 @@ set(MESHFIELD_HEADERS
3235
src/MeshField_Scan.hpp
3336
src/MeshField_Field.hpp
3437
src/MeshField.hpp
38+
src/MeshField_SPR_ErrorEstimator.hpp
3539
"${CMAKE_CURRENT_BINARY_DIR}/MeshField_Config.hpp"
3640
)
3741
if(MeshFields_USE_Cabana)
@@ -112,8 +116,8 @@ endif()
112116
enable_testing()
113117
include(CTest)
114118

115-
option(IS_TESTING "Build for CTest" OFF)
116-
message(STATUS "IS_TESTING: ${IS_TESTING}")
119+
option(MeshFields_IS_TESTING "Build for CTest" OFF)
120+
message(STATUS "MeshFields_IS_TESTING: ${MeshFields_IS_TESTING}")
117121

118122
#check for valgrind
119123
find_program(VALGRIND_CMD valgrind DOC "Location of the valgrind program")
@@ -124,79 +128,125 @@ function(test_func_impl TEST_NAME)
124128
# need to run as a cmake script to capture assert and other 'system failures'
125129
# https://cmake.org/cmake/help/latest/prop_test/WILL_FAIL.html#prop_test:WILL_FAIL
126130
add_test(NAME ${TEST_NAME} COMMAND ${CMAKE_COMMAND} -E env ${TEST_STR})
131+
if(TEST ${TEST_NAME})
132+
set_property(TEST ${TEST_NAME} PROPERTY LABELS "meshfields::base")
133+
endif()
127134
endfunction(test_func_impl)
128135

129-
function(test_func TEST_NAME)
136+
#smoke tests that are always enabled
137+
function(smoke_test_func TEST_NAME)
130138
test_func_impl(${TEST_NAME} ${ARGN})
131139
if(TEST ${TEST_NAME})
132-
set_property(TEST ${TEST_NAME} PROPERTY LABELS "base")
140+
set_property(TEST ${TEST_NAME} PROPERTY LABELS "meshfields::smoke")
141+
endif()
142+
endfunction(smoke_test_func)
143+
144+
function(test_func TEST_NAME)
145+
if(MeshFields_IS_TESTING)
146+
test_func_impl(${TEST_NAME} ${ARGN})
133147
endif()
134148
endfunction(test_func)
135149

150+
function(add_test_property TEST_NAME PROP)
151+
if(TEST ${TEST_NAME})
152+
set_property(TEST ${TEST_NAME} PROPERTY ${PROP} ${ARGN})
153+
endif()
154+
endfunction(add_test_property)
155+
136156
# Unlike test_func, will_fail_test_func assumes the command for the test will fail
137157
function(will_fail_test_func TEST_NAME)
138-
test_func_impl(${TEST_NAME} ${ARGN})
139-
set_property(TEST ${TEST_NAME} PROPERTY WILL_FAIL TRUE)
140-
if(TEST ${TEST_NAME})
141-
set_property(TEST ${TEST_NAME} PROPERTY LABELS "base")
158+
if(MeshFields_IS_TESTING)
159+
test_func_impl(${TEST_NAME} ${ARGN})
160+
set_property(TEST ${TEST_NAME} PROPERTY WILL_FAIL TRUE)
142161
endif()
143162
endfunction()
144163

145164
function(will_fail_valgrind_test_func TEST_NAME)
146-
if(VALGRIND_CMD)
147-
test_func_impl(${TEST_NAME} ${VALGRIND_CMD} ${ARGN})
148-
set_property(TEST ${TEST_NAME} PROPERTY
149-
FAIL_REGULAR_EXPRESSION "Invalid read;Invalid write"
150-
)
151-
set_property(TEST ${TEST_NAME} PROPERTY WILL_FAIL TRUE)
152-
if(TEST ${TEST_NAME})
153-
set_property(TEST ${TEST_NAME} PROPERTY LABELS "base")
165+
if(MeshFields_IS_TESTING)
166+
if(VALGRIND_CMD)
167+
test_func_impl(${TEST_NAME} ${VALGRIND_CMD} ${ARGN})
168+
set_property(TEST ${TEST_NAME} PROPERTY
169+
FAIL_REGULAR_EXPRESSION "Invalid read;Invalid write"
170+
)
171+
set_property(TEST ${TEST_NAME} PROPERTY WILL_FAIL TRUE)
154172
endif()
155173
endif()
156174
endfunction()
157175

158-
function(meshfields_add_exe EXE_NAME EXE_SRC)
176+
#smoke executables are always built
177+
function(meshfields_add_smoke_exe EXE_NAME EXE_SRC)
159178
add_executable(${EXE_NAME} ${EXE_SRC})
160179
target_link_libraries(${EXE_NAME} PRIVATE meshfields)
161180
endfunction()
162181

163-
# Creating minimal reproduction of error
164-
meshfields_add_exe(KokkosTests test/testKokkos.cpp)
182+
function(meshfields_add_exe EXE_NAME EXE_SRC)
183+
if(MeshFields_IS_TESTING)
184+
add_executable(${EXE_NAME} ${EXE_SRC})
185+
target_link_libraries(${EXE_NAME} PRIVATE meshfields)
186+
endif()
187+
endfunction()
188+
189+
meshfields_add_smoke_exe(KokkosTests test/testKokkos.cpp)
165190
meshfields_add_exe(SerializationTests test/testSerialize.cpp)
166191
meshfields_add_exe(ElementTests test/testElement.cpp)
167192
meshfields_add_exe(ElementJacobian1d test/testElementJacobian1d.cpp)
168193
meshfields_add_exe(ElementJacobian2d test/testElementJacobian2d.cpp)
169194
meshfields_add_exe(ElementJacobian3d test/testElementJacobian3d.cpp)
170195
meshfields_add_exe(CountIntegrator test/testCountIntegrator.cpp)
171-
meshfields_add_exe(OmegahTriTests test/testOmegahTri.cpp)
196+
meshfields_add_smoke_exe(OmegahTriTests test/testOmegahTri.cpp)
172197
meshfields_add_exe(ExceptionTest test/testExceptions.cpp)
173198
meshfields_add_exe(PointMapping test/testPointMapping.cpp)
174199
meshfields_add_exe(OmegahTetTest test/testOmegahTet.cpp)
200+
meshfields_add_exe(OmegahThwaitesSprAdapt test/testSprThwaitesAdapt.cpp)
175201

176202
if(MeshFields_USE_Cabana)
177203
meshfields_add_exe(ControllerPerformance test/testControllerPerformance.cpp)
178-
meshfields_add_exe(CabanaTests test/testCabana.cpp)
179-
test_func(CabanaTests ./CabanaTests)
204+
meshfields_add_smoke_exe(CabanaTests test/testCabana.cpp)
205+
smoke_test_func(CabanaTests ./CabanaTests)
180206
test_func(ControllerPerformance ./ControllerPerformance)
181207
endif()
182208

183-
test_func(KokkosTests ./KokkosTests)
209+
smoke_test_func(KokkosTests ./KokkosTests)
184210
test_func(SerializationTests ./SerializationTests)
185211
test_func(ElementTests ./ElementTests)
186212
test_func(ElementJacobian1d ./ElementJacobian1d)
187213
test_func(ElementJacobian2d ./ElementJacobian2d)
188214
test_func(ElementJacobian3d ./ElementJacobian3d)
189215
test_func(CountIntegrator ./CountIntegrator)
190-
test_func(OmegahTriTests ./OmegahTriTests)
216+
smoke_test_func(OmegahTriTests ./OmegahTriTests)
191217
test_func(PointMapping ./PointMapping)
192-
test_func(OmegahTetTest, ./OmegahTetTest)
218+
test_func(OmegahTetTest ./OmegahTetTest)
193219
if(MeshFields_USE_EXCEPTIONS)
194220
# exception caught - no error
195221
test_func(ExceptionTest ./ExceptionTest)
196222
else()
197223
will_fail_test_func(ExceptionTest ./ExceptionTest)
198224
endif()
199225

226+
meshfields_add_exe(OmegahSprAdapt test/testSprThwaitesAdapt.cpp)
227+
test_func(OmegahSprAdapt ./OmegahSprAdapt
228+
${CMAKE_SOURCE_DIR}/meshes/thwaites_basal_effectiveStrain.osh/
229+
thwaitesAdapted #output prefix
230+
0.1 # adapt ratio
231+
1.0 # min size
232+
16.0 # max size
233+
)
234+
add_test_property(OmegahSprAdapt
235+
PASS_REGULAR_EXPRESSION
236+
"afterAdapt nTri: 14439; solution_1 min -4084.78 max 213.322")
237+
238+
test_func(OmegahSprAdapt_p2
239+
${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS}
240+
./OmegahSprAdapt ${CMAKE_SOURCE_DIR}/meshes/thwaites_basal_effectiveStrain.osh/
241+
thwaitesAdapted_p2 #output prefix
242+
0.1 # adapt ratio
243+
1.0 # min size
244+
16.0 # max size
245+
)
246+
add_test_property(OmegahSprAdapt_p2
247+
PASS_REGULAR_EXPRESSION
248+
"afterAdapt nTri: 14468; solution_1 min -4098.9 max 213.322")
249+
200250
#Code Coverage set up -------------------------------------------------------
201251

202252
option(meshfields_ENABLE_COVERAGE_BUILD "Do a coverage build" OFF)

docs/addingShapeFunctions.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
In order to add shape function, you must create a struct in
2+
https://github.com/SCOREC/meshFields/blob/main/src/MeshField_Shape.hpp.
3+
4+
You must define numNodes, meshEntDim, and Order as const variables as well as the functions
5+
getValues and getLocalGradients. You then need to define a mapping from how you store the
6+
nodes to the ordering of the shape function defined earlier. The Omegah mappings are in
7+
https://github.com/SCOREC/meshFields/blob/main/src/MeshField.hpp#L63. In the Jacobian
8+
tests we also an identity mapping defined as another example:
9+
https://github.com/SCOREC/meshFields/blob/main/test/testElementJacobian2d.cpp#L12.
10+
11+
In order to use integration with the added shape function it must be added here:
12+
https://github.com/SCOREC/meshFields/blob/main/src/MeshField_Integrate.hpp#L44.
13+
14+
Finally, when trying to compute an integral using the shape function, a class derived from the
15+
class Integrator (defined here:
16+
https://github.com/SCOREC/meshFields/blob/main/src/MeshField_Integrate.hpp#L204) must be
17+
declared and should implement the atPoints function. An example of this can be found here:
18+
https://github.com/SCOREC/meshFields/blob/main/test/testCountIntegrator.cpp#L41.
12.2 MB
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
10

src/MeshField.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ class OmegahMeshField {
312312
// HACK assumes there is a vertex field.. in the Field Mixin object
313313
auto field_view = field.vtxField.serialize();
314314
Omega_h::Write<FieldDataType> field_write(field_view);
315-
mesh.add_tag(0, "field", 1, Omega_h::read(field_write));
315+
mesh.add_tag(0, "field", 1, Omega_h::read(field_write), false,
316+
Omega_h::ArrayType::VectorND);
316317
Omega_h::vtk::write_parallel("foo.vtk", &mesh, mesh.dim());
317318
}
318319

src/MeshField_Element.hpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,15 @@ struct FieldElement {
170170
*/
171171
KOKKOS_INLINE_FUNCTION ValArray
172172
getValue(int ent, Kokkos::Array<Real, MeshEntDim + 1> localCoord) const {
173-
assert(ent < numMeshEnts);
173+
assert(ent >= 0);
174+
assert(static_cast<size_t>(ent) < numMeshEnts);
174175
ValArray c;
175176
const auto shapeValues = shapeFn.getValues(localCoord);
176-
for (int ci = 0; ci < NumComponents; ++ci)
177+
for (size_t ci = 0; ci < NumComponents; ++ci)
177178
c[ci] = 0;
178179
for (auto topo : elm2dof.getTopology()) { // element topology
179-
for (int ni = 0; ni < shapeFn.numNodes; ++ni) {
180-
for (int ci = 0; ci < NumComponents; ++ci) {
180+
for (size_t ni = 0; ni < shapeFn.numNodes; ++ni) {
181+
for (size_t ci = 0; ci < NumComponents; ++ci) {
181182
auto map = elm2dof(ni, ci, ent, topo);
182183
const auto fval =
183184
field(map.entity, map.node, map.component, map.topo);
@@ -194,8 +195,8 @@ struct FieldElement {
194195
KOKKOS_INLINE_FUNCTION NodeArray getNodeValues(int ent) const {
195196
NodeArray c;
196197
for (auto topo : elm2dof.getTopology()) { // element topology
197-
for (int ni = 0; ni < ShapeType::numNodes; ++ni) {
198-
for (int d = 0; d < ShapeType::meshEntDim; ++d) {
198+
for (size_t ni = 0; ni < ShapeType::numNodes; ++ni) {
199+
for (size_t d = 0; d < ShapeType::meshEntDim; ++d) {
199200
auto map = elm2dof(ni, d, ent, topo);
200201
const auto fval =
201202
field(map.entity, map.node, map.component, map.topo);
@@ -219,11 +220,12 @@ struct FieldElement {
219220
* @return the result of evaluation
220221
*/
221222
KOKKOS_INLINE_FUNCTION Real getJacobian1d(int ent) const {
222-
assert(ent < numMeshEnts);
223+
assert(ent >= 0);
224+
assert(static_cast<size_t>(ent) < numMeshEnts);
223225
const auto nodalGradients = shapeFn.getLocalGradients();
224226
const auto nodeValues = getNodeValues(ent);
225227
auto g = nodalGradients[0] * nodeValues[0];
226-
for (int i = 1; i < shapeFn.numNodes; ++i) {
228+
for (size_t i = 1; i < shapeFn.numNodes; ++i) {
227229
g = g + nodalGradients[i] * nodeValues[i];
228230
}
229231
return g;
@@ -328,7 +330,7 @@ struct FieldElement {
328330
KOKKOS_LAMBDA(const int &ent, LO &lerrors) {
329331
Real sum = 0;
330332
LO isError = 0;
331-
for (int i = 0; i < localCoords.extent(1); i++) {
333+
for (size_t i = 0; i < localCoords.extent(1); i++) {
332334
if (localCoords(ent, i) < 0)
333335
isError++;
334336
sum += localCoords(ent, i);
@@ -449,7 +451,7 @@ evaluate(FieldElement &fes, Kokkos::View<Real **> localCoords,
449451
KOKKOS_LAMBDA(const int &ent, LO &lerrors) {
450452
Real sum = 0;
451453
LO isError = 0;
452-
for (int i = 0; i < localCoords.extent(1); i++) {
454+
for (size_t i = 0; i < localCoords.extent(1); i++) {
453455
if (localCoords(ent, i) < 0)
454456
isError++;
455457
sum += localCoords(ent, i);
@@ -477,7 +479,7 @@ evaluate(FieldElement &fes, Kokkos::View<Real **> localCoords,
477479
LO numLocalCoords;
478480
Kokkos::deep_copy(numLocalCoords,
479481
Kokkos::subview(offsets, offsets.size() - 1));
480-
if (localCoords.extent(0) != numLocalCoords) {
482+
if (localCoords.extent(0) != static_cast<size_t>(numLocalCoords)) {
481483
fail("The size of dimension 0 of the local coordinates input array (%zu) "
482484
"does not match the last entry of the offsets array (%d).\n",
483485
localCoords.extent(0), numLocalCoords);
@@ -491,10 +493,10 @@ evaluate(FieldElement &fes, Kokkos::View<Real **> localCoords,
491493
Kokkos::Array<Real, FieldElement::MeshEntDim + 1> lc;
492494
// TODO use nested parallel for?
493495
for (auto pt = offsets(ent); pt < offsets(ent + 1); pt++) {
494-
for (int i = 0; i < localCoords.extent(1); i++) // better way?
496+
for (size_t i = 0; i < localCoords.extent(1); i++) // better way?
495497
lc[i] = localCoords(pt, i);
496498
const auto val = fes.getValue(ent, lc);
497-
for (int i = 0; i < numComponents; i++)
499+
for (size_t i = 0; i < numComponents; i++)
498500
res(pt, i) = val[i];
499501
}
500502
});

0 commit comments

Comments
 (0)