### Install Python project normally Source: https://pythonfmu3.readthedocs.io/en/latest/install Installs the Python project normally. ```bash pip install . ``` -------------------------------- ### Install, build, and deploy pythonfmu3 Source: https://pythonfmu3.readthedocs.io/en/latest/dependencies Commands to install pythonfmu3, build an FMU with a requirements.txt file, and deploy the FMU to update the current Python environment. ```bash pip install pythonfmu3 ``` ```bash pythonfmu3 build -f myscript.py requirements.txt ``` ```bash pip install pythonfmu3 ``` ```bash pythonfmu3 deploy -f my.fmu ``` -------------------------------- ### Install pythonfmu3 with pip Source: https://pythonfmu3.readthedocs.io/en/latest/install Installs the pythonfmu3 package from PyPI using pip. ```bash pip install pythonfmu3 ``` -------------------------------- ### Install Python project in editable mode Source: https://pythonfmu3.readthedocs.io/en/latest/install Installs the Python project in editable mode, which is useful for development. ```bash pip install -e . ``` -------------------------------- ### Simulate and plot PID controller FMU with FMPy Source: https://pythonfmu3.readthedocs.io/en/latest/usage Use FMPy's simulate_fmu to run a co-simulation of a PID controller FMU, then plot the setpoint, measurement, and control output. The example sets start and stop times, step size, and initial values for PID gains and setpoint, and provides a measurement input schedule. ```python # Example of co-simulation setup import fmpy from fmpy import simulate_fmu import matplotlib.pyplot as plt # Simulate the PID controller FMU result = simulate_fmu( filename='PIDController.fmu', start_time=0.0, stop_time=10.0, step_size=0.01, start_values={ 'Kp': 2.0, 'Ki': 0.5, 'Kd': 0.1, 'setpoint': 1.0 }, input={ 'measurement': [(0.0, 0.0), (1.0, 0.3), (5.0, 0.8), (10.0, 1.0)] } ) # Plot results plt.figure(figsize=(12, 6)) plt.subplot(2, 1, 1) plt.plot(result['time'], result['setpoint'], label='Setpoint') plt.plot(result['time'], result['measurement'], label='Measurement') plt.ylabel('Value') plt.legend() plt.grid(True) plt.subplot(2, 1, 2) plt.plot(result['time'], result['output'], label='Control Output') plt.xlabel('Time [s]') plt.ylabel('Control Signal') plt.legend() plt.grid(True) plt.show() ``` -------------------------------- ### Simulate FMU with FMPy and Plot Results Source: https://pythonfmu3.readthedocs.io/en/latest/usageMX Simulates a generated FMU using FMPy and plots the results. The example loads VanDerPol.fmu, simulates for 20 seconds with a step size of 0.01, and sets initial values for mu, x0, and x1. ```python import fmpy # Load and simulate the FMU fmu_filename = "VanDerPol.fmu" result = fmpy.simulate_fmu( fmu_filename, stop_time=20.0, step_size=0.01, start_values={'mu': 1.0, 'x0': 2.0, 'x1': 0.0} ) # Plot results import matplotlib.pyplot as plt plt.plot(result['time'], result['x0'], label='x0') plt.plot(result['time'], result['x1'], label='x1') plt.xlabel('Time') plt.ylabel('State Values') plt.legend() plt.grid(True) plt.show() ``` -------------------------------- ### Return FmiStepResult from do_step Source: https://pythonfmu3.readthedocs.io/en/latest/usage Shows how to return a tuple of flags from do_step using the FmiStepResult tuple. The example sets status to Fmi3Status.ok and terminateSimulation to False. ```python from pythonfmu3 import Fmi3Status, Fmi3StepResult def do_step(self, current_time, step_size): self.y = 1 + 2 + 3 + 4 + ... terminate = False status = Fmi3Status.ok return Fmi3StepResult(status=Fmi3Status.ok, terminateSimulation=terminate) ``` -------------------------------- ### BouncingBall FMU Example with Event Handling Source: https://pythonfmu3.readthedocs.io/en/latest/usageMX Complete example of a BouncingBall FMU slave class that implements event handling. It registers variables with event indicators, defines continuous state derivatives, and updates discrete states on impact. ```python from pythonfmu3 import Fmi3Causality, Fmi3Variability, Fmi3SlaveBase, ModelExchange, Float64, Fmi3Initial, Fmi3UpdateDiscreteStatesResult from typing import List import sys EVENT_EPS = 1e-12 class BouncingBall(Fmi3SlaveBase, ModelExchange): def __init__(self, **kwargs): super().__init__(**kwargs) self.author = "..." self.description = "Bouncing Ball" self.time = 0.0 self.h = 1.0 self.v = 0.0 self.derh = 0.0 self.derv = 0.0 self.g = -9.81 self.e = 0.7 self.v_min = 0.1 self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous)) self.register_variable(Float64("h", causality=Fmi3Causality.output, start=1, variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact), has_event_indicator=True) self.register_variable(Float64("derh", causality=Fmi3Causality.local, variability=Fmi3Variability.continuous, derivative=1)) self.register_variable(Float64("v", causality=Fmi3Causality.output, start=0, variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact)) self.register_variable(Float64("derv", causality=Fmi3Causality.local, variability=Fmi3Variability.continuous, derivative=3)) self.register_variable(Float64("g", causality=Fmi3Causality.parameter, variability=Fmi3Variability.fixed)) self.register_variable(Float64("e", causality=Fmi3Causality.parameter, variability=Fmi3Variability.tunable)) self.register_variable(Float64("v_min", variability=Fmi3Variability.constant, start=0.1)) def get_continuous_state_derivatives(self) -> List[float]: self.derh = self.v self.derv = self.g return [self.derh, self.derv] def get_event_indicators(self) -> List[float]: z = [self.h] if self.h > -EVENT_EPS and self.h <=0 and self.v > 0: z[0] = -EVENT_EPS return z def update_discrete_states(self): fdsr = Fmi3UpdateDiscreteStatesResult() if self.h <= 0 and self.v < 0: self.h = sys.float_info.min self.v = -self.v * self.e if self.v < self.v_min: self.v = 0.0; self.g = 0.0; fdsr.valuesOfContinuousStatesChanged = True return fdsr ``` -------------------------------- ### Clone PythonFMU3 repository Source: https://pythonfmu3.readthedocs.io/en/latest/install Clones the PythonFMU3 repository from GitHub to get the source code. ```bash git clone https://github.com/StephenSmith25/PythonFMU3.git ``` -------------------------------- ### Define a LinearTransform slave with numpy arrays Source: https://pythonfmu3.readthedocs.io/en/latest/usage Shows a complete Fmi3Slave subclass using numpy arrays for inputs, parameters, and outputs. Registers variables with dimensions and computes y = scalar*A*u + offset in do_step. Requires numpy to be installed. ```python from pythonfmu3 import Fmi3Causality, Fmi3Variability, Fmi3Slave, Float64, UInt64, Fmi3Initial, Dimension import numpy as np class LinearTransform(Fmi3Slave): def __init__(self, **kwargs): super().__init__(**kwargs) self.author = "..." self.description = "LinearTransform" self.time = 0.0 self.m = 2 self.n = 2 self.scalar = 2.00 self.u = np.array([1.0, 2.0]).reshape((self.m, 1)) self.offset = np.array([1.0, 2.0]).reshape((self.m, 1)) self.A = np.array([1.0, 1.0, 2.0, 1.0]).reshape((self.m, self.n)) self.y = np.array([0.0, 0.0]).reshape((self.m, 1)) self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous)) self.register_variable(UInt64("m", causality=Fmi3Causality.structuralParameter, variability=Fmi3Variability.tunable, start=2)) self.register_variable(Float64("scalar", causality=Fmi3Causality.input, start=2.0)) self.register_variable(Float64("u", causality=Fmi3Causality.input, dimensions=[Dimension(start=f"{self.n}")])) self.register_variable(Float64("offset", causality=Fmi3Causality.input, dimensions=[Dimension(start=f"{self.m}")])) self.register_variable(Float64("A", causality=Fmi3Causality.parameter, variability=Fmi3Variability.tunable, dimensions=[Dimension(start=f"{self.m}"), Dimension(start=f"{self.n}")])) self.register_variable(Float64("y", causality=Fmi3Causality.output, dimensions=[Dimension(valueReference="1")])) def do_step(self, current_time, step_size): self.y = self.scalar*self.A.dot(self.u) + self.offset return True ``` -------------------------------- ### pythonfmu3 deploy help output Source: https://pythonfmu3.readthedocs.io/en/latest/dependencies Help output for the pythonfmu3 deploy command, showing its usage, arguments, and behavior when no package manager is specified. ```text usage: pythonfmu3 deploy [-h] -f FMU [-e ENVIRONMENT] [{pip,conda}] Deploy a Python FMU. The command will look in the `resources` folder for one of the following files: `requirements.txt` or `environment.yml`. If you specify a environment file but no package manager, `conda` will be selected for `.yaml` and `.yml` otherwise `pip` will be used. The tool assume the Python environment in which the FMU should be executed is the current one. positional arguments: {pip,conda} Python packages manager optional arguments: -h, --help show this help message and exit -f FMU, --file FMU Path to the Python FMU. -e ENVIRONMENT, --env ENVIRONMENT Requirements or environment file. ``` -------------------------------- ### Build the FMU Source: https://pythonfmu3.readthedocs.io/en/latest Builds an FMU from the Python model file my_model.py. ```bash pythonfmu3 build -f my_model.py ``` -------------------------------- ### Build C++ code with CMake and make Source: https://pythonfmu3.readthedocs.io/en/latest/install Builds the C++ code for the project. Run these commands in the cloned repository directory. ```bash mkdir build cd build cmake -S ../pythonfmu3/pythonfmu-export/ make ``` -------------------------------- ### Implement PID Controller Co-simulation FMU with do_step Source: https://pythonfmu3.readthedocs.io/en/latest/usage Complete PID controller Co-simulation FMU implementing the required `__init__` and `do_step` methods. Registers inputs, outputs, and tunable parameters, and computes proportional, integral, and derivative terms each step. ```python from pythonfmu3 import Fmi3Causality, Fmi3Slave, Float64 class PIDController(Fmi3Slave): """PID Controller implementation""" def __init__(self, **kwargs): super().__init__(**kwargs) self.author = "PythonFMU3 Team" self.description = "PID Controller" # Inputs self.setpoint = 0.0 self.measurement = 0.0 # Outputs self.control_output = 0.0 # Parameters self.kp = 1.0 # Proportional gain self.ki = 0.1 # Integral gain self.kd = 0.01 # Derivative gain # Internal states self.integral_error = 0.0 self.previous_error = 0.0 self.first_step = True # Register variables self.register_variable(Float64("setpoint", causality=Fmi3Causality.input, start=0.0)) self.register_variable(Float64("measurement", causality=Fmi3Causality.input, start=0.0)) self.register_variable(Float64("output", causality=Fmi3Causality.output)) self.register_variable(Float64("Kp", causality=Fmi3Causality.parameter, start=1.0)) self.register_variable(Float64("Ki", causality=Fmi3Causality.parameter, start=0.1)) self.register_variable(Float64("Kd", causality=Fmi3Causality.parameter, start=0.01)) def do_step(self, current_time, step_size): # Calculate error error = self.setpoint - self.measurement # Proportional term p_term = self.kp * error # Integral term self.integral_error += error * step_size i_term = self.ki * self.integral_error # Derivative term if self.first_step: d_term = 0.0 self.first_step = False else: d_term = self.kd * (error - self.previous_error) / step_size # PID output self.control_output = p_term + i_term + d_term # Store error for next iteration self.previous_error = error return True ``` -------------------------------- ### Simulate the FMU with fmpy Source: https://pythonfmu3.readthedocs.io/en/latest Simulates the built FMU using the fmpy library, running until stop_time=10.0. ```python import fmpy result = fmpy.simulate_fmu('MyModel.fmu', stop_time=10.0) ``` -------------------------------- ### Register Co-simulation FMU variables with Fmi3Causality Source: https://pythonfmu3.readthedocs.io/en/latest/usage Shows how to register input, output, and parameter variables in a Co-simulation FMU. Inputs are set by the master algorithm, outputs are read by it, and parameters are configurable and usually fixed during simulation. ```python # Input variables (set by master algorithm) self.register_variable(Float64("input_signal", causality=Fmi3Causality.input, start=0.0)) # Output variables (read by master algorithm) self.register_variable(Float64("output_signal", causality=Fmi3Causality.output)) # Parameters (configurable, usually fixed during simulation) self.register_variable(Float64("gain", causality=Fmi3Causality.parameter, variability=Fmi3Variability.tunable, start=1.0)) ``` -------------------------------- ### Build FMU with pythonfmu3 CLI Source: https://pythonfmu3.readthedocs.io/en/latest/usageMX Builds an FMU from a Python script using the pythonfmu3 CLI. The -f flag specifies the input Python file. ```bash pythonfmu3 build -f bouncing_ball.py ``` -------------------------------- ### Build FMU with pythonfmu3 CLI Source: https://pythonfmu3.readthedocs.io/en/latest/usageMX Builds an FMU from a Python script using the pythonfmu3 CLI. The -f flag specifies the Python file to compile. ```bash pythonfmu3 build -f van_der_pol.py ``` -------------------------------- ### Create Unit for m/s with pythonfmu3 Unit class Source: https://pythonfmu3.readthedocs.io/en/latest/usage Creates a Unit instance for meters per second using the `Unit` class. This unit can be registered and attached to variables via the `unit` kwarg. ```python from pythonfmu3 import Unit velocity_unit = Unit(name="m/s", m=1, s=-1) ``` -------------------------------- ### Implement get_continuous_state_derivatives for Van der Pol oscillator Source: https://pythonfmu3.readthedocs.io/en/latest/usageMX Implement the derivative function for a Van der Pol oscillator. Returns a list of derivatives for the continuous states, using the registered local variables. ```python def get_continuous_state_derivatives(self): """Calculate derivatives of continuous states""" # Van der Pol oscillator equations: # dx0/dt = x1 # dx1/dt = μ(1-x0²)x1 - x0 self.derx0 = self.x1 self.derx1 = self.mu * ((1 - self.x0**2) * self.x1) - self.x0 return [self.derx0, self.derx1] ``` -------------------------------- ### Define a Python FMI 3.0 model Source: https://pythonfmu3.readthedocs.io/en/latest Defines a simple FMI 3.0 slave model with an input and output variable, and a do_step method that doubles the input. ```python from pythonfmu3 import Fmi3Slave, Fmi3Causality, Float64 class MyModel(Fmi3Slave): def __init__(self, **kwargs): super().__init__(**kwargs) # Register variables self.register_variable(Float64("input", causality=Fmi3Causality.input)) self.register_variable(Float64("output", causality=Fmi3Causality.output)) # Initialize values self.input = 0.0 self.output = 0.0 def do_step(self, current_time, step_size): # Your model logic here self.output = 2.0 * self.input return True ``` -------------------------------- ### Define Event Methods for Discrete Events Source: https://pythonfmu3.readthedocs.io/en/latest/usageMX Defines the event methods get_event_indicators() and update_discrete_states() for handling discrete events. The update_discrete_states method returns an Fmi3UpdateDiscreteStatesResult with valuesOfContinuousStatesChanged set to True. ```python def get_event_indicators(self): return [0.2] def update_discrete_states(self): """Handle discrete state updates after events""" fdsr = Fmi3UpdateDiscreteStatesResult() fdsr.valuesOfContinuousStatesChanged = True ``` -------------------------------- ### Register unit and attach to variable with unit kwarg Source: https://pythonfmu3.readthedocs.io/en/latest/usage Registers a previously created unit and uses it in a variable registration. The `register_units` call makes the unit available, and the `unit` kwarg attaches it to the variable. ```python velocity_unit = Unit(name="m/s", m=1, s=-1) self.register_units([velocity_unit]) self.register_variable(Float64("v", causality=Fmi3Causality.output, start=0, variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact, unit=velocity_unit.name)) ``` -------------------------------- ### Register Variable with Event Indicator Source: https://pythonfmu3.readthedocs.io/en/latest/usageMX Registers a variable as an event indicator by passing has_event_indicator=True to register_variable. This is required for systems with discrete events. ```python self.register_variable(Float64("h", causality=Fmi3Causality.output, start=1, variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact), has_event_indicator=True) ``` -------------------------------- ### Register Model Exchange variables (time, state, derivative) Source: https://pythonfmu3.readthedocs.io/en/latest/usageMX Register the independent time variable, a continuous state with an exact initial value, and a local derivative variable. The derivative attribute links derx0 to x0 (variable 1). ```python self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous)) # States with initial values self.register_variable(Float64("x0", causality=Fmi3Causality.output, start=2.0, # Initial value variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact)) # Must be exact # Derivatives (local variables) self.register_variable(Float64("derx0", causality=Fmi3Causality.local, variability=Fmi3Variability.continuous, derivative=1)) # Derivative of variable 1 (x0) ``` -------------------------------- ### VanDerPol FMI 3.0 model exchange FMU Source: https://pythonfmu3.readthedocs.io/en/latest/usageMX Defines a Van Der Pol oscillator as an FMI 3.0 model exchange FMU using pythonfmu3. Registers continuous states, outputs, and a fixed parameter, then implements the required derivative and nominal state methods. ```python from pythonfmu3 import Fmi3Causality, ModelExchange, Fmi3Variability, Fmi3SlaveBase, Fmi3Status, Float64, Fmi3Initial, Unit, Float64Type, Fmi3StepResult from typing import List class VanDerPol(Fmi3SlaveBase, ModelExchange): def __init__(self, **kwargs): super().__init__(**kwargs) self.author = "" self.description = "Van Der Pol oscillator problem for model exchange FMUs" self.time = 0.0 self.mu = 1.0 self.x0 = 2 self.x1 = 0 self.derx0 = 0.0 self.derx1 = 0.0 self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous)) self.register_variable(Float64("x0", causality=Fmi3Causality.output, start=2, variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact)) self.register_variable(Float64("x1", causality=Fmi3Causality.output, start=0, variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact)) self.register_variable(Float64("derx0", causality=Fmi3Causality.local, variability=Fmi3Variability.continuous, derivative=1)) self.register_variable(Float64("derx1", causality=Fmi3Causality.local, variability=Fmi3Variability.continuous, derivative=2)) self.register_variable(Float64("mu", causality=Fmi3Causality.parameter, variability=Fmi3Variability.fixed)) def get_continuous_state_derivatives(self) -> List[float]: self.derx0 = self.x1 self.derx1 = self.mu * ((1 - self.x0**2) * self.x1) - self.x0 return [self.derx0, self.derx1] def get_nominals_of_continuous_states(self, nStates: int) -> List[float]: return [1.0, 1.0] ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.