Add Flex component.

PiperOrigin-RevId: 572830650
Change-Id: I6908228087b7b9683be3506c8d9cdc725ed5dcd5
This commit is contained in:
Alessio Quaglino
2023-10-12 10:15:46 +01:00
committed by Saran Tunyasuvunakool
parent 649a474788
commit 5a70ad08ab
82 changed files with 9658 additions and 1581 deletions
+27 -4
View File
@@ -41,8 +41,8 @@ static std::vector<GeomPair> colliding_pairs(
const mjModel* model, const mjData* data) {
std::vector<GeomPair> result;
for (int i = 0; i < data->ncon; i++) {
std::string geom1 = mj_id2name(model, mjOBJ_GEOM, data->contact[i].geom1);
std::string geom2 = mj_id2name(model, mjOBJ_GEOM, data->contact[i].geom2);
std::string geom1 = mj_id2name(model, mjOBJ_GEOM, data->contact[i].geom[0]);
std::string geom2 = mj_id2name(model, mjOBJ_GEOM, data->contact[i].geom[1]);
result.push_back(GeomPair(std::min(geom1, geom2), std::max(geom1, geom2)));
}
std::sort(result.begin(), result.end());
@@ -211,14 +211,37 @@ TEST_F(MjCollisionTest, TestOBB) {
mjtNum mat2[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
EXPECT_THAT(
mj_collideOBB(bvh1, bvh2, pos1, mat1, pos2, mat2, NULL, NULL, 0), true);
mj_collideOBB(bvh1, bvh2, pos1, mat1, pos2, mat2, 0, NULL, NULL, 0), true);
// rotate by 45 degrees
mat2[0] = 1./mju_sqrt(2.); mat2[1] = -1./mju_sqrt(2.);
mat2[3] = 1./mju_sqrt(2.); mat2[4] = 1./mju_sqrt(2.);
EXPECT_THAT(
mj_collideOBB(bvh1, bvh2, pos1, mat1, pos2, mat2, NULL, NULL, 0), false);
mj_collideOBB(bvh1, bvh2, pos1, mat1, pos2, mat2, 0, NULL, NULL, 0), false);
}
TEST_F(MjCollisionTest, PlaneInBody) {
constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<geom pos="0 0 0" type="plane" size="1 1 .01"/>
</body>
<body pos="0 0 .0499">
<joint type="slide" axis="0 0 1"/>
<geom size=".05"/>
</body>
</worldbody>
</mujoco>
)";
mjModel* m = LoadModelFromString(xml);
ASSERT_THAT(m, NotNull());
mjData* d = mj_makeData(m);
ASSERT_THAT(d, NotNull());
mj_step(m, d);
mj_deleteData(d);
mj_deleteModel(m);
}
} // namespace
+3
View File
@@ -18,6 +18,9 @@ target_link_libraries(user_model_test fixture gmock absl::str_format)
mujoco_test(user_objects_test)
target_link_libraries(user_objects_test fixture gmock)
mujoco_test(user_flex_test)
target_link_libraries(user_flex_test fixture gmock)
mujoco_test(user_mesh_test)
target_link_libraries(
user_mesh_test
+33
View File
@@ -0,0 +1,33 @@
# cube.obj
#
g cube
v 0.0 0.0 0.0
v 0.0 0.0 1.0
v 0.0 1.0 0.0
v 0.0 1.0 1.0
v 1.0 0.0 0.0
v 1.0 0.0 1.0
v 1.0 1.0 0.0
v 1.0 1.0 1.0
vn 0.0 0.0 1.0
vn 0.0 0.0 -1.0
vn 0.0 1.0 0.0
vn 0.0 -1.0 0.0
vn 1.0 0.0 0.0
vn -1.0 0.0 0.0
f 1//2 7//2 5//2
f 1//2 3//2 7//2
f 1//6 4//6 3//6
f 1//6 2//6 4//6
f 3//3 8//3 7//3
f 3//3 4//3 8//3
f 5//5 7//5 8//5
f 5//5 8//5 6//5
f 1//4 5//4 6//4
f 1//4 6//4 2//4
f 2//1 6//1 8//1
f 2//1 8//1 4//1
+5
View File
@@ -0,0 +1,5 @@
<mujoco>
<worldbody>
<flexcomp name="test" type="mesh" file="cube.obj"/>
</worldbody>
</mujoco>
+157
View File
@@ -0,0 +1,157 @@
<mujoco>
<default>
<geom contype='1' conaffinity='1' condim='3' friction='.1 .1' solimp='.95 .98 .0005' solref='0.02 1.1' density='1'/>
<joint type='hinge' armature='0' damping='0'
solimpfriction='.95 .95 0' solreffriction='.02 1' solimplimit='0 .99 .01' solreflimit='.02 1'/>
<site rgba='.5 .5 .5 .3'/>
<general ctrllimited='true' ctrlrange='-0.84 0.84' forcelimited='true'/>
<default class='big_joint'>
<joint frictionloss='.01' armature='1' damping='0.01' range='-3.141592653589793 9.42477796076938' limited='false'/>
<velocity kv='20' forcerange='-3.15 3.15'/>
</default>
<default class='little_joint'>
<joint frictionloss='.01' armature='1' damping='0.01' range='-3.141592653589793 9.42477796076938' limited='false'/>
<velocity kv='20' forcerange='-3.15 3.15'/>
</default>
<default class='finger'>
<joint frictionloss='0.1' armature='.1' axis='0 0 1' limited='true' range='0.15 1.2' damping='.1'/>
<velocity kv='10' ctrlrange='-0.84 0.84' gear='1' forcerange='-1.5 1.5'/>
</default>
<default class='fingertip'>
<geom type='box' pos='0.065 -0.022 0' size='0.02 .005 .011' rgba='1 0 0 1'
quat='1 0 0 -0.235' condim='4'/>
<site type='ellipsoid' pos='0.065 -0.022 0' size='0.02 .005 .011'
quat='1 0 0 -0.235'/>
</default>
<default class='base'>
<geom type='capsule' size='0.0350512 0.0555543' pos='-0.000132925 -0.000516418 0.0820911' quat='0.6951 -0.00714564 0.00738544 0.71884'/>
</default>
<default class='link_1'>
<geom type='capsule' size='0.031417 0.0668352' pos='-3.49946e-05 0.010651 -0.0670012' quat='0.704277 0.0627825 -0.0628 0.70435'/>
</default>
<default class='link_2'>
<geom type='capsule' size='0.0251592 0.240341' pos='0.205004 7.5835e-05 -0.0202812' quat='2.23957e-06 0.707108 5.30416e-06 0.707106'/>
</default>
<default class='link_3'>
<geom type='capsule' size='0.0255647 0.120643' pos='0.0843942 7.48907e-06 -0.0177123' quat='-4.64475e-05 0.692702 -4.11814e-05 0.721224'/>
</default>
<default class='link_4'>
<geom type='capsule' size='0.0257405 0.0289568' pos='0.0101659 -4.64261e-05 -0.0369867' quat='0.965925 1.43712e-05 -0.258823 3.85082e-06'/>
</default>
<default class='link_5'>
<geom type='capsule' size='0.0257405 0.0289568' pos='0.0101659 -4.64261e-05 -0.0369867' quat='0.965925 1.43712e-05 -0.258823 3.85082e-06'/>
</default>
<default class='link_6'>
<geom type='capsule' size='0.0368731 0.0322296' pos='0.00628384 -2.92087e-05 -0.0608681' quat='0.708562 -0.0338601 -0.0358744 0.703923'/>
</default>
<default class='finger_knuckle'>
<geom type='capsule' size='0.0108231 0.0145116' pos='0.0190913 -0.0112192 1.10387e-06' quat='0.475811 -0.475815 0.523071 -0.523068'/>
</default>
</default>
<worldbody>
<body name='b_base' pos='0 0 0.005'>
<site type='sphere' size='.01' name='basesite' pos='0 0 0' rgba='1 0 0 1'/>
<inertial pos='-0.000132925 -0.000516418 0.0820911' quat='0.6951 -0.00714556 0.00738537 0.71884' mass='0.00718278' diaginertia='0.00157301 0.00157269 0.00058831'/>
<geom name='base' class='base' rgba='0 0.4470 0.7410 1'/>
<body name='b_1' pos='0 0 0.1535' quat='0 -1 0 0'>
<inertial pos='-3.49946e-005 0.010651 -0.0670012' quat='0.704277 0.0627825 -0.0628 0.70435' mass='0.00644357' diaginertia='0.00172311 0.00163259 0.00042883'/>
<joint name='joint_1' class='big_joint' axis='0 0 1'/>
<geom name='link_1' class='link_1' rgba='0.8500 0.3250 0.0980 1'/>
<geom name='ring_1' contype='0' conaffinity='0' type='cylinder' size='0.044 0.011' pos='0 0 0' rgba='0.7 0.7 0.72 1'/>
<body name='b_2' pos='0 0 -0.1185' quat='-0.7071067811865475 0.7071067811865475 0.7071067811865475 0.7071067811865475'>
<inertial pos='0.205004 7.5835e-005 -0.0202812' quat='2.24027e-006 0.707108 5.30493e-006 0.707106' mass='0.011691' diaginertia='0.0253426 0.0250512 0.000536357'/>
<joint name='joint_2' class='big_joint' axis='0 0 1'/>
<geom name='link_2' class='link_2' rgba='0.9290 0.6940 0.1250 1'/>
<geom name='ring_2' contype='0' conaffinity='0' type='cylinder' size='0.044 0.011' pos='0 0 0' euler='0 0 0' rgba='0.7 0.7 0.72 1'/>
<body name='b_3' pos='0.41 0 0' quat='0 0 1 0'>
<inertial pos='0.0843942 7.48909e-006 -0.0177123' quat='-4.64469e-005 0.692702 -4.11798e-005 0.721224' mass='0.00673417' diaginertia='0.00420255 0.00409328 0.000303584'/>
<joint name='joint_3' class='big_joint' axis='0 0 1' range='0.6131110819452792 5.673924357222234' limited='true'/>
<geom name='link_3' class='link_3' rgba='0.4940 0.1840 0.5560 1'/>
<geom name='ring_3' contype='0' conaffinity='0' type='cylinder' size='0.044 0.011' pos='0 0 0' euler='0 0 0' rgba='0.7 0.7 0.72 1'/>
<body name='b_4' pos='0.207 0 -0.01125' quat='-0.7071067811865475 0 0.7071067811865475 0'>
<inertial pos='0.0101659 -4.64261e-005 -0.0369867' quat='0.965925 1.91737e-005 -0.258823 -1.40769e-005' mass='0.00221423' diaginertia='0.0001816 0.000174586 9.79319e-005'/>
<joint name='joint_4' class='little_joint' axis='0 0 1'/>
<geom name='link_4' class='link_4' rgba='0.4660 0.6740 0.1880 1'/>
<geom name='ring_4' contype='0' conaffinity='0' type='cylinder' size='0.035 0.009' pos='0 0 0' euler='0 0 0' rgba='0.7 0.7 0.7 1'/>
<body name='b_5' pos='0.037 0 -0.06408' quat='0 0.5 0 -0.8660254037844386'>
<inertial pos='0.0101659 -4.64261e-005 -0.0369867' quat='0.965925 1.91737e-005 -0.258823 -1.40769e-005' mass='0.00221423' diaginertia='0.0001816 0.000174586 9.79319e-005'/>
<joint name='joint_5' class='little_joint' axis='0 0 1'/>
<geom name='ring_5' contype='0' conaffinity='0' type='cylinder' size='0.035 0.009' pos='0 0 0' euler='0 0 0' rgba='0.7 0.7 0.72 1'/>
<geom name='link_5' class='link_5' rgba='0.3010 0.7450 0.9330 1'/>
<body name='b_hand' pos='0.037 0 -0.06408' quat='0 -0.5 0 0.8660254037844386'>
<camera name='cam_hand' pos='0 .015 -.13' fovy='135'/>
<site type='sphere' size='.01' name='wristsite' pos='0 0 0' rgba='1 0 0 1'/>
<site type='sphere' size='.01' name='gripsite' pos='0 0 -.16' rgba='.5 .5 .5 .3'/>
<site type='sphere' size='.01' name='pinchsite' pos='0 0.015 -0.195' rgba='.5 .5 .5 .3'/>
<inertial pos='0.00628384 -2.92087e-005 -0.0608681' quat='0.708562 -0.0338601 -0.0358744 0.703923' mass='0.00547172' diaginertia='0.000759818 0.000676099 0.0004995'/>
<joint name='joint_6' class='little_joint' axis='0 0 1'/>
<geom name='link_6' class='link_6' rgba='0.6350 0.0780 0.1840 1'/>
<geom name='ring_hand' contype='0' conaffinity='0' type='cylinder' size='0.035 0.009' pos='0 0 0' euler='0 0 0' rgba='0.7 0.7 0.72 1'/>
<body name = 'b_palm' pos='0.005 0 -0.11' euler='0 0 0'>
<geom type='cylinder' contype='0' conaffinity='7' size='.0275 0.01' friction='1 1' rgba='0.7 0.7 0.7 1' name='palm'/>
</body>
<body name='b_finger_1' childclass='finger' pos='-0.029 .003 -0.1145' quat='-0.414818 -0.329751 -0.663854 0.52772'>
<inertial pos='0.0485761 -0.000715511 0' quat='0.507589 0.507348 0.492543 0.492294' mass='0.000379077' diaginertia='4.00708e-005 4.00527e-005 2.156e-006'/>
<joint name='joint_finger_1'/>
<geom name='finger_knuckle_1' class='finger_knuckle' rgba='0 0.4470 0.7410 1'/>
<geom class='fingertip' name='finger_tip_1' rgba='0 0.4470 0.7410 1'/>
<site class='fingertip' name='fingertip1'/>
</body>
<body name='b_finger_2' childclass='finger' pos='0.0295 0.0216 -0.115' quat='0.561254 -0.620653 0.321748 0.443014'>
<inertial pos='0.0485761 -0.000715511 0' quat='0.507589 0.507348 0.492543 0.492294' mass='0.000379077' diaginertia='4.00708e-005 4.00527e-005 2.156e-006'/>
<joint name='joint_finger_2'/>
<geom name='finger_knuckle_2' class='finger_knuckle' rgba='0.9290 0.6940 0.1250 1'/>
<geom class='fingertip' name='finger_tip_2' rgba='0.9290 0.6940 0.1250 1'/>
<site class='fingertip' name='fingertip2'/>
</body>
<body name='b_finger_3' childclass='finger' pos='0.0295 -0.0216 -0.1145' quat='0.625248 -0.567602 0.434845 0.312735'>
<inertial pos='0.0485761 -0.000715511 0' quat='0.507589 0.507348 0.492543 0.492294' mass='0.000379077' diaginertia='4.00708e-005 4.00527e-005 2.156e-006'/>
<joint name='joint_finger_3'/>
<geom name='finger_knuckle_3' class='finger_knuckle' rgba='0.8500 0.3250 0.0980 1'/>
<geom class='fingertip' name='finger_tip_3' rgba='0.8500 0.3250 0.0980 1'/>
<site class='fingertip' name='fingertip3'/>
</body>
</body>
</body>
</body>
</body>
</body>
</body>
</body>
</worldbody>
<contact>
<exclude body1='b_base' body2='b_1'/>
<exclude body1='b_finger_1' body2='b_finger_2'/>
<exclude body1='b_finger_1' body2='b_finger_3'/>
<exclude body1='b_finger_2' body2='b_finger_3'/>
</contact>
<sensor>
<touch name="fingertip1" site='fingertip1'/>
<touch name="fingertip2" site='fingertip2'/>
<touch name="fingertip3" site='fingertip3'/>
<force name="wristforce" site='wristsite'/>
<torque name="wristtorque" site='wristsite'/>
<force name="baseforce" site='basesite'/>
<torque name="basetorque" site='basesite'/>
</sensor>
<actuator>
<velocity joint='joint_1' class='big_joint'/>
<velocity joint='joint_2' class='big_joint'/>
<velocity joint='joint_3' class='big_joint'/>
<velocity joint='joint_4' class='little_joint'/>
<velocity joint='joint_5' class='little_joint'/>
<velocity joint='joint_6' class='little_joint'/>
<velocity joint='joint_finger_1' class='finger'/>
<velocity joint='joint_finger_2' class='finger'/>
<velocity joint='joint_finger_3' class='finger'/>
</actuator>
</mujoco>
+231
View File
@@ -0,0 +1,231 @@
// Copyright 2021 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Tests for user/user_model.cc.
#include <array>
#include <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mujoco.h>
#include "test/fixture.h"
namespace mujoco {
namespace {
using ::testing::IsNull;
using ::testing::NotNull;
using ::testing::HasSubstr;
using UserFlexTest = MujocoTest;
TEST_F(UserFlexTest, ParentMustHaveName) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull());
EXPECT_THAT(error.data(), HasSubstr("required attribute missing: 'name'"));
}
TEST_F(UserFlexTest, InvalidDim) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" dim="4"/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull());
EXPECT_THAT(error.data(), HasSubstr("Invalid dim, must be between 1 and 3"));
}
TEST_F(UserFlexTest, CountTooSmall) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" count="2 2 0"/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull());
EXPECT_THAT(error.data(), HasSubstr("Count too small"));
}
TEST_F(UserFlexTest, SpacingGreaterThanGeometry) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" spacing="0.5 0.5 0.5" radius="1"/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(),
HasSubstr("Spacing must be larger than geometry size"));
}
TEST_F(UserFlexTest, ScaleMinValue) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" scale="0 1 1"/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(), HasSubstr("Scale must be larger than mjMINVAL"));
}
TEST_F(UserFlexTest, MassMinValue) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" mass="0"/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(),
HasSubstr("Mass and inertiabox must be larger than mjMINVAL"));
}
TEST_F(UserFlexTest, PointSizeNotMultipleOf3) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" point="0 0 0 0"/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(), HasSubstr("Point size must be a multiple of 3"));
}
TEST_F(UserFlexTest, ElementSize) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" point="0 0 0" element="0 1 2" dim="3"/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(),
HasSubstr("Element size must be a multiple of dim+1"));
}
TEST_F(UserFlexTest, PointAndElementNotInDirect) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" type="direct"/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(), HasSubstr("Point and element required"));
}
TEST_F(UserFlexTest, UknownFlexCompType) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" type="unknown"/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(), HasSubstr("invalid keyword: 'unknown'"));
}
TEST_F(UserFlexTest, InvalidPinid) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" type="direct" point="0 0 0" element="0 1 2">
<pin id="1"/>
</flexcomp>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(),
HasSubstr("element 1 has point id 1, number of points is 1"));
}
TEST_F(UserFlexTest, MeshFileMissing) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<flexcomp name="test" type="mesh"/>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(), HasSubstr("File is required"));
}
TEST_F(UserFlexTest, VertexOrFaceDataMissing) {
const std::string xml_path =
GetTestDataFilePath("user/testdata/malformed_flex_nofaces.xml");
std::array<char, 1024> error;
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
EXPECT_THAT(m, IsNull()) << error.data();
EXPECT_THAT(error.data(), HasSubstr("Vertex and face data required"));
}
TEST_F(UserFlexTest, CreateBVHSuccess) {
const std::string xml_path =
GetTestDataFilePath("user/testdata/robot_arm.xml");
std::array<char, 1024> error;
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
mjData* d = mj_makeData(m);
EXPECT_THAT(m, NotNull()) << error.data();
mj_step(m, d);
mj_deleteModel(m);
mj_deleteData(d);
}
} // namespace
} // namespace mujoco
+1 -1
View File
@@ -631,7 +631,7 @@ TEST_F(XMLReaderTest, InvalidSkinGroup) {
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull());
EXPECT_THAT(model, IsNull());
EXPECT_THAT(
error.data(),
HasSubstr("skin group must be between 0 and 5\nElement 'skin', line 7"));
+1
View File
@@ -1062,6 +1062,7 @@ TEST_F(PluginTest, WriteReadCompare) {
// if file is meant to fail, skip it
if (absl::StrContains(p.path().string(), "malformed_") ||
absl::StrContains(p.path().string(), "touch_grid") ||
absl::StrContains(p.path().string(), "gmsh_") ||
absl::StrContains(p.path().string(), "cow")) {
continue;
}