def test_allowed_time_varying_constraints(self):
        """
        `file=` is only allowed on a hardcoded list of constraints, unless
        `_time_varying` is appended to the constraint (i.e. user input)
        """

        allowed_constraints_no_file = list(
            set(defaults_model.tech_groups.storage.allowed_constraints)
            .difference(defaults.file_allowed)
        )

        allowed_constraints_file = list(
            set(defaults_model.tech_groups.storage.allowed_constraints)
            .intersection(defaults.file_allowed)
        )

        override = lambda param: AttrDict.from_yaml_string(
            "techs.test_storage.constraints.{}: file=binary_one_day.csv".format(param)
        )

        # should fail: Cannot have `file=` on the following constraints
        for param in allowed_constraints_no_file:
            with pytest.raises(exceptions.ModelError) as errors:
                build_model(override_dict=override(param), scenario='simple_storage,one_day')
            assert check_error_or_warning(
                errors,
                'Cannot load `{}` from file for configuration'.format(param)
            )

        # should pass: can have `file=` on the following constraints
        for param in allowed_constraints_file:
            build_model(override_dict=override(param), scenario='simple_storage,one_day')
    def test_incorrect_subset_time(self):
        """
        If subset_time is a list, it must have two entries (start_time, end_time)
        If subset_time is not a list, it should successfully subset on the given
        string/integer
        """

        override = lambda param: AttrDict.from_yaml_string(
            "model.subset_time: {}".format(param)
        )

        # should fail: one string in list
        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override(['2005-01']), scenario='simple_supply')

        # should fail: three strings in list
        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override(['2005-01-01', '2005-01-02', '2005-01-03']), scenario='simple_supply')

        # should pass: two string in list as slice
        model = build_model(override_dict=override(['2005-01-01', '2005-01-07']), scenario='simple_supply')
        assert all(model.inputs.timesteps.to_index() == pd.date_range('2005-01', '2005-01-07 23:00:00', freq='H'))

        # should pass: one integer/string
        model = build_model(override_dict=override('2005-01'), scenario='simple_supply')
        assert all(model.inputs.timesteps.to_index() == pd.date_range('2005-01', '2005-01-31 23:00:00', freq='H'))

        # should fail: time subset out of range of input data
        with pytest.raises(KeyError):
            build_model(override_dict=override('2005-03'), scenario='simple_supply')

        # should fail: time subset out of range of input data
        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override(['2005-02-01', '2005-02-05']), scenario='simple_supply')
    def test_resource_as_carrier(self):
        """
        No carrier in technology or technology group can be called `resource`
        """

        override1 = AttrDict.from_yaml_string(
            """
            techs:
                test_supply_elec:
                    essentials:
                        name: Supply tech
                        carrier: resource
                        parent: supply
            """
        )

        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override1, scenario='simple_supply,one_day')

        override2 = AttrDict.from_yaml_string(
            """
            tech_groups:
                test_supply_group:
                    essentials:
                        name: Supply tech
                        carrier: resource
                        parent: supply
            techs.test_supply_elec.essentials.parent: test_supply_group
            """
        )

        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override2, scenario='simple_supply,one_day')
    def test_unrecognised_model_run_keys(self):
        """
        Check that the only keys allowed in 'model' and 'run' are those in the
        model defaults
        """
        override1 = {'model.nonsensical_key': 'random_string'}

        with pytest.warns(exceptions.ModelWarning) as excinfo:
            build_model(override_dict=override1, scenario='simple_supply')

        assert check_error_or_warning(
            excinfo, 'Unrecognised setting in model configuration: nonsensical_key'
        )

        override2 = {'run.nonsensical_key': 'random_string'}

        with pytest.warns(exceptions.ModelWarning) as excinfo:
            build_model(override_dict=override2, scenario='simple_supply')

        assert check_error_or_warning(
            excinfo, 'Unrecognised setting in run configuration: nonsensical_key'
        )

        # A key that should be in run but is given in model
        override3 = {'model.solver': 'glpk'}

        with pytest.warns(exceptions.ModelWarning) as excinfo:
            build_model(override_dict=override3, scenario='simple_supply')

        assert check_error_or_warning(
            excinfo, 'Unrecognised setting in model configuration: solver'
        )

        # A key that should be in model but is given in run
        override4 = {'run.subset_time': None}

        with pytest.warns(exceptions.ModelWarning) as excinfo:
            build_model(override_dict=override4, scenario='simple_supply')

        assert check_error_or_warning(
            excinfo, 'Unrecognised setting in run configuration: subset_time'
        )

        override5 = {
            'run.objective': 'minmax_cost_optimization',
            'run.objective_options': {
                'cost_class': 'monetary',
                'sense': 'minimize',
                'unused_option': 'some_value'
            }
        }

        with pytest.warns(exceptions.ModelWarning) as excinfo:
            build_model(override_dict=override5, scenario='simple_supply')

        assert check_error_or_warning(
            excinfo, 'Objective function argument `unused_option` given but not used by objective function `minmax_cost_optimization`'
        )
    def test_model_version_mismatch(self):
        """
        Model config says model.calliope_version = 0.1, which is not what we
        are running, so we want a warning.
        """
        override = {'model.calliope_version': 0.1}

        with pytest.warns(exceptions.ModelWarning) as excinfo:
            build_model(override_dict=override, scenario='simple_supply,one_day')

        assert check_error_or_warning(excinfo, 'Model configuration specifies calliope_version')
    def test_positive_demand(self):
        """
        Resource for demand must be negative
        """

        override = {
            'techs.test_demand_elec.constraints.resource': 'file=demand_elec_positive.csv',
        }

        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override, scenario='simple_supply,one_day')
    def test_key_clash_on_set_loc_key(self):
        """
        Raise error on attempted overwrite of information regarding a recently
        exploded location
        """
        override = {
            'locations.0.test_supply_elec.constraints.resource': 10,
            'locations.0,1.test_supply_elec.constraints.resource': 15
        }

        with pytest.raises(KeyError):
            build_model(override_dict=override, scenario='simple_supply,one_day')
    def test_unrecognised_config_keys(self):
        """
        Check that the only top level keys can be 'model', 'run', 'locations',
        'techs', 'tech_groups' (+ 'config_path', but that is an internal addition)
        """
        override = {'nonsensical_key': 'random_string'}

        with pytest.warns(exceptions.ModelWarning) as excinfo:
            build_model(override_dict=override, scenario='simple_supply')

        assert check_error_or_warning(
            excinfo, 'Unrecognised top-level configuration item: nonsensical_key'
        )
    def test_exporting_unspecified_carrier(self):
        """
        User can only define an export carrier if it is defined in
        ['carrier_out', 'carrier_out_2', 'carrier_out_3']
        """
        override_supply = lambda param: AttrDict.from_yaml_string(
            "techs.test_supply_elec.constraints.export_carrier: {}".format(param)
        )

        override_converison_plus = lambda param: AttrDict.from_yaml_string(
            "techs.test_conversion_plus.constraints.export_carrier: {}".format(param)
        )

        # should fail: exporting `heat` not allowed for electricity supply tech
        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override_supply('heat'), scenario='simple_supply,one_day')

        # should fail: exporting `random` not allowed for conversion_plus tech
        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override_converison_plus('random'), scenario='simple_conversion_plus,one_day')

        # should pass: exporting electricity for supply tech
        build_model(override_dict=override_supply('electricity'), scenario='simple_supply,one_day')

        # should pass: exporting heat for conversion tech
        build_model(override_dict=override_converison_plus('heat'), scenario='simple_conversion_plus,one_day')
