def add_namespace_to(cls, model, time): """ """ name = DynamicBase.get_namespace_name() derived_name = cls.namespace_name if hasattr(model, name): # Return if namespace has already been added. Don't throw an error # as this is expected if the user, say wants to use the same model # for NMPC and MHE. return if time.model() != model.model(): raise ValueError( 'time must belong to same top-level model as model') model.add_component(name, Block()) namespace = getattr(model, name) derived_namespace = getattr(model, derived_name) def get_time(): return time namespace.get_time = get_time derived_namespace.get_time = namespace.get_time # Validate discretization scheme and get ncp: namespace.ncp = dyn_config.get_ncp(time) namespace.variables_categorized = False
def remove_namespace_from(cls, model): """ """ # TODO: add remove_namespace_from to derived classes name = DynamicBase.get_namespace_name() if not hasattr(model, name): raise RuntimeError( 'Trying to delete block %s that does not exist on model' % name) model.del_component(name, Block())
def build_Block_with_objects(): """Build an empty Block""" obj = Block(concrete=True) obj.construct() obj.x = Var() obj.x._domain = None obj.c = Constraint() obj.o = Objective() return obj
def create_subsystem_block(constraints, variables=None, include_fixed=False): """ This function creates a block to serve as a subsystem with the specified variables and constraints. To satisfy certain writers, other variables that appear in the constraints must be added to the block as well. We call these the "input vars." They may be thought of as parameters in the subsystem, but we do not fix them here as it is not obvious that this is desired. Arguments --------- constraints: List List of Pyomo constraint data objects variables: List List of Pyomo var data objects include_fixed: Bool Indicates whether fixed variables should be attached to the block. This is useful if they may be unfixed at some point. Returns ------- Block containing references to the specified constraints and variables, as well as other variables present in the constraints """ if variables is None: variables = [] block = Block(concrete=True) block.vars = Reference(variables) block.cons = Reference(constraints) var_set = ComponentSet(variables) input_vars = [] for con in constraints: for var in identify_variables(con.expr, include_fixed=include_fixed): if var not in var_set: input_vars.append(var) var_set.add(var) block.input_vars = Reference(input_vars) add_local_external_functions(block) return block
def get_numeric_incidence_matrix(variables, constraints): """ This function gets the numeric incidence matrix (Jacobian) of Pyomo constraints with respect to variables. """ # NOTE: There are several ways to get a numeric incidence matrix # from a Pyomo model. This function implements a somewhat roundabout # method, which is to construct a dummy Block with the necessary # variables and constraints, then construct a PyNumero PyomoNLP # from the block and have PyNumero evaluate the desired Jacobian # via ASL. comps = list(variables) + list(constraints) _check_unindexed(comps) M, N = len(constraints), len(variables) _block = Block() _block.construct() _block.obj = Objective(expr=0) _block.vars = Reference(variables) _block.cons = Reference(constraints) var_set = ComponentSet(variables) other_vars = [] for con in constraints: for var in identify_variables(con.body, include_fixed=False): # Fixed vars will be ignored by the nl file write, so # there is no point to including them here. # A different method of assembling this matrix, e.g. # Pyomo's automatic differentiation, could support taking # derivatives with respect to fixed variables. if var not in var_set: other_vars.append(var) var_set.add(var) # These variables are necessary due to the nl writer's philosophy # about what constitutes a model. Note that we take derivatives with # respect to them even though this is not necessary. We could fix them # here to avoid doing this extra work, but that would alter the user's # model, which we would rather not do. _block.other_vars = Reference(other_vars) _nlp = PyomoNLP(_block) return _nlp.extract_submatrix_jacobian(variables, constraints)
def build_indexed_BlockWVars(): model = build_indexed_BlockWVars.model model.indexed_Block = Block( model.ndx, rule=build_indexed_BlockWVars.indexed_Block_rule) return model.indexed_Block
def _reset(): build_indexed_BlockWVars.model = Block(concrete=True) build_indexed_BlockWVars.model.ndx = RangeSet(0, N - 1) build_indexed_BlockWVars.indexed_Block_rule = _indexed_Block_rule
def build_Block(): """Build a Block with a few components.""" obj = Block(concrete=True) obj.construct() return obj
def _reset(): build_indexed_Constraint.model = Block(concrete=True) build_indexed_Constraint.model.ndx = RangeSet(0, N - 1) build_indexed_Constraint.rule = _con_rule
def _reset(): build_indexed_Var.model = Block(concrete=True) build_indexed_Var.model.ndx = RangeSet(0, N - 1) build_indexed_Var.bounds_rule = _bounds_rule build_indexed_Var.initialize_rule = _initialize_rule
def build_Block(): """Build a Block with a few components.""" obj = Block(concrete=True) obj.construct() return obj def build_BlockData(): """Build a _BlockData with a few components.""" obj = _BlockData(build_BlockData.owner) obj._component = None return obj build_BlockData.owner = Block() def build_block(): b = block() b._activate_large_storage_mode() return b build_small_block = block def build_Block_with_objects(): """Build an empty Block""" obj = Block(concrete=True) obj.construct()
def solve(self, model, first_stage_variables, second_stage_variables, uncertain_params, uncertainty_set, local_solver, global_solver, **kwds): """Solve the model. Parameters ---------- model: ConcreteModel A ``ConcreteModel`` object representing the deterministic model, cast as a minimization problem. first_stage_variables: List[Var] The list of ``Var`` objects referenced in ``model`` representing the design variables. second_stage_variables: List[Var] The list of ``Var`` objects referenced in ``model`` representing the control variables. uncertain_params: List[Param] The list of ``Param`` objects referenced in ``model`` representing the uncertain parameters. MUST be ``mutable``. Assumes entries are provided in consistent order with the entries of 'nominal_uncertain_param_vals' input. uncertainty_set: UncertaintySet ``UncertaintySet`` object representing the uncertainty space that the final solutions will be robust against. local_solver: Solver ``Solver`` object to utilize as the primary local NLP solver. global_solver: Solver ``Solver`` object to utilize as the primary global NLP solver. """ # === Add the explicit arguments to the config config = self.CONFIG(kwds.pop('options', {})) config.first_stage_variables = first_stage_variables config.second_stage_variables = second_stage_variables config.uncertain_params = uncertain_params config.uncertainty_set = uncertainty_set config.local_solver = local_solver config.global_solver = global_solver dev_options = kwds.pop('dev_options', {}) config.set_value(kwds) config.set_value(dev_options) model = model # === Validate kwarg inputs validate_kwarg_inputs(model, config) # === Validate ability of grcs RO solver to handle this model if not model_is_valid(model): raise AttributeError( "This model structure is not currently handled by the ROSolver." ) # === Define nominal point if not specified if len(config.nominal_uncertain_param_vals) == 0: config.nominal_uncertain_param_vals = list( p.value for p in config.uncertain_params) elif len(config.nominal_uncertain_param_vals) != len( config.uncertain_params): raise AttributeError( "The nominal_uncertain_param_vals list must be the same length" "as the uncertain_params list") # === Create data containers model_data = ROSolveResults() model_data.timing = Bunch() # === Set up logger for logging results with time_code(model_data.timing, 'total', is_main_timer=True): config.progress_logger.setLevel(logging.INFO) # === PREAMBLE output_logger(config=config, preamble=True, version=str(self.version())) # === DISCLAIMER output_logger(config=config, disclaimer=True) # === A block to hold list-type data to make cloning easy util = Block(concrete=True) util.first_stage_variables = config.first_stage_variables util.second_stage_variables = config.second_stage_variables util.uncertain_params = config.uncertain_params model_data.util_block = unique_component_name(model, 'util') model.add_component(model_data.util_block, util) # Note: model.component(model_data.util_block) is util # === Validate uncertainty set happens here, requires util block for Cardinality and FactorModel sets validate_uncertainty_set(config=config) # === Deactivate objective on model for o in model.component_data_objects(Objective): o.deactivate() # === Leads to a logger warning here for inactive obj when cloning model_data.original_model = model # === For keeping track of variables after cloning cname = unique_component_name(model_data.original_model, 'tmp_var_list') src_vars = list( model_data.original_model.component_data_objects(Var)) setattr(model_data.original_model, cname, src_vars) model_data.working_model = model_data.original_model.clone() # === Add objective expressions identify_objective_functions(model_data.working_model, config) # === Put model in standard form transform_to_standard_form(model_data.working_model) # === Replace variable bounds depending on uncertain params with # explicit inequality constraints replace_uncertain_bounds_with_constraints( model_data.working_model, model_data.working_model.util.uncertain_params) # === Add decision rule information add_decision_rule_variables(model_data, config) add_decision_rule_constraints(model_data, config) # === Move bounds on control variables to explicit ineq constraints wm_util = model_data.working_model # === Assuming all other Var objects in the model are state variables fsv = ComponentSet( model_data.working_model.util.first_stage_variables) ssv = ComponentSet( model_data.working_model.util.second_stage_variables) sv = ComponentSet() model_data.working_model.util.state_vars = [] for v in model_data.working_model.component_data_objects(Var): if v not in fsv and v not in ssv and v not in sv: model_data.working_model.util.state_vars.append(v) sv.add(v) # Bounds on second stage variables and state variables are separation objectives, # they are brought in this was as explicit constraints for c in model_data.working_model.util.second_stage_variables: turn_bounds_to_constraints(c, wm_util, config) for c in model_data.working_model.util.state_vars: turn_bounds_to_constraints(c, wm_util, config) # === Make control_variable_bounds array wm_util.ssv_bounds = [] for c in model_data.working_model.component_data_objects( Constraint, descend_into=True): if "bound_con" in c.name: wm_util.ssv_bounds.append(c) # === Solve and load solution into model pyros_soln, final_iter_separation_solns = ROSolver_iterative_solve( model_data, config) return_soln = ROSolveResults() if pyros_soln is not None and final_iter_separation_solns is not None: if config.load_solution and \ (pyros_soln.pyros_termination_condition is pyrosTerminationCondition.robust_optimal or pyros_soln.pyros_termination_condition is pyrosTerminationCondition.robust_feasible): load_final_solution(model_data, pyros_soln.master_soln, config) # === Return time info model_data.total_cpu_time = get_main_elapsed_time( model_data.timing) iterations = pyros_soln.total_iters + 1 # === Return config to user return_soln.config = config # Report the negative of the objective value if it was originally maximize, since we use the minimize form in the algorithm if next(model.component_data_objects( Objective)).sense == maximize: negation = -1 else: negation = 1 if config.objective_focus == ObjectiveType.nominal: return_soln.final_objective_value = negation * value( pyros_soln.master_soln.master_model.obj) elif config.objective_focus == ObjectiveType.worst_case: return_soln.final_objective_value = negation * value( pyros_soln.master_soln.master_model.zeta) return_soln.pyros_termination_condition = pyros_soln.pyros_termination_condition return_soln.time = model_data.total_cpu_time return_soln.iterations = iterations # === Remove util block model.del_component(model_data.util_block) del pyros_soln.util_block del pyros_soln.working_model else: return_soln.pyros_termination_condition = pyrosTerminationCondition.robust_infeasible return_soln.final_objective_value = None return_soln.time = get_main_elapsed_time(model_data.timing) return_soln.iterations = 0 return return_soln
def __init__(self, *args, **kwds): kwds.setdefault('ctype', ExternalGreyBoxBlock) self._init_model = Initializer(kwds.pop('external_model', None)) Block.__init__(self, *args, **kwds)