def solveMocoInverse(): #Construct the MocoInverse tool. inverse = osim.MocoInverse() inverse.setName('inverseTorqueTracking') #Construct a ModelProcessor and set it on the tool. The muscles are removed #and reserve actuators added to generate a torque driven solution modelProcessor = osim.ModelProcessor('scaledModelMuscle.osim') modelProcessor.append(osim.ModOpAddExternalLoads('Jog05_grf.xml')) modelProcessor.append(osim.ModOpRemoveMuscles()) modelProcessor.append(osim.ModOpAddReserves(300)) inverse.setModel(modelProcessor) #Construct a TableProcessor of the coordinate data and pass it to the #inverse tool. TableProcessors can be used in the same way as #ModelProcessors by appending TableOperators to modify the base table. #A TableProcessor with no operators, as we have here, simply returns the #base table. inverse.setKinematics(osim.TableProcessor('ikResults_states.sto')) # Initial time, final time, and mesh interval. inverse.set_initial_time(osim.Storage('ikResults_states.sto').getFirstTime()) inverse.set_final_time(osim.Storage('ikResults_states.sto').getLastTime()) inverse.set_mesh_interval(0.02) # By default, Moco gives an error if the kinematics contains extra columns. # Here, we tell Moco to allow (and ignore) those extra columns. inverse.set_kinematics_allow_extra_columns(True) # Solve the problem and write the solution to a Storage file. solution = inverse.solve() #Return the solution as an object that we can use return solution
def create_opensim_storage(time, data, column_names): """Creates a OpenSim::Storage. Parameters ---------- time: SimTK::Vector data: SimTK::Matrix column_names: list of strings Returns ------- sto: OpenSim::Storage """ sto = opensim.Storage() sto.setColumnLabels(list_to_osim_array_str(['time'] + column_names)) for i in range(data.nrow()): row = opensim.ArrayDouble() for j in range(data.ncol()): row.append(data.getElt(i, j)) sto.append(time[i], row) return sto
def read_from_storage(file_name, to_filter=False): """Read OpenSim.Storage files. Parameters ---------- file_name: (string) path to file Returns ------- tuple: (labels, time, data) """ sto = opensim.Storage(file_name) sto.resampleLinear(0.01) if to_filter: sto.lowpassFIR(4, 6) labels = osim_array_to_list(sto.getColumnLabels()) time = opensim.ArrayDouble() sto.getTimeColumn(time) time = np.round(osim_array_to_list(time), 3) data = [] for i in range(sto.getSize()): temp = osim_array_to_list(sto.getStateVector(i).getData()) temp.insert(0, time[i]) data.append(temp) df = pd.DataFrame(data, columns=labels) df.index = df.time return df
def read_from_storage(model_file, file_name): """Read OpenSim.Storage files. Parameters ---------- file_name: (string) path to file Returns ------- tuple: (labels, time, data) """ sto = opensim.Storage(file_name) if sto.isInDegrees(): model = opensim.Model(model_file) model.initSystem() model.getSimbodyEngine().convertDegreesToRadians(sto) # sto.resampleLinear(sampling_interval) labels = osim_array_to_list(sto.getColumnLabels()) time = opensim.ArrayDouble() sto.getTimeColumn(time) time = osim_array_to_list(time) data = [] for i in range(sto.getSize()): temp = osim_array_to_list(sto.getStateVector(i).getData()) temp.insert(0, time[i]) data.append(temp) df = pd.DataFrame(data, columns=labels) df.index = df.time return df
def read_from_storage(file_name, sampling_interval=0.01, to_filter=False): """Read OpenSim.Storage files. Parameters ---------- file_name: (string) path to file sampling_interval: resample the data with a given interval (0.01) to_filter: use low pass 4th order FIR filter with 6Hz cut off frequency Returns ------- df: pandas data frame """ sto = opensim.Storage(file_name) sto.resampleLinear(sampling_interval) if to_filter: sto.lowpassFIR(4, 6) labels = osim_array_to_list(sto.getColumnLabels()) time = opensim.ArrayDouble() sto.getTimeColumn(time) time = osim_array_to_list(time) data = [] for i in range(sto.getSize()): temp = osim_array_to_list(sto.getStateVector(i).getData()) temp.insert(0, time[i]) data.append(temp) df = pd.DataFrame(data, columns=labels) df.index = df.time return df
def test_StorageToPieceWiseLinearFunction(): sto = osim.Storage(os.path.join(this_file_dir, 'storage.sto')) column_name = 'column1' scale_factor = 2.5 time = osim.ArrayDouble() sto.getTimeColumn(time) state_index = sto.getStateIndex(column_name) if type(scale_factor) == float: sto.multiplyColumn(state_index, scale_factor) elif scale_factor == None: pass else: raise Exception('scale_factor, if specified, must be a float.') ordinate = osim.ArrayDouble() sto.getDataColumn(state_index, ordinate) fcn = osim.PiecewiseLinearFunction() for idx in range(time.getSize()): fcn.addPoint(time.get(idx), ordinate.get(idx)) fcnName = os.path.join(this_file_dir, 'piecewiseLinearFunction.xml') fcn.printToXML(fcnName) assert (open(fcnName).readlines() == open(fcnName.replace('.xml', '_desired.xml')).readlines()) os.remove(fcnName)
def solveMocoInverseMuscle(): #Construct the MocoInverse tool. inverse = osim.MocoInverse() inverse.setName('inverseMuscleTracking') #Construct a ModelProcessor and set it on the tool. #Currently the coordinate actuators for the pelvis, along with the reserve #actuators are fairly generally set, and not weighted at all in cost function. #These actuators could be more carefully considered to generate an appropriate #muscle driven simulation. For example, if they max and min control to 1 - the #pelvis actuators may not produce enough torque. modelProcessor = osim.ModelProcessor('scaledModelMuscle.osim') modelProcessor.append(osim.ModOpAddExternalLoads('Jog05_grf.xml')) modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) # Only valid for DeGrooteFregly2016Muscles. # modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) # Only valid for DeGrooteFregly2016Muscles. modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5)) modelProcessor.append(osim.ModOpAddReserves(2)) inverse.setModel(modelProcessor) #Construct a TableProcessor of the coordinate data and pass it to the #inverse tool. TableProcessors can be used in the same way as #ModelProcessors by appending TableOperators to modify the base table. #A TableProcessor with no operators, as we have here, simply returns the #base table. inverse.setKinematics(osim.TableProcessor('ikResults_states.sto')) #Initial time, final time, and mesh interval. inverse.set_initial_time(osim.Storage('ikResults_states.sto').getFirstTime()) inverse.set_final_time(osim.Storage('ikResults_states.sto').getLastTime()) inverse.set_mesh_interval(0.02) # By default, Moco gives an error if the kinematics contains extra columns. # Here, we tell Moco to allow (and ignore) those extra columns. inverse.set_kinematics_allow_extra_columns(True) # Solve the problem and write the solution to a Storage file. solution = inverse.solve() #Return the solution as an object that we can use return solution
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 test_states_storage_optional_arguments(self): # Try all combinations of optional arguments, just to ensure the # wrapping works. model = osim.Model( os.path.join(test_dir, "gait10dof18musc_subject01.osim")) sto = osim.Storage(self.states_sto_fname) states = osim.StatesTrajectory.createFromStatesStorage(model, sto) states = osim.StatesTrajectory.createFromStatesStorage( model, sto, False, False) states = osim.StatesTrajectory.createFromStatesStorage( model, sto, False, True) states = osim.StatesTrajectory.createFromStatesStorage( model, sto, True, False) states = osim.StatesTrajectory.createFromStatesStorage( model, sto, True, True)
def read_from_storage(file_name): """Read OpenSim.Storage files. """ sto = opensim.Storage(file_name) labels = osim_array_to_list(sto.getColumnLabels()) time = opensim.ArrayDouble() sto.getTimeColumn(time) time = osim_array_to_list(time) data = [] for i in range(sto.getSize()): temp = osim_array_to_list(sto.getStateVector(i).getData()) temp.insert(0, time[i]) data.append(temp) df = pd.DataFrame(data, columns=labels) df.index = df.time return df
def stoToDF(fileName, sampleInterval=None, filterFreq=None): """ Parameters ---------- fileName: filename of opensim .mot or .sto file Returns ------- df: pandas data frame """ #Load file osimSto = osim.Storage(fileName) #Resample if sampleInterval != None: osimSto.resampleLinear(sampleInterval) #Filter if filterFreq != None: osimSto.lowpassFIR(4, int(filterFreq)) #Get column labels labels = osimToList(osimSto.getColumnLabels()) #Set time values time = osim.ArrayDouble() osimSto.getTimeColumn(time) time = osimToList(time) #Allocate space for data data = [] #Loop through columns and get data for i in range(osimSto.getSize()): temp = osimToList(osimSto.getStateVector(i).getData()) temp.insert(0, time[i]) data.append(temp) #Convert to dataframe df = pd.DataFrame(data, columns=labels) return df
def finalize_model(self, mot, filter_param=None): self.state = self.model.initSystem() # get some reference that will be modified during the optimization (for speed sake) self.n_dof = self.state.getQ().size() self.actuators = self.model.getForceSet() self.n_actuators = self.actuators.getSize() self.muscle_actuators = self.model.getMuscles() self.n_muscles = self.muscle_actuators.getSize() self._data_storage = osim.Storage(mot) self.filter_param = filter_param self.__dispatch_kinematics() force_set = self.model.getForceSet() for i in range(force_set.getSize()): coord = osim.CoordinateActuator.safeDownCast(force_set.get(i)) if coord: coord.overrideActuation(self.state, True)
def test_StorageToPieceWiseLinearFunction(self): sto = osim.Storage(os.path.join(test_dir, 'storage.sto')) column_name = 'column1' scale_factor = 2.5 time = osim.ArrayDouble() sto.getTimeColumn(time) state_index = sto.getStateIndex(column_name) if type(scale_factor) == float: sto.multiplyColumn(state_index, scale_factor) elif scale_factor == None: pass else: raise Exception('scale_factor, if specified, must be a float.') ordinate = osim.ArrayDouble() sto.getDataColumn(state_index, ordinate) fcn = osim.PiecewiseLinearFunction() for idx in range(time.getSize()): fcn.addPoint(time.get(idx), ordinate.get(idx)) fcnName = os.path.join(test_dir, 'piecewiseLinearFunction.xml') fcn.printToXML(fcnName) assert fcn.getX(0) == 0 assert_almost_equal(fcn.getX(1), 0.01) assert_almost_equal(fcn.getX(2), 0.02) assert_almost_equal(fcn.getX(3), 0.03) assert_almost_equal(fcn.getX(4), 0.04) assert_almost_equal(fcn.getY(0), 3.75) assert_almost_equal(fcn.getY(1), 23.025) assert_almost_equal(fcn.getY(2), 13.5575) os.remove(fcnName)
def get_open_sim_model(prob): if prob in runningOpenSimModels: return runningOpenSimModels[prob][0], runningOpenSimModels[prob][ 1], runningOpenSimModels[prob][2], runningOpenSimModels[prob][ 3], runningOpenSimModels[prob][4] else: runningOpenSimModels[prob] = [ osim.Model(subject_model), get_open_sim_model.idx ] runningOpenSimModels[prob].append( runningOpenSimModels[prob][0].initSystem()) data_storage = osim.Storage( f'{PROJECT_PATH}/{subject}/1_inverse_kinematic/{mot_file}') model = runningOpenSimModels[prob][0] model.getSimbodyEngine().convertDegreesToRadians(data_storage) data_storage.lowpassFIR(2, 6) gen_coord_function = osim.GCVSplineSet(5, data_storage) runningOpenSimModels[prob].append(list()) for frame in range(data_storage.getSize()): q = list() for idx_q in range(data_storage.getStateVector(frame).getSize()): q.append( gen_coord_function.evaluate( idx_q, 0, data_storage.getStateVector(frame).getTime())) runningOpenSimModels[prob][3].append(osim.Vector(q)) runningOpenSimModels[prob].append( np.linspace(data_storage.getFirstTime(), data_storage.getLastTime(), num=data_storage.getSize())) get_open_sim_model.idx += 1 return runningOpenSimModels[prob][0], runningOpenSimModels[prob][ 1], runningOpenSimModels[prob][2], runningOpenSimModels[prob][ 3], runningOpenSimModels[prob][4]
def perform_jra(model_file, ik_file, grf_file, grf_xml, reserve_actuators, muscle_forces_file, results_dir, prefix=''): """Performs Static Optimization using OpenSim. Parameters ---------- model_file: str OpenSim model (.osim) ik_file: str kinematics calculated from Inverse Kinematics grf_file: str the ground reaction forces grf_xml: str xml description containing how to apply the GRF forces reserve_actuators: str path to the reserve actuator .xml file muscle_forces_file: str path to the file containing the muscle forces from SO results_dir: str directory to store the results prefix: str prefix of the resultant joint reaction loads """ # model model = opensim.Model(model_file) # prepare external forces xml file name = os.path.basename(grf_file)[:-8] external_loads = opensim.ExternalLoads(model, grf_xml) external_loads.setExternalLoadsModelKinematicsFileName(ik_file) external_loads.setDataFileName(grf_file) external_loads.setLowpassCutoffFrequencyForLoadKinematics(6) external_loads.printToXML(results_dir + name + '.xml') # TODO this may not be needed # add reserve actuators (must not be appended when performing JRA) # force_set = opensim.ForceSet(model, reserve_actuators) # force_set.setMemoryOwner(False) # model will be the owner # for i in range(0, force_set.getSize()): # model.updForceSet().append(force_set.get(i)) # # model.addForce(force_set.get(i)) # construct joint reaction analysis motion = opensim.Storage(ik_file) joint_reaction = opensim.JointReaction(model) joint_reaction.setName('JointReaction') joint_reaction.setStartTime(motion.getFirstTime()) joint_reaction.setEndTime(motion.getLastTime()) joint_reaction.setForcesFileName(muscle_forces_file) model.addAnalysis(joint_reaction) model.initSystem() # analysis analysis = opensim.AnalyzeTool(model) analysis.setName(prefix + name) analysis.setModel(model) analysis.setModelFilename(model_file) analysis.setInitialTime(motion.getFirstTime()) analysis.setFinalTime(motion.getLastTime()) analysis.setLowpassCutoffFrequency(6) analysis.setCoordinatesFileName(ik_file) analysis.setExternalLoadsFileName(results_dir + name + '.xml') analysis.setLoadModelAndInput(True) analysis.setResultsDir(results_dir) analysis.run() jra_file = results_dir + name + '_JointReaction_ReactionLoads.sto' return jra_file
def perform_so(model_file, ik_file, grf_file, grf_xml, reserve_actuators, results_dir): """Performs Static Optimization using OpenSim. Parameters ---------- model_file: str OpenSim model (.osim) ik_file: str kinematics calculated from Inverse Kinematics grf_file: str the ground reaction forces grf_xml: str xml description containing how to apply the GRF forces reserve_actuators: str path to the reserve actuator .xml file results_dir: str directory to store the results """ # model model = opensim.Model(model_file) # prepare external forces xml file name = os.path.basename(grf_file)[:-8] external_loads = opensim.ExternalLoads(model, grf_xml) external_loads.setExternalLoadsModelKinematicsFileName(ik_file) external_loads.setDataFileName(grf_file) external_loads.setLowpassCutoffFrequencyForLoadKinematics(6) external_loads.printToXML(results_dir + name + '.xml') # add reserve actuators force_set = opensim.ForceSet(model, reserve_actuators) force_set.setMemoryOwner(False) # model will be the owner for i in range(0, force_set.getSize()): model.updForceSet().append(force_set.get(i)) # construct static optimization motion = opensim.Storage(ik_file) static_optimization = opensim.StaticOptimization() static_optimization.setStartTime(motion.getFirstTime()) static_optimization.setEndTime(motion.getLastTime()) static_optimization.setUseModelForceSet(True) static_optimization.setUseMusclePhysiology(True) static_optimization.setActivationExponent(2) static_optimization.setConvergenceCriterion(0.0001) static_optimization.setMaxIterations(100) model.addAnalysis(static_optimization) # analysis analysis = opensim.AnalyzeTool(model) analysis.setName(name) analysis.setModel(model) analysis.setInitialTime(motion.getFirstTime()) analysis.setFinalTime(motion.getLastTime()) analysis.setLowpassCutoffFrequency(6) analysis.setCoordinatesFileName(ik_file) analysis.setExternalLoadsFileName(results_dir + name + '.xml') analysis.setLoadModelAndInput(True) analysis.setResultsDir(results_dir) analysis.run() so_force_file = results_dir + name + '_StaticOptimization_force.sto' so_activations_file = results_dir + name + \ '_StaticOptimization_activation.sto' return (so_force_file, so_activations_file)
def calculate_muscle_data(model_file, ik_file): """This function calculates the moment arm and maximum muscle force provided an OpenSim model and a motion from inverse kinematics. Parameters ---------- model_file: string OpenSim .osim file ik_file: string .mot from inverse kinematics Returns ------- tuple: (moment arm[time x coordinates x muscles], max_force[time x muscles]) """ model = opensim.Model(model_file) state = model.initSystem() # model coordinates dictionary model_coordinates = {} for i in range(0, model.getNumCoordinates()): model_coordinates[model.getCoordinateSet().get(i).getName()] = i # model muscles dictionary model_muscles = {} for i in range(0, model.getNumControls()): model_muscles[model.getMuscles().get(i).getName()] = i # process the motion motion = opensim.Storage(ik_file) labels = motion.getColumnLabels() isInDeg = motion.isInDegrees() # calculate moment arm and max force max_force = np.empty([motion.getSize(), len(model_muscles)], float) moment_arm = np.empty( [motion.getSize(), len(model_coordinates), len(model_muscles)], float) for t in tqdm(range(0, motion.getSize())): state_vector = motion.getStateVector(t) state_data = state_vector.getData() # update model pose for j in range(0, state_data.getSize()): coordinate = model_coordinates[labels.get(j + 1)] # time is 0 if isInDeg: value = np.deg2rad(state_data.get(j)) else: value = state_data.get(j) model.updCoordinateSet().get(coordinate).setValue(state, value) model.realizePosition(state) # calculate muscle moment arm for coordinate_index in model_coordinates.values(): for muscle_index in model_muscles.values(): coordinate = model.getCoordinateSet().get(coordinate_index) muscle = model.getMuscles().get(muscle_index) ma = muscle.computeMomentArm(state, coordinate) moment_arm[t, coordinate_index, muscle_index] = ma # calculate max force (TODO use force-length/velocity relations) for muscle_index in model_muscles.values(): muscle = model.getMuscles().get(muscle_index) max_force[t, muscle_index] = muscle.getMaxIsometricForce() return (moment_arm, max_force)
def torqueDrivenStateTracking(): #Create and name an instance of the MocoTrack tool. track = osim.MocoTrack() track.setName('torqueDrivenStateTracking') #Construct a ModelProcessor and set it on the tool. Remove the muscles and #add reserve actuators modelProcessor = osim.ModelProcessor('scaledModelMuscle.osim') modelProcessor.append(osim.ModOpAddExternalLoads('Jog05_grf.xml')) modelProcessor.append(osim.ModOpRemoveMuscles()) modelProcessor.append(osim.ModOpAddReserves(300)) track.setModel(modelProcessor) #Construct a TableProcessor of the coordinate data and pass it to the #tracking tool. TableProcessors can be used in the same way as #ModelProcessors by appending TableOperators to modify the base table. #A TableProcessor with no operators, as we have here, simply returns the #base table. track.setStatesReference(osim.TableProcessor('ikResults_states.sto')) track.set_states_global_tracking_weight(5) ##### TODO: add more specific weights for different state coordinates like in RRA #This setting allows extra data columns contained in the states #reference that don't correspond to model coordinates. track.set_allow_unused_references(True) # Since there is only coordinate position data the states references, this # setting is enabled to fill in the missing coordinate speed data using # the derivative of splined position data. track.set_track_reference_position_derivatives(True) # Initial time, final time, and mesh interval. track.set_initial_time(osim.Storage('ikResults_states.sto').getFirstTime()) track.set_final_time(osim.Storage('ikResults_states.sto').getLastTime()) track.set_mesh_interval(0.08) #Instead of calling solve(), call initialize() to receive a pre-configured #MocoStudy object based on the settings above. Use this to customize the #problem beyond the MocoTrack interface. study = track.initialize() #Get a reference to the MocoControlCost that is added to every MocoTrack #problem by default. problem = study.updProblem() effort = osim.MocoControlGoal.safeDownCast(problem.updGoal('control_effort')) effort.setWeight(1) # # Put a large weight on the pelvis CoordinateActuators, which act as the # # residual, or 'hand-of-god', forces which we would like to keep as small # # as possible. # model = modelProcessor.process() # model.initSystem() # forceSet = model.getForceSet() # for ii in range(forceSet.getSize()): # forcePath = forceSet.get(ii).getAbsolutePathString() # if 'pelvis' in str(forcePath): # effort.setWeightForControl(forcePath, 10) #Get solver and set the mesh interval solver = study.initCasADiSolver() #50 mesh intervals for half gait cycle recommended, keep smaller for now #19 will produce the same as inverse solution above # solver.set_num_mesh_intervals(19) #Set solver parameters solver.set_optim_constraint_tolerance(1e-3) solver.set_optim_convergence_tolerance(1e-3) #Set guess from inverse solution using the convenience function to transfer #an inverse solution to a solver guess osimHelper.inverseSolutionToTrackGuess(guessFile = 'inverseTorqueSolution_fromIK.sto', mocoSolver = solver) # Solve and visualize. solution = study.solve() #Return the solution as an object that we can use return solution
def run_analyze_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}") # model model = osim.Model(self.model_input) if isinstance(self.model_input, str) is True else self.model_input model.initSystem() # get starting and ending time motion = osim.Storage(f"{trial.resolve()}") first_time = motion.getFirstTime() last_time = motion.getLastTime() # prepare external forces xml file if self.xml_forces: external_loads = osim.ExternalLoads(self.xml_forces, True) if self.prefix: external_loads.setDataFileName( f"{Path(self.ext_forces_dir, trial.stem.replace(f'{self.prefix}_', '')).resolve()}.sto" ) else: external_loads.setDataFileName( f"{Path(self.ext_forces_dir, trial.stem).resolve()}.sto" ) external_loads.setExternalLoadsModelKinematicsFileName( f"{trial.resolve()}" ) if self.low_pass: external_loads.setLowpassCutoffFrequencyForLoadKinematics( self.low_pass ) temp_xml = Path(f"{trial.stem}_temp.xml") external_loads.printToXML(f"{temp_xml.resolve()}") # temporary xml file current_class = self.get_class_name() params = self.parse_analyze_set_xml(self.xml_input, node=current_class) solve_for_equilibrium = False if current_class == "StaticOptimization": analysis = osim.StaticOptimization(model) analysis.setUseModelForceSet(params["use_model_force_set"]) analysis.setActivationExponent(params["activation_exponent"]) analysis.setUseMusclePhysiology(params["use_muscle_physiology"]) analysis.setConvergenceCriterion( params["optimizer_convergence_criterion"] ) analysis.setMaxIterations(int(params["optimizer_max_iterations"])) elif current_class == "MuscleAnalysis": solve_for_equilibrium = True analysis = osim.MuscleAnalysis(model) coord = osim.ArrayStr() for c in params["moment_arm_coordinate_list"]: coord.append(c) analysis.setCoordinates(coord) mus = osim.ArrayStr() for m in params["muscle_list"]: mus.append(m) analysis.setMuscles(mus) # analysis.setComputeMoments(params["compute_moments"]) elif current_class == "JointReaction": # construct joint reaction analysis analysis = osim.JointReaction(model) if params["forces_file"] or self.forces_file: force_file = self.forces_file if self.forces_file else params["forces_file"] analysis.setForcesFileName(force_file) joint = osim.ArrayStr() for j in params["joint_names"]: joint.append(j) analysis.setJointNames(joint) body = osim.ArrayStr() for b in params["apply_on_bodies"]: body.append(b) analysis.setOnBody(body) frame = osim.ArrayStr() for f in params["express_in_frame"]: frame.append(f) analysis.setInFrame(frame) else: raise ValueError("AnalyzeTool must be called from a child class") analysis.setModel(model) analysis.setName(current_class) analysis.setOn(params["on"]) analysis.setStepInterval(int(params["step_interval"])) analysis.setInDegrees(params["in_degrees"]) analysis.setStartTime(first_time) analysis.setEndTime(last_time) model.addAnalysis(analysis) if self.print_to_xml is True: analysis.printToXML(f"{self.xml_output}/{current_class}_analysis.xml") # analysis tool analyze_tool = osim.AnalyzeTool(model) analyze_tool.setName(trial.stem) analyze_tool.setModel(model) analyze_tool.setModelFilename(Path(model.toString()).stem) analyze_tool.setSolveForEquilibrium(solve_for_equilibrium) if self.xml_actuators: force_set = osim.ArrayStr() force_set.append(self.xml_actuators) analyze_tool.setForceSetFiles(force_set) analyze_tool.updateModelForces(model, self.xml_actuators) analyze_tool.setInitialTime(first_time) analyze_tool.setFinalTime(last_time) if self.low_pass: analyze_tool.setLowpassCutoffFrequency(self.low_pass) analyze_tool.setCoordinatesFileName(f"{trial.resolve()}") if self.xml_forces: analyze_tool.setExternalLoadsFileName(f"{temp_xml}") analyze_tool.setLoadModelAndInput(True) analyze_tool.setResultsDir(f"{self.sto_output}") analyze_tool.run() if self.xml_forces: temp_xml.unlink() # delete temporary xml file if self.remove_empty_files: self._remove_empty_files(directory=self.sto_output) if self.contains: self._subset_output(directory=self.sto_output, contains=self.contains)
c3d = osim.C3DFileAdapter() trc = osim.TRCFileAdapter() #Get markers static = c3d.read(staticFile[0]) markersStatic = c3d.getMarkersTable(static) #Write static data to file trc.write(markersStatic, staticFile[0].split('.')[0]+'.trc') #Set variable for static trial trc staticTrial_trc = staticFile[0].split('.')[0]+'.trc' #Set scale time range scaleTimeRange = osim.ArrayDouble() scaleTimeRange.set(0,osim.Storage(staticTrial_trc).getFirstTime()) scaleTimeRange.set(1,osim.Storage(staticTrial_trc).getFirstTime()+0.5) #Set-up scale tool scaleTool.append(osim.ScaleTool()) #Set mass in scale tool scaleTool[ii-startInd].setSubjectMass(mass) #Set generic model file scaleTool[ii-startInd].getGenericModelMaker().setModelFileName(genModelFileName) #Set the measurement set scaleTool[ii-startInd].getModelScaler().setMeasurementSet(measurementSet) #Set scale tasks
def _populate_references(self): # Initialize objects needed to populate the references. coord_functions = opensim.FunctionSet() marker_weights = opensim.SetMarkerWeights() # Load coordinate data, if available. if self.coordinate_file and (self.coordinate_file != "" and self.coordinate_file != "Unassigned"): coordinate_values = opensim.Storage(self.coordinate_file) # Convert to radians, if in degrees. if not coordinate_values.isInDegrees(): self.model.getSimbodyEngine().convertDegreesToRadians( coordinate_values) coord_functions = opensim.GCVSplineSet(5, coordinate_values) index = 0 for i in range(0, self.ik_task_set.getSize()): if not self.ik_task_set.get(i).getApply(): continue if opensim.IKCoordinateTask.safeDownCast(self.ik_task_set.get(i)): # NOTE: Opposed to C++, a variable cannot be declared in the above if statement, so do it now. coord_task = opensim.IKCoordinateTask.safeDownCast( self.ik_task_set.get(i)) coord_ref = opensim.CoordinateReference() if coord_task.getValueType( ) == opensim.IKCoordinateTask.FromFile: if not coord_functions: raise Exception( "InverseKinematicsTool: value for coordinate " + coord_task.getName() + " not found.") index = coord_functions.getIndex(coord_task.getName(), index) if index >= 0: coord_ref = opensim.CoordinateReference( coord_task.getName(), coord_functions.get(index)) elif coord_task.getValueType( ) == opensim.IKCoordinateTask.ManualValue: reference = opensim.Constant( opensim.Constant(coord_task.getValue())) coord_ref = opensim.CoordinateReference( coord_task.getName(), reference) else: # Assume it should be held at its default value value = self.model.getCoordinateSet().get( coord_task.getName()).getDefaultValue() reference = opensim.Constant(value) coord_ref = opensim.CoordinateReference( coord_task.getName(), reference) if not coord_ref: raise Exception( "InverseKinematicsTool: value for coordinate " + coord_task.getName() + " not found.") else: coord_ref.setWeight(coord_task.getWeight()) self.coordinate_references.push_back(coord_ref) elif opensim.IKMarkerTask.safeDownCast(self.ik_task_set.get(i)): # NOTE: Opposed to C++, a variable cannot be declared in the above if statement, so do it now. marker_task = opensim.IKMarkerTask.safeDownCast( self.ik_task_set.get(i)) if marker_task.getApply(): # Only track markers that have a task and it is "applied" marker_weights.cloneAndAppend( opensim.MarkerWeight(marker_task.getName(), marker_task.getWeight())) self.markers_reference.initializeFromMarkersFile( self.marker_file, marker_weights)
# Musculoskeletal model osimModel = osim.Model(scaled_MM_Moved_path) state = osimModel.initSystem() MOT_file = MOT_files[0] 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,
aTool.setResultsDir(resultDir) ##Set the condition of SO aSet = aTool.getAnalysisSet() so = osim.StaticOptimization() so.setName('StaticOptimization') aSet.insert(0, so) for sub in subjectList: for mot in motList: for exf in exforceList: motionFilename = sub + ".mot" exforceFilename = sub + "_" + str(mot) + "_" + str(exf) + ".xml" outputFilename = sub + "_" + str(mot) + "_" + str(exf) motData = osim.Storage(motionFilename) ##Get the time of Start and End initial_time = motData.getFirstTime() final_time = motData.getLastTime() aTool.setName(outputFilename) ##Calculation start time aTool.setInitialTime(initial_time) ##Calculation finish time aTool.setFinalTime(final_time) ##Output precision aTool.setOutputPrecision(8) aTool.setLowpassCutoffFrequency(6.0) aTool.setSolveForEquilibrium(False) ##Set the model
# base table. track.setStatesReference(osim.TableProcessor("coordinates.sto")) track.set_states_global_tracking_weight(5) # This setting allows extra data columns contained in the states # reference that don't correspond to model coordinates. track.set_allow_unused_references(True) # Since there is only coordinate position data the states references, this # setting is enabled to fill in the missing coordinate speed data using # the derivative of splined position data. track.set_track_reference_position_derivatives(True) # Initial time, final time, and mesh interval. # The IK data doesn't match the GRF data, so specific times need ti be taken from this track.set_initial_time(osim.Storage('coordinates.sto').getFirstTime()) track.set_final_time(osim.Storage('coordinates.sto').getLastTime()) # track.set_mesh_interval(0.05) # Instead of calling solve(), call initialize() to receive a pre-configured # MocoStudy object based on the settings above. Use this to customize the # problem beyond the MocoTrack interface. study = track.initialize() # Get a reference to the MocoControlCost that is added to every MocoTrack # problem by default. problem = study.updProblem() effort = osim.MocoControlGoal.safeDownCast(problem.updGoal("control_effort")) # Put a large weight on the pelvis CoordinateActuators, which act as the # residual, or 'hand-of-god', forces which we would like to keep as small
def run_analyze_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}') # model model = osim.Model(self.model_input) model.initSystem() # get starting and ending time motion = osim.Storage(f'{trial.resolve()}') first_time = motion.getFirstTime() last_time = motion.getLastTime() # prepare external forces xml file if self.xml_forces: external_loads = osim.ExternalLoads(model, self.xml_forces) if self.prefix: external_loads.setDataFileName( f"{Path(self.ext_forces_dir, trial.stem.replace(f'{self.prefix}_', '')).resolve()}.sto" ) else: external_loads.setDataFileName( f"{Path(self.ext_forces_dir, trial.stem).resolve()}.sto" ) external_loads.setExternalLoadsModelKinematicsFileName(f'{trial.resolve()}') if self.low_pass: external_loads.setLowpassCutoffFrequencyForLoadKinematics(self.low_pass) temp_xml = Path(f'{trial.stem}_temp.xml') external_loads.printToXML(f'{temp_xml.resolve()}') # temporary xml file current_class = self.get_class_name() params = self.parse_analyze_set_xml(self.xml_input, node=current_class) if current_class == 'StaticOptimization': analysis = osim.StaticOptimization(model) analysis.setUseModelForceSet(params['use_model_force_set']) analysis.setActivationExponent(params['activation_exponent']) analysis.setUseMusclePhysiology(params['use_muscle_physiology']) analysis.setConvergenceCriterion(params['optimizer_convergence_criterion']) analysis.setMaxIterations(int(params['optimizer_max_iterations'])) elif current_class == 'MuscleAnalysis': analysis = osim.MuscleAnalysis(model) analysis.setComputeMoments(params['compute_moments']) elif current_class == 'JointReaction': # construct joint reaction analysis analysis = osim.JointReaction(model) # analysis.setForcesFileName( # f"{Path(self.muscle_forces_dir, trial.stem).resolve()}_StaticOptimization_force.sto" # ) joint = osim.ArrayStr() joint.append(params['joint_names'].replace(' ', '')) analysis.setJointNames(joint) body = osim.ArrayStr() body.append(params['apply_on_bodies'].replace(' ', '')) analysis.setOnBody(body) frame = osim.ArrayStr() frame.append(params['express_in_frame'].replace(' ', '')) analysis.setInFrame(frame) else: raise ValueError('AnalyzeTool must be called from a child class') analysis.setModel(model) analysis.setName(current_class) analysis.setOn(params['on']) analysis.setStepInterval(int(params['step_interval'])) analysis.setInDegrees(params['in_degrees']) analysis.setStartTime(first_time) analysis.setEndTime(last_time) model.addAnalysis(analysis) # analysis tool analyze_tool = osim.AnalyzeTool(model) analyze_tool.setName(trial.stem) analyze_tool.setModel(model) analyze_tool.setModelFilename(Path(self.model_input).stem) if self.xml_actuators: force_set = osim.ArrayStr() force_set.append(self.xml_actuators) analyze_tool.setForceSetFiles(force_set) analyze_tool.updateModelForces(model, self.xml_actuators) analyze_tool.setInitialTime(first_time) analyze_tool.setFinalTime(last_time) if self.low_pass: analyze_tool.setLowpassCutoffFrequency(self.low_pass) analyze_tool.setCoordinatesFileName(f'{trial.resolve()}') analyze_tool.setExternalLoadsFileName(f'{temp_xml}') analyze_tool.setLoadModelAndInput(True) analyze_tool.setResultsDir(f'{self.sto_output}') analyze_tool.run() if self.xml_forces: temp_xml.unlink() # delete temporary xml file if self.remove_empty_files: self._remove_empty_files(directory=self.sto_output)
def muscleDrivenStateTracking(): #Create and name an instance of the MocoTrack tool. track = osim.MocoTrack() track.setName('muscleDrivenStateTracking') #Construct a ModelProcessor and set it on the tool. #Currently the coordinate actuators for the pelvis, along with the reserve #actuators are fairly generally set, and not weighted at all in cost function. #These actuators could be more carefully considered to generate an appropriate #muscle driven simulation. For example, if they max and min control to 1 - the #pelvis actuators may not produce enough torque. modelProcessor = osim.ModelProcessor('scaledModelMuscle.osim') modelProcessor.append(osim.ModOpAddExternalLoads('Jog05_grf.xml')) modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) # Only valid for DeGrooteFregly2016Muscles. modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) # Only valid for DeGrooteFregly2016Muscles. modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5)) modelProcessor.append(osim.ModOpAddReserves(2)) track.setModel(modelProcessor) #Construct a TableProcessor of the coordinate data and pass it to the #tracking tool. TableProcessors can be used in the same way as #ModelProcessors by appending TableOperators to modify the base table. #A TableProcessor with no operators, as we have here, simply returns the #base table. track.setStatesReference(osim.TableProcessor('ikResults_states.sto')) track.set_states_global_tracking_weight(5) ##### TODO: add more specific weights for different state coordinates like in RRA #This setting allows extra data columns contained in the states #reference that don't correspond to model coordinates. track.set_allow_unused_references(True) # Since there is only coordinate position data the states references, this # setting is enabled to fill in the missing coordinate speed data using # the derivative of splined position data. track.set_track_reference_position_derivatives(True) # Initial time, final time, and mesh interval. track.set_initial_time(osim.Storage('ikResults_states.sto').getFirstTime()) track.set_final_time(osim.Storage('ikResults_states.sto').getLastTime()) track.set_mesh_interval(0.08) #Instead of calling solve(), call initialize() to receive a pre-configured #MocoStudy object based on the settings above. Use this to customize the #problem beyond the MocoTrack interface. study = track.initialize() #Get a reference to the MocoControlCost that is added to every MocoTrack #problem by default. problem = study.updProblem() effort = osim.MocoControlGoal.safeDownCast(problem.updGoal('control_effort')) effort.setWeight(1) # # Put a large weight on the pelvis CoordinateActuators, which act as the # # residual, or 'hand-of-god', forces which we would like to keep as small # # as possible. # model = modelProcessor.process() # model.initSystem() # forceSet = model.getForceSet() # for ii in range(forceSet.getSize()): # forcePath = forceSet.get(ii).getAbsolutePathString() # if 'pelvis' in str(forcePath): # effort.setWeightForControl(forcePath, 10) #Get solver and set the mesh interval solver = study.initCasADiSolver() #50 mesh intervals for half gait cycle recommended, keep smaller for now #19 will produce the same as inverse solution above # solver.set_num_mesh_intervals(19) #Set solver parameters solver.set_optim_constraint_tolerance(1e-3) solver.set_optim_convergence_tolerance(1e-3) # Solve and visualize. solution = study.solve() #Return the solution as an object that we can use return solution
def kinematicsToStates(kinematicsFileName = None, osimModelFileName = None, outputFileName = 'coordinates.sto', inDegrees = True, outDegrees = False): # Convenience function for scaling muscle strength based on height/mass relationship. # The scaling is based on the Handsfield et al. equations, and this function # is adapted from that which comes with the Rajagopal et al. model # # Input: kinematicsFileName - file containing kinematic data. Header should only be coordinates name, rather than path to state # osimModelFileName - opensim model filename that corresponds to kinematic data # outputFileName - optional filename to output to (defaults to coordinates.sto) # inDegrees - set to true if kinematics file is in degrees (defaults to True) # outDegrees - set to true if desired output is in degrees (defaults to False) if kinematicsFileName is None: raise ValueError('Filename for kinematics is required') if osimModelFileName is None: raise ValueError('OpenSim model filename is required') #Load in the kinematic data kinematicsStorage = osim.Storage(kinematicsFileName) #Create a copy of the kinematics data to alter the column labels in statesStorage = osim.Storage(kinematicsFileName) #Resample the data points linearly to avoid any later issues with matching #time points. Use a time stamp for 250 Hz kinematicsStorage.resampleLinear(1/250) statesStorage.resampleLinear(1/250) #Get the column headers for the storage file angleNames = kinematicsStorage.getColumnLabels() #Get the corresponding full paths from the model to rename the #angles in the kinematics file kinematicModel = osim.Model(osimModelFileName) for ii in range(0,angleNames.getSize()-1): currAngle = angleNames.get(ii) if currAngle != 'time': #Get full path to coordinate fullPath = kinematicModel.updCoordinateSet().get(currAngle).getAbsolutePathString()+'/value' #Set angle name appropriately using full path angleNames.set(ii,fullPath) #Set the states storage object to have the updated column labels statesStorage.setColumnLabels(angleNames) #Appropriately set output in degrees or radians if inDegrees and not outDegrees: #Convert degrees values to radians for consistency with the current #file label (defaults back to inDegrees=no). Radians seem to work #better with the Moco process as well. kinematicModel.initSystem() kinematicModel.getSimbodyEngine().convertDegreesToRadians(statesStorage) elif inDegrees and outDegrees: #Change the storage label back to specifying indegrees=yes statesStorage.setInDegrees(True) elif not inDegrees and outDegrees: #Convert radians to degrees kinematicModel.initSystem() kinematicModel.getSimbodyEngine().convertRadiansToDegrees(statesStorage) #Reset labeling for degrees statesStorage.setInDegrees(True) #Write the states storage object to file statesStorage.printToXML(outputFileName)
#Set the model processor in the problem problem.setModel(simModel) #Navigate to guess directory os.chdir('..\\GuessFiles') #Set guess path guessPath = os.getcwd() #Set time bounds on the problem ##### NOTE: first iteration with end time bounds seemed to try and solve to the ##### the final end time bound (i.e. 1.0) rather than as fast as possible. Test ##### and see whether removing these fixes it. # Set to a percentage of the final guess time to end timeLB = 0.9 * osim.Storage(taskName + '_StartingGuess.sto').getLastTime() timeUB = 1.1 * osim.Storage(taskName + '_StartingGuess.sto').getLastTime() problem.setTimeBounds(osim.MocoInitialBounds(0.0), osim.MocoFinalBounds(timeLB, timeUB)) # problem.setTimeBounds(0,[]) #Define marker end point goals osimHelper.addMarkerEndPoints(taskName, problem, simModel) #Define kinematic task bounds osimHelper.addTaskBounds(taskName, problem, simModel, taskBoundsElv, taskBoundsRot, taskBoundsAng) #Add a control cost to the problem problem.addGoal(osim.MocoControlGoal('effort', 1))
def write(filename): import opensim as osim import csv import numpy as np import directories allDir = list(directories.main(directories)) idResultsDir = allDir[7] soResultsDir = allDir[8] cmcResultsDir = allDir[10] storage = osim.Storage(filename) labels = storage.getColumnLabels() labelSize = labels.getSize() header = [] for i in range(labelSize): header.append(labels.getitem(i)) nrows = storage.getSize() data = [] dataArray = [] if header[0] == 'time': st = 1 dataArray.append(osim.ArrayDouble()) storage.getTimeColumn(dataArray[0]) column = [] for j in range(nrows): column.append(dataArray[0].getitem(j)) data.append(column) else: st = 0 for i in range(st, labelSize): dataArray.append(osim.ArrayDouble()) storage.getDataColumn(header[i], dataArray[i]) column = [] for j in range(nrows): column.append(dataArray[i].getitem(j)) data.append(column) dataFixed = np.transpose(data) headerFixed = [] headerFixed.append(header) # Writing excel file for plotting if filename == idResultsDir + "/" + "subject01_walk1_id.sto": with open((idResultsDir + "/" + "idData.csv"), "wb") as fid: csvWriter = csv.writer(fid, dialect='excel') csvWriter.writerows(headerFixed) csvWriter.writerows(dataFixed) if filename == soResultsDir + "/" + "subject01_walk1_StaticOptimization_force.sto": with open((soResultsDir + "/" + "soData.csv"), "wb") as fid: csvWriter = csv.writer(fid, dialect='excel') csvWriter.writerows(headerFixed) csvWriter.writerows(dataFixed) if filename == soResultsDir + "/" + "_Gait2354 Joint RXN_ReactionLoads.sto": with open((soResultsDir + "/" + "soJrData.csv"), "wb") as fid: csvWriter = csv.writer(fid, dialect='excel') csvWriter.writerows(headerFixed) csvWriter.writerows(dataFixed) if filename == cmcResultsDir + "/" + "_Gait2354 Joint RXN_ReactionLoads.sto": with open((cmcResultsDir + "/" + "cmcJrData.csv"), "wb") as fid: csvWriter = csv.writer(fid, dialect='excel') csvWriter.writerows(headerFixed) csvWriter.writerows(dataFixed) return ()
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 ()