Exemplo n.º 10
0
    def test_invalid_scenarios_str(self):
        """
        Test that invalid scenario definition raises appropriate error
        """
        override = AttrDict.from_yaml_string(
            """
            scenarios:
                scenario_1: 'foo1,foo2'
            """
        )
        with pytest.raises(exceptions.ModelError) as error:
            build_model(override_dict=override, scenario='scenario_1')

        assert check_error_or_warning(error, 'Scenario definition must be a list of override names.')
Exemplo n.º 11
0
    def test_scenario_name_overlaps_overrides(self):
        """
        Test that a scenario name cannot be a combination of override names
        """
        override = AttrDict.from_yaml_string(
            """
            scenarios:
                'simple_supply,group_share_energy_cap_min': 'foobar'
            """
        )
        with pytest.raises(exceptions.ModelError) as error:
            build_model(override_dict=override, scenario='simple_supply,group_share_energy_cap_min')

        assert check_error_or_warning(error, 'Manually defined scenario cannot be a combination of override names.')
Exemplo n.º 12
0
 def test_defining_non_allowed_constraints(self):
     """
     A technology within an abstract base technology can only define a subset
     of hardcoded constraints, anything else will not be implemented, so are
     not allowed for that technology. This includes misspellings
     """
     # should fail: storage_cap_max not allowed for supply tech
     override_supply1 = AttrDict.from_yaml_string(
         """
         techs.test_supply_elec.constraints.storage_cap_max: 10
         """
     )
     with pytest.raises(exceptions.ModelError):
         build_model(override_dict=override_supply1, override_groups='simple_supply,one_day')
Exemplo n.º 13
0
 def test_defining_non_allowed_constraints(self):
     """
     A technology within an abstract base technology can only define a subset
     of hardcoded constraints, anything else will not be implemented, so are
     not allowed for that technology. This includes misspellings
     """
     # should fail: storage_cap_max not allowed for supply tech
     override_supply1 = AttrDict.from_yaml_string(
         """
         techs.test_supply_elec.constraints.storage_cap_max: 10
         """
     )
     with pytest.raises(exceptions.ModelError):
         build_model(override_dict=override_supply1, scenario='simple_supply,one_day')
