class FmuMeAdapter(): ''' FMU Model Exchange adapter for energysim ''' def __init__(self, fmu_location, instanceName=None, start_time=0, tolerance=1e-06, stop_time=100, step_size=1.0e-3, inputs=[], outputs=[], solver_name='Cvode', show_fmu_info=False, exist=False, validate=True): assert (fmu_location is not None), "Must specify FMU location" self.fmu_location = fmu_location if instanceName is None: instanceID = int(random() * 1000) self.instanceName = 'fmu' + str(instanceID) print('FMU instance created as: ' + self.instanceName) else: self.instanceName = instanceName self.tolerance = tolerance self.start_time = start_time self.stop_time = stop_time self.step_size = step_size self.inputs = inputs self.outputs = outputs self.solver_name = solver_name self.validate = validate if show_fmu_info: dump(self.fmu_location) self.exist = exist self.setup() def setup(self): fmi_call_logger = None self.t_next = self.start_time self.unzipDir = extract(self.fmu_location) self.modelDescription = read_model_description(self.fmu_location, validate=self.validate) self.is_fmi1 = self.modelDescription.fmiVersion == '1.0' logger = printLogMessage # common FMU constructor arguments self.fmu_args = { 'guid': self.modelDescription.guid, 'unzipDirectory': self.unzipDir, 'instanceName': self.instanceName, 'fmiCallLogger': fmi_call_logger } if self.exist: from fmpy.util import compile_dll # compile the shared library from the C sources self.fmu_args['libraryPath'] = compile_dll( model_description=self.modelDescription, sources_dir=os.path.join(self.unzipDir, 'sources')) self.fmu_args[ 'modelIdentifier'] = self.modelDescription.modelExchange.modelIdentifier if self.is_fmi1: callbacks = fmi1CallbackFunctions() callbacks.logger = fmi1CallbackLoggerTYPE(logger) callbacks.allocateMemory = fmi1CallbackAllocateMemoryTYPE( allocateMemory) callbacks.freeMemory = fmi1CallbackFreeMemoryTYPE(freeMemory) callbacks.stepFinished = None else: callbacks = fmi2CallbackFunctions() callbacks.logger = fmi2CallbackLoggerTYPE(logger) callbacks.allocateMemory = fmi2CallbackAllocateMemoryTYPE( allocateMemory) callbacks.freeMemory = fmi2CallbackFreeMemoryTYPE(freeMemory) #define var values for input and output variables self.vrs = {} for variable in self.modelDescription.modelVariables: self.vrs[variable.name] = [variable.valueReference, variable.type] if self.is_fmi1: self.fmu = FMU1Model(guid=self.modelDescription.guid, unzipDirectory=self.unzipDir, modelIdentifier=self.modelDescription. modelExchange.modelIdentifier, instanceName=self.instanceName) #instantiate FMU self.fmu.instantiate(functions=callbacks) self.fmu.setTime(self.start_time) else: self.fmu = FMU2Model(guid=self.modelDescription.guid, unzipDirectory=self.unzipDir, modelIdentifier=self.modelDescription. modelExchange.modelIdentifier, instanceName=self.instanceName) #instantiate FMU self.fmu.instantiate(callbacks=callbacks) self.fmu.setupExperiment(startTime=self.start_time) self.input = Input(self.fmu, self.modelDescription, None) def set_start_values(self, init_dict): apply_start_values(self.fmu, self.modelDescription, init_dict, apply_default_start_values=False) def set_value(self, parameterName, Value): ''' Must specify parameters and values in list format ''' for i, j in zip(parameterName, Value): if self.vrs[i][1] == 'Real': self.fmu.setReal([self.vrs[i][0]], [j]) elif self.vrs[i][1] in ['Integer', 'Enumeration']: self.fmu.setInteger([self.vrs[i][0]], [j]) elif self.vrs[i][1] == 'Boolean': if isinstance(j, str): if j.lower() not in ['true', 'false']: raise Exception( 'The value "%s" for variable "%s" could not be converted to Boolean' % (j, i)) else: j = j.lower() == 'true' self.fmu.setBoolean([self.vrs[i][0]], [bool(j)]) elif self.vrs[i][1] == 'String': self.fmu.setString([self.vrs[i][0]], [j]) def get_value(self, parameterName, time): ''' Must specify parameter in a list format. ''' values_ = [] for i in parameterName: if self.vrs[i][1] == 'Real': temp = self.fmu.getReal([self.vrs[i][0]]) elif self.vrs[i][1] in ['Integer', 'Enumeration']: temp = self.fmu.getInteger([self.vrs[i][0]]) elif self.vrs[i][1] == 'Boolean': temp = self.fmu.getBoolean([self.vrs[i][0]]) elif self.vrs[i][1] == 'String': temp = self.fmu.getString([self.vrs[i][0]]) values_.append(temp[0]) # values_ = self.fmu.getReal(list(self.parameterVar)) return values_ def reset(self): self.fmu.reset() def init(self): #self.set_inital_inputs({}) self.input = Input(self.fmu, self.modelDescription, None) if self.is_fmi1: # self.fmu.setTime(self.start_time) self.input.apply(0) self.fmu.initialize() else: # self.fmu.setupExperiment(startTime=self.start_time) self.fmu.enterInitializationMode() self.input.apply(0) self.fmu.exitInitializationMode() # event iteration self.fmu.eventInfo.newDiscreteStatesNeeded = fmi2True self.fmu.eventInfo.terminateSimulation = fmi2False while self.fmu.eventInfo.newDiscreteStatesNeeded == fmi2True and self.fmu.eventInfo.terminateSimulation == fmi2False: # update discrete states self.fmu.newDiscreteStates() self.fmu.enterContinuousTimeMode() #self.fmu.initialize() self.set_solver() self.t_next = self.start_time def set_solver(self): solver_args = { 'nx': self.modelDescription.numberOfContinuousStates, 'nz': self.modelDescription.numberOfEventIndicators, 'get_x': self.fmu.getContinuousStates, 'set_x': self.fmu.setContinuousStates, 'get_dx': self.fmu.getDerivatives, 'get_z': self.fmu.getEventIndicators } if self.solver_name == 'Cvode': from fmpy.sundials import CVodeSolver self.solver = CVodeSolver( set_time=self.fmu.setTime, startTime=self.start_time, maxStep=(self.stop_time - self.start_time) / 50., relativeTolerance=0.001, **solver_args) self.fixed_step = False if self.solver_name == 'Euler': self.solver = ForwardEuler(**solver_args) self.fixed_step = True def setInput(self, inputValues): self.inputVariables = [] for i in self.inputs: self.inputVariables.append(self.vrs[i][0]) self.fmu.setReal(list(self.inputVariables), list(inputValues)) def getOutput(self): self.outputVariables = [] for i in self.outputs: self.outputVariables.append(self.vrs[i][0]) return self.fmu.getReal(list(self.outputVariables)) def step(self, time, csStep=False): if csStep: print( 'Variable step is only supported in cosimulation FMUs. Exiting simulation.' ) sys.exit() eps = 1.0e-13 #step ahead in time if self.fixed_step: if time + self.step_size < self.stop_time + eps: self.t_next = time + self.step_size # else: # break else: if time + eps >= self.t_next: # t_next has been reached # integrate to the next grid point # self.t_next = round(time / self.step_size) * self.step_size + self.step_size self.t_next = np.floor( time / self.step_size) * self.step_size + self.step_size if self.t_next < time + eps: self.t_next += self.step_size #gets the time of input event t_input_event = self.input.nextEvent(time) # check for input event input_event = t_input_event <= self.t_next if input_event: self.t_next = t_input_event #check the time of next event. if self.is_fmi1: time_event = self.fmu.eventInfo.upcomingTimeEvent != fmi1False and self.fmu.eventInfo.nextEventTime <= self.t_next else: time_event = self.fmu.eventInfo.nextEventTimeDefined != fmi2False and self.fmu.eventInfo.nextEventTime <= self.t_next # time_event = self.fmu.eventInfo.upcomingTimeEvent != fmi1False and self.fmu.eventInfo.nextEventTime <= self.t_next if time_event and not self.fixed_step: self.t_next = self.fmu.eventInfo.nextEventTime if self.t_next - time > eps: # do one step state_event, time = self.solver.step(time, self.t_next) else: # skip time = self.t_next state_event = False # set the time self.fmu.setTime(time) # check for step event, e.g.dynamic state selection if self.is_fmi1: step_event = self.fmu.completedIntegratorStep() else: step_event, _ = self.fmu.completedIntegratorStep() step_event = step_event != fmi2False # handle events if input_event or time_event or state_event or step_event: #recorder.sample(time, force=True) if input_event: input.apply(time=time, after_event=True) # handle events if self.is_fmi1: self.fmu.eventUpdate() else: # handle events self.fmu.enterEventMode() self.fmu.eventInfo.newDiscreteStatesNeeded = fmi2True self.fmu.eventInfo.terminateSimulation = fmi2False # update discrete states while self.fmu.eventInfo.newDiscreteStatesNeeded != fmi2False and self.fmu.eventInfo.terminateSimulation == fmi2False: self.fmu.newDiscreteStates() self.fmu.enterContinuousTimeMode() self.solver.reset(time) def terminate(self): self.fmu.terminate() def cleanUp(self): self.fmu.terminate() self.fmu.freeInstance() del self.solver # shutil.rmtree(self.unzipDir) def simulate(self, timeout=180): from fmpy import simulate_fmu result = simulate_fmu(self.fmu_location, start_time=self.start_time, stop_time=self.stop_time, timeout=timeout, step_size=self.step_size, output=self.outputs) return result
class FMPY(Element): def __init__(self, name, options): super().__init__(name, options) # self.createFlexInputPin() # self.createPin('out', VALUETYPES.REAL) self.firstRun = 1 self.inType = VALUETYPES.REAL self.outType = VALUETYPES.REAL if options['dyn'] == "full": if options['inType'] == "const": self.inType = VALUETYPES.REAL elif options['inType'] == "variab": self.inType = VALUETYPES.VECTOR if options['outType'] == "const": self.outType = VALUETYPES.REAL elif options['outType'] == "variab": self.outType = VALUETYPES.VECTOR elif options['dyn'] == "step": self.inType = VALUETYPES.REAL self.outType = VALUETYPES.REAL else: Exception('Error! FMPY.init(): Unsupported value for "dyn".') if 'fmu' in options: self.myFMUid = options['fmu'] else: self.myFMUid = options['model_path'] + '\\' + options[ 'model'] + '.fmu' if 'interval' in options: if 'Tstart' in options['interval']: self.Tstart = options['interval']['Tstart'] else: self.Tstart = 0.0 self.time = self.Tstart if 'Tstep' in options[ 'interval'] and options['interval']['Tstep'] > 0: self.Tstep = options['interval']['Tstep'] elif 'Tstop' in options['interval']: if options['interval']['Tstop'] - self.Tstart > 0: self.Tstep = options['interval']['Tstop'] - self.Tstart else: Exception( 'Error! FMPY.init(): Tstop must be greater than Tstart.' ) else: Exception( 'Step size Tstep must be specified and greater than 0.') if 'Tstop' in options[ 'interval'] and options['interval']['Tstep'] > self.Tstart: self.Tstop = options['interval']['Tstop'] elif 'Tstep' in options['interval']: if options['interval']['Tstep'] > 0: self.Tstop = options['interval']['Tstep'] else: Exception('Tstep must be positive.') else: Exception( 'Stop time Tstop must be specified and greater than start time.' ) else: Exception('Interval for dynamic simulation must be specified.') if 'solOpt' in options: if 'Timeout' in options['interval']: self.Timeout = options['interval']['Timeout'] else: self.Timeout = 100 if 'Tolerance' in options['interval']: self.Tolerance = options['interval']['Tolerance'] else: self.Tolerance = 1e-06 self.t_next = self.Tstart self.FMUinput = [] self.FMUoutput = [] self.modelDescription = read_model_description(self.myFMUid, validate=True) self.unzipdir = extract( self.myFMUid) # is this one needed or I can delete it logger = printLogMessage callbacks = None if options['fmu_ver'] == 1: callbacks = fmi1CallbackFunctions() callbacks.logger = fmi1CallbackLoggerTYPE(logger) callbacks.allocateMemory = fmi1CallbackAllocateMemoryTYPE( allocateMemory) callbacks.freeMemory = fmi1CallbackFreeMemoryTYPE(freeMemory) callbacks.stepFinished = None elif options['fmu_ver'] == 2: callbacks = fmi2CallbackFunctions() callbacks.logger = fmi2CallbackLoggerTYPE(logger) callbacks.allocateMemory = fmi2CallbackAllocateMemoryTYPE( allocateMemory) callbacks.freeMemory = fmi2CallbackFreeMemoryTYPE(freeMemory) else: Exception("Please provide an existing FMU version") self.vrs = {} for variable in self.modelDescription.modelVariables: self.vrs[variable.name] = variable.valueReference # tIPSL = IPSLtranslator(self.modelDescription.modelVariables) self.FMUoutput = [] for i in self.options['outputs']: self.FMUoutput.append(self.vrs[i]) self.createPin('out', self.outType, i) self.FMUinput = [] for i in self.options['inputs']: self.FMUinput.append(self.vrs[i]) self.createPin('in', self.inType, i) self.FMUinit = [] for i in self.options['x0']: self.FMUinit.append(self.vrs[i]) self.createPin('in', self.inType, i, "init") self.setInputCondition("edge{" + i + "}", 'init') if options['type'] == 'CS': if options['fmu_ver'] == 1: self.myFMU = FMU1Slave(guid=self.modelDescription.guid, unzipDirectory=self.unzipdir, modelIdentifier=self.modelDescription. coSimulation.modelIdentifier, instanceName=options['model']) self.myFMU.instantiate(functions=callbacks) elif options['fmu_ver'] == 2: self.myFMU = FMU2Slave(guid=self.modelDescription.guid, unzipDirectory=self.unzipdir, modelIdentifier=self.modelDescription. coSimulation.modelIdentifier, instanceName=options['model']) self.myFMU.instantiate(callbacks=callbacks) self.myFMU.setupExperiment(startTime=self.Tstart, tolerance=self.Tolerance) else: Exception("Please provide an existing FMU version") elif options['type'] == 'ME': if options['fmu_ver'] == 1: self.myFMU = FMU1Model(guid=self.modelDescription.guid, unzipDirectory=self.unzipdir, modelIdentifier=self.modelDescription. modelExchange.modelIdentifier, instanceName=options['model']) # instantiate FMU self.myFMU.instantiate(functions=callbacks) self.myFMU.setTime(self.Tstart) elif options['fmu_ver'] == 2: self.myFMU = FMU2Model(guid=self.modelDescription.guid, unzipDirectory=self.unzipdir, modelIdentifier=self.modelDescription. modelExchange.modelIdentifier, instanceName=options['model']) # instantiate FMU self.myFMU.instantiate(callbacks=callbacks) self.myFMU.setupExperiment(startTime=self.Tstart) else: Exception("Please provide an existing FMU version") if 'fixedStep' in options['solOpt']: self.fixed_step = options['solOpt']['fixedStep'] else: self.fixed_step = False self.inEvent = FMPYinput(self.myFMU, self.modelDescription, None) def doFunc(self): inputValues = [] FMUinputRefs = [] if self.inType == VALUETYPES.REAL: # for i in range(0, len(self.input)): # if self.options['inmask'][i] == 0: # The mask vector is used to separate initialization inputs (inmask=1) from regular causality="input" (inmask=0) for i in range(0, len(self.options['inputs'])): inputValues.append(self.input[i]['value']) FMUinputRefs.append(self.FMUinput[i]) else: print( "This function is not supported yet!" ) # figure out how to initialize fmu when the entire input vector is given self.myFMU.setReal(list(FMUinputRefs), list(inputValues)) # self.myFMU.setReal(list(self.FMUinput), list(inputValues)) if self.options[ 'dyn'] == 'full': #TODO: probably need to change all self.options['inputs'] into combination of self.options['inputs'] and self.options['x0'] # setup the numpy format for specifying input variables dt = [('time', np.float64)] dt += zip(self.options['inputs'], [np.float64] * len(self.options['inputs'])) # print the numpy format for specifying input variables just to make sure it's ok print(dt) # assign the input to input variables # pom = numpy.empty(len(inputValues),dtype=dt) if self.options['type'] == "ME": pom = numpy.empty( 2, dtype=dt ) # with ME it is necessary to assign first step value and last step value pom['time'] = [self.Tstart, self.Tstop] elif self.options['type'] == 'CS': pom = numpy.empty( 1, dtype=dt ) # with CS it is necessary just to assign one value for the entire period pom['time'] = self.Tstart for i in range(0, len(self.options['inputs'])): pom[self.options['inputs'][i]] = inputValues[ i] # assign all input values, time has been assigned previously print(pom) inputValues = pom result = simulate_fmu(self.options['fmu'], start_time=self.Tstart, stop_time=self.Tstop, timeout=self.Timeout, step_size=self.Tstep, input=inputValues, output=self.options['outputs']) print("result of simulate_fmu is " + str(result)) print("dtype is " + str(result.dtype)) for i in range(0, len(self.options['outputs'])): pom = result[self.options['outputs'][i]] print(pom) if self.outType == VALUETYPES.REAL: self.output[i]['value'] = pom[-1] elif self.outType == VALUETYPES.VECTOR: self.output[i]['value'] = pom elif self.options['dyn'] == 'step': time = self.time if self.options['type'] == 'CS': self.inEvent.apply(time) self.myFMU.doStep(currentCommunicationPoint=time, communicationStepSize=self.Tstep) self.time += self.Tstep elif self.options['type'] == 'ME': eps = 1.0e-13 # step ahead in time if self.fixed_step: if time + self.Tstep < self.Tstop + eps: self.t_next = time + self.Tstep # else: # break else: if time + eps >= self.t_next: # t_next has been reached # integrate to the next grid point self.t_next = round( time / self.Tstep) * self.Tstep + self.Tstep # gets the time of input event t_input_event = self.inEvent.apply(time) # check for input event input_event = t_input_event <= self.t_next if input_event: self.t_next = t_input_event # check the time of next event. time_event = None if self.options['fmu_ver'] == 1: time_event = self.myFMU.eventInfo.upcomingTimeEvent != fmi1False and self.myFMU.eventInfo.nextEventTime <= self.t_next elif self.options['fmu_ver'] == 2: time_event = self.myFMU.eventInfo.nextEventTimeDefined != fmi2False and self.myFMU.eventInfo.nextEventTime <= self.t_next else: Exception("Please provide an existing FMU version") if time_event and not self.fixed_step: self.t_next = self.myFMU.eventInfo.nextEventTime state_event = None if self.t_next - time > eps: # do one step state_event, time = self.solver.step(time, self.t_next) else: # skip time = self.t_next # set the time self.myFMU.setTime(time) # check for step event, e.g.dynamic state selection step_event = None if self.options['fmu_ver'] == 1: step_event = self.myFMU.completedIntegratorStep() elif self.options['fmu_ver'] == 2: step_event, _ = self.myFMU.completedIntegratorStep() step_event = step_event != fmi2False else: Exception("Please provide an existing FMU version") # handle events if input_event or time_event or state_event or step_event: # recorder.sample(time, force=True) if input_event: self.inEvent.apply(time=time, after_event=True) # handle events if self.options['fmu_ver'] == 1: self.myFMU.eventUpdate() elif self.options['fmu_ver'] == 2: # handle events self.myFMU.enterEventMode() self.myFMU.eventInfo.newDiscreteStatesNeeded = fmi2True self.myFMU.eventInfo.terminateSimulation = fmi2False # update discrete states while self.myFMU.eventInfo.newDiscreteStatesNeeded != fmi2False and self.myFMU.eventInfo.terminateSimulation == fmi2False: self.myFMU.newDiscreteStates() self.myFMU.enterContinuousTimeMode() else: Exception("Please provide an existing FMU version") self.solver.reset(time) else: Exception("Please provide either 'ME' or 'CS' type.") pom = self.myFMU.getReal(list(self.FMUoutput)) for i in range(0, len(self.FMUoutput)): self.output[i]['value'] = pom[i] print(pom) else: Exception( "Simulation option 'dyn' can be either 'step' or 'full'.") def compile(self): if self.firstRun == 0: inputValues = [] FMUinputRefs = [] if self.inType == VALUETYPES.REAL: # for i in range(0, len(self.input)): # if self.options['inmask'][i] == 1: # The mask vector is used to separate initialization inputs (inmask=1) from regular causality="input" (inmask=0) for i in range(0, len(self.options['x0'])): inputValues.append( self.input[i + len(self.options['inputs'])]['value']) FMUinputRefs.append(self.FMUinit[i]) else: print( "This function is not supported yet!" ) # figure out how to initialize fmu when the entire input vector is given # self.myFMU.setReal(list(self.FMUinput), list(inputValues)) self.myFMU.setReal(list(FMUinputRefs), list(inputValues)) self.firstRun -= 1 if self.firstRun < 0: self.firstRun = 0 self.time = self.Tstart self.t_next = self.Tstart self.myFMU.reset() if self.options['type'] == 'CS': if self.options['fmu_ver'] == 1: self.myFMU.initialize() elif self.options['fmu_ver'] == 2: self.myFMU.setupExperiment(startTime=self.Tstart, tolerance=self.Tolerance) self.myFMU.enterInitializationMode() self.myFMU.exitInitializationMode() else: Exception("Please provide an existing FMU version") elif self.options['type'] == 'ME': if self.options['fmu_ver'] == 1: self.myFMU.initialize() elif self.options['fmu_ver'] == 2: self.myFMU.setupExperiment(startTime=self.Tstart) self.myFMU.enterInitializationMode() self.myFMU.exitInitializationMode() # event iteration self.myFMU.eventInfo.newDiscreteStatesNeeded = fmi2True self.myFMU.eventInfo.terminateSimulation = fmi2False while self.myFMU.eventInfo.newDiscreteStatesNeeded == fmi2True and self.myFMU.eventInfo.terminateSimulation == fmi2False: # update discrete states self.myFMU.newDiscreteStates() self.myFMU.enterContinuousTimeMode() # self.fmu.initialize() else: Exception("Please provide an existing FMU version") solver_args = { 'nx': self.modelDescription.numberOfContinuousStates, 'nz': self.modelDescription.numberOfEventIndicators, 'get_x': self.myFMU.getContinuousStates, 'set_x': self.myFMU.setContinuousStates, 'get_dx': self.myFMU.getDerivatives, 'get_z': self.myFMU.getEventIndicators } if 'solver' in self.options['solOpt']: if self.options['solOpt']['solver'] == 'CVODE': from fmpy.sundials import CVodeSolver self.solver = CVodeSolver( set_time=self.myFMU.setTime, startTime=self.Tstart, maxStep=(self.Tstop - self.Tstart) / 50., relativeTolerance=0.001, **solver_args) else: Exception("Please provide either 'ME' or 'CS' type.") def decompile(self): self.firstRun = 1 self.myFMU.terminate() self.myFMU.freeInstance() if self.options['type'] == 'ME': del self.solver shutil.rmtree(self.unzipdir)
class FmuCsAdapter(): ''' FMU CoSimulation adapter for energysim ''' eps = 1.0e-13 def __init__(self, fmu_location, instanceName=None, start_time=0, tolerance=1e-06, stop_time = 100, step_size = 1.0e-3, inputs = [], outputs = [], show_fmu_info = False, exist=False, validate=True): assert (fmu_location is not None), "Must specify FMU location" self.fmu_location = fmu_location if instanceName is None: instanceID = int(random()*1000) self.instanceName = 'fmu'+str(instanceID) print(self.instanceName) else: self.instanceName = instanceName self.exist = exist self.tolerance = tolerance self.start_time = start_time self.stop_time = stop_time self.output_interval = step_size self.inputs = inputs self.outputs = outputs self.validate=validate if show_fmu_info: dump(self.fmu_location) self.setup() def setup(self): self.t_next = self.start_time if self.exist: self.unzipDir = self.fmu_location else: self.unzipDir = extract(self.fmu_location) self.modelDescription = read_model_description(self.fmu_location, validate=self.validate) self.is_fmi1 = self.modelDescription.fmiVersion == '1.0' logger = printLogMessage if self.is_fmi1: callbacks = fmi1CallbackFunctions() callbacks.logger = fmi1CallbackLoggerTYPE(logger) callbacks.allocateMemory = fmi1CallbackAllocateMemoryTYPE(allocateMemory) callbacks.freeMemory = fmi1CallbackFreeMemoryTYPE(freeMemory) callbacks.stepFinished = None else: callbacks = fmi2CallbackFunctions() callbacks.logger = fmi2CallbackLoggerTYPE(logger) callbacks.allocateMemory = fmi2CallbackAllocateMemoryTYPE(allocateMemory) callbacks.freeMemory = fmi2CallbackFreeMemoryTYPE(freeMemory) #define var values for input and output variables self.vrs = {} for variable in self.modelDescription.modelVariables: self.vrs[variable.name] = [variable.valueReference, variable.type] if self.is_fmi1: self.fmu = FMU1Slave(guid = self.modelDescription.guid, unzipDirectory=self.unzipDir, modelIdentifier=self.modelDescription.coSimulation.modelIdentifier, instanceName=self.instanceName) self.fmu.instantiate(functions=callbacks) else: self.fmu = FMU2Slave(guid = self.modelDescription.guid, unzipDirectory=self.unzipDir, modelIdentifier=self.modelDescription.coSimulation.modelIdentifier, instanceName=self.instanceName) self.fmu.instantiate(callbacks=callbacks) self.fmu.setupExperiment(startTime=self.start_time, tolerance=self.tolerance) self.input = Input(self.fmu, self.modelDescription, None) def set_start_values(self, init_dict): apply_start_values(self.fmu, self.modelDescription, init_dict, apply_default_start_values=False) def set_value(self,parameterName,Value): ''' Must specify parameters and values in list format ''' for i, j in zip(parameterName, Value): if self.vrs[i][1] == 'Real': self.fmu.setReal([self.vrs[i][0]], [j]) elif self.vrs[i][1] in ['Integer', 'Enumeration']: self.fmu.setInteger([self.vrs[i][0]], [j]) elif self.vrs[i][1] == 'Boolean': if isinstance(j, str): if j.lower() not in ['true', 'false']: raise Exception('The value "%s" for variable "%s" could not be converted to Boolean' % (j, i)) else: j = j.lower() == 'true' self.fmu.setBoolean([self.vrs[i][0]], [bool(j)]) elif self.vrs[i][1] == 'String': self.fmu.setString([self.vrs[i][0]], [j]) def get_value(self,parameterName, time): ''' Must specify parameter in a list format. ''' values_ = [] for i in parameterName: if self.vrs[i][1] == 'Real': temp = self.fmu.getReal([self.vrs[i][0]]) elif self.vrs[i][1] in ['Integer', 'Enumeration']: temp = self.fmu.getInteger([self.vrs[i][0]]) elif self.vrs[i][1] == 'Boolean': temp = self.fmu.getBoolean([self.vrs[i][0]]) elif self.vrs[i][1] == 'String': temp = self.fmu.getString([self.vrs[i][0]]) values_.append(temp[0]) return values_ def reset(self): self.fmu.reset() def init(self): if self.is_fmi1: #self.input.apply(0) self.fmu.initialize() else: self.fmu.enterInitializationMode() #input.apply(0) self.fmu.exitInitializationMode() def set_inital_inputs(self, starting_values): from fmpy.simulation import apply_start_values apply_start_values(fmu = self.fmu, model_description = self.modelDescription, start_values = starting_values, apply_default_start_values=False) def setInput(self, inputValues): self.inputVariables = [] for i in self.inputs: self.inputVariables.append(self.vrs[i][0]) self.fmu.setReal(list(self.inputVariables), list(inputValues)) def getOutput(self): self.outputVariables = [] for i in self.outputs: self.outputVariables.append(self.vrs[i][0]) return self.fmu.getReal(list(self.outputVariables)) def step_advanced(self, time, step_size=None): #step ahead in time self.input.apply(time) if step_size is None: self.fmu.doStep(currentCommunicationPoint = time, communicationStepSize = self.output_interval) else: self.fmu.doStep(currentCommunicationPoint = time, communicationStepSize = step_size) # TODO - while a!=0: # self.fmu.setFMUstate(state) ## print(f"Didnt work with stepsize = {step_size}, new stepsize = {step_size/2}.") # step_size = step_size/2 # a = self.fmu.doStep(currentCommunicationPoint = time, communicationStepSize = step_size) # self.fmu.freeFMUstate(state) # print(f'returning to master: status = {a}, step size = {step_size}.') # return a, step_size def step_v2(self,time, stepsize): self.input.apply(time) return self.fmu.doStep(currentCommunicationPoint = time, communicationStepSize = stepsize) def step(self, time): #step ahead in time self.input.apply(time) return self.fmu.doStep(currentCommunicationPoint = time, communicationStepSize = self.output_interval) def cleanUp(self): self.fmu.terminate() self.fmu.freeInstance() # shutil.rmtree(self.unzipDir) def simulate(self, timeout=180): from fmpy import simulate_fmu result = simulate_fmu(self.fmu_location, start_time = self.start_time, stop_time =self.stop_time, timeout = timeout, output_interval = self.output_interval, output = self.outputs) return result