def perform_id(events_file, model_file, ik_file, grf_file, grf_xml_file, results_dir, opensimtools_dir, opensimplugin_dir, settings_dir): """Performs Inverse dynamics using Opensim.""" # model model = opensim.Model(model_file) trial = os.path.basename(grf_file).strip('_GRF.mot') # external_loads = opensim.ExternalLoads(model, grf_xml_file) # external_loads.setExternalLoadsModelKinematicsFileName(ik_file) # external_loads.setDataFileName(grf_file) # external_loads.setLowpassCutoffFrequencyForLoadKinematics(6) # external_loads.printToXML(settings_dir + name + 'ExternalLoads.xml') # create the setuo file model.initSystem() id_tool = opensim.InverseDynamicsTool() id_tool.setName(trial) id_tool.setModel(model) id_tool.setExternalLoadsFileName(grf_xml_file) id_tool.setResultsDir(results_dir) id_tool.setStartTime(events_file.InitialContactTime.iloc[0]) id_tool.setEndTime(events_file.TimeLowestCOMX.iloc[1]) id_tool.setCoordinatesFileName(ik_file) id_tool.setOutputGenForceFileName(trial + '_ID.sto') id_tool.setLowpassCutoffFrequency(6) id_xml = settings_dir + trial + '_Setup_ID.xml' id_tool.printToXML(id_xml) id_tool.run() id_file = results_dir + trial + '_ID.sto' return id_file
def run_id_tool(self, trial): if self.prefix and not trial.stem.startswith(self.prefix): # skip file if user specified a prefix and prefix is not present in current file pass else: print(f'\t{trial.stem}') # initialize inverse dynamic tool from setup file model = osim.Model(self.model_input) id_tool = osim.InverseDynamicsTool(self.xml_input) id_tool.setModel(model) # get starting and ending time motion = osim.Storage(f'{trial.resolve()}') start = motion.getFirstTime() end = motion.getLastTime() # inverse dynamics tool id_tool.setStartTime(start) id_tool.setEndTime(end) id_tool.setCoordinatesFileName(f'{trial.resolve()}') if self.low_pass: id_tool.setLowpassCutoffFrequency(self.low_pass) # set name of input (mot) file and output (sto) filename = f'{trial.stem}' id_tool.setName(filename) id_tool.setOutputGenForceFileName('inverse_dynamic_output.sto') id_tool.setResultsDir(f'{self.sto_output}') # external loads file if self.forces_dir: loads = osim.ExternalLoads(self.xml_forces, True) if self.prefix: loads.setDataFileName( f"{Path(self.forces_dir, trial.stem.replace(f'{self.prefix}_', '')).resolve()}.sto" ) else: loads.setDataFileName( f"{Path(self.forces_dir, trial.stem).resolve()}.sto") loads.setExternalLoadsModelKinematicsFileName( f'{trial.resolve()}') temp_xml = Path(f'{trial.stem}_temp.xml') loads.printToXML(f'{temp_xml.resolve()}') # temporary xml file id_tool.setExternalLoadsFileName(f'{temp_xml}') else: id_tool.setExternalLoadsFileName(self.xml_forces) id_tool.printToXML(self.xml_output) id_tool.run() if self.forces_dir: temp_xml.unlink() # delete temporary xml file
def setup_ID_xml(trial: str, model: str, directory: str, time_range: list, cut_off_freq: np.float64): ''' Rewrites the ID setup xml file for a new trial Inputs: trial: trial name, e.g., "_12Mar_ss_12ms_01" model: model name, e.g., "AB08" directory: output directory name time_range: start and end times cuf_off_frequency: low pass cut-off frequency ''' # Create an instance of the inverse dynamics tool ID_tool = osim.InverseDynamicsTool() # Set tool name ID_tool.setName(model) # Set the opensim model name ID_tool.setModelFileName(directory + "\\" + model + "\\" + model + ".osim") # Set excluded forces excluded_forces = osim.ArrayStr() excluded_forces.setitem(0, 'Muscles') ID_tool.setExcludedForces(excluded_forces) # Set low pass cut-off frequency, NOTE: Must be a double (np.float64) ID_tool.setLowpassCutoffFrequency(np.float64(cut_off_freq)) # Set the input and results directory ID_tool.setResultsDir(directory + "\\" + model + "\\" + trial) ID_tool.setInputsDir(directory + "\\" + model + "\\" + trial) # Set the time range, NOTE: Must be a double (np.float64) ID_tool.setStartTime(np.float64(time_range[0])) ID_tool.setEndTime(np.float64(time_range[-1])) # Set the external loads file external_loads_file = directory + "\\" + model + "\\" + trial + "\\" + trial + 'ExternalLoads.xml' ID_tool.setExternalLoadsFileName(external_loads_file) # Set the coordinates file coordindate_file = directory + "\\" + model + "\\" + trial + "\\" + trial + 'IKResults.mot' ID_tool.setCoordinatesFileName(coordindate_file) # Set the output file output_file_name = trial + "IDResults.sto" ID_tool.setOutputGenForceFileName(output_file_name) ''' Write changes to an XML setup file ''' xml_setup_path = directory + "\\" + model + "\\" + trial + "\\" + trial + "IDSetup.xml" ID_tool.printToXML(xml_setup_path)
def calc_net_generalized_forces(model, motion): model.initSystem() net_joint_moments = None import tempfile with tempfile.TemporaryDirectory() as tmpdirname: id_tool = osim.InverseDynamicsTool() modelID = osim.Model(model) id_tool.setModel(modelID) if type(motion) == osim.Storage: id_tool.setLowpassCutoffFrequency(6) storage = motion else: table = motion.exportToStatesTable() labels = list(table.getColumnLabels()) import re for ilabel in range(len(labels)): labels[ilabel] = labels[ilabel].replace('/value', '') labels[ilabel] = re.sub('/jointset/(.*?)/', '', labels[ilabel]) table.setColumnLabels(labels) storage = osim.convertTableToStorage(table) # TODO: There's a bug in converting column labels in # convertTableToStorage(). stolabels = osim.ArrayStr() stolabels.append('time') for label in labels: stolabels.append(label) storage.setColumnLabels(stolabels) id_tool.setCoordinateValues(storage) # id_tool.setExternalLoadsFileName(extloads_fpath) excludedForces = osim.ArrayStr() excludedForces.append('ACTUATORS') id_tool.setExcludedForces(excludedForces) id_result = 'joint_moment_breakdown_residuals.sto' id_tool.setResultsDir(tmpdirname) id_tool.setOutputGenForceFileName(id_result) # TODO: Remove muscles from the model? id_tool.run() net_joint_moments = osim.TimeSeriesTable( os.path.join(tmpdirname, id_result)) return net_joint_moments
PFF_MOT_file = PFF_MOT_files[0] path, filename = os.path.split(MOT_file) filename, ext = os.path.splitext(filename) STO_file = filename + '.sto' # Path to the output .MOT file that will be created and contain the IK results XML_ID_file = dir_path + 'XML\\' + filename + '_ID.xml' # Path to the ID XML file that will be created XML_External_Load_ID_file = dir_path + 'XML\\' + filename + '_External_Load_ID.xml' # Path to the External Load ID XML file that will be created # Mot Data motData = osim.Storage(MOT_file) initial_time = motData.getFirstTime() final_time = motData.getLastTime() # ID tool idTool = osim.InverseDynamicsTool(XML_generic_ID_path) idTool.setResultsDir(dir_path + '\\STO\\') idTool.setName(filename) idTool.setModel(osimModel) idTool.setCoordinatesFileName(MOT_file) idTool.setStartTime(initial_time) idTool.setEndTime(final_time) idTool.setOutputGenForceFileName(STO_file) # External Load File externalLoads = osim.ExternalLoads(osimModel, XML_generic_External_Load_ID_path) externalLoads.setName(filename) externalLoads.setDataFileName(PFF_MOT_file) # Set the PFF MOT filename externalLoads.setLowpassCutoffFrequencyForLoadKinematics(4)
def plot_passive_joint_moments(model, coord_table, coord_paths, muscle_paths=None): model.initSystem() # for muscle in model.getMuscleList(): # muscle.set_ignore_tendon_compliance(True) # model.initSystem() num_coords = len(coord_paths) if not muscle_paths: muscle_paths = list() for muscle in model.getMuscleList(): muscle_paths.append(muscle.getAbsolutePathString()) num_muscles = len(muscle_paths) labels = list(coord_table.getColumnLabels()) import re for ilabel in range(len(labels)): labels[ilabel] = labels[ilabel].replace('/value', '') labels[ilabel] = re.sub('/jointset/(.*?)/', '', labels[ilabel]) coord_table.setColumnLabels(labels) storage = osim.convertTableToStorage(coord_table) # TODO: There's a bug in converting column labels in # convertTableToStorage(). stolabels = osim.ArrayStr() stolabels.append('time') for label in labels: stolabels.append(label) storage.setColumnLabels(stolabels) net_joint_moments = None import tempfile with tempfile.TemporaryDirectory() as tmpdirname: id_tool = osim.InverseDynamicsTool() modelID = osim.Model(model) id_tool.setModel(modelID) id_tool.setCoordinateValues(storage) id_tool.setLowpassCutoffFrequency(6) # id_tool.setExternalLoadsFileName(extloads_fpath) excludedForces = osim.ArrayStr() excludedForces.append('ACTUATORS') id_tool.setExcludedForces(excludedForces) id_result = 'joint_moment_breakdown_residuals.sto' id_tool.setResultsDir(tmpdirname) id_tool.setOutputGenForceFileName(id_result) # TODO: Remove muscles from the model? id_tool.run() net_joint_moments = osim.TimeSeriesTable( os.path.join(tmpdirname, id_result)) time = coord_table.getIndependentColumn() states_traj = osim.StatesTrajectory.createFromStatesStorage(model, storage, True, True, True) # TODO for models without activation dynamics, we must prescribeControlsToModel(). fig = pl.figure(figsize=(8.5, 11)) tendon_forces = np.empty((len(time), num_muscles)) for imusc, muscle_path in enumerate(muscle_paths): muscle = model.getComponent(muscle_path) for itime in range(len(time)): state = states_traj.get(itime) state.updU().setToZero() muscle.setActivation(state, 0.01) model.realizeVelocity(state) muscle.computeEquilibrium(state) model.realizeDynamics(state) tendon_forces[itime, imusc] = muscle.getTendonForce(state) for icoord, coord_path in enumerate(coord_paths): coord = model.getComponent(coord_path) label = os.path.split(coord_path)[-1] + '_moment' net_moment = toarray(net_joint_moments.getDependentColumn(label)) moment_arms = np.empty((len(time), num_muscles)) for imusc, muscle_path in enumerate(muscle_paths): muscle = model.getComponent(muscle_path) for itime in range(len(time)): state = states_traj.get(itime) moment_arms[itime, imusc] = \ muscle.computeMomentArm(state, coord) ax = fig.add_subplot(num_coords, 1, icoord + 1) # net_integ = np.trapz(np.abs(net_moment), x=time) sum_actuators_shown = np.zeros_like(time) for imusc, muscle_path in enumerate(muscle_paths): if np.any(moment_arms[:, imusc]) > 0.00001: this_moment = tendon_forces[:, imusc] * moment_arms[:, imusc] mom_integ = np.trapz(np.abs(this_moment), time) if mom_integ > 0.5: ax.plot(time, this_moment, label=muscle_path) sum_actuators_shown += this_moment ax.plot(time, sum_actuators_shown, label='sum actuators shown', color='gray', linewidth=2) time_net = np.array(net_joint_moments.getIndependentColumn()) filter = (time_net > time[0]) & (time_net < time[-1]) # ax.plot(time_net[filter], net_moment[filter], # label='net', color='black', linewidth=2) ax.set_title(coord_path) ax.set_ylabel('moment (N-m)') ax.legend(frameon=False, bbox_to_anchor=(1, 1), loc='upper left', ncol=2) ax.tick_params(axis='both') ax.set_xlim([time[0], time[-1]]) ax.set_xlabel('time (% gait cycle)') fig.tight_layout() return fig
# #Set output filename # ikTool[ii-startInd][tt].set_output_motion_file(dynamicFiles[tt].split('.')[0]+'_ik.mot') # #Print and run tool # ikTool[ii-startInd][tt].printToXML(dynamicFiles[tt].split('.')[0]+'_setupIK.xml') # ikTool[ii-startInd][tt].run() # #Rename marker errors file # shutil.move('_ik_marker_errors.sto',dynamicFiles[tt].split('.')[0]+'_ik_marker_errors.sto') # #Print confirmation # print('IK complete for '+dynamicFiles[tt].split('.')[0]) #Initialise ID tool idTool[ii-startInd].append(osim.InverseDynamicsTool()) #Set the model idTool[ii-startInd][tt].setModelFileName(subList[ii]+'_scaledModelAdjusted_sensors.osim') #Set times idTool[ii-startInd][tt].setStartTime(startTime) idTool[ii-startInd][tt].setEndTime(endTime) #Set external loads file idTool[ii-startInd][tt].setExternalLoadsFileName(dynamicFiles[tt].split('.')[0]+'_grf'+'.xml') #Set kinematics idTool[ii-startInd][tt].setCoordinatesFileName(dynamicFiles[tt].split('.')[0]+'_ik.mot') #Set lowpass filter frequency for kinematics (10Hz)
def inverseDynamics(): import os import re import shutil import opensim as osim import directories allDir = list(directories.main(directories)) parentDir = allDir[0] paramsDir = allDir[1] subID = allDir[4] subResultsDir = allDir[5] ikResultsDir = allDir[6] idResultsDir = allDir[7] # Clear Inverse Dynamics Folder if os.path.exists(idResultsDir): shutil.rmtree(idResultsDir, ignore_errors=True) if not os.path.exists(idResultsDir): os.mkdir(idResultsDir) # Input data files genericExtLoads = paramsDir + "/externalLoads.xml" motData = parentDir + "/data/osDemo/subject01_walk1_grf.mot" motFileName = "subject01_walk1_grf.mot" # saveDir = subResultsDir + "/" + subID + "motionFile.mot" ikFileName = "subject01_walk1_ik.mot" ikFile = ikResultsDir + "/" + ikFileName # Copy GRF File over to Current Directory shutil.copy(motData, idResultsDir + "/" + motFileName) # Load Inverse Kinematics Model aModel = osim.Model(subResultsDir + "/" + subID + ".osim") # initialize system aModel.initSystem() # Initialize External Loads File from Generic File extLoads = osim.ExternalLoads(aModel, genericExtLoads) # Initialize idTool idTool = osim.InverseDynamicsTool() idTool.setLowpassCutoffFrequency(6.0) idTool.setInputsDir(idResultsDir) idTool.setResultsDir(idResultsDir) idTool.setModel(aModel) idTool.setModelFileName(subResultsDir + "/" + subID + ".osim") # Get .mot data to determine time range motCoordsData = osim.Storage(ikFile) # Get initial and final time initial_time = motCoordsData.getFirstTime() final_time = motCoordsData.getLastTime() # Creat output ID idFileName = re.sub('ik.mot', 'id.sto', ikFileName) # Customize and save external loads ile extLoads.setName(motFileName) extLoads.setDataFileName(motData) extLoads.setExternalLoadsModelKinematicsFileName(ikFile) extLoads.printToXML(idResultsDir + "/" + re.sub('ik.mot', 'extLoads.xml', ikFileName)) # Setup idTool idTool.setName(motFileName) idTool.setCoordinatesFileName(ikFile) idTool.setStartTime(initial_time) idTool.setEndTime(final_time) # Must be relative to output directory, not full path! idTool.setOutputGenForceFileName(idFileName) idTool.setExternalLoadsFileName( idResultsDir + "/" + re.sub('ik.mot', 'extLoads.xml', ikFileName)) # Can comment out if not needed in GUI idTool.printToXML(idResultsDir + "/" + re.sub('ik.mot', 'setupID.xml', ikFileName)) # Run idTool idTool.run() os.system('cls' if os.name == 'nt' else 'clear') return ()
os.path.join(location_motion_data, save_ik_name)) ik_tool.run() #Build external loads file and save to disk - this will be loaded in for IK and SO external_loads = opensim.ExternalLoads( os.path.join(location_XMLs, external_loads_xml), True) external_loads.setLowpassCutoffFrequencyForLoadKinematics( kinematic_filter_frequency) external_loads.setDataFileName( os.path.join(location_motion_data, pedal_data_filenames)) external_loads.setName('both_pedal_forces') external_loads.printToXML( os.path.join(location_motion_data, save_external_loads_name)) #perform ID id_tool = opensim.InverseDynamicsTool() id_tool.setModel(model) # id_tool.setModelFileName() id_tool.setCoordinatesFileName(os.path.join(location_motion_data, save_ik_name)) id_tool.setLowpassCutoffFrequency(kinematic_filter_frequency) id_tool.setResultsDir(location_motion_data) id_tool.setOutputGenForceFileName(save_id_name) id_tool.setStartTime(id_start_time) id_tool.setEndTime(id_end_time) excludedForces = opensim.ArrayStr() excludedForces.append('Muscles') id_tool.setExcludedForces(excludedForces) id_tool.setExternalLoadsFileName( os.path.join(location_motion_data, save_external_loads_name))