Exemple #1
0
class JMIDAESens(Implicit_Problem):
    """
    An Assimulo Implicit Model extended to JMI interface with support for 
    sensitivities.
    """
    def __init__(self, model, input=None, result_file_name='', start_time=0.0):
        """
        Sets the initial values.
        """
        if input != None and not isinstance(input[0],list):
            input = ([input[0]], input[1])
        
        self._model = model
        self.input = input
        
        #Set start time to the model
        self._model.t = start_time
        
        self.t0 = start_time
        self.y0 = N.append(self._model.real_x,self._model.real_w)
        self.yd0 = N.append(self._model.real_dx,[0]*len(self._model.real_w))
        #Sets the algebraic components of the model
        self.algvar = [1.0]*len(self._model.real_x) + [0.0]*len(self._model.real_w) 
        
        #Used for determine if there are discontinuities
        [f_nbr, g_nbr] = self._model.jmimodel.dae_get_sizes() 
        [f0_nbr, f1_nbr, fp_nbr, g0_nbr] = self._model.jmimodel.init_get_sizes()
        
        if g_nbr > 0:
            raise JMIModel_Exception("Hybrid models with event functions are currently not supported.")
        
        if f_nbr == 0:
            raise Exception("The JMI framework does not support 'simulation' of 0-dimension systems. Use the FMI framework.")

        
        #Construct the input nominal vector
        if self.input != None:
            self._input_nominal = N.array([1.0]*len(self.input[0]))
            if (self._model.get_scaling_method() == jmi.JMI_SCALING_VARIABLES):
                for i in range(len(self.input[0])):
                    val_ref = self._model._xmldoc.get_value_reference(self.input[0][i])
                    for j, nom in enumerate(self._model._xmldoc.get_u_nominal()):
                        if val_ref == nom[0]:
                            if nom[1] == None:
                                self._input_nominal[i] = 1.0
                            else:
                                self._input_nominal[i] = nom[1]
        
        if self._model.has_cppad_derivatives():
            self.jac = self.j #Activates the jacobian
        
        #Default values
        self.export = ResultWriterDymolaSensitivity(model)
        
        #Determine the result file name
        if result_file_name == '':
            self.result_file_name = model.get_name()+'_result.txt'
        else:
            self.result_file_name = result_file_name
        
        #Internal values
        self._parameter_names = [
            name[1] for name in self._model.get_p_opt_variable_names()]
        self._parameter_valref = [
            name[0] for name in self._model.get_p_opt_variable_names()]
        self._parameter_pos = [jmi._translate_value_ref(x)[0] for x in self._parameter_valref]
        self._sens_matrix = [] #Sensitivity matrix
        self._f_nbr = f_nbr #Number of equations
        self._f0_nbr = f0_nbr #Number of initial equations
        self._g_nbr = g_nbr #Number of event indicatiors
        self._x_nbr = len(self._model.real_x) #Number of differentiated
        self._w_nbr = len(self._model.real_w) #Number of algebraic
        self._dx_nbr = len(self._model.real_dx) #Number of derivatives
        self._p_nbr = len(self._parameter_names) #Number of parameters
        self._write_header = True
        self._input_names = [k[1] for k in sorted(model.get_u_variable_names())]

        #Used for logging
        self._logLevel = logging.CRITICAL
        self._log = createLogger(model, self._logLevel)
        
        #Set the start values to the parameters.
        if self._parameter_names:
            self.p0 = N.array([])
            for i,n in enumerate(self._parameter_names):
                self.p0 = N.append(self.p0, self._model.z[self._parameter_pos[i]])
                self._sens_matrix += [[]] 
            self.pbar = N.array([N.abs(x) if N.abs(x) > 0 else 1.0 for x in self.p0])
            self._p_nbr = len(self.p0) #Number of parameters
        else:
            self._p_nbr = 0
            
        #Initial values for sensitivity
        if self._p_nbr > 0:
            self.yS0 = self._sens_init()

        self._log.debug('Number of parameters: ' +str(self._p_nbr))
    
    def _sens_init(self):
        """
        Calculates the initial values of the sensitivity.
        """
        yS0 = N.zeros((self._p_nbr,self._f_nbr))
        
        if self._f0_nbr != self._f_nbr:
            #Evaluating the jacobian
            #-Setting options
            #Used to give independent_vars full control
            z_l = N.array([1]*len(self._model.z),dtype=N.int32) 
            #Derivation with respect to these variables
            independent_vars = [jmi.JMI_DER_DX, jmi.JMI_DER_X, jmi.JMI_DER_W, 
                                jmi.JMI_DER_PI, jmi.JMI_DER_PD] 
            sparsity = jmi.JMI_DER_DENSE_ROW_MAJOR
            evaluation_options = jmi.JMI_DER_CPPAD#jmi.JMI_DER_SYMBOLIC
            
            #-Evaluating
            #Matrix that hold information about dx and dw
            dFdxw = N.zeros(self._f0_nbr*(self._x_nbr+self._w_nbr)) 
            #Output x+w
            self._model.jmimodel.init_dF0(
                evaluation_options, sparsity, independent_vars[1:3], z_l, dFdxw) 
            
            #Matrix that hold information about dx'
            dFddx = N.zeros(self._x_nbr*self._f0_nbr) 
            #Output dx'
            self._model.jmimodel.init_dF0(
                evaluation_options, sparsity, independent_vars[0], z_l, dFddx) 
            
            #Matrix that hold information about dp
            dFdp = N.zeros(self._p_nbr*self._f0_nbr) 
            #Output dp
            z_l = N.array([0]*len(self._model.z),dtype=N.int32) 
            for i in self._parameter_pos:
                z_l[i] = 1
            self._model.jmimodel.init_dF0(
                evaluation_options, sparsity, independent_vars[3:], z_l, dFdp) 
            
            #-Vector manipulation
            dFdxw = dFdxw.reshape(self._f0_nbr,self._x_nbr+self._w_nbr)[self._f_nbr:,:]
            dFddx = dFddx.reshape(self._f0_nbr,self._dx_nbr)[self._f_nbr:,:]
            dFdp  = dFdp.reshape(self._f0_nbr,self._p_nbr)[self._f_nbr:,:]

            p_order = N.zeros(len(self._parameter_pos),dtype=int)
            p_sort = N.sort(self._parameter_pos)
            for ind,val in enumerate(p_sort):
                p_order[self._parameter_pos.index(val)]=ind
            
            #print "Param order, ", self._model.get_p_opt_variable_names(), p_order
            dFdp = N.transpose(N.transpose(dFdp)[p_order])

            yS0= N.transpose(N.linalg.lstsq(dFdxw,-dFdp)[0])
        
        return yS0
    
    def res(self, t, y, yd, p=None):
        """
        The residual function for an DAE problem.
        """
        #Moving data to the model
        self._model.t = t
        self._model.real_x = y[0:self._x_nbr]
        self._model.real_w = y[self._x_nbr:self._f_nbr]
        self._model.real_dx = yd[0:self._dx_nbr]
        
        #Set the free parameters
        if not p==None:
            for ind, val in enumerate(p):
                self._model.z[self._parameter_pos[ind]] = val
            
        #Sets the inputs, if any
        if self.input!=None:
            self._model.set(self.input[0], self.input[1].eval(t)[0,:])
        
        #Evaluating the residual function
        residual = N.array([.0]*self._f_nbr)
        self._model.jmimodel.dae_F(residual)

        return residual
        
    def j(self, c, t, y, yd, sw=None, p=None):
        """
        The jacobian function for an DAE problem.
        """
        #Moving data to the model
        self._model.t = t
        self._model.real_x = y[0:self._x_nbr]
        self._model.real_w = y[self._x_nbr:self._f_nbr]
        self._model.real_dx = yd[0:self._dx_nbr]
        
        #Set the free parameters
        if not p==None:
            for ind, val in enumerate(p):
                self._model.z[self._parameter_pos[ind]] = val
        
        #Sets the inputs, if any
        if self.input!=None:
            self._model.set(self.input[0], self.input[1].eval(t)[0,:])
        
        #Evaluating the jacobian
        #-Setting options
        #Used to give independent_vars full control
        z_l = N.array([1]*len(self._model.z),dtype=N.int32) 
        #Derivation with respect to these variables
        independent_vars = [jmi.JMI_DER_DX, jmi.JMI_DER_X, jmi.JMI_DER_W] 
        sparsity = jmi.JMI_DER_DENSE_ROW_MAJOR
        evaluation_options = jmi.JMI_DER_CPPAD#jmi.JMI_DER_SYMBOLIC
        
        #-Evaluating
        #Matrix that hold information about dx and dw
        Jac = N.zeros(self._f_nbr**2) 
        #Output x+w
        self._model.jmimodel.dae_dF(
            evaluation_options, sparsity, independent_vars[1:], z_l, Jac) 
        
        #Matrix that hold information about dx'
        dx = N.zeros(len(self._model.real_dx)*self._f_nbr) 
        #Output dx'
        self._model.jmimodel.dae_dF(
            evaluation_options, sparsity, independent_vars[0], z_l, dx) 
        dx = dx*c #Scale
        
        #-Vector manipulation
        Jac = Jac.reshape(self._f_nbr,self._f_nbr)
        dx = dx.reshape(self._f_nbr,self._dx_nbr)
        Jac[:,0:self._dx_nbr] += dx

        return Jac
        
    def handle_result(self, solver, t ,y, yd):
        """
        Post processing (stores the time points and the sensitivity result).
        """
        if solver.report_continuously:
            if self._write_header:
                self._write_header = False
                self.export.write_header(file_name=self.result_file_name)
                
            p_data = []
            for i in range(self._p_nbr):
                p_data += [solver.interpolate_sensitivity(t, 0, i)]
            
            # extends the time array with the states columnwise
            data = N.append(t,yd[0:len(self._model.real_dx)])
            data = N.append(data, y[0:len(self._model.real_x)])
            if self.input!=None:
                input_data = N.ones(len(self._input_names))*self._model.real_u
                input_eval = self.input[1].eval(float(t))[0,:]
                for i,n in enumerate(self.input[0]):
                    input_data[self._input_names.index(n)] = input_eval[i]/self._input_nominal[i]
                data = N.append(data, input_data)
            else:
                data = N.append(data,N.ones(len(self._model.real_u))*self._model.real_u)
            data = N.append(data, y[len(self._model.real_x):len(self._model.real_x)+len(self._model.real_w)])
            
            for i in range(len(p_data)):
                data = N.append(data, p_data[i])
            
            self.export.write_point(data)
        else:
            solver.t_sol  += [t]
            solver.y_sol  += [y]
            solver.yd_sol += [yd]
            
            #Store the sensitivity matrix
            for i in range(self._p_nbr):
                self._sens_matrix[i] += [solver.interpolate_sensitivity(t, 0, i)]
    
    def finalize(self, solver):
        if solver.report_continuously:
            self.export.write_finalize()
    
    def get_sens_result(self):
        """
        Returns the sensitivity results together with the names.
        
        Returns::
        
            parameter_names, sensitivity_matrix = JMIDAESens.get_sens_result()
                
            parameters_names -- 
                The names of the parameters for which sensitivities have been 
                calculated.
                                       
            sensitivity_matrix -- 
                A matrix containing the sensitivities for all the parameters. 
                sensitivity_matrix[0], gives the result for the first parameter 
                in the parameters_names list.
        """
        for i in range(self._p_nbr):
            self._sens_matrix[i] = N.array(
                self._sens_matrix[i]).reshape(-1,self._f_nbr)
            
        return self._parameter_names, self._sens_matrix
        
    def _set_logging_level(self, level):
        if bool(level):
            self._log.setLevel(logging.DEBUG) #Log all entries
        else:
            self._log.setLevel(50) #Log nothing (log nothing below level 50)
    
    def _get_logging_level(self):
        return self._logLevel
        
    log = property(fget=_get_logging_level, fset=_set_logging_level, doc = 
    """
    Property for accessing the logging level. Determines if the logging should 
    be activated (True) or deactivated (False).
    """)
