def simulate_controlled_drivetrain(show_plot=True): """ Download and simulate ControlledDrivetrain.ssp Parameters: show_plot plot the results """ ssp_filename = r'ControlledDrivetrain.ssp' download_file('https://github.com/CATIA-Systems/FMPy/releases/download/v0.1.1/' + ssp_filename, checksum='45e667ed') print("Simulating %s..." % ssp_filename) result = simulate_ssp(ssp_filename, stop_time=4, step_size=1e-3) if show_plot: print("Plotting results...") plot_result(result, names=['reference.y', 'drivetrain.w', 'controller.y'], window_title=ssp_filename) print('Done.') return result
def simulate_coupled_clutches( fmi_version='2.0', fmi_type='ModelExchange', output=['outputs[1]', 'outputs[2]', 'outputs[3]', 'outputs[4]'], solver='CVode', fmi_logging=False, show_plot=True): # download the FMU and input file for filename in ['CoupledClutches.fmu', 'CoupledClutches_in.csv']: download_test_file(fmi_version, fmi_type, 'MapleSim', '2016.2', 'CoupledClutches', filename) print("Loading input...") input = np.genfromtxt('CoupledClutches_in.csv', delimiter=',', names=True) print("Simulating CoupledClutches.fmu (FMI %s, %s, %s)..." % (fmi_version, fmi_type, solver)) result = simulate_fmu(filename='CoupledClutches.fmu', start_time=0, stop_time=1.5, solver=solver, step_size=1e-2, output_interval=2e-2, start_values={'CoupledClutches1_freqHz': 0.4}, input=input, output=output, validate=False, fmi_logging=fmi_logging) if show_plot: print("Plotting results...") from fmpy.util import plot_result plot_result(result=result, window_title="CoupledClutches.fmu (FMI %s, %s, %s)" % (fmi_version, fmi_type, solver)) print("Done.") return result
def main(): import argparse import textwrap description = """\ Validate and simulate Functional Mock-up Units (FMUs) Get information about an FMU: fmpy info Rectifier.fmu Simulate an FMU: fmpy simulate Rectifier.fmu --show-plot Compile a source code FMU: fmpy compile Rectifier.fmu Create a Jupyter Notebook fmpy create-jupyter-notebook Rectifier.fmu """ parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description=textwrap.dedent(description)) parser.add_argument('command', choices=[ 'info', 'validate', 'simulate', 'compile', 'add-cswrapper', 'add-remoting', 'create-cmake-project', 'create-jupyter-notebook' ], help="Command to execute") parser.add_argument('fmu_filename', help="filename of the FMU") parser.add_argument('--validate', action='store_true', help="validate the FMU") parser.add_argument('--start-time', type=float, help="start time for the simulation") parser.add_argument('--stop-time', type=float, help="stop time for the simulation") parser.add_argument('--solver', choices=['Euler', 'CVode'], default='CVode', help="solver to use for Model Exchange") parser.add_argument('--step-size', type=float, help="step size for fixed-step solvers") parser.add_argument( '--relative-tolerance', type=float, help= "relative tolerance for the 'CVode' solver and FMI 2.0 co-simulation FMUs" ) parser.add_argument( '--dont-record-events', action='store_true', help="dont't record outputs at events (model exchange only)") parser.add_argument('--start-values', nargs='+', help="name-value pairs of start values") parser.add_argument( '--apply-default-start-values', action='store_true', help="apply the start values from the model description") parser.add_argument('--output-interval', type=float, help="interval for sampling the output") parser.add_argument('--input-file', help="CSV file to use as input") parser.add_argument('--output-variables', nargs='+', help="Variables to record") parser.add_argument('--output-file', help="CSV to store the results") parser.add_argument('--timeout', type=float, help="max. time to wait for the simulation to finish") parser.add_argument('--debug-logging', action='store_true', help="enable the FMU's debug logging") parser.add_argument('--visible', action='store_true', help="enable interactive mode") parser.add_argument('--fmi-logging', action='store_true', help="enable FMI logging") parser.add_argument('--show-plot', action='store_true', help="plot the results") parser.add_argument('--cmake-project-dir', help="Directory for the CMake project") parser.add_argument('--target-platform', help="The target platform to compile the binary for") args = parser.parse_args() if args.command == 'info': from fmpy import dump dump(args.fmu_filename) elif args.command == 'validate': import sys from fmpy.validation import validate_fmu problems = validate_fmu(args.fmu_filename) if len(problems) == 0: print('No problems found.') else: print('%d problems were found:' % len(problems)) for message in problems: print() print(message) sys.exit(len(problems)) elif args.command == 'compile': from fmpy.util import compile_platform_binary compile_platform_binary(args.fmu_filename, target_platform=args.target_platform) elif args.command == 'add-cswrapper': from fmpy.cswrapper import add_cswrapper add_cswrapper(args.fmu_filename) elif args.command == 'add-remoting': from fmpy.util import add_remoting from fmpy import supported_platforms platforms = supported_platforms(args.fmu_filename) if 'win32' in platforms and 'win64' not in platforms: add_remoting(args.fmu_filename, 'win64', 'win32') elif 'win64' in platforms and 'linux64' not in platforms: add_remoting(args.fmu_filename, 'linux64', 'win64') else: print("Failed to add remoting binaries.") elif args.command == 'create-cmake-project': import os from fmpy.util import create_cmake_project project_dir = args.cmake_project_dir if project_dir is None: project_dir = os.path.basename(args.fmu_filename) project_dir, _ = os.path.splitext(project_dir) print("Creating CMake project in %s" % os.path.abspath(project_dir)) create_cmake_project(args.fmu_filename, project_dir) elif args.command == 'create-jupyter-notebook': from fmpy.util import create_jupyter_notebook create_jupyter_notebook(args.fmu_filename) elif args.command == 'simulate': from fmpy import simulate_fmu from fmpy.util import read_csv, write_csv, plot_result if args.start_values: if len(args.start_values) % 2 != 0: raise Exception("Start values must be name-value pairs.") start_values = { k: v for k, v in zip(args.start_values[::2], args.start_values[1::2]) } else: start_values = {} input = read_csv(args.input_file) if args.input_file else None if args.fmi_logging: fmi_call_logger = lambda s: print('[FMI] ' + s) else: fmi_call_logger = None result = simulate_fmu( args.fmu_filename, validate=args.validate, start_time=args.start_time, stop_time=args.stop_time, solver=args.solver, step_size=args.step_size, relative_tolerance=args.relative_tolerance, output_interval=args.output_interval, record_events=not args.dont_record_events, fmi_type=None, start_values=start_values, apply_default_start_values=args.apply_default_start_values, input=input, output=args.output_variables, timeout=args.timeout, debug_logging=args.debug_logging, visible=args.visible, fmi_call_logger=fmi_call_logger) if args.output_file: write_csv(filename=args.output_file, result=result) if args.show_plot: plot_result(result=result, window_title=args.fmu_filename)
def simulate_custom_input(show_plot=True): # define the model name and simulation parameters fmu_filename = 'CoupledClutches.fmu' start_time = 0.0 threshold = 2.0 stop_time = 2.0 step_size = 1e-3 # download the FMU download_test_file('2.0', 'CoSimulation', 'MapleSim', '2016.2', 'CoupledClutches', fmu_filename) # read the model description model_description = read_model_description(fmu_filename) # collect the value references vrs = {} for variable in model_description.modelVariables: vrs[variable.name] = variable.valueReference # get the value references for the variables we want to get/set vr_inputs = vrs['inputs'] # normalized force on the 3rd clutch vr_outputs4 = vrs['outputs[4]'] # angular velocity of the 4th inertia # extract the FMU unzipdir = extract(fmu_filename) fmu = FMU2Slave(guid=model_description.guid, unzipDirectory=unzipdir, modelIdentifier=model_description.coSimulation.modelIdentifier, instanceName='instance1') # initialize fmu.instantiate() fmu.setupExperiment(startTime=start_time) fmu.enterInitializationMode() fmu.exitInitializationMode() time = start_time rows = [] # list to record the results # simulation loop while time < stop_time: # NOTE: the FMU.get*() and FMU.set*() functions take lists of # value references as arguments and return lists of values # set the input fmu.setReal([vr_inputs], [0.0 if time < 0.9 else 1.0]) # perform one step fmu.doStep(currentCommunicationPoint=time, communicationStepSize=step_size) # get the values for 'inputs' and 'outputs[4]' inputs, outputs4 = fmu.getReal([vr_inputs, vr_outputs4]) # use the threshold to terminate the simulation if outputs4 > threshold: print("Threshold reached at t = %g s" % time) break # append the results rows.append((time, inputs, outputs4)) # advance the time time += step_size fmu.terminate() fmu.freeInstance() # clean up shutil.rmtree(unzipdir) # convert the results to a structured NumPy array result = np.array(rows, dtype=np.dtype([('time', np.float64), ('inputs', np.float64), ('outputs[4]', np.float64)])) # plot the results if show_plot: plot_result(result) return time
def main(): import argparse import textwrap description = """\ Validate and simulate Functional Mock-up Units (FMUs) Get information about an FMU: fmpy info Rectifier.fmu Simulate an FMU: fmpy simulate Rectifier.fmu --show-plot Compile a source code FMU: fmpy compile Rectifier.fmu """ parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description=textwrap.dedent(description)) parser.add_argument( 'command', choices=['info', 'validate', 'simulate', 'compile', 'add-remoting'], help="Command to execute") parser.add_argument('fmu_filename', help="filename of the FMU") parser.add_argument('--validate', action='store_true', help="validate the FMU") parser.add_argument('--start-time', type=float, help="start time for the simulation") parser.add_argument('--stop-time', type=float, help="stop time for the simulation") parser.add_argument('--solver', choices=['Euler', 'CVode'], default='CVode', help="solver to use for Model Exchange") parser.add_argument('--step-size', type=float, help="step size for fixed-step solvers") parser.add_argument( '--relative-tolerance', type=float, help= "relative tolerance for the 'CVode' solver and FMI 2.0 co-simulation FMUs" ) parser.add_argument( '--dont-record-events', action='store_true', help="dont't record outputs at events (model exchange only)") parser.add_argument('--start-values', nargs='+', help="name-value pairs of start values") parser.add_argument( '--apply-default-start-values', action='store_true', help="apply the start values from the model description") parser.add_argument('--output-interval', type=float, help="interval for sampling the output") parser.add_argument('--input-file', help="CSV file to use as input") parser.add_argument('--output-variables', nargs='+', help="Variables to record") parser.add_argument('--output-file', help="CSV to store the results") parser.add_argument('--timeout', type=float, help="max. time to wait for the simulation to finish") parser.add_argument('--debug-logging', action='store_true', help="enable the FMU's debug logging") parser.add_argument('--visible', action='store_true', help="enable interactive mode") parser.add_argument('--fmi-logging', action='store_true', help="enable FMI logging") parser.add_argument('--show-plot', action='store_true', help="plot the results") args = parser.parse_args() if args.command == 'info': from fmpy import dump dump(args.fmu_filename) elif args.command == 'validate': import sys from fmpy.util import validate_fmu messages = validate_fmu(args.fmu_filename) if len(messages) == 0: print('The validation passed') else: print('The following errors were found:') for message in messages: print() print(message) sys.exit(1) elif args.command == 'compile': from fmpy.util import compile_platform_binary compile_platform_binary(args.fmu_filename) elif args.command == 'add-remoting': from fmpy.util import add_remoting add_remoting(args.fmu_filename) elif args.command == 'simulate': from fmpy import simulate_fmu from fmpy.util import read_csv, write_csv, plot_result if args.start_values: if len(args.start_values) % 2 != 0: raise Exception("Start values must be name-value pairs.") start_values = { k: v for k, v in zip(args.start_values[::2], args.start_values[1::2]) } else: start_values = {} input = read_csv(args.input_file) if args.input_file else None if args.fmi_logging: fmi_call_logger = lambda s: print('[FMI] ' + s) else: fmi_call_logger = None result = simulate_fmu( args.fmu_filename, validate=args.validate, start_time=args.start_time, stop_time=args.stop_time, solver=args.solver, step_size=args.step_size, relative_tolerance=args.relative_tolerance, output_interval=args.output_interval, record_events=not args.dont_record_events, fmi_type=None, start_values=start_values, apply_default_start_values=args.apply_default_start_values, input=input, output=args.output_variables, timeout=args.timeout, debug_logging=args.debug_logging, visible=args.visible, fmi_call_logger=fmi_call_logger) if args.output_file: write_csv(filename=args.output_file, result=result) if args.show_plot: plot_result(result=result, window_title=args.fmu_filename)
def main(): import argparse import textwrap description = """\ Simulate an FMU Example: > python -m fmpy.simulate Rectifier.fmu """ parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description=textwrap.dedent(description)) parser.add_argument('command', choices=['info', 'simulate'], help="Command to execute") parser.add_argument('fmu_filename', help="filename of the FMU") parser.add_argument('--solver', choices=['Euler', 'CVode'], default='CVode', help="solver to use for Model Exchange") parser.add_argument('--input-file', help="CSV file to use as input") parser.add_argument('--output-variables', nargs='+', help="Variables to record") parser.add_argument('--output-file', help="CSV to store the results") parser.add_argument('--num-samples', default=500, type=int, help="number of samples to record") parser.add_argument('--step-size', type=float, help="step size for fixed-step solvers") parser.add_argument('--start-time', type=float, help="start time for the simulation") parser.add_argument('--stop-time', type=float, help="stop time for the simulation") parser.add_argument('--show-plot', action='store_true', help="plot the results") parser.add_argument('--timeout', type=float, help="max. time to wait for the simulation to finish") parser.add_argument('--fmi-logging', action='store_true', help="enable FMI logging") parser.add_argument('--start-values', nargs='+', help="name-value pairs of start values") args = parser.parse_args() if args.command == 'info': from fmpy import dump dump(args.fmu_filename) elif args.command == 'simulate': from fmpy import simulate_fmu from fmpy.util import read_csv, write_csv, plot_result if args.start_values: if len(args.start_values) % 2 != 0: raise Exception("Start values must be name-value pairs.") start_values = { k: v for k, v in zip(args.start_values[::2], args.start_values[1::2]) } else: start_values = {} input = read_csv(args.input_file) if args.input_file else None result = simulate_fmu(args.fmu_filename, validate=True, start_time=args.start_time, stop_time=args.stop_time, solver=args.solver, step_size=args.step_size, output_interval=None, fmi_type=None, start_values=start_values, input=input, output=args.output_variables, timeout=args.timeout, fmi_logging=args.fmi_logging) if args.output_file: write_csv(args.output_file, result) if args.show_plot: plot_result(result=result, window_title=args.fmu_filename)
in_csv = os.path.join(src_dir, model_name, model_name + '_in.csv') if os.path.isfile(in_csv): input = read_csv(in_csv) else: input = None result = simulate_fmu(fmu, fmi_type='ModelExchange', # solver='Euler', start_values=start_values, input=input, output_interval=output_interval ) write_csv(ref_csv, result) ref = read_csv(ref_csv) plot_result(ref, events=True, filename=ref_png) md_file = os.path.join(src_dir, model_name, 'readme.md') html_file = os.path.join(src_dir, model_name, 'readme.html') md = markdown2.markdown_path(md_file, extras=['tables', 'fenced-code-blocks']) with open(html_file, 'w') as html: html.write(header1) html.write("<title>%s</title>" % model_name) html.write(header2) html.write(md) html.write(footer)
def simulateCustomInput(filename, showPlot=True): # define the model name and simulation parameters startTime = 0.0 threshold = 2.0 stopTime = 30.0 stepSize = (stopTime - startTime) / 500 # read the model description modelDescription = read_model_description(filename) # collect the value references vrs = {} for variable in modelDescription.modelVariables: vrs[variable.name] = variable.valueReference # get the value references for the variables we want to get/set vrInputs = vrs[ 'u'] # These need to be changed per model, or use standardised naming conventions vrOutputs = vrs['y'] unzipdir = extract(filename) fmu = FMU2Slave( guid=modelDescription.guid, unzipDirectory=unzipdir, modelIdentifier=modelDescription.coSimulation.modelIdentifier, instanceName='instance1') # initalize fmu.instantiate() fmu.setupExperiment(startTime=startTime) fmu.enterInitializationMode() fmu.exitInitializationMode() time = startTime rows = [] # Sim loop while time < stopTime: # NOTE: the FMU.get*() and FMU.set*() functions take lists of # value references as arguments and return lists of values # set the input fmu.setReal([vrInputs], [0.0 if time < 1.0 else 1.0]) # perform 1 step fmu.doStep(currentCommunicationPoint=time, communicationStepSize=stepSize) # get the values for 'inputs' and 'outputs' inputs, outputs = fmu.getReal([vrInputs, vrOutputs]) # Use threshold to terminate sim if outputs > threshold: print("Threshold reached at t = {:.3f} s".format(time)) break # append the results rows.append((time, inputs, outputs)) # advance the time time += stepSize fmu.terminate() fmu.freeInstance() result = np.array(rows, dtype=np.dtype([('time', np.float64), ('inputs', np.float64), ('outputs', np.float64)])) if showPlot: plot_result(result) return time