Exemplo n.º 14
0
    def test_force_infinite_resource(self):
        """
        Ensure that no loc-tech specifies infinite resource and force_resource=True
        """

        override = {
            'techs.test_supply_plus.constraints.resource': 'file=supply_plus_resource_inf.csv',
            'techs.test_supply_plus.constraints.force_resource': True,
        }

        with pytest.raises(exceptions.ModelError) as error_info:
            build_model(override_dict=override, scenario='simple_supply_plus,one_day')

        assert check_error_or_warning(error_info, 'Ensure all entries are numeric')
Exemplo n.º 15
0
    def test_inconsistent_time_indeces(self):
        """
        Test that, including after any time subsetting, the indeces of all time
        varying input data are consistent with each other
        """
        # should fail: wrong length of demand_heat csv vs demand_elec
        override1 = {
            'techs.test_demand_heat.constraints.resource': 'file=demand_heat_wrong_length.csv'
        }
        # check in output error that it points to: 07/01/2005 10:00:00
        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override1, override_groups='simple_conversion')

        # should pass: wrong length of demand_heat csv, but time subsetting removes the difference
        build_model(override_dict=override1, override_groups='simple_conversion,one_day')
Exemplo n.º 16
0
    def test_invalid_scenarios(self):
        """
        Test that invalid scenario definition raises appropriate error
        """
        override = AttrDict.from_yaml_string("""
            scenarios:
                scenario_1:
                    techs.foo.bar: 1
            """)
        with pytest.raises(exceptions.ModelError) as error:
            build_model(override_dict=override, scenario='scenario_1')

        assert check_error_or_warning(
            error,
            'Scenario definition must be string of comma-separated overrides.')
    def test_loc_techs_carrier_production_min_conversion_plus_milp_constraint(
            self):
        m = build_model({}, 'conversion_plus_milp,two_hours,investment_costs')
        m.run(build_only=True)
        assert not hasattr(
            m._backend_model,
            'carrier_production_min_conversion_plus_constraint')

        m = build_model(
            {'techs.test_conversion_plus.constraints.energy_cap_min_use': 0.1},
            'conversion_plus_milp,two_hours,investment_costs')
        m.run(build_only=True)
        assert not hasattr(
            m._backend_model,
            'carrier_production_min_conversion_plus_constraint')
Exemplo n.º 18
0
    def test_inconsistent_time_indeces(self):
        """
        Test that, including after any time subsetting, the indeces of all time
        varying input data are consistent with each other
        """
        # should fail: wrong length of demand_heat csv vs demand_elec
        override1 = {
            'techs.test_demand_heat.constraints.resource': 'file=demand_heat_wrong_length.csv'
        }
        # check in output error that it points to: 07/01/2005 10:00:00
        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override1, scenario='simple_conversion')

        # should pass: wrong length of demand_heat csv, but time subsetting removes the difference
        build_model(override_dict=override1, scenario='simple_conversion,one_day')
Exemplo n.º 19
0
    def test_abstract_base_tech_group_override(self):
        """
        Abstract base technology groups can be overridden
        """
        override = AttrDict.from_yaml_string("""
            tech_groups:
                supply:
                    constraints:
                        lifetime: 25
            locations:
                1.techs.test_supply_elec:
                1.techs.test_demand_elec:
            """)

        build_model(override_dict=override, scenario='one_day')
Exemplo n.º 20
0
    def test_scenario_name_overlaps_overrides(self):
        """
        Test that a scenario name cannot be a combination of override names
        """
        override = AttrDict.from_yaml_string("""
            scenarios:
                'simple_supply,group_share_energy_cap_min': 'foobar'
            """)
        with pytest.raises(exceptions.ModelError) as error:
            build_model(override_dict=override,
                        scenario='simple_supply,group_share_energy_cap_min')

        assert check_error_or_warning(
            error,
            'Manually defined scenario cannot be a combination of override names.'
        )
Exemplo n.º 21
0
    def test_clustering_no_datestep(self):
        """
        On clustering, there are a few new dimensions in the model_data, and a
        few new lookup arrays. Cyclic storage is set to False as you cannot
        have cyclic storage without `storage_inter_cluster` being active.
        """
        override = {
            'model.subset_time': ['2005-01-01', '2005-01-04'],
            'model.time': {
                'function': 'apply_clustering',
                'function_options': {
                    'clustering_func': 'file=cluster_days.csv:0',
                    'how': 'mean',
                    'storage_inter_cluster': False
                }
            },
            'run.cyclic_storage': False
        }

        model = build_model(override, scenario='simple_supply')

        assert 'clusters' in model._model_data.dims
        assert 'datesteps' not in model._model_data.dims
        assert 'lookup_cluster_first_timestep' in model._model_data.data_vars
        assert 'lookup_cluster_last_timestep' in model._model_data.data_vars
        assert 'lookup_datestep_last_cluster_timestep' not in model._model_data.data_vars
        assert 'lookup_datestep_cluster' not in model._model_data.data_vars
        assert 'timestep_cluster' in model._model_data.data_vars
