Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add platform-specific test support (and fix testCMCGait10dof18musc.cpp) #3616

Merged
merged 23 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
574e9ff
Update standard file for testCMCGait10dof18musc.cpp
nickbianco Nov 17, 2023
bea4e96
Update gait10dof18musc test to use Catch2 framework
nickbianco Nov 22, 2023
3dc998b
Update test tolerance
nickbianco Nov 22, 2023
efc3175
Loosen test tolerance
nickbianco Nov 22, 2023
c2555f2
Revert back to original tolerance
nickbianco Nov 23, 2023
3bb11ba
Use separate solution files for Windows and Unix systems
nickbianco Nov 27, 2023
1a047e0
Use unique test names
nickbianco Nov 28, 2023
ac7c102
Debugging Catch2 (might need to upgrade)
nickbianco Nov 29, 2023
523e7ae
Merge branch 'catch_v3' into test_cmc_gait10dof18musc_update
nickbianco Dec 19, 2023
c1e55b6
Use a weaker test for the Mac builds
nickbianco Dec 19, 2023
eb5859f
Merge branch 'catch_v3' into test_cmc_gait10dof18musc_update
nickbianco Dec 19, 2023
5829b9a
Add Catch2WithMain link target back to Common tests
nickbianco Dec 19, 2023
b47d122
Use exclusion over inclusion logic
nickbianco Dec 19, 2023
fd994dd
Add all CMC tests back in
nickbianco Dec 19, 2023
f442a61
Try updating std file on Mac again
nickbianco Dec 19, 2023
54e1bcc
Fix the test exclusion logic
nickbianco Dec 19, 2023
16f1870
Fix test exclusion logic typo
nickbianco Dec 20, 2023
32afdc2
Test exclusion logic take 3
nickbianco Dec 20, 2023
d79ffe6
Update `CONTRIBUTING.md` with platform-specific test instructions
nickbianco Dec 20, 2023
7cb434f
Move Linux test to weaker test case
nickbianco Dec 20, 2023
8f3325e
Merge branch 'main' into test_cmc_gait10dof18musc_update
nickbianco Jan 8, 2024
4881a68
Small corrections
nickbianco Jan 8, 2024
0ca8d7e
Update `CONTRIBUTING.md` and revert debug code
nickbianco Jan 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Applications/CMC/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
find_package(Catch2 REQUIRED
HINTS "${OPENSIM_DEPENDENCIES_DIR}/catch2")

file(GLOB TEST_PROGS "test*.cpp")
file(GLOB TEST_FILES *.osim *.xml *.sto *.mot)

OpenSimAddTests(
TESTPROGRAMS ${TEST_PROGS}
DATAFILES ${TEST_FILES}
LINKLIBS osimTools
LINKLIBS osimTools Catch2::Catch2WithMain
)

1,693 changes: 0 additions & 1,693 deletions Applications/CMC/test/gait10dof18musc_std_walk_subject_states.sto

This file was deleted.

411 changes: 411 additions & 0 deletions Applications/CMC/test/gait10dof18musc_std_walk_subject_states_unix.sto

Large diffs are not rendered by default.

411 changes: 411 additions & 0 deletions Applications/CMC/test/gait10dof18musc_std_walk_subject_states_win.sto

Large diffs are not rendered by default.

114 changes: 58 additions & 56 deletions Applications/CMC/test/testCMCGait10dof18musc.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* -------------------------------------------------------------------------- *
* OpenSim: testCMCGait10dof18musc.cpp *
* OpenSim: testCMCGait10dof18musc.cpp *
* -------------------------------------------------------------------------- *
* The OpenSim API is a toolkit for musculoskeletal modeling and simulation. *
* See http://opensim.stanford.edu and the NOTICE file for more information. *
* OpenSim is developed at Stanford University and supported by the US *
* National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA *
* through the Warrior Web program. *
* *
* Copyright (c) 2005-2017 Stanford University and the Authors *
* Copyright (c) 2005-2023 Stanford University and the Authors *
* *
* 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 *
Expand All @@ -21,67 +21,69 @@
* -------------------------------------------------------------------------- */

