Version 2.1.1: Binaries for ARM64, proper macOS bundles, minor bugfixes.

Closes #2
Closes #42
Closes #59

PiperOrigin-RevId: 416794598
Change-Id: I1306df1127d6acecf2323873c0da0910f35d31a0
This commit is contained in:
Saran Tunyasuvunakool
2021-12-16 14:36:53 +00:00
parent 4bf5630558
commit a499b38120
49 changed files with 6055 additions and 5712 deletions
Regular → Executable
+107 -111
View File
@@ -12,163 +12,159 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "mujoco.h"
#include "mjxmacro.h"
#include <stdlib.h>
#include <stdio.h>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <string>
#include <chrono>
#include "mjxmacro.h"
#include "mujoco.h"
using namespace std;
#include "array_safety.h"
namespace mju = ::mujoco::sample_util;
static constexpr int kFieldSize = 500;
// help
const char helpstring[] = "\n Usage: testxml modelfile.xml\n";
// deallocate and print message
int finish(const char* msg = 0, mjModel* m = 0, mjData* d = 0)
{
// deallocated everything
if( d )
mj_deleteData(d);
if( m )
mj_deleteModel(m);
int finish(const char* msg = 0, mjModel* m = 0, mjData* d = 0) {
// deallocated everything
if (d) {
mj_deleteData(d);
}
if (m) {
mj_deleteModel(m);
}
// print message
if( msg )
printf("%s\n", msg);
// print message
if (msg) {
std::printf("%s\n", msg);
}
return 0;
return 0;
}
// return absolute difference if it is below 1, relative difference otherwise
static mjtNum _compare(mjtNum val1, mjtNum val2)
{
mjtNum magnitude = mju_max(mju_abs(val1), mju_abs(val2));
static mjtNum _compare(mjtNum val1, mjtNum val2) {
mjtNum magnitude = mju_max(mju_abs(val1), mju_abs(val2));
if( magnitude>1.0 )
return mju_abs(val1-val2) / magnitude;
else
return mju_abs(val1-val2);
if (magnitude>1.0) {
return mju_abs(val1-val2) / magnitude;
} else {
return mju_abs(val1-val2);
}
}
// compare two models, return largest difference and field name
mjtNum compareModel(const mjModel* m1, const mjModel* m2, char* field)
{
int r, c;
mjtNum dif, maxdif = 0.0;
mjtNum compareModel(const mjModel* m1, const mjModel* m2, char (&field)[kFieldSize]) {
int r, c;
mjtNum dif, maxdif = 0.0;
// define symbols corresponding to number of columns (needed in MJMODEL_POINTERS)
int nq = m1->nq;
int nv = m1->nv;
int na = m1->na;
int nmocap3 = 3*m1->nmocap;
int nmocap4 = 4*m1->nmocap;
int nuser_body = m1->nuser_body;
int nuser_jnt = m1->nuser_jnt;
int nuser_geom = m1->nuser_geom;
int nuser_site = m1->nuser_site;
int nuser_cam = m1->nuser_cam;
int nuser_tendon = m1->nuser_tendon;
int nuser_actuator = m1->nuser_actuator;
int nuser_sensor = m1->nuser_sensor;
// define symbols corresponding to number of columns (needed in MJMODEL_POINTERS)
MJMODEL_POINTERS_PREAMBLE(m1);
// compare ints
#define X(name) if(m1->name!=m2->name) {strcpy(field, #name); return 1.0;}
// compare ints
#define X(name) if(m1->name!=m2->name) {mju::strcpy_arr(field, #name); return 1.0;}
MJMODEL_INTS
#undef X
MJMODEL_INTS
#undef X
// compare arrays
#define X(type, name, nr, nc) \
for( r=0; r<m1->nr; r++ ) \
for( c=0; c<nc; c++ ) { \
dif = _compare(m1->name[r*nc+c], m2->name[r*nc+c]); \
if(dif>maxdif) {maxdif=dif; strcpy(field, #name);} }
#define X(type, name, nr, nc) \
for( r=0; r<m1->nr; r++ ) \
for( c=0; c<nc; c++ ) { \
dif = _compare(m1->name[r*nc+c], m2->name[r*nc+c]); \
if(dif>maxdif) {maxdif=dif; mju::strcpy_arr(field, #name);} }
MJMODEL_POINTERS
#undef X
MJMODEL_POINTERS
#undef X
// compare scalars in mjOption
#define X(type, name) \
dif = _compare(m1->opt.name, m2->opt.name); \
if(dif>maxdif) {maxdif=dif; strcpy(field, #name);}
// compare scalars in mjOption
#define X(type, name) \
dif = _compare(m1->opt.name, m2->opt.name); \
if(dif>maxdif) {maxdif=dif; mju::strcpy_arr(field, #name);}
MJOPTION_SCALARS
#undef X
MJOPTION_SCALARS
#undef X
// compare arrays in mjOption
#define X(name, n) \
for( c=0; c<n; c++ ) { \
dif = _compare(m1->opt.name[c], m2->opt.name[c]); \
if(dif>maxdif) {maxdif=dif; strcpy(field, #name);} }
// compare arrays in mjOption
#define X(name, n) \
for( c=0; c<n; c++ ) { \
dif = _compare(m1->opt.name[c], m2->opt.name[c]); \
if(dif>maxdif) {maxdif=dif; mju::strcpy_arr(field, #name);} }
MJOPTION_VECTORS
#undef X
MJOPTION_VECTORS
#undef X
// mjVisual and mjStatistics ignored for now
// mjVisual and mjStatistics ignored for now
return maxdif;
return maxdif;
}
// main function
int main(int argc, const char** argv)
{
// print help if arguments are missing
if( argc<2 )
return finish(helpstring);
int main(int argc, const char** argv) {
// print help if arguments are missing
if (argc<2) {
return finish(helpstring);
}
// get filename, check file type
std::string filename(argv[1]);
if( filename.find(".xml")==std::string::npos )
return finish("xml model file is required");
// get filename, check file type
std::string filename(argv[1]);
if (filename.find(".xml")==std::string::npos) {
return finish("xml model file is required");
}
// load model
char error[1000];
mjModel* m = mj_loadXML(argv[1], 0, error, 1000);
if( !m )
return finish(error);
// load model
char error[1000];
mjModel* m = mj_loadXML(argv[1], 0, error, 1000);
if (!m) {
return finish(error);
}
// make data
mjData* d = mj_makeData(m);
if( !d )
return finish("Could not allocate mjData", m);
// make data
mjData* d = mj_makeData(m);
if (!d) {
return finish("Could not allocate mjData", m);
}
// prepare temp filename in the same directory as original (for asset loading)
std::string tempfile;
size_t lastpath = filename.find_last_of("/\\");
if( lastpath==std::string::npos )
tempfile = "_tempfile_.xml";
else
tempfile = filename.substr(0, lastpath+1) + "_tempfile_.xml";
// prepare temp filename in the same directory as original (for asset loading)
std::string tempfile;
std::size_t lastpath = filename.find_last_of("/\\");
if (lastpath==std::string::npos) {
tempfile = "_tempfile_.xml";
} else {
tempfile = filename.substr(0, lastpath+1) + "_tempfile_.xml";
}
// save
if( !mj_saveLastXML(tempfile.c_str(), m, error, 1000) )
return finish(error, m, d);
// save
if (!mj_saveLastXML(tempfile.c_str(), m, error, 1000)) {
return finish(error, m, d);
}
// load back
mjModel* mtemp = mj_loadXML(tempfile.c_str(), 0, error, 100);
if( !mtemp )
return finish(error, m, d);
// load back
mjModel* mtemp = mj_loadXML(tempfile.c_str(), 0, error, 100);
if (!mtemp) {
return finish(error, m, d);
}
// compare
char field[500] = "";
mjtNum result = compareModel(m, mtemp, field);
printf("\nComparison of original and saved model\n");
printf(" Max difference : %.3g\n", result);
printf(" Field name : %s\n", field);
// compare
char field[kFieldSize] = "";
mjtNum result = compareModel(m, mtemp, field);
std::printf("\nComparison of original and saved model\n");
std::printf(" Max difference : %.3g\n", result);
std::printf(" Field name : %s\n", field);
// delete temp model and file
mj_deleteModel(mtemp);
remove(tempfile.c_str());
// delete temp model and file
mj_deleteModel(mtemp);
remove(tempfile.c_str());
// finalize
return finish();
// finalize
return finish();
}