Skip to content

Commit 65dd664

Browse files
committed
MFD Matlab plugin was heavily refactored to make muscle selection easier, include visualisation and generally make it faster. Fixed a few bugs.
1 parent df7620c commit 65dd664

3 files changed

Lines changed: 64 additions & 91 deletions

File tree

matlab_tool/muscleForceDirection_plugin.m

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
bodyOfInterest_name,...
3838
bodyExpressResultsIn_name,...
3939
effective_attachm,...
40+
visualise,...
4041
test_input)
4142

4243
% Load Library
@@ -67,78 +68,83 @@
6768
end
6869
end
6970

71+
% define muscles to include in the analysis
7072
% get muscles
7173
muscleSet = osimModel.getMuscles();
72-
N_muscles = muscleSet.getSize();
74+
n_keep = 1;
75+
for n_m = 0:muscleSet.getSize()-1
76+
77+
% extract muscle
78+
curr_mus = muscleSet.get(n_m);
79+
curr_mus_name = char(muscleSet.get(n_m).getName());
80+
81+
% check if muscle is attached (1) or not (0) to bone of interest
82+
% left in internal loop to handle conditional viapoints, if
83+
% necessary. They might be active only at certain states, therefore
84+
% it is risky to exclude muscles a priori.
85+
% NO! CANNOT CHANGE ORIGIN OR INSERTION
86+
musc_attach = isMuscleConnectedToBody(curr_mus, bodyOfInterest_name);
87+
88+
if musc_attach == 1
89+
target_mus_names{n_keep} = curr_mus_name;
90+
91+
% defining headers as well
92+
rowheaders{n_keep,1} = curr_mus_name;
93+
store_range = 1+3*(n_keep-1):3+3*(n_keep-1);
94+
colheaders_MFD_vec(store_range) = { [curr_mus_name,'_vx_in_',bodyExpressResultsIn_name],...
95+
[curr_mus_name,'_vy_in_',bodyExpressResultsIn_name],...
96+
[curr_mus_name,'_vz_in_',bodyExpressResultsIn_name]};
97+
colheaders_MFD_attach(store_range) = { [curr_mus_name,'_px_in_',bodyExpressResultsIn_name],...
98+
[curr_mus_name,'_py_in_',bodyExpressResultsIn_name],...
99+
[curr_mus_name,'_pz_in_',bodyExpressResultsIn_name]};
100+
n_keep = n_keep +1;
101+
end
102+
end
73103

74-
% TODO: get subset of muscles if needed
104+
N_target_muscles = length(target_mus_names);
75105

76106
% current state. It will change according to kinematics
107+
if strcmp(visualise, 'true')
108+
osimModel.setUseVisualizer(true);
109+
end
77110
curr_state = osimModel.initSystem();
78111

112+
% number of frames
79113
N_frames = size(IKStruct.data,1);
80-
81-
% initialize matrix to use as output. Same output as plugin.
82-
% The idea is to have a matrix with a row for each muscle and three groups
83-
% of columns: attachment on bone, line of action and transport moment.
84-
% This matrix will make easy both checking the equilibrium and setting the
85-
% loads in the FE model
86-
colheaders = {'bone_attach_X', 'bone_attach_Y', 'bone_attach_Z', 'effect_attach_X', 'effect_attach_Y', 'effect_attach_Z', ...
87-
'act_line_X', 'act_line_Y', 'act_line_Z', 'trans_mom_X', 'trans_mom_Y', 'trans_mom_Z'};
88-
89-
90-
% Variables could be preallocated for speed, but I didn't like to have all
91-
% zeros, which might be confused with actual values from the analysis.
92-
% mus_info_mat = zeros(muscleSet.getSize(),12, N_frames);
93-
94114
% this is a testing option to reduce processed kinematics frames when
95115
% developing related functions
96116
if ~isempty(test_input)
97117
N_frames = test_input;
98118
end
99119

100-
120+
% Variables could be preallocated for speed, but I didn't like to have all
121+
% zeros, which might be confused with actual values from the analysis.
122+
% mus_info_mat = zeros(muscleSet.getSize(),12, N_frames);
101123
for n_frame = 1:N_frames
102124

103125
% realize kinematics
104126
state_new = realizeMatStructKinematics(osimModel, curr_state, IKStruct, n_frame);
105-
127+
if strcmp(visualise, 'true')
128+
osimModel.updVisualizer().show(state_new);
129+
end
106130
% counter for muscles to be kept at each frame
107131
n_keep = 1;
108132

109-
for n_m = 0:N_muscles-1
133+
% display time progression
134+
disp('--------------------');
135+
disp(['FRAME: ',num2str(n_frame),'/',num2str(N_frames),'.']);
136+
disp('--------------------');
137+
138+
for n_m = 0:N_target_muscles-1
110139

111140
% extract muscle
112-
curr_mus = muscleSet.get(n_m);
113-
curr_mus_name = muscleSet.get(n_m).getName();
141+
curr_mus_name = target_mus_names{n_m+1};
142+
curr_mus = muscleSet.get(curr_mus_name);
114143

115144
% loop through the points
116-
disp('----------------------')
117-
disp(['FRAME: ',num2str(n_frame),'/',num2str(N_frames),'. Processing muscle (',num2str(n_m+1),'/',num2str(N_muscles),'): ',char(curr_mus_name)])
118145