Exemplo n.º 22
0
    def test_clustering(self):
        """
        On clustering, there are a few new dimensions in the model_data, and a
        few new lookup arrays
        """
        override = {
            'model.subset_time': ['2005-01-01', '2005-01-04'],
            'model.time': {
                'function': 'apply_clustering',
                'function_options': {
                    'clustering_func': 'file=cluster_days.csv:0',
                    'how': 'mean'
                }
            }
        }

        model = build_model(override, scenario='simple_supply')

        assert 'clusters' in model._model_data.dims
        assert 'lookup_cluster_first_timestep' in model._model_data.data_vars
        assert 'lookup_cluster_last_timestep' in model._model_data.data_vars
        assert 'lookup_datestep_last_cluster_timestep' in model._model_data.data_vars
        assert 'lookup_datestep_cluster' in model._model_data.data_vars
        assert 'timestep_cluster' in model._model_data.data_vars

        datesteps = model.inputs.datesteps.to_index().strftime('%Y-%m-%d')
        daterange = pd.date_range('2005-01-01', '2005-01-04',
                                  freq='1D').strftime('%Y-%m-%d')
        assert np.array_equal(datesteps, daterange)
Exemplo n.º 23
0
    def test_clustering_no_datestep(self):
        """
        On clustering, there are a few new dimensions in the model_data, and a
        few new lookup arrays
        """
        override = {
            'model.subset_time': ['2005-01-01', '2005-01-04'],
            'model.time': {
                'function': 'apply_clustering',
                'function_options': {
                    'clustering_func': 'file=cluster_days.csv:0',
                    'how': 'mean',
                    'storage_inter_cluster': False
                }
            }
        }

        model = build_model(override, override_groups='simple_supply')

        assert 'clusters' in model._model_data.dims
        assert 'datesteps' not in model._model_data.dims
        assert 'lookup_cluster_first_timestep' in model._model_data.data_vars
        assert 'lookup_cluster_last_timestep' in model._model_data.data_vars
        assert 'lookup_datestep_last_cluster_timestep' not in model._model_data.data_vars
        assert 'lookup_datestep_cluster' not in model._model_data.data_vars
        assert 'timestep_cluster' in model._model_data.data_vars
Exemplo n.º 24
0
    def test_valid_scenarios(self):
        """
        Test that valid scenario definition raises no error and results in applied scenario.
        """
        override = AttrDict.from_yaml_string("""
            scenarios:
                scenario_1: ['one', 'two']

            overrides:
                one:
                    techs.test_supply_gas.constraints.energy_cap_max: 20
                two:
                    techs.test_supply_elec.constraints.energy_cap_max: 20

            locations:
                0:
                    techs:
                        test_supply_gas:
                        test_supply_elec:
                        test_demand_elec:
            """)
        model = build_model(override_dict=override, scenario='scenario_1')

        assert model._model_run.locations[
            '0'].techs.test_supply_gas.constraints.energy_cap_max == 20
        assert model._model_run.locations[
            '0'].techs.test_supply_elec.constraints.energy_cap_max == 20
 def test_loc_techs_carrier_production_max_conversion_plus_milp_constraint(
         self):
     m = build_model({}, "conversion_plus_milp,two_hours,investment_costs")
     m.run(build_only=True)
     assert not hasattr(
         m._backend_model,
         "carrier_production_max_conversion_plus_constraint")
Exemplo n.º 26
0
 def test_equals(self, model_file):
     model = build_model(model_file=model_file, scenario="equals")
     model.run()
     assert model.results.termination_condition == "optimal"
     energy_capacity = model.get_formatted_array("energy_cap").loc[{'techs': 'my_storage'}].sum().item()
     storage_capacity = model.get_formatted_array("storage_cap").loc[{'techs': 'my_storage'}].sum().item()
     assert storage_capacity == pytest.approx(1 / 10 * energy_capacity)
Exemplo n.º 27
0
 def test_group_constraint_without_technology(self):
     model = build_model(
         model_file='group_constraints.yaml',
         scenario='group_constraint_without_tech'
     )
     with pytest.raises(calliope.exceptions.ModelError):
         model.run()