// INCLUDE
#include <OpenSim/Common/GCVSplineSet.h>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Simulation/Model/AnalysisSet.h>
#include <OpenSim/Tools/CMCTool.h>
#include <OpenSim/Tools/ForwardTool.h>
#include <OpenSim/Auxiliary/auxiliaryTestFunctions.h>

using namespace OpenSim;
using namespace std;

void testGait10dof18musc();

int main() {
#include <catch2/catch_all.hpp>

SimTK::Array_<std::string> failures;

// Model uses Millard2012EquilibriumMuscle type muscles
try { testGait10dof18musc(); }
catch (const std::exception& e) {
cout << e.what() << endl;
failures.push_back("testGait10dof18musc");
}
using namespace OpenSim;

if (!failures.empty()) {
cout << "Done, with failure(s): " << failures << endl;
return 1;
TEST_CASE("testGait10dof18musc (Windows)", "[win]") {
CMCTool cmc("gait10dof18musc_Setup_CMC.xml");
cmc.run();

const TimeSeriesTable results(
"gait10dof18musc_ResultsCMC/walk_subject_states.sto");
const TimeSeriesTable std(
"gait10dof18musc_std_walk_subject_states_win.sto");

// TODO: Replace with macro from OpenSim/Moco/Test/Testing.h
const auto& actual = results.getMatrix();
const auto& expected = std.getMatrix();
REQUIRE((actual.nrow() == expected.nrow()));
REQUIRE((actual.ncol() == expected.ncol()));
for (int ir = 0; ir < actual.nrow(); ++ir) {
for (int ic = 0; ic < actual.ncol(); ++ic) {
INFO("(" << ir << "," << ic << "): " << actual.getElt(ir, ic) <<
" vs " << expected.getElt(ir, ic));
REQUIRE((Catch::Approx(actual.getElt(ir, ic)).margin(1e-3)
== expected.getElt(ir, ic)));
}
}

cout << "Done" << endl;

return 0;
}

// Perform regression test with standard generated from Gait10dof18musc
// example in OpenSim 3.2
void testGait10dof18musc() {
cout<<"\n******************************************************************" << endl;
cout << "* testGait10dof18musc *" << endl;
cout << "******************************************************************\n" << endl;
TEST_CASE("testGait10dof18musc (Mac/Linux)", "[unix]") {
CMCTool cmc("gait10dof18musc_Setup_CMC.xml");
const string& muscleType = cmc.getModel().getMuscles()[0].getConcreteClassName();

if (!cmc.run())
OPENSIM_THROW(Exception, "testGait10dof18musc " + muscleType +
" failed to complete.");

Storage results("gait10dof18musc_ResultsCMC/walk_subject_states.sto");
Storage temp("gait10dof18musc_std_walk_subject_states.sto");

Storage *standard = new Storage();
cmc.getModel().formStateStorage(temp, *standard);

int nstates = standard->getColumnLabels().size() - 1;

// angles and speeds within 0.01 rads and 0.01 rad/s;
// and activations to within 1%
std::vector<double> rms_tols(nstates, 0.01);

CHECK_STORAGE_AGAINST_STANDARD(results, *standard, rms_tols,
__FILE__, __LINE__, "testGait10dof18musc "+ muscleType + " failed");

cout << "\ntestGait10dof18musc "+ muscleType +" passed\n" << endl;
cmc.run();

const TimeSeriesTable results(
"gait10dof18musc_ResultsCMC/walk_subject_states.sto");
const TimeSeriesTable std(
"gait10dof18musc_std_walk_subject_states_unix.sto");

// Unix systems produce inconsistent results compared to Windows. Somehow,
// CMC produces results with differing number of time points, so we need to
// interpolate the results to the same time points as the standard results.
// The shapes of the muscle activity curves also differ slightly, so we
// allow a larger margin of error for the muscle activity curves. Therefore,
// this is a weaker test compared to the Windows test.
GCVSplineSet resultSplines(results);
GCVSplineSet stdSplines(std);

// TODO: Replace with (a new) macro from OpenSim/Moco/Test/Testing.h
const auto& time = std.getIndependentColumn();
for (const auto& label : results.getColumnLabels()) {
const auto& result = resultSplines.get(label);
const auto& expected = stdSplines.get(label);
SimTK::Vector timeVec(1, 0.0);
for (int it = 0; it < static_cast<int>(time.size()); ++it) {
timeVec[0] = time[it];
INFO(label << " at time " << time[it] << ": " <<
result.calcValue(timeVec) << " vs " <<
expected.calcValue(timeVec));
REQUIRE((Catch::Approx(result.calcValue(timeVec)).margin(1e-1)
== expected.calcValue(timeVec)));
}
}
}


56 changes: 47 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,21 +83,59 @@ that are already in `OpenSim/Tests/shared`; you could inadvertently weaken tests
that rely on some obscure aspect of the files.


Platform-specific tests
-----------------------
The Catch2 testing framework can be used to write platform-specific tests. Such
tests should be avoided if possible, but may be necessary in certain cases (e.g.,
slightly different numerical optimization behavior on different platforms). For
example, if you want to write a test that only runs on Windows, you can use the
`TEST_CASE()` or `TEMPLATE_TEST_CASE` macros with the tag `"[win]"`:

```cpp
TEST_CASE("MyTest", "[win]") {
// ...
}
```

```cpp
TEMPLATE_TEST_CASE("MyTest", "[win]", TestType) {
// ...
}
```

Specifying the tag `"[win]"` means that this test will be _excluded_ on Mac and
Linux. The tags `"[mac]"` and `"[linux]"` can be used similarly for tests specific
to Mac or Linux. If you want to run a test on two platforms but not the third,
use combined tags (e.g., `"[win/linux]"`, `"[mac/win]"`, or `"[unix]"`). Do not
concatenate tags; for example, `"[win][linux]"`) will not run on Linux or Windows
since Windows excludes Linux-only tests and vice-versa. Specifying no tag means
that the test will run on all platforms. The table below summarizes the tags that
can be used to specify platform-specific tests.

| Platform(s) | Tag(s) |
|-------------------|----------------------------------------------|
| Windows | `"[win]"` |
| Mac | `"[mac]"` |
| Linux | `"[linux]"` |
| Mac and Linux | `"[unix]"`, `"[mac/linux]"`, `"[linux/mac]"` |
| Windows and Mac | `"[win/mac]"`, `"[mac/win]"` |
| Windows and Linux | `"[win/linux]"`, `"[linux/win]"` |
| All platforms | (no tag) |


Running Moco tests
------------------
In general, Moco's tests depend on the CasADi and Tropter libraries, whose use
is determined by the `OPENSIM_WITH_CASADI` and `OPENSIM_WITH_TROPTER` CMake
variables. The CTests are designed to succeed regardless of the value of these
CMake variables: if `OPENSIM_WITH_CASADI` is off, Moco's C++ tests are run with
arguments `"exclude:*MocoCasADiSolver*" "exclude:[casadi]"`,
which excludes Catch2 templatized tests using MocoCasADiSolver and other tests
that are tagged as relying on CasADi (likewise for Tropter).
If the test executables are run without CTest (e.g., debugging a project in
Visual Studio), the tests will fail if either `OPENSIM_WITH_CASADI` or
`OPENSIM_WITH_TROPTER` is false; for the tests to pass, provide the argument(s)
`"exclude:*MocoCasADiSolver*" "exclude:[casadi]"` and/or
`"exclude:*MocoTropterSolver*" "exclude:[tropter]"` (depending on which
libraries are available).
arguments `"~*MocoCasADiSolver*" "~[casadi]"`, which excludes Catch2 templatized
tests using MocoCasADiSolver and other tests that are tagged as relying on CasADi
(likewise for Tropter). If the test executables are run without CTest (e.g.,
debugging a project in Visual Studio), the tests will fail if either
`OPENSIM_WITH_CASADI` orv`OPENSIM_WITH_TROPTER` is false; for the tests to pass,
provide the argument(s) `"~*MocoCasADiSolver*" "~[casadi]"` and/or
`"~*MocoTropterSolver*" "~[tropter]"` (depending on which libraries are available).


Checking for Memory Leaks with LibASAN
Expand Down
2 changes: 1 addition & 1 deletion OpenSim/Common/Test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ OpenSimAddTests(
TESTPROGRAMS ${TEST_PROGS}
DATAFILES ${TEST_FILES} ${C3D_TEST_FILES} ${TRC_TEST_FILES} ${XSENS_TEST_FILES} ${APDM_TEST_FILES}
${MOT_TEST_FILES}
LINKLIBS osimCommon ${SIMTK_ALL_LIBS} Catch2::Catch2WithMain
LINKLIBS osimCommon Catch2::Catch2WithMain ${SIMTK_ALL_LIBS}
)
10 changes: 4 additions & 6 deletions OpenSim/Moco/Test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ function(MocoAddTest)
target_link_libraries(${MOCOTEST_NAME} osimMoco ${MOCOTEST_LIB_DEPENDS} Catch2::Catch2WithMain)
# Skip tests relying on MocoCasADiSolver if CasADi is not available.
if(NOT OPENSIM_WITH_CASADI)
list(APPEND test_args "exclude:*MocoCasADiSolver*")
list(APPEND test_args "exclude:[casadi]")
list(APPEND test_args "~*MocoCasADiSolver*")
list(APPEND test_args "~[casadi]")
endif()
if(NOT OPENSIM_WITH_TROPTER)
list(APPEND test_args "exclude:*MocoTropterSolver*")
list(APPEND test_args "exclude:[tropter]")
list(APPEND test_args "~*MocoTropterSolver*")
list(APPEND test_args "~[tropter]")
endif()
add_test(NAME ${MOCOTEST_NAME} COMMAND ${MOCOTEST_NAME} ${test_args})
# Tests likely run faster if we parallelize the tests rather than the
Expand Down Expand Up @@ -62,8 +62,6 @@ MocoAddTest(NAME testMocoTrack RESOURCES
std_testMocoTrackGait10dof18musc_solution.sto
)

# MocoAddTest(NAME testMultivariatePolynomial)

MocoAddTest(NAME testMocoAnalytic)

MocoAddTest(NAME testMocoMetabolics)
Expand Down
21 changes: 15 additions & 6 deletions cmake/OpenSimMacros.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,9 @@ function(OpenSimAddLibrary)

# This is for exporting classes on Windows.
if(OSIMADDLIB_VENDORLIB)
set(OSIMADDLIB_FOLDER "Vendor Libraries")
set(OSIMADDLIB_FOLDER "Vendor Libraries")
else()
set(OSIMADDLIB_FOLDER "Libraries")
set(OSIMADDLIB_FOLDER "Libraries")
endif()
set_target_properties(${OSIMADDLIB_LIBRARY_NAME} PROPERTIES
DEFINE_SYMBOL OSIM${OSIMADDLIB_UKIT}_EXPORTS
Expand Down Expand Up @@ -334,7 +334,7 @@ endfunction()
# file(GLOB TEST_PROGRAMS "test*.cpp")
# file(GLOB DATA_FILES *.osim *.xml *.sto *.mot)
# OpenSimAddTests(
# TESTPROGRAMS ${TEST_ROGRAMS}
# TESTPROGRAMS ${TEST_PROGRAMS}
# DATAFILES ${DATA_FILES}
# LINKLIBS osimCommon osimSimulation osimAnalyses
# )
Expand Down Expand Up @@ -367,11 +367,20 @@ function(OpenSimAddTests)
add_executable(${TEST_NAME} ${test_program}
${OSIMADDTESTS_SOURCES})
target_link_libraries(${TEST_NAME} ${OSIMADDTESTS_LINKLIBS})
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
set(test_args "")
if(APPLE)
list(APPEND test_args "~[win]~[linux]~[win/linux]~[linux/win]")
endif()
if(LINUX)
list(APPEND test_args "~[win]~[mac]~[win/mac]~[mac/win]")
endif()
if(WIN32)
list(APPEND test_args "~[mac]~[linux]~[mac/linux]~[linux/mac]~[unix]")
endif()
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} ${test_args})
set_target_properties(${TEST_NAME} PROPERTIES
FOLDER "Tests"
)

)
endforeach()

# Copy data files to build directory.
Expand Down