Exemple #2
0
    def __init__(self, model, input=None, result_file_name='', start_time=0.0):
        """
        Sets the initial values.
        """
        if input != None and not isinstance(input[0],list):
            input = ([input[0]], input[1])
        
        self._model = model
        self.input = input
        
        #Set start time to the model
        self._model.t = start_time
        
        self.t0 = start_time
        self.y0 = N.append(self._model.real_x,self._model.real_w)
        self.yd0 = N.append(self._model.real_dx,[0]*len(self._model.real_w))
        #Sets the algebraic components of the model
        self.algvar = [1.0]*len(self._model.real_x) + [0.0]*len(self._model.real_w) 
        
        #Used for determine if there are discontinuities
        [f_nbr, g_nbr] = self._model.jmimodel.dae_get_sizes() 
        [f0_nbr, f1_nbr, fp_nbr, g0_nbr] = self._model.jmimodel.init_get_sizes()
        
        if g_nbr > 0:
            raise JMIModel_Exception("Hybrid models with event functions are currently not supported.")
        
        if f_nbr == 0:
            raise Exception("The JMI framework does not support 'simulation' of 0-dimension systems. Use the FMI framework.")

        
        #Construct the input nominal vector
        if self.input != None:
            self._input_nominal = N.array([1.0]*len(self.input[0]))
            if (self._model.get_scaling_method() == jmi.JMI_SCALING_VARIABLES):
                for i in range(len(self.input[0])):
                    val_ref = self._model._xmldoc.get_value_reference(self.input[0][i])
                    for j, nom in enumerate(self._model._xmldoc.get_u_nominal()):
                        if val_ref == nom[0]:
                            if nom[1] == None:
                                self._input_nominal[i] = 1.0
                            else:
                                self._input_nominal[i] = nom[1]
        
        if self._model.has_cppad_derivatives():
            self.jac = self.j #Activates the jacobian
        
        #Default values
        self.export = ResultWriterDymolaSensitivity(model)
        
        #Determine the result file name
        if result_file_name == '':
            self.result_file_name = model.get_name()+'_result.txt'
        else:
            self.result_file_name = result_file_name
        
        #Internal values
        self._parameter_names = [
            name[1] for name in self._model.get_p_opt_variable_names()]
        self._parameter_valref = [
            name[0] for name in self._model.get_p_opt_variable_names()]
        self._parameter_pos = [jmi._translate_value_ref(x)[0] for x in self._parameter_valref]
        self._sens_matrix = [] #Sensitivity matrix
        self._f_nbr = f_nbr #Number of equations
        self._f0_nbr = f0_nbr #Number of initial equations
        self._g_nbr = g_nbr #Number of event indicatiors
        self._x_nbr = len(self._model.real_x) #Number of differentiated
        self._w_nbr = len(self._model.real_w) #Number of algebraic
        self._dx_nbr = len(self._model.real_dx) #Number of derivatives
        self._p_nbr = len(self._parameter_names) #Number of parameters
        self._write_header = True
        self._input_names = [k[1] for k in sorted(model.get_u_variable_names())]

        #Used for logging
        self._logLevel = logging.CRITICAL
        self._log = createLogger(model, self._logLevel)
        
        #Set the start values to the parameters.
        if self._parameter_names:
            self.p0 = N.array([])
            for i,n in enumerate(self._parameter_names):
                self.p0 = N.append(self.p0, self._model.z[self._parameter_pos[i]])
                self._sens_matrix += [[]] 
            self.pbar = N.array([N.abs(x) if N.abs(x) > 0 else 1.0 for x in self.p0])
            self._p_nbr = len(self.p0) #Number of parameters
        else:
            self._p_nbr = 0
            
        #Initial values for sensitivity
        if self._p_nbr > 0:
            self.yS0 = self._sens_init()

        self._log.debug('Number of parameters: ' +str(self._p_nbr))