Exemplo n.º 28
0
    def test_demand_share_per_timestep_decision_inf_with_heat_constrain_heat_and_electricity(self):
        model = build_model(
            model_file='demand_share_decision.yaml',
            scenario='demand_share_per_timestep_decision_inf_with_heat,demand_share_per_timestep_decision_not_one,with_electricity_conversion_tech'
        )
        model.run()
        demand_heat = -1 * model.get_formatted_array("carrier_con").loc[{'carriers': "heat"}].sum(['locs', 'techs']).to_pandas()
        supply_heat = model.get_formatted_array("carrier_prod").loc[{'carriers': "heat"}].sum('locs').to_pandas().T
        shares_heat = supply_heat.div(demand_heat, axis=0)

        demand_elec = -1 * (
            model._model_data.carrier_con.loc[{
                'loc_tech_carriers_con': [
                    i for i in model._model_data.loc_tech_carriers_demand.values
                    if 'electricity' in i
                ]
            }].sum(['loc_tech_carriers_con']).to_pandas()
        )
        supply_elec = model.get_formatted_array("carrier_prod").loc[{'carriers': "electricity"}].sum('locs').to_pandas().T
        shares_elec = supply_elec.div(demand_elec, axis=0)

        assert all([i == pytest.approx(0.5) for i in shares_heat['elec_to_heat'].values])
        assert all([i == pytest.approx(0.5) for i in shares_heat['heating'].values])
        assert all([i == pytest.approx(0.9) for i in shares_elec['normal_elec_supply'].values])
        assert all([round(i, 5) >= 0.1 for i in shares_elec['cheap_elec_supply'].values])
Exemplo n.º 29
0
 def test_operate_mode(self, model_file):
     model = build_model(model_file=model_file, scenario="operate_mode_min")
     with pytest.raises(calliope.exceptions.ModelError) as error:
         model.run()
     assert check_error_or_warning(
         error, "Operational mode requires a timestep window and horizon"
     )
Exemplo n.º 30
0
    def test_clustering(self):
        """
        On clustering, there are a few new dimensions in the model_data, and a
        few new lookup arrays
        """
        override = {
            'model.subset_time': ['2005-01-01', '2005-01-04'],
            'model.time': {
                'function': 'apply_clustering',
                'function_options': {
                    'clustering_func': 'file=cluster_days.csv:0', 'how': 'mean'
                }
            }
        }

        model = build_model(override, scenario='simple_supply')

        assert 'clusters' in model._model_data.dims
        assert 'lookup_cluster_first_timestep' in model._model_data.data_vars
        assert 'lookup_cluster_last_timestep' in model._model_data.data_vars
        assert 'lookup_datestep_last_cluster_timestep' in model._model_data.data_vars
        assert 'lookup_datestep_cluster' in model._model_data.data_vars
        assert 'timestep_cluster' in model._model_data.data_vars

        datesteps = model.inputs.datesteps.to_index().strftime('%Y-%m-%d')
        daterange = pd.date_range('2005-01-01', '2005-01-04', freq='1D').strftime('%Y-%m-%d')
        assert np.array_equal(datesteps, daterange)
Exemplo n.º 31
0
    def test_clustering_no_datestep(self):
        """
        On clustering, there are a few new dimensions in the model_data, and a
        few new lookup arrays. Cyclic storage is set to False as you cannot
        have cyclic storage without `storage_inter_cluster` being active.
        """
        override = {
            'model.subset_time': ['2005-01-01', '2005-01-04'],
            'model.time': {
                'function': 'apply_clustering',
                'function_options': {
                    'clustering_func': 'file=cluster_days.csv:0', 'how': 'mean',
                    'storage_inter_cluster': False
                }
            },
            'run.cyclic_storage': False
        }

        model = build_model(override, scenario='simple_supply')

        assert 'clusters' in model._model_data.dims
        assert 'datesteps' not in model._model_data.dims
        assert 'lookup_cluster_first_timestep' in model._model_data.data_vars
        assert 'lookup_cluster_last_timestep' in model._model_data.data_vars
        assert 'lookup_datestep_last_cluster_timestep' not in model._model_data.data_vars
        assert 'lookup_datestep_cluster' not in model._model_data.data_vars
        assert 'timestep_cluster' in model._model_data.data_vars
Exemplo n.º 32
0
    def test_valid_scenarios(self):
        """
        Test that valid scenario definition raises no error and results in applied scenario.
        """
        override = AttrDict.from_yaml_string(
            """
            scenarios:
                scenario_1: ['one', 'two']

            overrides:
                one:
                    techs.test_supply_gas.constraints.energy_cap_max: 20
                two:
                    techs.test_supply_elec.constraints.energy_cap_max: 20

            locations:
                0:
                    techs:
                        test_supply_gas:
                        test_supply_elec:
                        test_demand_elec:
            """
        )
        model = build_model(override_dict=override, scenario='scenario_1')

        assert model._model_run.locations['0'].techs.test_supply_gas.constraints.energy_cap_max == 20
        assert model._model_run.locations['0'].techs.test_supply_elec.constraints.energy_cap_max == 20
Exemplo n.º 33
0
 def test_weighted_objective_results(self, scenario, cost_class, weight):
     model = build_model(model_file="weighted_obj_func.yaml",
                         scenario=scenario)
     model.run()
     assert sum(model.results.cost.loc[{
         "costs": cost_class[i]
     }].sum().item() * weight[i] for i in range(len(cost_class))) == approx(
         po.value(model._backend_model.obj))
