Add elasticity plugins to xml_native_writer_test. Fixes #961.
PiperOrigin-RevId: 545454207 Change-Id: I4e93499eaa53e5bc8c8afa682986657cef3ac20f
This commit is contained in:
committed by
Copybara-Service
parent
2b38148d24
commit
46e06c4cac
@@ -1390,7 +1390,7 @@ void mjXWriter::Body(XMLElement* elem, mjCBody* body) {
|
|||||||
|
|
||||||
// write plugin
|
// write plugin
|
||||||
if (body->is_plugin) {
|
if (body->is_plugin) {
|
||||||
OnePlugin(elem, body);
|
OnePlugin(InsertEnd(elem, "plugin"), body);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write child bodies recursively
|
// write child bodies recursively
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <absl/strings/string_view.h>
|
#include <absl/strings/string_view.h>
|
||||||
#include <mujoco/mjdata.h>
|
#include <mujoco/mjdata.h>
|
||||||
#include <mujoco/mjmodel.h>
|
#include <mujoco/mjmodel.h>
|
||||||
|
#include <mujoco/mujoco.h>
|
||||||
|
|
||||||
namespace mujoco {
|
namespace mujoco {
|
||||||
|
|
||||||
@@ -65,5 +66,29 @@ const std::string SaveAndReadXml(const mjModel* model);
|
|||||||
std::vector<mjtNum> GetCtrlNoise(const mjModel* m, int nsteps,
|
std::vector<mjtNum> GetCtrlNoise(const mjModel* m, int nsteps,
|
||||||
mjtNum ctrlnoise = 0.01);
|
mjtNum ctrlnoise = 0.01);
|
||||||
|
|
||||||
|
// Installs elasticity plugins
|
||||||
|
// TODO(quaglino): load all plugins with a macro
|
||||||
|
class PluginTest : public MujocoTest {
|
||||||
|
public:
|
||||||
|
// load plugin library
|
||||||
|
PluginTest() : MujocoTest() {
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
mj_loadPluginLibrary((
|
||||||
|
std::string(std::getenv("MUJOCO_PLUGIN_DIR")) +
|
||||||
|
std::string("\\elasticity.dll")).c_str());
|
||||||
|
#else
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
mj_loadPluginLibrary((
|
||||||
|
std::string(std::getenv("MUJOCO_PLUGIN_DIR")) +
|
||||||
|
std::string("/libelasticity.dylib")).c_str());
|
||||||
|
#else
|
||||||
|
mj_loadPluginLibrary((
|
||||||
|
std::string(std::getenv("MUJOCO_PLUGIN_DIR")) +
|
||||||
|
std::string("/libelasticity.so")).c_str());
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mujoco
|
} // namespace mujoco
|
||||||
#endif // MUJOCO_TEST_FIXTURE_H_
|
#endif // MUJOCO_TEST_FIXTURE_H_
|
||||||
|
|||||||
@@ -29,28 +29,6 @@
|
|||||||
namespace mujoco {
|
namespace mujoco {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class PluginTest : public MujocoTest {
|
|
||||||
public:
|
|
||||||
// load plugin library
|
|
||||||
PluginTest() : MujocoTest() {
|
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
|
||||||
mj_loadPluginLibrary((
|
|
||||||
std::string(std::getenv("MUJOCO_PLUGIN_DIR")) +
|
|
||||||
std::string("\\elasticity.dll")).c_str());
|
|
||||||
#else
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
mj_loadPluginLibrary((
|
|
||||||
std::string(std::getenv("MUJOCO_PLUGIN_DIR")) +
|
|
||||||
std::string("/libelasticity.dylib")).c_str());
|
|
||||||
#else
|
|
||||||
mj_loadPluginLibrary((
|
|
||||||
std::string(std::getenv("MUJOCO_PLUGIN_DIR")) +
|
|
||||||
std::string("/libelasticity.so")).c_str());
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// -------------------------------- solid -----------------------------------
|
// -------------------------------- solid -----------------------------------
|
||||||
TEST_F(PluginTest, ElasticEnergy) {
|
TEST_F(PluginTest, ElasticEnergy) {
|
||||||
static constexpr char cantilever_xml[] = R"(
|
static constexpr char cantilever_xml[] = R"(
|
||||||
|
|||||||
@@ -18,7 +18,12 @@ target_link_libraries(xml_api_test fixture gmock)
|
|||||||
mujoco_test(xml_native_reader_test)
|
mujoco_test(xml_native_reader_test)
|
||||||
target_link_libraries(xml_native_reader_test fixture gmock)
|
target_link_libraries(xml_native_reader_test fixture gmock)
|
||||||
|
|
||||||
mujoco_test(xml_native_writer_test)
|
mujoco_test(
|
||||||
|
xml_native_writer_test
|
||||||
|
PROPERTIES
|
||||||
|
ENVIRONMENT
|
||||||
|
"MUJOCO_PLUGIN_DIR=$<TARGET_FILE_DIR:elasticity>"
|
||||||
|
)
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
xml_native_writer_test
|
xml_native_writer_test
|
||||||
fixture
|
fixture
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
// Tests for xml/xml_native_writer.cc.
|
// Tests for xml/xml_native_writer.cc.
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -959,17 +960,23 @@ static constexpr int kFieldSize = 500;
|
|||||||
// The maximum spacing between a normalised floating point number x and an
|
// The maximum spacing between a normalised floating point number x and an
|
||||||
// adjacent normalised number is 2 epsilon |x|; a factor 10 is added accounting
|
// adjacent normalised number is 2 epsilon |x|; a factor 10 is added accounting
|
||||||
// for losses during non-idempotent operations such as vector normalizations.
|
// for losses during non-idempotent operations such as vector normalizations.
|
||||||
template<typename T = mjtNum> T Compare(T val1, T val2) {
|
template <typename T>
|
||||||
T error;
|
auto Compare(T val1, T val2) {
|
||||||
|
using ReturnType =
|
||||||
|
std::conditional_t<std::is_same_v<T, float>, float, double>;
|
||||||
|
ReturnType error;
|
||||||
if (mju_abs(val1) <= 1 || mju_abs(val2) <= 1) {
|
if (mju_abs(val1) <= 1 || mju_abs(val2) <= 1) {
|
||||||
// Asbolute precision for small numbers
|
// Absolute precision for small numbers
|
||||||
error = mju_abs(val1-val2);
|
error = mju_abs(val1-val2);
|
||||||
} else {
|
} else {
|
||||||
// Relative precision for larger numbers
|
// Relative precision for larger numbers
|
||||||
T magnitude = mju_max(mju_abs(val1), mju_abs(val2));
|
ReturnType magnitude = mju_abs(val1) + mju_abs(val2);
|
||||||
error = mju_abs(val1/magnitude - val2/magnitude) / magnitude;
|
error = mju_abs(val1/magnitude - val2/magnitude) / magnitude;
|
||||||
}
|
}
|
||||||
return error < 2*10*std::numeric_limits<T>::epsilon() ? 0 : error;
|
ReturnType safety_factor = 10;
|
||||||
|
return error < safety_factor * std::numeric_limits<ReturnType>::epsilon()
|
||||||
|
? 0
|
||||||
|
: error;
|
||||||
}
|
}
|
||||||
|
|
||||||
mjtNum CompareModel(const mjModel* m1, const mjModel* m2,
|
mjtNum CompareModel(const mjModel* m1, const mjModel* m2,
|
||||||
@@ -1015,7 +1022,7 @@ mjtNum CompareModel(const mjModel* m1, const mjModel* m2,
|
|||||||
return maxdif;
|
return maxdif;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(XMLWriterTest, WriteReadCompare) {
|
TEST_F(PluginTest, WriteReadCompare) {
|
||||||
FullFloatPrecision increase_precision;
|
FullFloatPrecision increase_precision;
|
||||||
// Loop over all xml files in data
|
// Loop over all xml files in data
|
||||||
std::vector<std::string> paths = {GetTestDataFilePath("."),
|
std::vector<std::string> paths = {GetTestDataFilePath("."),
|
||||||
@@ -1028,7 +1035,7 @@ TEST_F(XMLWriterTest, WriteReadCompare) {
|
|||||||
|
|
||||||
// if file is meant to fail, skip it
|
// if file is meant to fail, skip it
|
||||||
if (absl::StrContains(p.path().string(), "malformed_") ||
|
if (absl::StrContains(p.path().string(), "malformed_") ||
|
||||||
absl::StrContains(p.path().string(), "plugin")) {
|
absl::StrContains(p.path().string(), "touch_grid")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1051,12 +1058,17 @@ TEST_F(XMLWriterTest, WriteReadCompare) {
|
|||||||
// if failing because assets are missing, accept the test
|
// if failing because assets are missing, accept the test
|
||||||
ASSERT_THAT(error.data(), HasSubstr("file")) << error.data();
|
ASSERT_THAT(error.data(), HasSubstr("file")) << error.data();
|
||||||
} else {
|
} else {
|
||||||
|
// for a particularly difficult example, relax the tolerance
|
||||||
|
mjtNum tol =
|
||||||
|
absl::StrContains(p.path().string(), "belt.xml") ? 1e-13 : 0;
|
||||||
|
|
||||||
// compare and delete
|
// compare and delete
|
||||||
char field[kFieldSize] = "";
|
char field[kFieldSize] = "";
|
||||||
mjtNum result = CompareModel(m, mtemp, field);
|
mjtNum result = CompareModel(m, mtemp, field);
|
||||||
EXPECT_LE(result, 0) << "Loaded and saved models are different!\n"
|
EXPECT_LE(result, tol)
|
||||||
<< "Affected file " << p.path().string() << '\n'
|
<< "Loaded and saved models are different!\n"
|
||||||
<< "Different field: " << field << '\n';
|
<< "Affected file " << p.path().string() << '\n'
|
||||||
|
<< "Different field: " << field << '\n';
|
||||||
mj_deleteModel(mtemp);
|
mj_deleteModel(mtemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user