119-
% check if muscle is attached (1) or not (0) to bone of interest
120-
% left in internal loop to handle conditional viapoints, if
121-
% necessary. They might be active only at certain states, therefore
122-
% it is risky to exclude muscles a priori.
123-
musc_attach = isMuscleConnectedToBody(curr_mus, bodyOfInterest_name);
146+
disp(['Processing muscle (',num2str(n_m+1),'/',num2str(N_target_muscles),'): ', curr_mus_name]);
124147

125-
if musc_attach == 0
126-
% if not attached then nan for the sake of this investigation
127-
continue
128-
else
129-
% if attached
130-
131-
% for final data structure
132-
if n_frame == 1
133-
rowheaders{n_keep,1} = char(curr_mus_name);
134-
store_range = 1+3*(n_keep-1):3+3*(n_keep-1);
135-
colheaders_MFD_vec(store_range) = {[char(curr_mus_name),'_vx_in_',bodyExpressResultsIn_name],...
136-
[char(curr_mus_name),'_vy_in_',bodyExpressResultsIn_name],...
137-
[char(curr_mus_name),'_vz_in_',bodyExpressResultsIn_name]};
138-
colheaders_MFD_attach(store_range) = {[char(curr_mus_name),'_px_in_',bodyExpressResultsIn_name],...
139-
[char(curr_mus_name),'_py_in_',bodyExpressResultsIn_name],...
140-
[char(curr_mus_name),'_pz_in_',bodyExpressResultsIn_name]};
141-
end
142148
% make available info about the muscle pointSet (body names
143149
% and points coordinates)
144150
[mus_bodyset_list, mus_pointset_mat] = getCurrentMusclePathAsMat(curr_mus, state_new);
@@ -167,7 +173,7 @@
167173
if attach_vec(1)==0 && attach_vec(end)==0
168174
% This case is for multi-articular muscles that jump the
169175
% body and can be attached with a viapoint.
170-
display(['Muscle has no bone attachments on ',bodyOfInterest_name]);
176+
display(['Muscle has only viapoints (no bone attachments) on ',bodyOfInterest_name,'. Skipping...']);
171177
continue
172178
end
173179

@@ -230,7 +236,7 @@
230236
% clear variables to avoid surprises
231237
clear attachment force_dir_norm transp_mom_norm lastAttach otherBodyAttach_vec force_dir_res
232238

233-
end
239+
% end
234240
end
235241
end
236242

@@ -257,12 +263,20 @@
257263
% attachments in the local reference system, the file will contain the
258264
% first and last muscle points specified for that muscle in the original model file.
259265
MFD_attachments.colheaders = colheaders_MFD_attach;
260-
if (effective_attachm==1) || strcmp(effective_attachm, 'true')
266+
if strcmp(effective_attachm, 'true')
261267
MFD_attachments.data = mus_info_mat(:, :, 1);
262268
else
263269
MFD_attachments.data = mus_info_mat(:, :, 2);
264270
end
265271

272+
%--------------------------
273+
% Advanced MATLAB summary |
274+
%--------------------------
275+
% The idea is to have a matrix with frames as rows and in column bone
276+
% attachments, effective attachments, lines of action and transport
277+
% moments.
278+
colheaders = {'bone_attach_X', 'bone_attach_Y', 'bone_attach_Z', 'effect_attach_X', 'effect_attach_Y', 'effect_attach_Z', ...
279+
'act_line_X', 'act_line_Y', 'act_line_Z', 'trans_mom_X', 'trans_mom_Y', 'trans_mom_Z'};
266280
% this is an advanced summary for Matlab use
267281
MFDStruct.colheaders = colheaders;
268282
MFDStruct.rowheaders = rowheaders;

opensim_plugin/svn_simtk_exported/Trunk/Plugin Results Verification/Plugin_verification.asv

Lines changed: 0 additions & 41 deletions
This file was deleted.

opensim_plugin/svn_simtk_exported/Trunk/Plugin Results Verification/Wrapping2.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
dist1 = sqrt(norm(v1)^2-R^2);
7171

7272
fun_min1= @(x) R*[cos(x) sin(x)]+lato*dist1*[-sin(x) cos(x)]-v1;
73-
options1=optimset('NonlEqnAlgorithm','gn','TolFun',10e-13,'TolX',10e-11);
73+
options1=optimset('TolFun',10e-13,'TolX',10e-11);
7474

7575
x0 = pi/4;
7676
[sol1,fval,exitflag] = fsolve(fun_min1,x0,options1);
@@ -96,7 +96,7 @@
9696
dist2 = sqrt(norm(v2)^2-R^2);
9797
fun_min2= @(x) R*[cos(x) sin(x)]-lato*dist2*[-sin(x) cos(x)]-v2;
9898
x0 = -pi/4;
99-
options2=optimset('NonlEqnAlgorithm','gn','TolFun',10e-11,'TolX',10e-11);
99+
options2=optimset('TolFun',10e-11,'TolX',10e-11);
100100
[sol2,fval2,exitflag2] = fsolve(fun_min2,x0,options2);
101101
% retry with new initial point
102102
if exitflag2 == -2

0 commit comments

Comments
 (0)