Skip to content

Commit e88992f

Browse files
Merge pull request #347 from rcnl-org/candidate
v1.3.2
2 parents 40f7dee + e78cf68 commit e88992f

File tree

13 files changed

+81
-8
lines changed

13 files changed

+81
-8
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## v1.3.2 - 2024-10-28
4+
5+
### Added
6+
- Treatment Optimization plotting function `plotTreatmentOptimizationResultsFromSettingsFile()` can optionally take an override results directory as a second argument to plot results from a directory other than the one in the given settings file
7+
8+
9+
### Fixed
10+
- Neural Control Personalization plots requiring multiple plot windows will correctly format overflow windows to match the first
11+
- Prescribed coordinates in Design Optimization are saved to results correctly for free final time problems
12+
13+
14+
### Changed
15+
- Updated calls to the MATLAB `size()` function to prevent compatibility warning messages on MATLAB R2024a and newer
16+
17+
318
## v1.3.1 - 2024-10-01
419

520
### Added

src/GroundContactPersonalization/Optimizations/ModelCalculation/findModeledMarkerCoordinates.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
findModeledMarkerCoordinates(model, state, modeledMarkerPositions, ...
3434
markerNames, index)
3535
markerNamesFields = fieldnames(markerNames);
36-
for j=1:size(markerNamesFields)
36+
for j=1:length(markerNamesFields)
3737
modeledMarkerPositions.(markerNamesFields{j})(:, index) = model. ...
3838
getMarkerSet().get(markerNames.(markerNamesFields{j})). ...
3939
getLocationInGround(state).getAsMat()';

