class_docstr: Model that uses conventional implementation for semi-continuous variables
  The model is adopted from Pyomo model 1: Conventional implementation for semi-continuous variables
  (https://jckantor.github.io/ND-Pyomo-Cookbook/04.06-Unit-Commitment.html)
  The constraints are added to the objective with a heavy penalty for violation.
  
  Parameters
  ----------
  num_timepoints: int
      number of time points
  num_generators: int
      number of generators
  penalty_weight: float
      weight to penalize for violation of constraints
code: def unit_commitment_obj_with_penalization(
      self, operational_output, operational_states
  ):
      operational_states = np.array(operational_states).reshape(
          self.num_generators, self.num_timepoints
      )
      demand_penalty, lb_penalty, ub_penalty = 0, 0, 0
      # From demand constraint
      demand_penalty = np.sum(
          np.abs(np.sum(operational_output, axis=0) - self.demands)
      )
      # From semi_continuous_constraints
      lb_penalty = np.sum(
          np.clip(
              self.p_min * operational_states - operational_output,
              0,
              a_max=None,
          ),
          axis=None,
      )
      ub_penalty = np.sum(
          np.clip(
              operational_output - self.p_max * operational_states,
              0,
              a_max=None,
          ),
          axis=None,
      )
      # Running cost
      running_cost = np.sum(
          np.sum(operational_output, axis=1) * self.cost_a
          + np.sum(operational_states, axis=1) * self.cost_b
      )
      ret = (
          running_cost
          + (demand_penalty + lb_penalty + ub_penalty)
          * self.penalty_weight
      )
      return ret
  
imports: import numpy
  import nevergrad
  from ..base import ExperimentFunction
label_desc: Use image node_id 2 for calling the UnitCommitmentProblem obj's underlying member method code with example usage: obj.unit_commitment_obj_with_penalization(operational_output, operational_states) and returns: ret