Exemplo n.º 34
0
    def test_force_infinite_resource(self):
        """
        Ensure that no loc-tech specifies infinite resource and force_resource=True
        """

        override = {
            'techs.test_supply_plus.constraints.resource':
            'file=supply_plus_resource_inf.csv',
            'techs.test_supply_plus.constraints.force_resource': True,
        }

        with pytest.raises(exceptions.ModelError) as error_info:
            build_model(override_dict=override,
                        scenario='simple_supply_plus,one_day')

        assert check_error_or_warning(error_info,
                                      'Ensure all entries are numeric')
Exemplo n.º 35
0
    def test_missing_constraints(self):
        """
        A technology must define at least one constraint.
        """

        override = AttrDict.from_yaml_string("""
            techs:
                supply_missing_constraint:
                    essentials:
                        parent: supply
                        carrier: electricity
                        name: supply missing constraint
            locations.1.techs.supply_missing_constraint:
            """)
        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override,
                        scenario='simple_supply,one_day')
Exemplo n.º 36
0
    def test_model_version_mismatch(self):
        """
        Model config says model.calliope_version = 0.1, which is not what we
        are running, so we want a warning.
        """
        override = AttrDict.from_yaml_string("""
            model.calliope_version: 0.1
            """)

        with pytest.warns(exceptions.ModelWarning) as excinfo:
            build_model(override_dict=override,
                        override_groups='simple_supply,one_day')

        all_warnings = ','.join(
            str(excinfo.list[i]) for i in range(len(excinfo.list)))

        assert 'Model configuration specifies calliope_version' in all_warnings
Exemplo n.º 37
0
 def test_no_group_constraint(self):
     model = build_model(model_file="group_constraints.yaml")
     model.run()
     expensive_generation = (
         model.get_formatted_array("carrier_prod")
              .loc[{'techs': 'expensive_supply'}].sum().item()
     )
     assert expensive_generation == 0
 def test_no_balance_conversion_plus_primary_constraint(self):
     """
     sets.loc_techs_conversion_plus,
     """
     m = build_model({}, "simple_supply,two_hours,investment_costs")
     m.run(build_only=True)
     assert not hasattr(m._backend_model,
                        "balance_conversion_plus_primary_constraint")
Exemplo n.º 39
0
    def test_abstract_base_tech_group_override(self):
        """
        Abstract base technology groups can be overridden
        """
        override = AttrDict.from_yaml_string(
            """
            tech_groups:
                supply:
                    constraints:
                        lifetime: 25
            locations:
                1.techs.test_supply_elec:
                1.techs.test_demand_elec:
            """
        )

        build_model(override_dict=override, scenario='one_day')
Exemplo n.º 40
0
    def test_conversion_plus_primary_carriers(self):
        """
        Test that user has input input/output primary carriers for conversion_plus techs
        """
        override1 = {'techs.test_conversion_plus.essentials.carrier_in': ['gas', 'coal']}
        override2 = {'techs.test_conversion_plus.essentials.primary_carrier_in': 'coal'}
        override3 = {'techs.test_conversion_plus.essentials.primary_carrier_out': 'coal'}

        model = build_model({}, scenario='simple_conversion_plus,two_hours')
        assert model._model_run.techs.test_conversion_plus.essentials.get_key(
            'primary_carrier_in', None
        ) == 'gas'

        # should fail: multiple carriers in, but no primary_carrier_in assigned
        with pytest.raises(exceptions.ModelError) as error:
            build_model(override1, scenario='simple_conversion_plus,two_hours')
        assert check_error_or_warning(error, 'Primary_carrier_in must be assigned')

        # should fail: primary_carrier_in not one of the carriers_in
        with pytest.raises(exceptions.ModelError) as error:
            build_model(override2, scenario='simple_conversion_plus,two_hours')
        assert check_error_or_warning(error, 'Primary_carrier_in `coal` not one')

        # should fail: primary_carrier_out not one of the carriers_out
        with pytest.raises(exceptions.ModelError) as error:
            build_model(override3, scenario='simple_conversion_plus,two_hours')
        assert check_error_or_warning(error, 'Primary_carrier_out `coal` not one')
Exemplo n.º 41
0
 def test_systemwide_emissions_max_constraint(self):
     model = build_model(
         model_file='model_cost_cap.yaml',
         scenario='emissions_max_systemwide'
     )
     model.run()
     emissions = (model.get_formatted_array('cost')
                       .loc[{'costs': 'emissions'}]).sum().item()
     assert round(emissions, 5) <= 400
Exemplo n.º 42
0
 def test_systemwide_energy_cap_max_constraint(self):
     model = build_model(
         model_file='energy_cap.yaml',
         scenario='energy_cap_max_systemwide'
     )
     model.run()
     cheap_capacity = (model.get_formatted_array("energy_cap")
                            .loc[{'techs': "cheap_supply"}].sum()).item()
     assert round(cheap_capacity, 5) <= 14