src/GroundContactPersonalization/parseGroundContactPersonalizationSettingsTree.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
grf = NaN(3, length(task.grfTime));
136136
moments = NaN(3, length(task.grfTime));
137137
ec = NaN(3, length(task.grfTime));
138-
for i=1:size(grfColumnNames')
138+
for i=1:size(grfColumnNames', 1)
139139
label = grfColumnNames(i);
140140
for j = 1:3
141141
if strcmpi(label, task.forceColumns(j, :))

src/NeuralControlPersonalization/Analysis/plotMomentMatchingResults.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ function plotMomentMatchingResults(experimentalMomentsFile, ...
9898
for i = 1:length(experimentalColumns)
9999
if i > figureSize * figureIndex
100100
figureIndex = figureIndex + 1;
101-
figure(figureNumber + figureIndex - 1)
101+
figure(Name = figureName, ...
102+
Units='normalized', ...
103+
Position=[0.05 0.05 0.9 0.85])
102104
t = tiledlayout(figureHeight, figureWidth, ...
103105
TileSpacing='compact', Padding='compact');
104106
subplotNumber = 1;

src/NeuralControlPersonalization/Analysis/plotNeuralControlPersonalizationActivations.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ function plotNeuralControlPersonalizationActivations(weightsFile, ...
7575
for i = 1:size(muscleActivations, 1)
7676
if i > figureSize * figureNumber
7777
figureNumber = figureNumber + 1;
78-
figure(figureNumber)
78+
figure(Name = figureName, ...
79+
Units='normalized', ...
80+
Position=[0.05 0.05 0.9 0.85])
7981
t = tiledlayout(figureHeight, figureWidth, ...
8082
TileSpacing='Compact', Padding='Compact');
8183
subplotNumber = 1;

src/TreatmentOptimization/Analysis/plotTreatmentOptimizationResultsFromSettingsFile.m

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@
2727
% permissions and limitations under the License. %
2828
% ----------------------------------------------------------------------- %
2929

30-
function plotTreatmentOptimizationResultsFromSettingsFile(settingsFileName)
30+
function plotTreatmentOptimizationResultsFromSettingsFile(settingsFileName, ...
31+
overrideResultsDirectory)
3132
settingsTree = xml2struct(settingsFileName);
3233
toolName = findToolName(settingsTree);
3334
resultsDirectory = getTextFromField(getFieldByName(settingsTree, ...
3435
'results_directory'));
36+
if nargin > 1
37+
resultsDirectory = overrideResultsDirectory;
38+
end
3539
trackedQuantitiesDirectory = getTextFromField(getFieldByName(settingsTree, ...
3640
'tracked_quantities_directory'));
3741
initialGuessDirectory = getTextFromField(getFieldByName(settingsTree, ...

src/TreatmentOptimization/gpops/makeGpopsValuesAsStruct.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@
100100
if size(values.time) == size(inputs.collocationTimeOriginal)
101101
positions = inputs.splinedJointAngles;
102102
velocities = inputs.splinedJointSpeeds;
103+
elseif size(values.time) == size(inputs.collocationTimeOriginal) + [1, 0]
104+
positions = inputs.splinedJointAngles;
105+
velocities = inputs.splinedJointSpeeds;
106+
positions(end+1, :) = inputs.experimentalJointAngles(end, :);
107+
velocities(end+1, :) = inputs.experimentalJointVelocities(end, :);
103108
else
104109
positions = evaluateGcvSplines(inputs.splineJointAngles, ...
105110
inputs.coordinateNames, values.time);
@@ -119,6 +124,9 @@
119124
function accelerations = recombineFullAccelerations(values, inputs)
120125
if size(values.time) == size(inputs.collocationTimeOriginal)
121126
accelerations = inputs.splinedJointAccelerations;
127+
elseif size(values.time) == size(inputs.collocationTimeOriginal) + [1, 0]
128+
accelerations = inputs.splinedJointAccelerations;
129+
accelerations(end+1, :) = inputs.experimentalJointAccelerations(end, :);
122130
else
123131
accelerations = evaluateGcvSplines(inputs.splineJointAngles, ...
124132
inputs.coordinateNames, values.time, 2);

src/TreatmentOptimization/parseGroundContactSurfaces.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
function output = parseGroundReactionDataWithoutTime(model, grfFile, output)
9797
import org.opensim.modeling.Storage
9898
[grfColumnNames, ~, grfData] = parseMotToComponents(model, Storage(grfFile));
99-
for i=1:size(grfColumnNames')
99+
for i=1:size(grfColumnNames', 1)
100100
label = grfColumnNames(i);
101101
for j = 1:3
102102
if strcmpi(label, output.forceColumns(j))
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## Compiling MEX files
2+
3+
New versions of MEX files may need to be compiled with new OpenSim API versions. These directions apply to compiling new MEX files for Windows only and adding them for use in the NMSM Pipeline.
4+
5+
1. Install [Visual Studio Community Edition 2019](https://visualstudio.microsoft.com/vs/older-downloads/).
6+
7+
2. While installing Visual Studio, download the Windows SDK (tested with Windows 10), available during Visual Studio Community setup or [alternatively here](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/).
8+
9+
3. Make sure Matlab is configured to use the correct compiler by running `mex -setup C++` in the Command Window. If the configured version is not 'Microsoft Visual C++ 2019', use one of the options given to choose the correct compiler.
10+
11+
4. Inside the scripts `compileInverseDynamicsMex.m` and `compilePointKinematicsMex.m` in the `nmsm-core\src\core\mex` directory, replace the references to the OpenSim installation directory with the directory on your computer for the OpenSim version you are compiling for. Keep the internal structure (such as `sdk\lib`) the same, only changing the start of the paths.
12+
13+
5. Change the include statement linking the Windows SDK `ucrt` directory to match your local Windows SDK installation. The only difference between your path and the one in the script is likely a version number.
14+
15+
6. Run the compilation script. If everything was linked correctly, you will see `Building with 'Microsoft Visual C++ 2019'.
16+
MEX completed successfully.` for each script.
17+
18+
These steps will compile new MEX files. To add them to the NMSM Pipeline:
19+
20+
1. You will need the OpenSim API version number in a number format. Assuming the API version linked to Matlab is the same as the one you just compiled, run getOpenSimVersion() in the Command Window to get this number. As an example, running this function on OpenSim 4.7 should return `40700`.
21+
22+
2. Rename the compiled inverse dynamics and point kinematics MEX functions to `inverseDynamicsWithExtraCalcsMexWindowsXXXXX.mexw64` and `pointKinematicsMexWindowsXXXXX.mexw64` respectively. The `XXXXX` should be replaced with the version number from the previous step.
23+
24+
3. Open `inverseDynamics.m` and `pointKinematics.m`. These files have a similar structure, each with a portion inside an `if isequal(mexext, 'mexw64')` statement.
25+
26+
4. In each file, copy the first if statement inside the `mexw64` case and paste a copy above it. As an example, if 4.5.1 is the most recent MEX version, you would copy this:
27+
28+
```
29+
if version >= 40501
30+
[inverseDynamicsMoments, angularMomentum, metabolicCost, ...
31+
massCenterVelocity] = ...
32+
inverseDynamicsWithExtraCalcsMexWindows40501(time, ...
33+
jointAngles, jointVelocities, jointAccelerations, ...
34+
coordinateLabels, appliedLoads, muscleActivations, ...
35+
computeAngularMomentum, computeMetabolicCost);
36+
```
37+
38+
5. Change the original if statement below your copy to an elseif statement.
39+
40+
6. Change the version number in your copied if statement at the top of the block to your current version number from the first step, and change the function call inside this if statment to use your new MEX file.
41+
42+
The NMSM Pipeline will now be able to use your new MEX functions when needed.
File renamed without changes.

0 commit comments

Comments
 (0)