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). """)
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 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