Exemple #3
0
def write_data(simulator,write_scaled_result=False, result_file_name=''):
    """
    Writes simulation data to a file. Takes as input a simulated model.
    """
    #Determine the result file name
    if result_file_name == '':
        result_file_name=simulator.problem._model.get_name()+'_result.txt'
    
    if isinstance(simulator.problem, JMIDAE):
        
        model = simulator.problem._model
        problem = simulator.problem
        
        t = N.array(simulator.t_sol)
        y = N.array(simulator.y_sol)
        yd = N.array(simulator.yd_sol)
        if simulator.problem.input:
            u_name = [k[1] for k in sorted(model.get_u_variable_names())]
            #u = N.zeros((len(t), len(u_name)))
            u = N.ones((len(t), len(u_name)))*model.real_u
            u_mat = simulator.problem.input[1].eval(t)

            if not isinstance(simulator.problem.input[0],list):
                u_input_name = [simulator.problem.input[0]]
            else:
                u_input_name = simulator.problem.input[0]

            for i,n in enumerate(u_input_name):
                u[:,u_name.index(n)] = u_mat[:,i]/problem._input_nominal[i]
        else:
            u = N.ones((len(t),len(model.real_u)))*model.real_u
        
        # extends the time array with the states columnwise
        data = N.c_[t,yd[:,0:len(model.real_dx)]]
        data = N.c_[data, y[:,0:len(model.real_x)]]
        data = N.c_[data, u]
        data = N.c_[data, y[
            :,len(model.real_x):len(model.real_x)+len(model.real_w)]]

        export_result_dymola(model,data,scaled=write_scaled_result, \
                                file_name=result_file_name)
    elif isinstance(simulator.problem, JMIDAESens):
        
        model = simulator.problem._model
        problem = simulator.problem
        
        t = N.array(simulator.t_sol)
        y = N.array(simulator.y_sol)
        yd = N.array(simulator.yd_sol)
        if simulator.problem.input:
            u_name = [k[1] for k in sorted(model.get_u_variable_names())]
            #u = N.zeros((len(t), len(u_name)))
            u = N.ones((len(t), len(u_name)))*model.real_u
            u_mat = simulator.problem.input[1].eval(t)
            
            if not isinstance(simulator.problem.input[0],list):
                u_input_name = [simulator.problem.input[0]]
            else:
                u_input_name = simulator.problem.input[0]
            
            for i,n in enumerate(u_input_name):
                u[:,u_name.index(n)] = u_mat[:,i]/problem._input_nominal[i]
        else:
            u = N.ones((len(t),len(model.real_u)))*model.real_u
        
        p_names , p_data = simulator.problem.get_sens_result()
        
        # extends the time array with the states columnwise
        data = N.c_[t,yd[:,0:len(model.real_dx)]]
        data = N.c_[data, y[:,0:len(model.real_x)]]
        data = N.c_[data, u]
        data = N.c_[data, y[
            :,len(model.real_x):len(model.real_x)+len(model.real_w)]]

        for i in range(len(p_data)):
            data = N.c_[data, p_data[i]]

        export = ResultWriterDymolaSensitivity(model)
        export.write_header(scaled=write_scaled_result, \
                            file_name=result_file_name)
        map(export.write_point,(row for row in data))
        export.write_finalize()
        
    else:
        raise NotImplementedError