def solve_consistent_initial_conditions(model, time, solver, tee=False, allow_skip=True, suppress_warnings=False): """ Solves a model with all Constraints and Blocks deactivated except at the initial value of the Set time. Reactivates Constraints and Blocks that got deactivated. Args: model: Model that will be solved time: Set whose initial conditions will remain active for solve solver: Something that implements a solve method that accepts a model and tee keyword as arguments tee: tee argument that will be sent to solver's solve method allow_skip: If True, KeyErrors due to Constraint.Skip being used will be ignored suppress_warnings: If True, warnings due to ignored KeyErrors will be suppressed Returns: The object returned by the solver's solve method """ # Need to deactivate discretization equations, wrt time, at t == 0 # This is challenging as the only way (to my knowledge) to do this # is to identify_variables in the expression, find the (assume only one?) # DerivativeVar, and access its get_continuousset_list # I would like a get_continuousset_list for discretization equations. # Possibly as a ComponentMap, possibly as an attribute of some new # DiscEquation subclass of Constraint # Until I have this, this function will only work for backward # discretization schemes # Also, would like to be able to check for zero degrees of freedom here scheme = time.get_discretization_info()['scheme'] if scheme != 'LAGRANGE-RADAU' and scheme != 'BACKWARD Difference': raise NotImplementedError('%s discretization scheme is not supported' % scheme) t0 = time.first() timelist = list(time)[1:] deactivated_dict = deactivate_model_at(model, time, timelist, allow_skip=allow_skip, suppress_warnings=suppress_warnings) result = solver.solve(model, tee=tee) for t in timelist: for comp in deactivated_dict[t]: comp.activate() return result
def test_deactivate_model_at(self): m = make_model() deactivate_model_at(m, m.time, m.time[2]) self.assertTrue(m.fs.con1[m.time[1]].active) self.assertFalse(m.fs.con1[m.time[2]].active) self.assertTrue(m.fs.con2[m.space[1]].active) self.assertFalse(m.fs.b1.con[m.time[2], m.space[1]].active) self.assertFalse(m.fs.b2[m.time[2], m.space.last()].active) self.assertTrue(m.fs.b2[m.time[2], m.space.last()].b3['a'].con['e'].active) deactivate_model_at(m, m.time, [m.time[1], m.time[3]]) # disc equations at time.first() self.assertFalse(m.fs.con1[m.time[1]].active) self.assertFalse(m.fs.con1[m.time[3]].active) self.assertFalse(m.fs.b1.con[m.time[1], m.space[1]].active) self.assertFalse(m.fs.b1.con[m.time[3], m.space[1]].active) with self.assertRaises(KeyError): deactivate_model_at(m, m.time, m.time[1], allow_skip=False, suppress_warnings=True)
def solve_setpoint(self, solver, **kwargs): """ This method performs a "real time optimization-type" solve on the model, using only the variables and constraints at the first point in time. The purpose is to calculate a (possibly steady state) setpoint. Parameters: solver: A Pyomo solver object that will be used to solve the model with only variables and constraints at t0 active. require_steady: Whether derivatives should be fixed to zero for the solve. Default is `True`. """ require_steady = kwargs.pop('require_steady', True) config = self.CONFIG(kwargs) model = self.mod time = self.time t0 = time.first() was_originally_active = ComponentMap([ (comp, comp.active) for comp in model.component_data_objects((Constraint, Block)) ]) non_initial_time = list(time)[1:] deactivated = deactivate_model_at( model, time, non_initial_time, allow_skip=True, suppress_warnings=True, ) was_fixed = ComponentMap() # Cache "important" values to re-load after solve init_input = list(self.vectors.input[:, t0].value) \ if VC.INPUT in self.categories else [] init_meas = list(self.vectors.measurement[:, t0].value) \ if VC.MEASUREMENT in self.categories else [] # Fix/unfix variables as appropriate # Order matters here. If a derivative is used as an IC, we still want # it to be fixed if steady state is required. if VC.MEASUREMENT in self.categories: self.vectors.measurement[:, t0].unfix() if VC.INPUT in self.categories: input_vars = self.vectors.input was_fixed = ComponentMap( (var, var.fixed) for var in input_vars[:, t0]) input_vars[:, t0].unfix() if VC.DERIVATIVE in self.categories: if require_steady == True: self.vectors.derivative[:, t0].fix(0.) self.setpoint_objective.activate() # Solve single-time point optimization problem # # If these sets do not necessarily exist, then I don't think # I can make any assertion about the number of degrees of freedom #dof = degrees_of_freedom(model) #if require_steady: # assert dof == len(self.INPUT_SET) #else: # assert dof == (len(self.INPUT_SET) + # len(self.DIFFERENTIAL_SET)) results = solver.solve(self, tee=config.tee) if results.solver.termination_condition == TerminationCondition.optimal: pass else: msg = 'Failed to solve for full state setpoint values' raise RuntimeError(msg) self.setpoint_objective.deactivate() # Revert changes. Again, order matters if VC.DERIVATIVE in self.categories: if require_steady == True: self.vectors.derivative[:, t0].unfix() if VC.MEASUREMENT in self.categories: self.vectors.measurement[:, t0].fix() # Reactivate components that were deactivated for t, complist in deactivated.items(): for comp in complist: if was_originally_active[comp]: comp.activate() # Fix inputs that were originally fixed if VC.INPUT in self.categories: for var in self.vectors.input[:, t0]: if was_fixed[var]: var.fix() setpoint_ctype = (DiffVar, AlgVar, InputVar, FixedVar, DerivVar, MeasuredVar) for var in self.component_objects(setpoint_ctype): var.setpoint = var[t0].value # Restore cached values if VC.INPUT in self.categories: self.vectors.input.values = init_input if VC.MEASUREMENT in self.categories: self.vectors.measurement.values = init_meas