### Development Installation Source: https://docs.temoaproject.org/en/latest/quick_start.html Steps for contributors to clone the repository and set up a development environment. ```bash # Clone the repository $ git clone TemoaProject/temoa.git $ cd temoa # Install in development mode with uv (recommended) $ uv sync --all-extras --dev # Install pre-commit hooks $ uv run pre-commit install ``` -------------------------------- ### Install and Run Temoa with pip Source: https://docs.temoaproject.org/en/latest/_sources/quick_start.rst Standard installation and execution commands for Temoa using pip. ```bash # Install from PyPI $ pip install temoa # Get started $ temoa tutorial $ temoa run tutorial_config.toml ``` -------------------------------- ### Install and Run Temoa with uv Source: https://docs.temoaproject.org/en/latest/_sources/quick_start.rst Alternative installation and execution commands using the uv package manager for faster dependency resolution. ```bash # Install uv (Linux / macOS) $ curl -LsSf https://astral.sh/uv/install.sh | sh # Install uv (Windows) PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Create a uv initialized virtual environment $ uv init $ cd # add Temoa from PyPI to pyproject.toml $ uv add temoa # Get started $ uv run temoa tutorial $ uv run temoa run tutorial_config.toml ``` -------------------------------- ### Development Installation Source: https://docs.temoaproject.org/en/latest/_sources/quick_start.rst Commands for cloning the repository and setting up a development environment with pre-commit hooks. ```bash # Clone the repository $ git clone https://github.com/TemoaProject/temoa.git $ cd temoa # Install in development mode with uv (recommended) $ uv sync --all-extras --dev # Install pre-commit hooks $ uv run pre-commit install ``` -------------------------------- ### Pedagogical Code Style Source: https://docs.temoaproject.org/en/latest/_sources/computational_implementation.rst Example of implementing logic to read like an English sentence. ```python if ( a > 5 and a < 10 ): doSomething() ``` -------------------------------- ### Install mpi-sppy dependency Source: https://docs.temoaproject.org/en/latest/_sources/stochastics.rst Install the required mpi-sppy package using either uv or pip. ```bash uv add mpi-sppy ``` ```bash pip install mpi-sppy ``` -------------------------------- ### Sample Unit Check Report Source: https://docs.temoaproject.org/en/latest/_sources/unit_checking.rst Example output from a unit check report showing validation results for various tables. ```text ======== Units Check 1 (DB Version): Started ======== Units Check 1 (DB Version): Passed ======== Units Check 2 (Units Entries in Tables): Started ======== existing_capacity: Energy units (not capacity) in capacity table: GW*year at rows: 1, 2, 3 ======== Units Check 3 (Tech I/O via Efficiency Table): Started ======== Efficiency units conflict with associated commodity for Technology E01 near row 1 ======== Units Check 4 (Related Tables): Started ======== limit_capacity: Non-standard units for tech E01 (expected GW) got: MW at rows: 5, 6 ======== Units Check 5 (Cost Tables): Started ======== cost_invest: Non-matching measure unit for tech/comm: E01 Table entry: Mdollar / (PJ) Expected: petajoule ** 2 / gigawatt Found: petajoule at rows: 1, 2, 3 ``` -------------------------------- ### Example Commit Message Summary Source: https://docs.temoaproject.org/en/latest/computational_implementation.html A template for a descriptive commit message that explains the rationale behind a code change. ```text Fixed broken storage algorithm The previous implementation erroneously assumed that only the energy flow out of a storage device mattered. However, Temoa needs to know the energy flow in to all devices so that it can appropriately calculate the inter-process commodity balance. License: MIT ``` -------------------------------- ### Define time_period table and insert data Source: https://docs.temoaproject.org/en/latest/_sources/database.rst Example SQL structure for the time_period table, including primary key definition and a foreign key reference to time_period_type. ```sql 1 CREATE TABLE time_period 2 ( 3 sequence INTEGER UNIQUE, 4 period INTEGER 5 PRIMARY KEY, 6 flag TEXT 7 REFERENCES time_period_type (label) 8 ); 9 INSERT INTO "time_period" VALUES(1,2015,'e'); 10 INSERT INTO "time_period" VALUES(2,2020,'f'); 11 INSERT INTO "time_period" VALUES(3,2025,'f'); 12 INSERT INTO "time_period" VALUES(4,2030,'f'); 13 INSERT INTO "time_period" VALUES(5,2035,'f'); ``` -------------------------------- ### Conditional Logic Semantic Improvements Source: https://docs.temoaproject.org/en/latest/computational_implementation.html Examples demonstrating how to structure conditional statements to mirror mathematical notation for better readability. ```python if ( a > 5 and a < 10 ): doSomething() ``` ```python if ( 5 < a and a < 10 ): doSomething() ``` ```python if ( a < 5 or a > 10 ): doSomething() ``` ```python if not ( 5 < a and a < 10 ): doSomething() ``` -------------------------------- ### Define Region Constraint with Exchange Flows Source: https://docs.temoaproject.org/en/latest/_sources/database.rst Example of a region string that includes specific exchange-technology keys to ensure flows between regions are included in the constraint summation. ```none east+east-west+west-east+west ``` -------------------------------- ### Initialize Technology and Commodity Sets Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/commodities.html Populates model subsets for flexible commodities and demand-satisfying technologies based on efficiency parameters. ```python def create_technology_and_commodity_sets(model: TemoaModel) -> None: """ Populates technology and commodity subset definitions based on their roles (e.g., demand, flexible) identified from the efficiency parameter. This function iterates through the `efficiency` parameter to identify and add technologies and commodities to special `Pyomo.Set` objects on the model. Populates: - M.commodity_flex: Commodities that can be over-produced. - M.tech_demand: Technologies that directly satisfy an end-use demand. """ logger.debug('Creating technology and commodity subsets.') for _r, _i, t, _v, o in model.efficiency.sparse_keys(): if t in model.tech_flex and o not in model.commodity_flex: model.commodity_flex.add(o) if o in model.commodity_demand and t not in model.tech_demand: model.tech_demand.add(t) ``` -------------------------------- ### Create and Activate Virtual Environment Source: https://docs.temoaproject.org/en/latest/_sources/quick_start.rst Commands to initialize and activate a Python virtual environment across different operating systems. ```bash # Linux / macOS $ python -m venv temoa_env $ source temoa_env/bin/activate # Windows (Command Prompt) > python -m venv temoa_env > temoa_env\Scripts\activate # Windows (PowerShell) PS> python -m venv temoa_env PS> .\temoa_env\Scripts\Activate.ps1 ``` -------------------------------- ### Python Line Wrapping and Formatting Source: https://docs.temoaproject.org/en/latest/_sources/computational_implementation.rst Demonstrates the preferred use of parentheses for line continuation and binary operator placement. ```python class Rectangle ( Blob ): def __init__ ( self, width, height, color='black', emphasis=None, highlight=0 ): if ( width == 0 and height == 0 and color == 'red' and emphasis == 'strong' or highlight > 100 ): raise ValueError("sorry, you lose") if width == 0 and height == 0 and (color == 'red' or emphasis is None): raise ValueError("I don't think so -- values are {}, {}".format( (width, height) )) Blob.__init__( self, width, height, color, emphasis, highlight ) ``` -------------------------------- ### Get Default Capacity Factor Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/capacity.html Initializer function to retrieve capacity factors from capacity_factor_tech when needed. ```python def get_default_capacity_factor( model: TemoaModel, r: Region, s: Season, d: TimeOfDay, t: Technology, v: Vintage ) -> float: """ This initializer is used to fill the capacity_factor_process from the capacity_factor_tech where needed. """ ``` -------------------------------- ### Explore branches and switch development versions Source: https://docs.temoaproject.org/en/latest/_sources/computational_implementation.rst List available branches and switch to a specific development branch within the repository. ```bash $ ls stochastic temoa tests pyproject.toml README.md $ git branch -a * energysystem remotes/origin/HEAD -> origin/energysystem remotes/origin/energysystem remotes/origin/exp_electric_load_duration_reorg remotes/origin/exp_electricity_sector remotes/origin/exp_energysystem_flow_based remotes/origin/exp_energysystem_match_markal remotes/origin/exp_energysystem_test_framework remotes/origin/misc_scripts remotes/origin/old_energysystem_coopr2 remotes/origin/temoaproject.org $ git checkout exp_energysystem_match_markal Branch exp_energysystem_match_markal set up to track remote branch exp_energysystem_match_markal from origin. Switched to a new branch 'exp_energysystem_match_markal' ``` -------------------------------- ### Import SQL Database via Command Line Source: https://docs.temoaproject.org/en/latest/_sources/database.rst Commands to convert a SQL file into a binary SQLite database file across different operating systems. ```bash $ sqlite3 my_database.sqlite < my_database.sql ``` ```powershell Get-Content my_database.sql | sqlite3 my_database.sqlite ``` ```none sqlite3 my_database.sqlite sqlite> .read my_database.sql ``` -------------------------------- ### Display Temoa Help Source: https://docs.temoaproject.org/en/latest/_sources/quick_start.rst Command to view available CLI options and commands. ```bash $ **temoa --help** Usage: temoa [OPTIONS] COMMAND [ARGS]... Tools for Energy Model Optimization and Analysis (Temoa) Options: -v, --version Show Temoa version and exit. --how-to-cite Show citation information and exit. -h, --help Show this message and exit. Commands: validate Validates a configuration file and database. run Builds and solves a Temoa model. check-units Check units consistency in a Temoa database. migrate Migrate a Temoa database file or directory. tutorial Create tutorial configuration and database files. ``` -------------------------------- ### Initialize Capacity and Retirement Sets Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/capacity.html Populates model-specific sets and dictionaries required for capacity and retirement calculations during model initialization. ```python def create_capacity_and_retirement_sets(model: TemoaModel) -> None: """ Creates and populates component-specific Python sets and dictionaries on the model object. This function is called once during model initialization and is responsible for creating the sparse indices related to technology capacity, retirement, and construction/end-of-life material flows. These data structures are then used by other functions in this module to build Pyomo components. Populates: - model.retirement_periods: dict mapping (r, t, v) to a set of periods `p` where retirement can occur. - model.capacity_consumption_techs: dict mapping (r, v, i) to a set of techs `t` that consume commodity `i` for construction. - model.retirement_production_processes: dict mapping (r, p, o) to a set of `(t, v)` processes that produce commodity `o` at end-of-life. - model.new_capacity_rtv: set of (r, t, v) for new capacity investments. - model.active_capacity_available_rpt: set of (r, p, t) where capacity is active. - model.active_capacity_available_rptv: set of (r, p, t, v) where vintage capacity is active. """ ``` -------------------------------- ### Define new capacity constraint Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/limits.html Sets a limit on the newly installed capacity of a given technology or group in a specific vintage year. ```python def limit_new_capacity_constraint( model: TemoaModel, r: Region, t: Technology, v: Vintage, op: str ) -> ExprLike: r""" The limit_new_capacity constraint sets a limit on the newly installed capacity of a given technology or group in a given vintage year. .. math:: :label: limit_new_capacity ``` -------------------------------- ### Implement Ramp Up Day Constraint Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/operations.html Calculates the hourly activity change between time slices and applies a constraint based on the technology's ramp-up rate. ```python s_next, d_next = model.time_next[s, d] # How many hours does this time slice represent hours_adjust = value(model.segment_fraction[s, d]) * value(model.days_per_period) * 24 hours_adjust_next = ( value(model.segment_fraction[s_next, d_next]) * value(model.days_per_period) * 24 ) hourly_activity_sd = ( sum( model.v_flow_out[r, p, s, d, S_i, t, v, S_o] for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) / hours_adjust ) hourly_activity_sd_next = ( sum( model.v_flow_out[r, p, s_next, d_next, S_i, t, v, S_o] for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) / hours_adjust_next ) # elapsed hours from middle of this time slice to middle of next time slice hours_elapsed = (model.time_of_day_hours[d] + model.time_of_day_hours[d_next]) / 2 ramp_fraction = hours_elapsed * value(model.ramp_up_hourly[r, t]) if ramp_fraction >= 1: msg = ( 'Warning: Hourly ramp up rate ({}, {}) is too large to be constraining from ' '({}, {}, {}) to ({}, {}, {}). ' f'Should be less than {1 / hours_elapsed:.4f}. Constraint skipped.' ) logger.warning(msg.format(r, t, p, s, d, p, s_next, d_next)) return Constraint.Skip activity_increase = hourly_activity_sd_next - hourly_activity_sd # opposite sign from rampdown rampable_activity = ( ramp_fraction * model.v_capacity[r, p, t, v] * value(model.capacity_to_activity[r, t]) / (24 * value(model.days_per_period)) # adjust capacity to hourly basis ) expr = activity_increase <= rampable_activity return expr ``` -------------------------------- ### Define Cost Table Units Source: https://docs.temoaproject.org/en/latest/_sources/unit_checking.rst Examples of unit definitions for investment and fixed costs, accounting for capacity-to-activity conversion and period-based scaling. ```text [V] cost_invest: "Mdollar / (PJ^2 / GW)" [V] cost_fixed: "Mdollar / (PJ^2 / GW / year)" (adds /year for period-based) ``` -------------------------------- ### Extension Framework Lifecycle Source: https://docs.temoaproject.org/en/latest/_sources/extensions.rst Visual representation of the extension lifecycle from configuration to model construction and data loading. ```text config: extensions = ["my_ext"] | v resolve_extension_specs() validate ids -> ExtensionSpec list | v TemoaModel(extensions=[...]) | +--> apply_model_extension_hooks() | calls spec.register_model_components(model) | -> attaches Params / Sets / Constraints to the model | v HybridLoader +--> ensure_enabled_extension_tables_exist() (offer to append schema) +--> assert_disabled_extension_tables_are_empty() +--> merge_regional_group_tables() +--> build_manifest() -> appends spec.build_manifest_items(model) -> loads each owned table into its component ``` -------------------------------- ### Enable extension in configuration Source: https://docs.temoaproject.org/en/latest/_sources/extensions.rst Add the extension identifier to the extensions list in the configuration TOML file to activate it. ```toml extensions = [""] ``` -------------------------------- ### Define Baseload Diurnal Constraint Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/operations.html Calculates the constraint expression to ensure activity across different times of day is equalized for baseload technologies. It uses multiplication to avoid division and returns a skip condition if the time index is at the start. ```python l_times = sorted(model.time_of_day) # i.e. a sorted Python list. # This is the commonality between invocations of this method. index = l_times.index(d) if 0 == index: # When index is 0, it means that we've reached the beginning of the array # For the algorithm, this is a terminating condition: do not create # an effectively useless constraint return Constraint.Skip # Step 2: Set the rest of the times of day equal in output to the first. # i.e. create a set of constraints that look something like: # tod[ 2 ] == tod[ 1 ] # tod[ 3 ] == tod[ 1 ] # tod[ 4 ] == tod[ 1 ] # and so on ... d_0 = l_times[0] # Step 3: the actual expression. For baseload, must compute the /average/ # activity over the segment. By definition, average is # (segment activity) / (segment length) # So: (ActA / SegA) == (ActB / SegB) # computationally, however, multiplication is cheaper than division, so: # (ActA * SegB) == (ActB * SegA) activity_sd = sum( model.v_flow_out[r, p, s, d, S_i, t, v, S_o] for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) activity_sd_0 = sum( model.v_flow_out[r, p, s, d_0, S_i, t, v, S_o] for S_i in model.process_inputs[r, p, t, v] for S_o in model.process_outputs_by_input[r, p, t, v, S_i] ) expr = activity_sd * value(model.segment_fraction[s, d_0]) == activity_sd_0 * value( model.segment_fraction[s, d] ) return expr ``` -------------------------------- ### Define Monte Carlo Settings Source: https://docs.temoaproject.org/en/latest/_sources/monte_carlo.rst Structure the CSV file to define parameter adjustments, including run index, parameter name, index, modification type, and value. ```none run,param,index,mod,value,notes 1,cost_invest,utopia|TXD|2010,a,-44.0,reduce invest cost to 1000 2,demand,utopia|2010|RH,r,0.1,increase demand by 10% 2,cost_fixed,utopia|TXD|2010|2010,s,15.0,set fixed cost to 15.0 ``` -------------------------------- ### Configure Single-Vector MGA (SVMGA) Source: https://docs.temoaproject.org/en/latest/_sources/mga.rst Enable SVMGA by setting the scenario mode to 'svmga' and specifying the labels for capacity, emissions, or activity to optimize. ```toml scenario_mode = "svmga" [SVMGA] cost_epsilon = 0.05 capacity_labels = ["solar_pv", "wind_onshore"] # emissions_labels = ["CO2"] # activity_labels = ["coal_power"] ``` -------------------------------- ### Verify extension imports Source: https://docs.temoaproject.org/en/latest/extensions.html Test that the extension module can be imported successfully. ```bash python -c "import temoa.extensions..extension" ``` -------------------------------- ### Configure Hull Expansion Source: https://docs.temoaproject.org/en/latest/_sources/mga.rst Enable hull expansion by setting the scenario mode to 'mga' and defining the MGA parameters in the configuration file. ```toml scenario_mode = "mga" [MGA] cost_epsilon = 0.05 # Relax cost by 5% iteration_limit = 20 # Maximum number of MGA iterations time_limit_hrs = 12 # Stop after 12 hours axis = "TECH_CATEGORY_ACTIVITY" weighting = "HULL_EXPANSION" ``` -------------------------------- ### Create vintage sets for split limits Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/limits.html Populates dictionaries mapping regions, periods, and technologies to sets of vintages for input/output split constraints. ```python def create_limit_vintage_sets(model: TemoaModel) -> None: """ Populates vintage-specific dictionaries for input/output split limit constraints. This function iterates through active processes and identifies which vintages are subject to split constraints, populating dictionaries that are then used by the index set functions below. Populates: - M.input_split_vintages: dict mapping (r, p, i, t, op) to a set of vintages `v`. - M.input_split_annual_vintages: dict for annual-specific input splits. - M.output_split_vintages: dict mapping (r, p, t, o, op) to a set of vintages `v`. - M.output_split_annual_vintages: dict for annual-specific output splits. """ logger.debug('Creating vintage sets for split limits.') # Assuming M.process_vintages is already populated for r, p, t in model.process_vintages: for v in model.process_vintages[r, p, t]: for i in model.process_inputs.get((r, p, t, v), []): for op in model.operator: if (r, p, i, t, op) in model.limit_tech_input_split: model.input_split_vintages.setdefault((r, p, i, t, op), set()).add(v) if (r, p, i, t, op) in model.limit_tech_input_split_annual: model.input_split_annual_vintages.setdefault((r, p, i, t, op), set()).add(v) for o in model.process_outputs.get((r, p, t, v), []): for op in model.operator: if (r, p, t, o, op) in model.limit_tech_output_split: model.output_split_vintages.setdefault((r, p, t, o, op), set()).add(v) if (r, p, t, o, op) in model.limit_tech_output_split_annual: model.output_split_annual_vintages.setdefault((r, p, t, o, op), set()).add( v ) ``` -------------------------------- ### Calculate Loan Costs with Survival Curves Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/costs.html Logic for calculating loan costs considering survival curves, with branching for discounted and undiscounted scenarios. ```python if not global_discount_rate: # Undiscounted result res = ( annuity * lifetime_loan_process # sum of loan payments over loan period / sum( # redistributed over survival curve within horizon value(model.lifetime_survival_curve[r, p, t, v]) for p in model.survival_curve_periods[r, t, v] if v <= p ) * sum( # summed over survival curve within horizon value(model.lifetime_survival_curve[r, p, t, v]) for p in model.survival_curve_periods[r, t, v] if v <= p < p_e ) ) else: # Discounted result res = ( annuity * annuity_to_pv( global_discount_rate, int(lifetime_loan_process) ) # PV of all loan payments, discounted to vintage year using GDR / sum( # redistributed over survival curve within horizon value( model.lifetime_survival_curve[r, p, t, v] ) # reamortised over survival curve of process using GDR * fv_to_pv( global_discount_rate, p - v + 1 ) # +1 because LSC is indexed to start of p not end of p for p in model.survival_curve_periods[r, t, v] if v <= p # this shouldnt be possible but play it safe ) * sum( # PV of all reamortised costs (within planning horizon) value(model.lifetime_survival_curve[r, p, t, v]) * fv_to_pv(global_discount_rate, p - v + 1) for p in model.survival_curve_periods[r, t, v] if v <= p < p_e ) * fv_to_pv( global_discount_rate, v - p_0 ) # finally, discounted from vintage year to P_0 ) return res ``` -------------------------------- ### Enable Visualization in Configuration Source: https://docs.temoaproject.org/en/latest/_sources/visualization.rst Add these settings to your TOML configuration file to trigger automatic generation of network visualizations during model execution. ```toml # Enable interactive HTML network graphs (requires source_trace = true) source_trace = true plot_commodity_network = true # Enable Graphviz static diagrams graphviz_output = true ``` -------------------------------- ### Compare Total System Cost across MGA iterations Source: https://docs.temoaproject.org/en/latest/_sources/mga.rst Retrieves the total system cost for all scenarios matching the MGA pattern. ```sql SELECT scenario, total_system_cost FROM output_objective WHERE scenario LIKE 'utopia_mga-%' ORDER BY scenario; ``` -------------------------------- ### Populate Operational Vintage Sets Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/operations.html Initializes dictionaries mapping technology vintages to specific operational characteristics like curtailment, storage, and ramping. This function should be called during model pre-computation. ```python def create_operational_vintage_sets(model: TemoaModel) -> None: """ Populates vintage-based dictionaries for technologies with special operational characteristics like curtailment, baseload, storage, ramping, and reserves. Populates: - M.curtailment_vintages, M.baseload_vintages, M.storage_vintages, M.ramp_up_vintages, M.ramp_down_vintages: Dictionaries mapping (r, p, t) to a set of vintages `v`. - M.process_reserve_periods: Dictionary mapping (r, p) to a set of (t, v) tuples. - M.is_seasonal_storage: A boolean lookup for seasonal storage technologies. """ logger.debug('Creating vintage sets for operational constraints.') for r, p, t in model.process_vintages: for v in model.process_vintages[r, p, t]: key_rpt = (r, p, t) key_rp = (r, p) if t in model.tech_curtailment: model.curtailment_vintages.setdefault(key_rpt, set()).add(v) if t in model.tech_baseload: model.baseload_vintages.setdefault(key_rpt, set()).add(v) if t in model.tech_storage: model.storage_vintages.setdefault(key_rpt, set()).add(v) if t in model.tech_upramping: model.ramp_up_vintages.setdefault(key_rpt, set()).add(v) if t in model.tech_downramping: model.ramp_down_vintages.setdefault(key_rpt, set()).add(v) if t in model.tech_reserve: model.process_reserve_periods.setdefault(key_rp, set()).add((t, v)) # A dictionary of whether a storage tech is seasonal, just to speed things up for t in model.tech_storage: model.is_seasonal_storage[t] = t in model.tech_seasonal_storage ``` -------------------------------- ### Initialize Fixed and Variable Costs Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/costs.html Populates unspecified fixed and variable costs using vintage defaults. This function is marked as deprecated. ```python @deprecated(reason='vintage defaults are no longer available, so this should not be needed') def create_costs(model: TemoaModel) -> None: """ Steps to creating fixed and variable costs: 1. Collect all possible cost indices (cost_fixed, cost_variable) 2. Find the ones _not_ specified in cost_fixed and cost_variable 3. Set them, based on Cost*VintageDefault """ logger.debug('Started Creating Fixed and Variable costs in CreateCosts()') cost_fixed = model.cost_fixed cost_variable = model.cost_variable # Step 1 fixed_indices = set(model.cost_fixed_rptv) var_indices = set(model.cost_variable_rptv) # Step 2 unspecified_fixed_prices = fixed_indices.difference(cost_fixed.sparse_keys()) unspecified_var_prices = var_indices.difference(cost_variable.sparse_keys()) # Step 3 # Some hackery: We futz with _constructed because Pyomo thinks that this # Param is already constructed. However, in our view, it is not yet, # because we're specifically targeting values that have not yet been # constructed, that we know are valid, and that we will need. if unspecified_fixed_prices: # CF._constructed = False for r, p, t, v in unspecified_fixed_prices: if (r, t, v) in model.cost_fixed_vintage_default: cost_fixed[r, p, t, v] = model.cost_fixed_vintage_default[ r, t, v ] # CF._constructed = True if unspecified_var_prices: # CV._constructed = False for r, p, t, v in unspecified_var_prices: if (r, t, v) in model.cost_variable_vintage_default: cost_variable[r, p, t, v] = model.cost_variable_vintage_default[r, t, v] # CV._constructed = True logger.debug('Created M.cost_fixed with size: %d', len(value(model.cost_fixed))) logger.debug('Created M.cost_variable with size: %d', len(value(model.cost_variable))) logger.debug('Finished creating Fixed and Variable costs') ``` -------------------------------- ### Execute Temoa Model Source: https://docs.temoaproject.org/en/latest/_sources/quick_start.rst Command to run the Temoa model using a specific configuration file. ```bash $ temoa run tutorial_config.toml ``` -------------------------------- ### Configure Parallel Execution and Solver Options Source: https://docs.temoaproject.org/en/latest/_sources/mga.rst Define the number of worker processes and solver-specific settings in an MGA_solver_options.toml file. ```toml # Global setting at the top level of the file num_workers = 4 [gurobi] Method = 2 Threads = 4 # Threads per solver instance BarConvTol = 0.01 ``` -------------------------------- ### Build Component Manifest for Data Loading Source: https://docs.temoaproject.org/en/latest/_sources/computational_implementation.rst Configures the mapping between model components and database tables for parameter loading. ```python def build_manifest(model: TemoaModel) -> list[LoadItem]: manifest = [ ... LoadItem( component=model.demand, # param name table='demand', # database table name columns=['region', 'period', 'commodity', 'demand'], # indices and value column ), ... ] ``` -------------------------------- ### Configure Monte Carlo Mode Source: https://docs.temoaproject.org/en/latest/_sources/monte_carlo.rst Enable Monte Carlo mode by updating the configuration TOML file with the scenario mode and path to settings. ```toml scenario_mode = "monte_carlo" [monte_carlo] run_settings = "path/to/mc_settings.csv" solver_options = "mc_solver_options.toml" # Optional ``` -------------------------------- ### Analyze Capacity Diversity using SQL Joins Source: https://docs.temoaproject.org/en/latest/_sources/mga.rst Calculates the difference in capacity for a specific technology between two distinct MGA scenarios. ```sql SELECT a.scenario, a.tech, a.capacity as cap_a, b.capacity as cap_b, (a.capacity - b.capacity) as diff FROM output_net_capacity a JOIN output_net_capacity b ON a.tech = b.tech AND a.period = b.period WHERE a.scenario = 'utopia_mga-1' AND b.scenario = 'utopia_mga-0' AND a.tech = 'solar_pv'; ``` -------------------------------- ### Recommended Extension Package Layout Source: https://docs.temoaproject.org/en/latest/_sources/extensions.rst Standard directory structure for organizing extension code to mirror the core Temoa model architecture. ```text temoa/extensions// __init__.py # re-export the ExtensionSpec extension.py # the ExtensionSpec definition data_manifest.py # build_manifest_items() tables.sql # CREATE TABLE IF NOT EXISTS for owned tables core/ __init__.py model.py # typing subtype + register_model_components() components/ __init__.py .py # one module per constraint family ``` -------------------------------- ### Verify extension types with Mypy Source: https://docs.temoaproject.org/en/latest/extensions.html Run Mypy on the extension directory to ensure type safety. ```bash mypy temoa/extensions/ ``` -------------------------------- ### Naive Summation Approach Source: https://docs.temoaproject.org/en/latest/_sources/computational_implementation.rst An inefficient approach using a list and for-loops to calculate supply, which requires multiple iterations. ```python to_sum = list() for S_t in model.tech_all: for S_v in model.vintage_all: for S_i in process_inputs_by_output( r, p, S_t, S_v, dem ): to_sum.append( model.v_flow_out_annual[r, p, S_i, S_t, S_v, dem] ) supply_annual = sum( to_sum ) ``` -------------------------------- ### Run Unit Checking via CLI Source: https://docs.temoaproject.org/en/latest/_sources/unit_checking.rst Execute standalone unit validation on a database file using the Temoa command-line interface. ```bash # Basic usage temoa check-units path/to/database.sqlite # Custom output directory temoa check-units database.sqlite --output ./reports # Silent mode (for scripting) temoa check-units database.sqlite --silent ``` -------------------------------- ### Enable Unit Checking in Configuration Source: https://docs.temoaproject.org/en/latest/_sources/unit_checking.rst Add this setting to your config.toml file to activate the unit validation system. ```toml check_units = true ``` -------------------------------- ### Create Demand Distributions Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/commodities.html Validates and populates demand distributions, ensuring all defined demands are utilized and correctly mapped to time slices. ```python def create_demands(model: TemoaModel) -> None: """ Steps to create the demand distributions 1. Use Demand keys to ensure that all demands in commodity_demand are used 2. Find any r p demands without any DSD and fill those with segfrac (flat demand distribution) 3. Warn if any subset of time slices missing for any r p demand with DSD defined 4. Validate that the per-demand distributions sum to 1. """ logger.debug('Started creating demand distributions in CreateDemands()') demand_specific_distribution = model.demand_specific_distribution # Warn if any demand commodities are going unused used_dems = {dem for _r, _p, dem in model.demand.sparse_keys()} unused_dems = sorted(model.commodity_demand.difference(used_dems)) if unused_dems: for dem in unused_dems: msg = "Warning: Demand '{}' is unused\n" logger.warning(msg.format(dem)) # Iterate over defined r p demands used_rp_dems = {(r, p, dem) for r, p, dem in model.demand.sparse_keys()} all_time_slices = set(cross_product(model.time_season, model.time_of_day)) expected_key_length = len(all_time_slices) dsd_keys_by_rpd: dict[Any, Any] = {} for _r, _p, _s, _d, _dem in demand_specific_distribution.sparse_keys(): dsd_keys_by_rpd.setdefault((_r, _p, _dem), []).append((_r, _p, _s, _d, _dem)) for r, p, dem in used_rp_dems: keys = dsd_keys_by_rpd.get((r, p, dem), []) if len(keys) > expected_key_length: msg = ( f'Too many demand_specific_distribution keys defined for {(r, p, dem)}. ' f'Expected at most one per time slice ({expected_key_length}) ' f'but found {len(keys)}. Likely code error.' ) logger.error(msg) raise ValueError(msg) ``` -------------------------------- ### Compare Technology Capacity across MGA iterations Source: https://docs.temoaproject.org/en/latest/_sources/mga.rst Filters capacity results for a specific technology across all MGA scenarios. ```sql SELECT scenario, tech, period, capacity, units FROM output_net_capacity WHERE scenario LIKE 'utopia_mga-%' AND tech = 'solar_pv' ORDER BY scenario, period; ``` -------------------------------- ### Implement Capacity Delta Constraint Logic Source: https://docs.temoaproject.org/en/latest/_modules/temoa/extensions/growth_rates/components/growth_new_capacity_delta.html Core logic for calculating the acceleration of new capacity deployment, supporting both growth and degrowth scenarios. ```python def limit_growth_new_capacity_delta( model: GrowthRatesModel, r: Region, p: Period, t: Technology, op: str, degrowth: bool = False, ) -> ExprLike: r""" Constrain the acceleration of new capacity deployed between periods. Forces the model to ramp up and down the change in deployment of new technologies more smoothly. Has constant (seed, :math:`S_{r,t}`) and proportional (rate, :math:`R_{r,t}`) terms. It is recommended to leave the rate term empty as it would prevent the possibility of inflection in the rate of deployment. This constraint can be defined for a technology group instead of one technology, in which case, new capacity is summed over all technologies in the group. In the first period, previous new capacities are replaced by previous existing capacities, if any can be found. .. math:: :label: Limit (De)Growth New Capacity Delta \begin{aligned}\text{Growth:}\\ &\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}} \quad \le, \ge, \text{or} = \quad S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}}) \end{aligned} \text{ where } v_i=p \qquad \forall \{r, p, t\} \in \Theta_{\text{limit\_growth\_capacityDelta}} \begin{aligned}\text{Degrowth:}\\ &\mathbf{NCAP}_{r,t,v_{i-1}} - \mathbf{NCAP}_{r,t,v_{i-2}} \quad \le, \ge, \text{or} = \quad S_{r,t} + (1+R_{r,t}) \cdot (\mathbf{NCAP}_{r,t,v_i} - \mathbf{NCAP}_{r,t,v_{i-1}}) \end{aligned} \text{ where } v_i=p \qquad \forall \{r, p, t\} \in \Theta_{\text{limit\_degrowth\_capacityDelta}} """ regions = geography.gather_group_regions(model, r) techs = technology.gather_group_techs(model, t) growth = ( model.limit_degrowth_new_capacity_delta if degrowth else model.limit_growth_new_capacity_delta ) rate = 1 + value(growth[r, t, op][0]) seed = value(growth[r, t, op][1]) new_cap_rtv = model.v_new_capacity cap_rtv = {(_r, _t, _v) for _r, _t, _v in new_cap_rtv.keys() if _t in techs and _r in regions} periods = sorted({_v for _r, _t, _v in cap_rtv}) if len(periods) == 0: return Constraint.Skip new_cap = quicksum(new_cap_rtv[_r, _t, _v] for _r, _t, _v in cap_rtv if _v == p) new_cap_prev = 0.0 new_cap_prev2 = 0.0 ``` -------------------------------- ### Clone the Temoa repository Source: https://docs.temoaproject.org/en/latest/_sources/computational_implementation.rst Use this command to download the entire Temoa project source code and history to your local machine. ```bash $ git clone git://github.com/TemoaProject/temoa.git Cloning into 'temoa'... remote: Counting objects: 2386, done. remote: Compressing objects: 100% (910/910), done. remote: Total 2386 (delta 1552), reused 2280 (delta 1446) Receiving objects: 100% (2386/2386), 2.79 MiB | 1.82 MiB/s, done. Resolving deltas: 100% (1552/1552), done. ``` -------------------------------- ### Implement Index Function for Ramp-Up Constraints Source: https://docs.temoaproject.org/en/latest/_sources/computational_implementation.rst Generates a set of valid tuples for the ramp-up constraint based on existing model components. ```python def ramp_up_day_constraint_indices( model: TemoaModel, ) -> set[tuple[Region, Period, Season, TimeOfDay, Technology, Vintage]]: indices = { (r, p, s, d, t, v) for r, p, t in model.ramp_up_vintages for v in model.ramp_up_vintages[r, p, t] for s in model.time_season for d in model.time_of_day } return indices ``` -------------------------------- ### Inspect local changes Source: https://docs.temoaproject.org/en/latest/computational_implementation.html Use git diff to see modifications made to the repository since the last commit. ```bash $ git diff diff --git a/temoa_model/temoa_lib.py b/temoa_model/temoa_lib.py index 4ff9b30..0ba15b0 100644 --- a/temoa_model/temoa_lib.py +++ b/temoa_model/temoa_lib.py @@ -246,7 +246,7 @@ def InitializeProcessParameters ( M ): if l_vin in M.vintage_exist: if l_process not in l_exist_indices: msg = ('Warning: %s has a specified efficiency, but does not ' - 'have any existing install base (existing_capacity)\n.') + 'have any existing install base (existing_capacity).\n') SE.write( msg % str(l_process) ) continue if 0 == M.existing_capacity[ l_process ]: [ ... ] ``` -------------------------------- ### Configure Temoa for stochastic mode Source: https://docs.temoaproject.org/en/latest/_sources/stochastics.rst Enable stochastic mode and specify the path to the stochastic configuration file in the main TOML file. ```toml scenario_mode = "stochastic" # ... other standard options ... [stochastic] # Path to the stochastic configuration file, relative to this file stochastic_config = "stochastic_config.toml" ``` -------------------------------- ### Define stochastic scenarios and perturbations Source: https://docs.temoaproject.org/en/latest/_sources/stochastics.rst Specify scenario probabilities and data perturbations in the stochastic configuration TOML file. ```toml # Define the scenarios [scenarios] # Each key is a scenario name, and the value is its probability # Probabilities must sum to 1.0 low_cost = 0.5 high_cost = 0.5 # Define perturbations for a specific scenario [[perturbations]] scenario = "low_cost" table = "cost_variable" # Filter specifies which rows in the table to perturb filter = { tech = "IMPHCO1" } # Action can be "multiply", "add", or "set" (defaults to "set") action = "multiply" value = 0.5 [[perturbations]] scenario = "high_cost" table = "cost_variable" filter = { tech = "IMPHCO1" } action = "multiply" value = 1.5 ``` -------------------------------- ### Implement constraint rule function Source: https://docs.temoaproject.org/en/latest/computational_implementation.html Use consistent naming for model, technology, and vintage parameters when defining constraint rules. ```python def capacity_constraint ( model: TemoaModel, t: Technology, v: Vintage ): ... ``` -------------------------------- ### Calculate Commodity Balance Constraints Source: https://docs.temoaproject.org/en/latest/_modules/temoa/components/commodities.html Calculates commodity consumption and production based on regional imports and exports, then enforces balance constraints. ```python # export of commodity c from region r to other regions if (r, p, c) in model.export_regions: consumed += sum( model.v_flow_out[cast('Region', r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o] / get_variable_efficiency( model, cast('Region', r + '-' + s_r), p, s_s, s_d, c, s_t, s_v, s_o ) for s_s in model.time_season for s_d in model.time_of_day for s_r, s_t, s_v, s_o in model.export_regions[r, p, c] if s_t not in model.tech_annual ) consumed += sum( model.v_flow_out_annual[cast('Region', r + '-' + s_r), p, c, s_t, s_v, s_o] / model.efficiency[cast('Region', r + '-' + s_r), c, s_t, s_v, s_o] for s_r, s_t, s_v, s_o in model.export_regions[r, p, c] if s_t in model.tech_annual ) # import of commodity c from other regions into region r if (r, p, c) in model.import_regions: produced += sum( model.v_flow_out[cast('Region', s_r + '-' + r), p, s_s, S_d, s_i, s_t, s_v, c] for s_s in model.time_season for S_d in model.time_of_day for s_r, s_t, s_v, s_i in model.import_regions[r, p, c] if s_t not in model.tech_annual ) produced += sum( model.v_flow_out_annual[cast('Region', s_r + '-' + r), p, s_i, s_t, s_v, c] for s_r, s_t, s_v, s_i in model.import_regions[r, p, c] if s_t in model.tech_annual ) annual_commodity_balance_constraint_error_check( produced, consumed, r, p, c, ) if c in model.commodity_waste: expr = produced >= consumed else: expr = produced == consumed return expr ``` -------------------------------- ### Declare Ramp-Up Constraint with Index Function Source: https://docs.temoaproject.org/en/latest/_sources/computational_implementation.rst Initializes a constraint set using an index function to handle complex dimensionality requirements. ```python self.ramp_up_day_constraint_rpsdtv = Set( dimen=6, initialize=operations.ramp_up_day_constraint_indices ) self.ramp_up_day_constraint = Constraint( self.ramp_up_day_constraint_rpsdtv, rule=operations.ramp_up_day_constraint ) ```