Exemplo n.º 43
0
 def test_systemwide_cost_equals_constraint(self):
     model = build_model(
         model_file='model_cost_cap.yaml',
         scenario='cheap_cost_equals_systemwide'
     )
     model.run()
     cheap_cost = (model.get_formatted_array('cost')
                        .loc[{'costs': 'monetary', 'techs': 'cheap_polluting_supply'}]).sum().item()
     assert cheap_cost == approx(210)
Exemplo n.º 44
0
 def test_undefined_carriers(self):
     """
     Test that user has input either carrier or carrier_in/_out for each tech
     """
     override = AttrDict.from_yaml_string("""
         techs:
             test_undefined_carrier:
                 essentials:
                     parent: supply
                     name: test
                 constraints:
                     resource: .inf
                     energy_cap_max: .inf
         locations.1.techs.test_undefined_carrier:
         """)
     with pytest.raises(exceptions.ModelError):
         build_model(override_dict=override,
                     scenario='simple_supply,one_day')
Exemplo n.º 45
0
    def test_15min_timesteps(self):

        override = {
            'techs.test_demand_elec.constraints.resource': 'file=demand_elec_15mins.csv',
        }

        model = build_model(override, scenario='simple_supply,one_day')

        assert model.inputs.timestep_resolution.to_pandas().unique() == [0.25]
Exemplo n.º 46
0
 def test_no_constraint_set(self, model_file):
     model = build_model(model_file=model_file)
     model.run()
     assert model.results.termination_condition == "optimal"
     energy_capacity = model.get_formatted_array("energy_cap").loc[{'techs': 'my_storage'}].sum().item()
     storage_capacity = model.get_formatted_array("storage_cap").loc[{'techs': 'my_storage'}].sum().item()
     assert energy_capacity == pytest.approx(10)
     assert storage_capacity == pytest.approx(175)
     assert storage_capacity != pytest.approx(1 / 10 * energy_capacity)
    def test_locations_instead_of_nodes(self):
        with pytest.warns(DeprecationWarning) as warning:
            model = build_model(
                scenario="simple_supply_locations,one_day,investment_costs")

        assert check_error_or_warning(warning, "`locations` has been renamed")

        model.run()
        assert model.get_formatted_array("carrier_prod").sum() == 420
Exemplo n.º 48
0
    def test_force_resource_ignored(self):
        """
        If a technology is defines force_resource but is not in loc_techs_finite_resource
        it will have no effect
        """

        override = {
            'techs.test_supply_elec.constraints.resource': np.inf,
            'techs.test_supply_elec.constraints.force_resource': True,
        }

        with pytest.warns(exceptions.ModelWarning) as excinfo:
            build_model(override_dict=override, scenario='simple_supply,one_day')

        assert check_error_or_warning(
            excinfo,
            '`test_supply_elec` at `0` defines force_resource but not a finite resource'
        )
Exemplo n.º 49
0
 def test_systemwide_resource_area_max_constraint(self):
     model = build_model(
         model_file='resource_area.yaml',
         scenario='resource_area_max_systemwide'
     )
     model.run()
     cheap_resource_area = (model.get_formatted_array("resource_area")
                                 .loc[{'techs': "cheap_supply"}].sum()).item()
     assert cheap_resource_area == 20
Exemplo n.º 50
0
 def test_systemwide_resource_area_min_constraint(self):
     model = build_model(
         model_file='resource_area.yaml',
         scenario='resource_area_min_systemwide'
     )
     model.run()
     resource_area = model.get_formatted_array("resource_area")
     assert resource_area.loc[{'techs': "cheap_supply"}].sum().item() == 0
     assert resource_area.loc[{'techs': "expensive_supply"}].sum().item() == 20
Exemplo n.º 51
0
    def test_missing_constraints(self):
        """
        A technology must define at least one constraint.
        """

        override = AttrDict.from_yaml_string(
            """
            techs:
                supply_missing_constraint:
                    essentials:
                        parent: supply
                        carrier: electricity
                        name: supply missing constraint
            locations.1.techs.supply_missing_constraint:
            """
        )
        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override, scenario='simple_supply,one_day')
Exemplo n.º 52
0
 def test_systemwide_cost_min_constraint(self):
     model = build_model(
         model_file='model_cost_cap.yaml',
         scenario='expensive_cost_min_systemwide'
     )
     model.run()
     expensive_cost = (model.get_formatted_array('cost')
                            .loc[{'costs': 'monetary', 'techs': 'expensive_clean_supply'}]).sum().item()
     assert round(expensive_cost, 5) >= 600
