def test_input_continuous(self): t = np.array( [ 0, 1, 2, 3]) y = np.array([[ 0, 0, 3, 3], [-1, 0, 1, 2]]) # extrapolate left (hold) v1, v2 = Input.interpolate(-1, t, y) self.assertEqual(v1, 0) self.assertEqual(v2, -1) # hit sample v1, v2 = Input.interpolate(1, t, y) self.assertEqual(v1, 0) self.assertEqual(v2, 0) # interpolate (linear) v1, v2 = Input.interpolate(1.5, t, y) self.assertAlmostEqual(v1, 1.5) self.assertAlmostEqual(v2, 0.5) # extrapolate right (hold) v1, v2 = Input.interpolate(4, t, y) self.assertEqual(v1, 3) self.assertEqual(v2, 2)
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 test_event_detection(self): fmx = sys.float_info.max # no event t = np.array([0.0, 1.0]) self.assertEqual(fmx, Input.nextEvent(0.8, t), "Expecting no events") # time grid with events at 0.5 and 0.8 t = np.array( [0.1, 0.2, 0.3, 0.4, 0.5, 0.5, 0.6, 0.7, 0.8, 0.8, 0.8, 0.9, 1.0]) self.assertEqual(0.5, Input.nextEvent(0.0, t), "Expecting first event before first sample") self.assertEqual(0.5, Input.nextEvent(0.2, t), "Expecting first event before first event") self.assertEqual(0.8, Input.nextEvent(0.5, t), "Expecting second event at first event") self.assertEqual( 0.8, Input.nextEvent(0.6, t), "Expecting second event between first and second event") self.assertEqual( fmx, Input.nextEvent(0.8, t), "Expecting no more events after second (multi) event") self.assertEqual(fmx, Input.nextEvent(1.0, t), "Expecting no more events after last event") self.assertEqual(fmx, Input.nextEvent(2.0, t), "Expecting no more events after last sample")
def test_continuous_signal_events(self): dtype = np.dtype([('time', np.float64)]) model_description = ModelDescription() # no event signals = np.array([(0,), (1,)], dtype=dtype) t_events = Input.findEvents(signals, model_description) self.assertEqual([inf], t_events) # time grid with events at 0.5 and 0.8 signals = np.array(list(zip([0.1, 0.2, 0.3, 0.4, 0.5, 0.5, 0.6, 0.7, 0.8, 0.8, 0.8, 0.9, 1.0])), dtype=dtype) t_events = Input.findEvents(signals, model_description) self.assertTrue(np.all([0.5, 0.8, inf] == t_events))
def test_single_sample(self): t = np.array([0]) y = np.array([2]) # "interpolate" input with only one sample v = Input.interpolate(1, t, y) self.assertEqual(v, 2)
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 test_input_discrete(self): t = np.array([0, 1, 1, 2]) y = np.array([[0, 0, 3, 3]]) # extrapolate left v = Input.interpolate(-1, t, y) self.assertEqual(v, 0) # hit sample v = Input.interpolate(0, t, y) self.assertEqual(v, 0) # interpolate v = Input.interpolate(0.5, t, y) self.assertEqual(v, 0) # before event v = Input.interpolate(1, t, y) self.assertEqual(v, 0) # after event v = Input.interpolate(1, t, y, after_event=True) self.assertEqual(v, 3) # extrapolate right v = Input.interpolate(0, t, y) self.assertEqual(v, 0)
def test_input_discrete(self): t = np.array([0, 1, 1, 1, 2]) y = np.array([[0, 0, 4, 3, 3]]) # extrapolate left v = Input.interpolate(-1, t, y) self.assertEqual(v, 0, "Expecting first value") # hit sample v = Input.interpolate(0, t, y) self.assertEqual(v, 0, "Expecting value at sample") # interpolate v = Input.interpolate(0.5, t, y) self.assertEqual(v, 0, "Expecting to hold previous value") # before event v = Input.interpolate(1, t, y) self.assertEqual(v, 0, "Expecting value before event") # after event v = Input.interpolate(1, t, y, after_event=True) self.assertEqual(v, 3, "Expecting value after event") # extrapolate right v = Input.interpolate(3, t, y) self.assertEqual(v, 3, "Expecting last value")
def test_input_continuous(self): t = np.array([0, 1, 2, 3]) y = np.array([[0, 0, 3, 3], [-1, 0, 1, 2]]) # extrapolate left (hold) (u1, u2), (du1, du2) = Input.interpolate(-1, t, y) self.assertTrue((u1, u2) == (0, -1)) self.assertTrue((du1, du2) == (0, 0)) # hit sample (u1, u2), (du1, du2) = Input.interpolate(1, t, y) self.assertTrue((u1, u2) == (0, 0)) self.assertTrue((du1, du2) == (0, 1)) # interpolate (linear) (u1, u2), (du1, du2) = Input.interpolate(1.5, t, y) self.assertTrue((u1, u2) == (1.5, 0.5)) self.assertTrue((du1, du2) == (3, 1)) # extrapolate right (hold) (u1, u2), (du1, du2) = Input.interpolate(4, t, y) self.assertTrue((u1, u2) == (3, 2)) self.assertTrue((du1, du2) == (0, 0))
def test_discrete_signal_events(self): # model with one discrete variable 'x' model_description = ModelDescription() variable = ScalarVariable('x', 0) variable.variability = 'discrete' model_description.modelVariables.append(variable) # discrete events at 0.1 and 0.4 signals = np.array([(0.0, 0), (0.1, 0), (0.2, 1), (0.3, 1), (0.4, 2)], dtype=np.dtype([('time', np.float64), ('x', np.int)])) t_event = Input.findEvents(signals, model_description) self.assertTrue(np.all([0.2, 0.4, inf] == t_event))
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)
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)
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)
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 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