Esempio n. 1
0
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
Esempio n. 2
0
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)
Esempio n. 3
0
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