Exemplo n.º 53
0
    def test_empty_dimensions(self):
        """
        Empty dimensions lead Pyomo to blow up (building sets with no data),
        so check that we have successfully removed them here.
        """

        model = build_model(scenario='simple_conversion_plus,one_day')

        assert 'distance' not in model._model_data.data_vars
        assert 'lookup_remotes' not in model._model_data.data_vars
Exemplo n.º 54
0
    def test_milp_constraints(self):
        """
        If `units` is defined, but not `energy_cap_per_unit`, throw an error
        """

        # should fail: no energy_cap_per_unit
        override1 = AttrDict.from_yaml_string("techs.test_supply_elec.constraints.units_max: 4")

        with pytest.raises(exceptions.ModelError):
            build_model(override_dict=override1, scenario='simple_supply,one_day')

        # should pass: energy_cap_per_unit given
        override2 = AttrDict.from_yaml_string("""
            techs.test_supply_elec.constraints:
                        units_max: 4
                        energy_cap_per_unit: 5
            """)

        build_model(override_dict=override2, scenario='simple_supply,one_day')
Exemplo n.º 55
0
 def test_undefined_carriers(self):
     """
     Test that user has input either carrier or carrier_in/_out for each tech
     """
     override = AttrDict.from_yaml_string(
         """
         techs:
             test_undefined_carrier:
                 essentials:
                     parent: supply
                     name: test
                 constraints:
                     resource: .inf
                     energy_cap_max: .inf
         locations.1.techs.test_undefined_carrier:
         """
     )
     with pytest.raises(exceptions.ModelError):
         build_model(override_dict=override, scenario='simple_supply,one_day')
Exemplo n.º 56
0
    def check_operate_mode_allowed(self):
        """
        On masking times, operate mode will no longer be allowed
        """

        model = build_model(scenario='simple_supply,one_day')
        assert model.model_data.attrs['allow_operate_mode'] == 1

        model1 = calliope.examples.time_masking()
        assert model1.model_data.attrs['allow_operate_mode'] == 0
Exemplo n.º 57
0
    def test_tech_as_parent(self):
        """
        All technologies and technology groups must specify a parent
        """

        override1 = AttrDict.from_yaml_string(
            """
            techs.test_supply_tech_parent:
                    essentials:
                        name: Supply tech
                        carrier: gas
                        parent: test_supply_elec
                    constraints:
                        energy_cap_max: 10
                        resource: .inf
            locations.1.test_supply_tech_parent:
            """
        )

        with pytest.raises(exceptions.ModelError) as error:
            build_model(override_dict=override1, scenario='simple_supply,one_day')
        check_error_or_warning(error, 'tech `test_supply_tech_parent` has another tech as a parent')

        override2 = AttrDict.from_yaml_string(
            """
            tech_groups.test_supply_group:
                    essentials:
                        carrier: gas
                        parent: test_supply_elec
                    constraints:
                        energy_cap_max: 10
                        resource: .inf
            techs.test_supply_tech_parent.essentials:
                        name: Supply tech
                        parent: test_supply_group
            locations.1.test_supply_tech_parent:
            """
        )

        with pytest.raises(exceptions.ModelError) as error:
            build_model(override_dict=override2, scenario='simple_supply,one_day')
        check_error_or_warning(error, 'tech_group `test_supply_group` has a tech as a parent')
Exemplo n.º 58
0
    def test_unspecified_parent(self):
        """
        All technologies and technology groups must specify a parent
        """

        override = AttrDict.from_yaml_string(
            """
            techs.test_supply_no_parent:
                    essentials:
                        name: Supply tech
                        carrier: gas
                    constraints:
                        energy_cap_max: 10
                        resource: .inf
            locations.1.test_supply_no_parent:
            """
        )

        with pytest.raises(KeyError):
            build_model(override_dict=override, scenario='simple_supply,one_day')
Exemplo n.º 59
0
    def test_delete_interest_rate(self):
        """
        If only 'interest_rate' is given in the cost class for a technology, we
        should be able to handle deleting it without leaving an empty cost key.
        """

        override1 = {
            'techs.test_supply_elec.costs.monetary.interest_rate': 0.1
        }
        m = build_model(override_dict=override1, scenario='simple_supply,one_day')
        assert 'loc_techs_cost' not in m._model_data.dims
Exemplo n.º 60
0
    def test_clustering_and_cyclic_storage(self):
        """
        Don't allow time clustering with cyclic storage if not also using
        storage_inter_cluster
        """

        override = {
            'model.subset_time': ['2005-01-01', '2005-01-04'],
            'model.time': {
                'function': 'apply_clustering',
                'function_options': {
                    'clustering_func': 'file=cluster_days.csv:0', 'how': 'mean',
                    'storage_inter_cluster': False
                }
            },
            'run.cyclic_storage': True
        }

        with pytest.raises(exceptions.ModelError) as error:
            build_model(override, scenario='simple_supply')

        assert check_error_or_warning(error, 'cannot have cyclic storage')