diff --git a/.travis.yml b/.travis.yml index 41f1cd5..ed6b408 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ os: - osx julia: - 1.0 - - 1.4 + - 1.5 - nightly codecov: true jobs: @@ -12,7 +12,7 @@ jobs: - julia: nightly include: - stage: "Documentation" - julia: 1.4 + julia: 1.5 os: linux script: - julia --project=docs/ -e 'using Pkg; Pkg.instantiate(); Pkg.develop(PackageSpec(path=pwd()))' diff --git a/README.md b/README.md index 649cbe4..cf3e888 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,94 @@ # GasPowerModels.jl - -Dev: [![Build Status](https://travis-ci.org/lanl-ansi/GasPowerModels.jl.svg?branch=master)](https://travis-ci.org/lanl-ansi/GasPowerModels.jl) [![codecov](https://codecov.io/gh/lanl-ansi/GasPowerModels.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/lanl-ansi/GasPowerModels.jl) -[![](https://img.shields.io/badge/docs-latest-blue.svg)](https://lanl-ansi.github.io/GasPowerModels.jl/latest) +[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://lanl-ansi.github.io/GasPowerModels.jl/stable) +[![](https://img.shields.io/badge/docs-latest-blue.svg)](https://lanl-ansi.github.io/GasPowerModels.jl/dev) -GasPowerModels.jl is a Julia/JuMP package for Simultaneous Steady-State Natural Gas and Electric Power Network Optimization. -It is designed to enable computational evaluation of emerging Gas-Grid network formulations and algorithms in a common platform. -The code is engineered to decouple problem specifications (e.g. Flow, Expansion planning, ...) from the gas and power network formulations (e.g. MINLP, MISOCP, ...) defined in PowerModels.jl and GasModels.jl -This enables the definition of a wide variety of formulations and their comparison on common problem specifications. +GasPowerModels.jl is a Julia/JuMP package for the joint optimization of steady state natural gas and power transmission networks. +It provides utilities for modeling problems that combine elements of natural gas and electric power systems. +It is designed to enable the computational evaluation of historical and emerging gas-power network optimization formulations and algorithms using a common platform. +The code is engineered to decouple problem specifications (e.g., gas-power flow, network expansion planning) from network formulations (e.g., mixed-integer linear, mixed-integer nonlinear). +This decoupling enables the definition of a variety of optimization formulations and their comparison on common problem specifications. **Core Problem Specifications** -* Flow (f) -* Expansion Planning (ne) +* Gas-Power Flow (`gpf`) +* Optimal Power Flow (`opf`) +* Network Expansion Planning (`ne`) +* Optimal Power Flow with Network Expansion Planning (`opf_ne`) **Core Network Formulations** -* MINLP -* MISOCP +* Mixed-integer nonconvex nonlinear program (`MINLP`) +* Mixed-integer second-order cone program (`MISOCP`) -## Installation +## Documentation +The package [documentation](https://lanl-ansi.github.io/GasPowerModels.jl/stable/) includes a [quick start guide](https://lanl-ansi.github.io/GasPowerModels.jl/stable/quickguide). -GasPowerModels.jl should be installed using the command +## Installation +The latest stable release of GasPowerModels can be installed using the Julia package manager with +```julia +] add GasPowerModels +``` -`add GasPowerModels` +For the current development version, install the package using +```julia +] add GasPowerModels#master +``` -At least one solver is required for running GasPowerModels. Commercial or psuedo-commerical solvers seem to handle these problems much better than some of the open source alternatives. Gurobi and Cplex perform well on the MISOCP model, and SCIP handles the MINLP model reasonably well. +Finally, test that the package works as expected by executing +```julia +] test GasPowerModels +``` -## Basic Usage +## Usage at a Glance +At least one optimization solver is required to run GasPowerModels. +The solver selected typically depends on the type of problem formulation being employed. +As an example, the mixed-integer nonlinear programming solver [Juniper](https://github.com/lanl-ansi/Juniper.jl) can be used for testing any of the problem formulations considered in this package. +Juniper itself depends on the installation of a nonlinear programming solver (e.g., [Ipopt](https://github.com/jump-dev/Ipopt.jl)) and a mixed-integer linear programming solver (e.g., [CBC](https://github.com/jump-dev/Cbc.jl)). +Installation of the JuMP interfaces to Juniper, Ipopt, and Cbc can be performed via the Julia package manager, i.e., -Once GasPowerModels is installed, a solver is installed, and a network data file has been acquired, a Gas-Grid Flow can be executed with, +```julia +] add JuMP Juniper Ipopt Cbc ``` + +After installation of the required solvers, an example gas-power flow feasibility problem (whose file inputs can be found in the `examples` directory within the [GasPowerModels repository](https://github.com/lanl-ansi/GasPowerModels.jl)) can be solved via +```julia +using JuMP, Juniper, Ipopt, Cbc using GasPowerModels -using -run_gpf("power.m", "gas.m", <>PowerModel, <>GasModel, <>Solver()) -``` +# Set up the optimization solvers. +ipopt = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "print_level"=>0, "sb"=>"yes") +cbc = JuMP.optimizer_with_attributes(Cbc.Optimizer, "logLevel"=>0) +juniper = JuMP.optimizer_with_attributes(Juniper.Optimizer, "nl_solver"=>ipopt, "mip_solver"=>cbc) -Similarly, an expansion solver can be executed with, -``` -run_ne("power.m", "gas.m", <>PowerModel, <>GasModel, <>Solver()) -``` +# Specify paths to the gas and power network files. +g_file = "examples/data/matgas/belgian.m" # Gas network. +p_file = "examples/data/matpower/case14.m" # Power network. -where <>GasModel is the implementation of the mathematical program of the Gas equations you plan to use (i.e. MINLPGasModel) and <>Solver is the JuMP solver you want to use to solve the optimization problem (i.e. IpoptSolver). +# Specify the gas and power formulation types separately. +g_type, p_type = MISOCPGasModel, SOCWRPowerModel +# Solve the gas-power flow feasibility problem. +result = run_gpf(g_file, p_file, g_type, p_type, juniper; + gm_solution_processors=[GasPowerModels._GM.sol_psqr_to_p!], + pm_solution_processors=[GasPowerModels._PM.sol_data_model!]) +``` -## Acknowledgments +After solving the problem, results can then be analyzed, e.g., +```julia +# The termination status of the optimization solver. +result["termination_status"] -The primary developers are Russell Bent and Kaarthik Sundar. Significant contributions on the technical model were made by Conrado Borraz-Sanchez, Pascal van Hentenryck, and Seth Blumsack. +# Generator 1's real power generation. +result["solution"]["gen"]["1"]["pg"] -Special thanks to Miles Lubin and Carleton Coffrin for their assistance in integrating with Julia/JuMP and PowerModels.jl. +# Junction 1's pressure. +result["solution"]["junction"]["1"]["p"] +``` +## Acknowledgments +The primary developers are Russell Bent and Kaarthik Sundar. +Significant contributions on the technical model were made by Conrado Borraz-Sanchez, Pascal van Hentenryck, and Seth Blumsack. +Special thanks to Miles Lubin and Carleton Coffrin for their assistance in integrating with Julia/JuMP and PowerModels.jl. ## License - This code is provided under a BSD license as part of the Multi-Infrastructure Control and Optimization Toolkit (MICOT) project, LA-CC-13-108. diff --git a/docs/README.md b/docs/README.md index e9de0b7..176e954 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,21 +1,21 @@ # Building the Documentation for GasPowerModels.jl ## Installation -We rely on [Documenter.jl](https://github.com/JuliaDocs/Documenter.jl). To install it, run the following command in a julia session: - +We rely on [Documenter.jl](https://github.com/JuliaDocs/Documenter.jl). +To install it, run the following command in a Julia session: ```julia Pkg.add("Documenter") ``` ## Building the Docs -To preview the html output of the documents, run the following command: - +To preview the HTML output of the documents, run the following command: ```julia julia --color=yes make.jl ``` You can then view the documents in `build/index.html`. -**Warning**: Do not `git commit` the contents of build (or any other content generated by Documenter) to your repository's master branch. This helps to avoid including unnecessary changes for anyone reviewing commits that happen to include documentation changes. +**Warning**: Do not `git commit` the contents of build (or any other content generated by Documenter) to your repository's master branch. +This helps to avoid including unnecessary changes for anyone reviewing commits that happen to include documentation changes. -For further details, please read the [documentation for Documenter.jl](https://juliadocs.github.io/Documenter.jl/stable/). \ No newline at end of file +For further details, please read the [documentation for Documenter.jl](https://juliadocs.github.io/Documenter.jl/stable/). diff --git a/docs/src/constraints.md b/docs/src/constraints.md index 3c649e4..6bd83eb 100644 --- a/docs/src/constraints.md +++ b/docs/src/constraints.md @@ -1,5 +1,4 @@ # Constraints - ```@autodocs Modules = [GasPowerModels] Pages = ["core/constraint_template.jl"] diff --git a/docs/src/developer.md b/docs/src/developer.md index 2af95dc..4796167 100644 --- a/docs/src/developer.md +++ b/docs/src/developer.md @@ -1,3 +1 @@ # Developer Documentation - -Nothing yet. diff --git a/docs/src/formulations.md b/docs/src/formulations.md index 3216899..ce00934 100644 --- a/docs/src/formulations.md +++ b/docs/src/formulations.md @@ -1,4 +1,2 @@ # Network Formulations - -The network formulations for coupled gas grid modeling directly use the formulations defined in GasModels.jl and PowerModels.jl - +The network formulations for joint gas-power modeling use the formulations defined in GasModels.jl and PowerModels.jl. diff --git a/docs/src/index.md b/docs/src/index.md index eb0db9a..1e470c2 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -5,33 +5,70 @@ CurrentModule = GasPowerModels ``` ## Overview - -GasPowerModels.jl is a Julia/JuMP package for Steady-State Gas Network Optimization. It provides utilities for modeling problems that combine elements of natural gas and electric power systems. It is designed to enable computational evaluation of emerging gas and power network formulations and algorithms in a common platform. - -The code is engineered to decouple [Problem Specifications](@ref) (e.g. Flow, Expansion Planning, ...) from [Network Formulations](@ref) (e.g. MINLP, MISOC-relaxation, ...). This enables the definition of a wide variety of coupled network formulations and their comparison on common problem specifications. +GasPowerModels.jl is a Julia/JuMP package for the joint optimization of steady state natural gas and power transmission networks. +It provides utilities for modeling problems that combine elements of natural gas and electric power systems. +It is designed to enable the computational evaluation of historical and emerging gas-power network optimization formulations and algorithms using a common platform. +The code is engineered to decouple [Problem Specifications](@ref) (e.g., gas-power flow, network expansion planning) from [Network Formulations](@ref) (e.g., mixed-integer linear, mixed-integer nonlinear). +This decoupling enables the definition of a variety of optimization formulations and their comparison on common problem specifications. ## Installation - -The latest stable release of GasPowerModels will be installed using the Julia package manager with - +The latest stable release of GasPowerModels can be installed using the Julia package manager with ```julia -Pkg.add("GasPowerModels") +] add GasPowerModels ``` -For the current development version, "checkout" this package with +For the current development version, install the package using +```julia +] add GasPowerModels#master +``` +Finally, test that the package works as expected by executing ```julia -Pkg.checkout("GasPowerModels") +] test GasPowerModels ``` -At least one solver is required for running GasModels. The open-source solver Pavito is recommended and can be used to solve a wide variety of the problems and network formulations provided in GasModels. The Pavito solver can be installed via the package manager with +## Usage at a Glance +At least one optimization solver is required to run GasPowerModels. +The solver selected typically depends on the type of problem formulation being employed. +As an example, the mixed-integer nonlinear programming solver [Juniper](https://github.com/lanl-ansi/Juniper.jl) can be used for testing any of the problem formulations considered in this package. +Juniper itself depends on the installation of a nonlinear programming solver (e.g., [Ipopt](https://github.com/jump-dev/Ipopt.jl)) and a mixed-integer linear programming solver (e.g., [CBC](https://github.com/jump-dev/Cbc.jl)). +Installation of the JuMP interfaces to Juniper, Ipopt, and Cbc can be performed via the Julia package manager, i.e., ```julia -Pkg.add("Pavito") +] add JuMP Juniper Ipopt Cbc ``` -Test that the package works by running +After installation of the required solvers, an example gas-power flow feasibility problem (whose file inputs can be found in the `examples` directory within the [GasPowerModels repository](https://github.com/lanl-ansi/GasPowerModels.jl)) can be solved via +```julia +using JuMP, Juniper, Ipopt, Cbc +using GasPowerModels + +# Set up the optimization solvers. +ipopt = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "print_level"=>0, "sb"=>"yes") +cbc = JuMP.optimizer_with_attributes(Cbc.Optimizer, "logLevel"=>0) +juniper = JuMP.optimizer_with_attributes(Juniper.Optimizer, "nl_solver"=>ipopt, "mip_solver"=>cbc) + +# Specify paths to the gas and power network files. +g_file = "examples/data/matgas/belgian.m" # Gas network. +p_file = "examples/data/matpower/case14.m" # Power network. +# Specify the gas and power formulation types separately. +g_type, p_type = MISOCPGasModel, SOCWRPowerModel + +# Solve the gas-power flow feasibility problem. +result = run_gpf(g_file, p_file, g_type, p_type, juniper; + gm_solution_processors=[GasPowerModels._GM.sol_psqr_to_p!], + pm_solution_processors=[GasPowerModels._PM.sol_data_model!]) +``` + +After solving the problem, results can then be analyzed, e.g., ```julia -Pkg.test("GasPowerModels") +# The termination status of the optimization solver. +result["termination_status"] + +# Generator 1's real power generation. +result["solution"]["gen"]["1"]["pg"] + +# Junction 1's pressure. +result["solution"]["junction"]["1"]["p"] ``` diff --git a/docs/src/math-model.md b/docs/src/math-model.md index 0f39245..7db6ac9 100644 --- a/docs/src/math-model.md +++ b/docs/src/math-model.md @@ -1,15 +1,14 @@ # The GasPowerModels Mathematical Model - -As GasPowerModels implements a variety of coupled gas grid network optimization problems, the implementation is the best reference for precise mathematical formulations. This section provides a mathematical specification for a prototypical coupled gas grid Flow problem, to provide an overview of the typical mathematical models in GasPowerModels. - +As GasPowerModels implements a variety of coupled gas grid network optimization problems, the implementation is the best reference for precise mathematical formulations. +This section provides a mathematical specification for a prototypical coupled gas grid flow problem to provide an overview of the typical mathematical models in GasPowerModels. ## Coupled Gas Electric Power Flow - -GasPowerModels implements a steady-state model of gas flow and power flow based on the implementations of gas flows in GasModels.jl and power flows in PowerModels.jl. The key coupling constraint between -power and gas systems is through generators that consume gas to produce power. This is expressed in terms of a heat rate curve, i.e. - +GasPowerModels implements a steady-state model of gas flow and power flow based on the implementations of gas flows in GasModels.jl and power flows in PowerModels.jl. +The key coupling constraint between power and gas systems is through generators that consume gas to produce power. +This is expressed in terms of a heat rate curve, i.e. ```math f = e * \rho (h_2 * pg^2 + h_1 * pg + h_0) ``` -where $h$ is a quadratic function used to convert MW ($pg$) into Joules consumed per second. This is then converted to mass flow, $f$, (kg/s) of gas consumed to produce this energy. Here, $e$ is an energy factor (m^3/s) and $\rho$ is standard density (kg/m^3). - +where $h$ is a quadratic function used to convert MW ($pg$) into Joules consumed per second. +This is then converted to mass flow, $f$, (kg/s) of gas consumed to produce this energy. +Here, $e$ is an energy factor (m^3/s) and $\rho$ is standard density (kg/m^3). diff --git a/docs/src/model.md b/docs/src/model.md index aac9eea..e4240d3 100644 --- a/docs/src/model.md +++ b/docs/src/model.md @@ -1,4 +1,2 @@ # Gas Grid Model - A gas grid model is defined in terms of a GasModel and a PowerModel. - diff --git a/docs/src/network-data.md b/docs/src/network-data.md index 2e97e43..c49c413 100644 --- a/docs/src/network-data.md +++ b/docs/src/network-data.md @@ -1,49 +1,61 @@ # GasPowerModels Network Data Format - ## The Network Data Dictionary +Internally, GasPowerModels uses a dictionary to store network data for power systems (see PowerModels) and gas models (see GasModels.jl). +The dictionary uses strings as key values so it can be serialized to JSON for algorithmic data exchange. +The I/O for GasPowerModels utilizes the serializations available in PowerModels.jl and GasModels.jl to construct the two network models. +All data is assumed to be in per unit (non-dimenisionalized) or SI units. -Internally GasPowerModels utilizes a dictionary to store network data for power systems (see PowerModels) and gas models (see GasModels.jl). The dictionary uses strings as key values so it can be serialized to JSON for algorithmic data exchange. The I/O for GasPowerModels utilizes the serializations available in PowerModels.jl and GasModels.jl to construct the two network models. All data is assumed to be in per_unit (non dimenisionalized) or SI units. - -Besides the standard network data supported by GasModels.jl and PowerModels.jl, there are a few extra fields that are required to couple the two systems together. These are discussed as follows: - +Besides the standard network data supported by GasModels.jl and PowerModels.jl, there are a few extra fields that are required to couple the two systems together. +These are discussed as follows: ### Gas Networks - ```json { -"energy_factor": , # factor for converting the Joules per second used by a generator to m^3 per second gas consumption. SI units are m^3 per Joules -"price_zone":{ - "1":{ - "junctions": , # array of junction ids for a natural gas price zone - "cost_q": , # array of floats that model a quadractic cost curve on non-firm gas consumed in the zone. SI units are dollars per m^3 at standard pressure - "cost_p": , # array of floats that model a quadractic cost curve on pressure squared in the zone. SI units are dollars per pascals^2 - "min_cost" , # minimum cost per unit of non-firm gas consumed in the zone. SI units are dollars per m^3 at standard pressure - "constant_p" , # bias factor for weighting pressure penalty cost relative to demand penalty cost - ... + "energy_factor": , # Factor for converting the Joules per second used by a generator to m^3 per second gas consumption. SI units are m^3 per Joules. + "price_zone": { + "1": { + "cost_q_1": , # Quadratic coefficient on the cost curve for non-firm gas consumed in the zone. SI units are dollars per m^3 at standard pressure. + "cost_q_2": , # Linear coefficient on the cost curve for non-firm gas consumed in the zone. SI units are dollars per m^3 at standard pressure. + "cost_q_3": , # Constant term on the cost curve for non-firm gas consumed in the zone. SI units are dollars per m^3 at standard pressure. + "cost_p_1": , # Quadratic coefficient on the cost curve for pressure squared in the zone. SI units are dollars per Pascal^2. + "cost_p_2": , # Linear coefficient on the cost curve for pressure squared in the zone. SI units are dollars per Pascal^2. + "cost_p_3": , # Constant term on the cost curve for pressure squared in the zone. SI units are dollars per Pascal^2. + "min_cost": , # Minimum cost per unit of non-firm gas consumed in the zone. SI units are dollars per m^3 at standard pressure. + "constant_p": , # Bias factor for weighting pressure penalty cost relative to demand penalty cost. + ... + }, + "2": { + ... + }, + ... + }, + "junction": { + "1": { + "price_zone": # Index of the corresponding price zone for the junction. -1 implies no zone. + ... + }, + "2": { + ... + }, + ... }, - "2":{...}, ... } -} ``` ### Power Networks - ```json { "gen":{ "1":{ - "heat_rate_quad_coeff": , # quadratic term of a heat rate curve that converts MW into J/s. SI Units are J per MW produced in a second - "heat_rate_linear_coeff": , # linear term of a heat rate curve that converts MW into J/s. SI Units are J per MW produced in a second - "heat_rate_constant_coeff": , # constant term of a heat rate curve that converts MW into J/s. SI Units are J per MW produced in a second + "heat_rate_quad_coeff": , # Quadratic term of a heat rate curve that converts MW into J/s. SI Units are J per MW produced in a second + "heat_rate_linear_coeff": , # Linear term of a heat rate curve that converts MW into J/s. SI Units are J per MW produced in a second + "heat_rate_constant_coeff": , # Constant term of a heat rate curve that converts MW into J/s. SI Units are J per MW produced in a second ... }, - "2":{...}, + "2": { + ... + }, ... } -} ``` - - - - diff --git a/docs/src/objective.md b/docs/src/objective.md index 9c8af46..d4619dd 100644 --- a/docs/src/objective.md +++ b/docs/src/objective.md @@ -1,5 +1,4 @@ # Objective - ```@autodocs Modules = [GasPowerModels] Pages = ["core/objective.jl"] diff --git a/docs/src/parser.md b/docs/src/parser.md index f5ae63c..7fd6056 100644 --- a/docs/src/parser.md +++ b/docs/src/parser.md @@ -1,3 +1,2 @@ # File IO - -Parsing uses the native parsing features of GasModels.jl and PowerModels.jl \ No newline at end of file +Parsing uses the native parsing features of GasModels.jl and PowerModels.jl. diff --git a/docs/src/quickguide.md b/docs/src/quickguide.md index 504cb09..6e4dc92 100644 --- a/docs/src/quickguide.md +++ b/docs/src/quickguide.md @@ -1,55 +1,149 @@ # Quick Start Guide +## Installation +The latest stable release of GasPowerModels can be installed using the Julia package manager with +```julia +] add GasPowerModels +``` -Once GasGrid Models is installed, Pavito is installed, and network data files (e.g. `"test/data/belgion.json"`, `"test/data/case14.m"`) have been acquired, a Gas and Power Flow with SOC relaxations can be executed with, - +For the current development version, install the package using ```julia -using GasPowerModels -using Pavito +] add GasPowerModels#master +``` -run_gpf("../test/data/case14.m", "../test/data/belgian.json", SOCWRPowerModel, MISOCPGasModel, PavitoSolver()) +Finally, test that the package works as expected by executing +```julia +] test GasPowerModels ``` -Similarly, a full non-convex Gas and Power Flow can be executed with a MINLP solver like +### Installation of Optimization Solvers +At least one optimization solver is required to run GasPowerModels. +The solver selected typically depends on the type of problem formulation being employed. +As an example, the mixed-integer nonlinear programming solver [Juniper](https://github.com/lanl-ansi/Juniper.jl) can be used for testing any of the problem formulations considered in this package. +Juniper itself depends on the installation of a nonlinear programming solver (e.g., [Ipopt](https://github.com/jump-dev/Ipopt.jl)) and a mixed-integer linear programming solver (e.g., [CBC](https://github.com/jump-dev/Cbc.jl)). +Installation of the JuMP interfaces to Juniper, Ipopt, and Cbc can be performed via the Julia package manager, i.e., ```julia -run_gpf("../test/data/case14.m", "../test/data/belgian.json", ACPowerModel, MINLPGasModel, PavitoSolver()) +] add JuMP Juniper Ipopt Cbc ``` +## Solving a Problem +Once the above dependencies have been installed, obtain the files [`belgian-ne_opf.m`](https://raw.githubusercontent.com/lanl-ansi/GasPowerModels.jl/master/examples/data/matgas/belgian-ne_opf.m) and [`case14-ne.m`](https://raw.githubusercontent.com/lanl-ansi/GasPowerModels.jl/master/examples/data/matpower/case14-ne.m). +Here, `belgian-ne_opf.m` is a MATGAS file describing a portion of the Belgian gas network. +In accord, `case14-ne.m` is a MATPOWER file specifying a 14-bus power network. +The combination of data from these two files provides the required information to set up the problem. +After downloading the data, the optimal power flow with network expansion problem can be solved with +```julia +using JuMP, Juniper, Ipopt, Cbc +using GasPowerModels + +# Set up the optimization solvers. +ipopt = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "print_level"=>0, "sb"=>"yes") +cbc = JuMP.optimizer_with_attributes(Cbc.Optimizer, "logLevel"=>0) +juniper = JuMP.optimizer_with_attributes(Juniper.Optimizer, "nl_solver"=>ipopt, "mip_solver"=>cbc) -## Getting Results +# Specify paths to the gas and power network files. +g_file = "examples/data/matgas/belgian-ne_opf.m" # Gas network. +p_file = "examples/data/matpower/case14-ne.m" # Power network. -The run commands in GasPowerModels return detailed results data in the form of a dictionary. -This dictionary can be saved for further processing as follows, +# Specify the gas and power formulation types separately. +g_type, p_type = MISOCPGasModel, SOCWRPowerModel + +# Solve the optimal power flow with network expansion problem. +result = run_ne_opf(g_file, p_file, g_type, p_type, juniper; + gm_solution_processors=[GasPowerModels._GM.sol_psqr_to_p!], + pm_solution_processors=[GasPowerModels._PM.sol_data_model!]) +``` +## Obtaining Results +The `run` commands in GasPowerModels return detailed results data in the form of a Julia `Dict`. +This dictionary can be saved for further processing as follows: ```julia -run_gpf("../test/data/case14.m", "../test/data/belgian.json", SOCWRPowerModel, MISOCPGasModel, PavitoSolver()) +result = run_ne_opf(g_file, p_file, g_type, p_type, juniper; + gm_solution_processors=[GasPowerModels._GM.sol_psqr_to_p!], + pm_solution_processors=[GasPowerModels._PM.sol_data_model!]) ``` -For example, the algorithm's runtime and final objective value can be accessed with, +For example, the algorithm's runtime and final objective value can be accessed with +```julia +result["solve_time"] # Total solve time required (seconds). +result["objective"] # Final objective value (in units of the objective). +``` +The `"solution"` field contains detailed information about the solution produced by the `run` method. +For example, the following can be used to read the build status of the network expansion pipe in the gas system +```julia +result["solution"]["ne_pipe"]["16"]["z"] ``` -result["solve_time"] -result["objective"] +As another example, the following can be used to inspect pressures in the solution +```julia +Dict(name => data["p"] for (name, data) in result["solution"]["junction"]) +``` +As a final example, the following can be used to inspect real power generation in the solution +```julia +Dict(name => data["pg"] for (name, data) in result["solution"]["gen"]) ``` -The `"solution"` field contains detailed information about the solution produced by the run method. -For example, the following dictionary comprehension can be used to inspect the junction pressures in the solution, +For more information about GasPowerModels result data, see the [GasPowerModels Result Data Format](@ref) section. +## Accessing Different Formulations +To solve the preceding problem using the mixed-integer nonconvex model for natural gas flow, the following can be executed: +```julia +# Specify the gas and power formulation types separately. +g_type, p_type = MINLPGasModel, SOCWRPowerModel + +# Solve the optimal power flow with network expansion problem. +result = run_ne_opf(g_file, p_file, g_type, p_type, juniper; + gm_solution_processors=[GasPowerModels._GM.sol_psqr_to_p!], + pm_solution_processors=[GasPowerModels._PM.sol_data_model!]) ``` -Dict(name => data["p"] for (name, data) in result["solution"]["junction"]) + +## Modifying Network Data +The following example demonstrates one way to perform GasPowerModels solves while modifying network data. +```julia +# Read in the gas and power network data. +g_data = GasPowerModels._GM.parse_file(g_file) +p_data = GasPowerModels._PM.parse_file(p_file) + +# Ensure the two datasets use the same units for power. +resolve_units!(g_data, p_data) + +# Reduce the minimum pressures for selected nodes. +g_data["junction"]["1"]["p_min"] *= 0.1 +g_data["junction"]["2"]["p_min"] *= 0.1 +g_data["junction"]["3"]["p_min"] *= 0.1 + +# Solve the problem using `g_data` and `p_data`. +result_mod = run_ne_opf(g_data, p_data, g_type, p_type, juniper; + gm_solution_processors=[GasPowerModels._GM.sol_psqr_to_p!], + pm_solution_processors=[GasPowerModels._PM.sol_data_model!]) ``` -For more information about GasPowerModels result data see the [GasPowerModels Result Data Format](@ref) section. +## Alternate Methods for Building and Solving Models +The following example demonstrates how to decompose a `run_ne_opf` call into separate model building and solving steps. +This allows inspection of the JuMP model created by GasPowerModels: +```julia +# Read in the gas and power network data. +g_data = GasPowerModels._GM.parse_file(g_file) +p_data = GasPowerModels._PM.parse_file(p_file) +# Ensure the two datasets use the same units for power. +resolve_units!(g_data, p_data) -## Inspecting the Formulation -The following example demonstrates how to break a `run_gpf` call into separate model building and solving steps. This allows inspection of the JuMP model created by GasPowerModels for the gas flow problem, +# Store the required `ref` extensions for the problem. +gm_ref_extensions = [GasPowerModels._GM.ref_add_ne!, ref_add_price_zones!] +pm_ref_extensions = [GasPowerModels._PM.ref_add_on_off_va_bounds!, GasPowerModels._PM.ref_add_ne_branch!] -```julia -pm, gm = build_generic_model("../test/data/case14.m", "../test/data/belgian.json", SOCWRPowerModel, MISOCPGasModel, GasPowerModels.build_gpf) +# Instantiate the model. +gm, pm = instantiate_model(g_data, p_data, g_type, p_type, build_ne_opf, + gm_ref_extensions=gm_ref_extensions, pm_ref_extensions=pm_ref_extensions) -print(gm.model) -print(pm.model) +# Print the contents of the JuMP model. +println(gm.model) +``` -run_generic_model(pm, gm, PavitoSolver()) +The problem can then be solved and its two result dictionaries can be stored via: +```julia +# Create separate gas and power result dictionaries. +gas_result = GasPowerModels._IM.optimize_model!(gm, optimizer=juniper) +power_result = GasPowerModels._IM.build_result(pm, gas_result["solve_time"]) ``` diff --git a/docs/src/result-data.md b/docs/src/result-data.md index 367d24c..f10cf01 100644 --- a/docs/src/result-data.md +++ b/docs/src/result-data.md @@ -1,92 +1,49 @@ # GasPowerModels Result Data Format ## The Result Data Dictionary - -GasPowerModels utilizes a dictionary to organize the results of a run command. The dictionary uses strings as key values so it can be serialized to JSON for algorithmic data exchange. -The data dictionary organization is designed to be consistent with the GasModels [The Network Data Dictionary](@ref). +GasPowerModels uses a dictionary to organize the results of a `run_` command. +The dictionary uses strings as key values so it can be serialized to JSON for algorithmic data exchange. +The data dictionary organization is designed to be consistent with the GasPowerModels [The Network Data Dictionary](@ref). At the top level the results data dictionary is structured as follows: ```json { -"solver":, # name of the Julia class used to solve the model -"status":, # solver status at termination -"solve_time":, # reported solve time (seconds) -"objective":, # the final evaluation of the objective function -"objective_lb":, # the final lower bound of the objective function (if available) -"machine":{...}, # computer hardware information (details below) -"data":{...}, # test case information (details below) -"solution":{...} # complete solution information (details below) -} -``` - -### Machine Data - -This object provides basic information about the hardware that was -used when the run command was called. - -```json -{ -"cpu":, # CPU product name -"memory": # the amount of system memory (units given) + "optimizer": , # name of the JuMP optimizer used to solve the model + "termination_status": , # solver status at termination + "dual_status": , # dual feasibility status at termination + "primal_status": , # primal feasibility status at termination + "solve_time": , # reported time required for solution + "objective": , # the final evaluation of the objective function + "objective_lb": , # the final lower bound of the objective function (if available) + "solution": {...} # problem solution information (details below) } ``` ### Solution Data - -The solution object provides detailed information about the solution -produced by the run command. The solution is organized similarly to -[The Network Data Dictionary](@ref) with the same nested structure and -parameter names, when available. A network solution most often only includes -a small subset of the data included in the network data. - -For example the data for a junction, `data["price_zone"]["1"]` is structured as follows, - -``` +The solution object provides detailed information about the problem solution produced by the `run` command. +The solution is organized similarly to [The Network Data Dictionary](@ref) with the same nested structure and parameter names, when available. +A network solution most often only includes a small subset of the data included in the network data. +For example the data for a gas network junction, e.g., `g_data["junction"]["1"]` is structured as follows: +```json { -"min_cost": 700, -... + "lat": 0.0, + ... } ``` -A solution specifying a pressure for the same case, i.e. `result["solution"]["price_zone"]["1"]`, would result in, +A solution specifying a pressure for the same object, i.e., `result["solution"]["junction"]["1"]`, would result in, -``` +```json { -"ql": 200, + "psqr": 0.486908, + "p": 0.697788 } ``` -Because the data dictionary and the solution dictionary have the same structure -InfrastructureModels `update_data!` helper function can be used to -update a data dictionary with the values from a solution as follows, - +Because the data dictionary and the solution dictionary have the same structure, the InfrastructureModels `update_data!` helper function can be used to update a data dictionary with values from a solution, e.g., ``` -InfrastructureModels.update_data!(data, result["solution"]) +GasPowerModels._IM.update_data!(g_data["junction"]["1"], result["solution"]["junction"]["1"]) ``` - -By default, all results are reported in per-unit (non-dimenionalized). Below are common outputs of implemented optimization models - -GasModels.add_setpoint(sol, gm, "price_zone", "lm", :zone_cost) - GasModels.add_setpoint(sol, gm, "price_zone", "lf", :zone_fl) - GasModels.add_setpoint(sol, gm, "price_zone", "lq", :zone_ql, scale = (x,item) -> GasModels.getvalue(x) / gm.data["standard_density"]) - GasModels.add_setpoint(sol, gm, "price_zone", "lp", :p_cost) - GasModels.add_setpoint(sol, gm, "price_zone", "max_p", :zone_p) - - -```json -{ -"price_zone":{ - "1":{ - "lm": , # cost incurred by the zone for satisfying non firm demand. - "lf": , # non firm demand in the zone in terms of mass flux. Reported in per unit, Multiply by baseQ to get kg/s - "lq": , # non firm demand in the zone in terms of volume flux. Reported in per unit, Multiply by baseQ to get m^3/s - "lp": , # cost incurred by the zone by high pressure - "max_p": , # Maximum pressure squared in the zone. Reported in per unit. Multiply by baseP^2 to get pascals - ... - }, - "2":{...}, - ... -}} -``` - +By default, all results are reported per-unit (non-dimensionalized). +Functions from GasModels and PowerModels can be used to convert such data back to their dimensional forms. diff --git a/docs/src/specifications.md b/docs/src/specifications.md index b0bcc6a..e92820f 100644 --- a/docs/src/specifications.md +++ b/docs/src/specifications.md @@ -1,200 +1,108 @@ # Problem Specifications +In these specifications, `pm` refers to a PowerModels model and `gm` refers to a GasModels model. -In these specifications, pm refers to a power system model and gm refers to a gas system model - -## Coupled Gas Power Flow (GPF) - - - -### Variables +## Gas-Power Flow (GPF) +### Inherited Variables and Constraints ```julia -PowerModels.variable_voltage(pm) -PowerModels.variable_generation(pm) -PowerModels.variable_branch_flow(pm) -PowerModels.variable_dcline_flow(pm) - -GasModels.variable_flow(gm) -GasModels.variable_pressure_sqr(gm) -GasModels.variable_valve_operation(gm) -GasModels.variable_load_mass_flow(gm) -GasModels.variable_production_mass_flow(gm) +# Gas-only related variables and constraints +_GM.build_gf(gm) + +# Power-only related variables and constraints +_PM.build_pf(pm) ``` ### Constraints ```julia -PowerModels.constraint_model_voltage(pm) - -for i in PowerModels.ids(pm, :ref_buses) - PowerModels.constraint_theta_ref(pm, i) - PowerModels.constraint_voltage_magnitude_setpoint(pm, i) -end - -for i in PowerModels.ids(pm, :bus) - PowerModels.constraint_power_balance_shunt(pm, i) - if length(ref(pm, :bus_gens, i)) > 0 && !(i in ids(pm,:ref_buses)) - PowerModels.constraint_voltage_magnitude_setpoint(pm, i) - for j in ref(pm, :bus_gens, i) - PowerModels.constraint_active_gen_setpoint(pm, j) - end - end -end - -for i in PowerModels.ids(pm, :branch) - PowerModels.constraint_ohms_yt_from(pm, i) - PowerModels.constraint_ohms_yt_to(pm, i) -end - -for i in PowerModels.ids(pm, :dcline) - PowerModels.constraint_active_dcline_setpoint(pm, i) - - f_bus = PowerModels.ref(pm, :bus)[dcline["f_bus"]] - if f_bus["bus_type"] == 1 - PowerModels.constraint_voltage_magnitude_setpoint(pm, f_bus["index"]) - end - - t_bus = PowerModels.ref(pm, :bus)[dcline["t_bus"]] - if t_bus["bus_type"] == 1 - PowerModels.constraint_voltage_magnitude_setpoint(pm, t_bus["index"]) - end -end - -for i in [collect(GasModels.ids(gm,:pipe)); collect(GasModels.ids(gm,:resistor))] - GasModels.constraint_pipe_flow(gm, i) -end - -for i in GasModels.ids(gm, :junction) - GasModels.constraint_junction_mass_flow_ls(gm, i) -end - -for i in GasModels.ids(gm, :short_pipe) - GasModels.constraint_short_pipe_flow(gm, i) -end - -for i in GasModels.ids(gm, :compressor) - GasModels.constraint_compressor_flow(gm, i) -end - -for i in GasModels.ids(gm, :valve) - GasModels.constraint_valve_flow(gm, i) -end - -for i in GasModels.ids(gm, :control_valve) - GasModels.constraint_control_valve_flow(gm, i) -end - -for i in GasModels.ids(gm, :consumer) +# Gas-power related parts of the problem formulation. +for i in _GM.ids(gm, :delivery) constraint_heat_rate_curve(pm, gm, i) end ``` -## Expansion Planning (NE) - +## Optimal Gas Power Flow (OGPF) ### Objective ```julia -objective_min_ne_cost(pm, gm) +# This objective function minimizes operation cost. +objective_min_opf_cost(gm, pm) +``` + +### Inherited Variables and Constraints +```julia +# Gas-only related variables and constraints +_GM.build_gf(gm) + +# Power-only related variables and constraints +_PM.build_pf(pm) ``` ### Variables ```julia -PowerModels.variable_branch_ne(pm) -PowerModels.variable_voltage(pm) -PowerModels.variable_voltage_ne(pm) -PowerModels.variable_generation(pm) -PowerModels.variable_branch_flow(pm) -PowerModels.variable_dcline_flow(pm) -PowerModels.variable_branch_flow_ne(pm) -PowerModels.constraint_model_voltage(pm) -PowerModels.constraint_model_voltage_ne(pm) - -GasModels.variable_flow(gm) -GasModels.variable_pressure_sqr(gm) -GasModels.variable_valve_operation(gm) -GasModels.variable_load_mass_flow(gm) -GasModels.variable_production_mass_flow(gm) -GasModels.variable_pipe_ne(gm) -GasModels.variable_compressor_ne(gm) -GasModels.variable_flow_ne(gm) +# Variables related to the OGPF problem. +variable_zone_demand(gm) +variable_zone_demand_price(gm) +variable_zone_pressure(gm) +variable_pressure_price(gm) ``` ### Constraints ```julia -PowerModels.constraint_model_voltage(pm) -PowerModels.constraint_model_voltage_ne(pm) - -for i in ids(pm, :ref_buses) - PowerModels.constraint_theta_ref(pm, i) -end - -for i in ids(pm, :bus) - PowerModels.constraint_power_balance_shunt_ne(pm, i) +# Gas-power related parts of the problem formulation. +for i in _GM.ids(gm, :delivery) + constraint_heat_rate_curve(pm, gm, i) end -for i in ids(pm, :branch) - PowerModels.constraint_ohms_yt_from(pm, i) - PowerModels.constraint_ohms_yt_to(pm, i) - PowerModels.constraint_voltage_angle_difference(pm, i) - PowerModels.constraint_thermal_limit_from(pm, i) - PowerModels.constraint_thermal_limit_to(pm, i) +# Constraints related to price zones. +for (i, price_zone) in _GM.ref(gm, :price_zone) + constraint_zone_demand(gm, i) + constraint_zone_demand_price(gm, i) + constraint_zone_pressure(gm, i) + constraint_pressure_price(gm, i) end +``` -for i in ids(pm, :ne_branch) - PowerModels.constraint_ohms_yt_from_ne(pm, i) - PowerModels.constraint_ohms_yt_to_ne(pm, i) - PowerModels.constraint_voltage_angle_difference_ne(pm, i) - PowerModels.constraint_thermal_limit_from_ne(pm, i) - PowerModels.constraint_thermal_limit_to_ne(pm, i) -end +## Network Expansion Planning (NE) +### Objective +```julia +# This objective function minimizes cost of network expansion. +objective_min_ne_cost(pm, gm) +``` -for i in GasModels.ids(gm, :junction) - GasModels.constraint_junction_mass_flow_ne_ls(gm, i) -end +### Inherited Variables and Constraints +```julia +# Gas-only-related variables and constraints. +_GM.build_nels(gm) -for i in [collect(GasModels.ids(gm,:pipe)); collect(GasModels.ids(gm,:resistor))] - GasModels.constraint_pipe_flow_ne(gm, i) -end +# Power-only-related variables and constraints. +_PM.build_tnep(pm) +``` -for i in GasModels.ids(gm,:ne_pipe) - GasModels.constraint_new_pipe_flow_ne(gm, i) -end - -for i in GasModels.ids(gm, :short_pipe) - GasModels.constraint_short_pipe_flow_ne(gm, i) -end - -for i in GasModels.ids(gm,:compressor) - GasModels.constraint_compressor_flow_ne(gm, i) -end - -for i in GasModels.ids(gm, :ne_compressor) - GasModels.constraint_new_compressor_flow_ne(gm, i) -end - -for i in GasModels.ids(gm, :valve) - GasModels.constraint_valve_flow(gm, i) -end - -for i in GasModels.ids(gm, :control_valve) - GasModels.constraint_control_valve_flow(gm, i) +### Constraints +```julia +# Gas-power related constraints of the problem formulation. +for i in _GM.ids(gm, :delivery) + constraint_heat_rate_curve(pm, gm, i) end - -for i in GasModels.ids(gm, :consumer) - constraint_heat_rate_curve(pm, gm, i) -end - ``` -## Expansion Planning with Optimal Power Flow (NEOPF) - +## Expansion Planning with Optimal Gas-Power Flow (NE OGPF) ### Objective ```julia -objective_min_ne_opf_cost +# Objective function minimizes network expansion, demand, and pressure cost. +objective_min_ne_opf_cost(pm, gm) ``` -### Variables +### Inherited Variables and Constraints +```julia +# Gas-only-related variables and constraints. +_GM.build_nels(gm) -NE Model variables and +# Power-only-related variables and constraints. +_PM.build_tnep(pm) +``` +### Variables ```julia +# Variables related to the NE OGPF problem. variable_zone_demand(gm) variable_zone_demand_price(gm) variable_zone_pressure(gm) @@ -202,11 +110,9 @@ variable_pressure_price(gm) ``` ### Constraints - -NE Model constraints and - ```julia -for (i, price_zone) in gm.ref[:nw][n][:price_zone] +# Constraints related to price zones. +for (i, price_zone) in _GM.ref(gm, :price_zone) constraint_zone_demand(gm, i) constraint_zone_demand_price(gm, i) constraint_zone_pressure(gm, i) diff --git a/docs/src/variables.md b/docs/src/variables.md index c3152bd..abf177f 100644 --- a/docs/src/variables.md +++ b/docs/src/variables.md @@ -1,6 +1,6 @@ # Variables - -We provide the following methods to provide a compositional approach for defining common variables used in coupled gas grid flow models. These methods should always be defined over "AbstractGasModels" and/or "AbstractPowerModels". +We provide the following methods to provide a compositional approach for defining common variables used in coupled gas grid flow models. +These methods should always be defined over `AbstractGasModel` and/or `AbstractPowerModel`. ```@autodocs Modules = [GasPowerModels] diff --git a/examples/data/matgas/belgian-ne_opf.m b/examples/data/matgas/belgian-ne_ogpf.m similarity index 99% rename from examples/data/matgas/belgian-ne_opf.m rename to examples/data/matgas/belgian-ne_ogpf.m index f810bf4..ba4ad66 100644 --- a/examples/data/matgas/belgian-ne_opf.m +++ b/examples/data/matgas/belgian-ne_ogpf.m @@ -151,31 +151,31 @@ %% junction data (extended) %column_names% price_zone mgc.junction_data = [ - 0 + -1 1 2 - 0 + -1 1 2 - 0 + -1 1 2 - 0 + -1 1 2 - 0 + -1 1 2 - 0 + -1 1 2 - 0 + -1 1 2 - 0 + -1 1 2 - 0 + -1 ]; %% ne_compressor data diff --git a/src/GasPowerModels.jl b/src/GasPowerModels.jl index f5758db..f74b4da 100644 --- a/src/GasPowerModels.jl +++ b/src/GasPowerModels.jl @@ -45,9 +45,9 @@ module GasPowerModels include("form/nlp.jl") include("prob/gpf.jl") - include("prob/ogpf.jl") + include("prob/opf.jl") include("prob/ne.jl") - include("prob/ne_ogpf.jl") + include("prob/ne_opf.jl") # This must come last to support automated export. include("core/export.jl") diff --git a/src/core/base.jl b/src/core/base.jl index e6c15f3..e2611c8 100644 --- a/src/core/base.jl +++ b/src/core/base.jl @@ -13,8 +13,6 @@ function instantiate_model( g_data::Dict{String,<:Any}, p_data::Dict{String,<:Any}, g_type::Type, p_type::Type, build_method::Function; gm_ref_extensions::Vector{<:Function}=Vector{Function}([]), pm_ref_extensions::Vector{<:Function}=Vector{Function}([]), kwargs...) - # Ensure the two datasets use the same units for power. - resolve_units!(g_data, p_data) # Instantiate the GasModels object. gm = _GM.instantiate_model( @@ -54,6 +52,9 @@ function instantiate_model( # Read gas and power data from files. g_data, p_data = _GM.parse_file(g_file), _PM.parse_file(p_file) + # Ensure the two datasets use the same units for power. + resolve_units!(g_data, p_data) + # Instantiate GasModels and PowerModels modeling objects. return instantiate_model( g_data, p_data, g_type, p_type, build_method; gm_ref_extensions=gm_ref_extensions, @@ -132,8 +133,12 @@ function run_model( pm_solution_processors::Vector{<:Function}=Vector{Function}([]), gm_ref_extensions::Vector{<:Function}=Vector{Function}([]), pm_ref_extensions::Vector{<:Function}=Vector{Function}([]), kwargs...) + # Read gas and power data from files. g_data, p_data = _GM.parse_file(g_file), _PM.parse_file(p_file) + # Ensure the two datasets use the same units for power. + resolve_units!(g_data, p_data) + return run_model( g_data, p_data, g_type, p_type, optimizer, build_method; gm_solution_processors=gm_solution_processors, diff --git a/src/core/constraint_template.jl b/src/core/constraint_template.jl index 0f9b181..bc4ad1a 100644 --- a/src/core/constraint_template.jl +++ b/src/core/constraint_template.jl @@ -7,8 +7,8 @@ # extract the required parameters from a given network data structure and # pass the data as named arguments to the Gas Flow or Power Flow formulations. # -# Constraint templates should always be defined over "GenericFooModel" -# and should never refer to model variables +# Constraint templates should always be defined over "AbstractGasModel" and +# "AbstractWaterModel" and should never refer to model variables. function constraint_heat_rate_curve(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel, n::Int, j::Int) delivery = _GM.ref(gm, n, :delivery, j) diff --git a/src/core/objective.jl b/src/core/objective.jl index 62ddc2c..e3d620d 100644 --- a/src/core/objective.jl +++ b/src/core/objective.jl @@ -2,7 +2,7 @@ # This file defines objectives used in gas-power problem specifications. # ########################################################################## -function objective_min_ogpf_cost(gm::_GM.AbstractGasModel, pm::_PM.AbstractPowerModel; n::Int=gm.cnw) +function objective_min_opf_cost(gm::_GM.AbstractGasModel, pm::_PM.AbstractPowerModel; n::Int=gm.cnw) gen_cost = Dict{Tuple{Int,Int},Any}() for (i, gen) in _PM.ref(pm, :gen, nw=n) @@ -37,7 +37,7 @@ end " function for congestion costs based on demand " # This is equation 27 in the HICCS paper -function objective_min_ne_ogpf_cost(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel; n::Int=gm.cnw) +function objective_min_ne_opf_cost(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel; n::Int=gm.cnw) gen_cost = Dict{Tuple{Int,Int},Any}() for (i, gen) in _PM.ref(pm, :gen, nw=n) diff --git a/src/core/ref.jl b/src/core/ref.jl index b054ec4..62bb571 100644 --- a/src/core/ref.jl +++ b/src/core/ref.jl @@ -1,7 +1,7 @@ "Add price zone information to GasModels data reference dictionary." function ref_add_price_zones!(ref::Dict{Symbol,<:Any}, data::Dict{String,<:Any}) nws_data = _IM.ismultinetwork(data) ? data["nw"] : Dict("0" => data) - q_base, p_base = ref[:base_flow], ref[:base_pressure] + q_base, p_base = Float64(ref[:base_flow]), Float64(ref[:base_pressure]) for (n, nw_data) in nws_data for (i, x) in nw_data["price_zone"] diff --git a/src/core/variable.jl b/src/core/variable.jl index b976a34..0e93ad3 100644 --- a/src/core/variable.jl +++ b/src/core/variable.jl @@ -24,7 +24,7 @@ function variable_zone_demand(gm::_GM.AbstractGasModel, n::Int=gm.cnw) _GM.var(gm, n)[:zone_fl] = JuMP.@variable( gm.model, [i in _GM.ids(gm, n, :price_zone)], base_name="$(n)_zone_fl", - lower_bound=0.0, upper_bound=fl_max[i], + lower_bound=0.0, upper_bound=max(0.0, fl_max[i]), start=getstart(_GM.ref(gm, n, :price_zone), i, "zone_fl_start", 0.0)) end @@ -54,7 +54,7 @@ function variable_zone_pressure(gm::_GM.AbstractGasModel, n::Int=gm.cnw) start=getstart(_GM.ref(gm, n, :price_zone), i, "zone_p_start", 0.0)) end -" function for creating variables associated with zonal pressure cost " +"Initializes variables associated with zonal pressure cost." function variable_pressure_price(gm::_GM.AbstractGasModel, n::Int=gm.cnw) junctions = filter(x -> x.second["price_zone"] != 0, _GM.ref(gm, n, :junction)) p_min, p_max = Dict{Int,Any}(), Dict{Int,Any}() @@ -70,6 +70,6 @@ function variable_pressure_price(gm::_GM.AbstractGasModel, n::Int=gm.cnw) gm.var[:nw][n][:p_cost] = JuMP.@variable( gm.model, [i in _GM.ids(gm, n, :price_zone)], base_name="$(n)_p_cost", - lower_bound=max(0, c_min[i]), upper_bound=c_max[i], + lower_bound=max(0.0, c_min[i]), upper_bound=max(0.0, c_max[i]), start=getstart(_GM.ref(gm, n, :price_zone), i, "p_cost_start", 0.0)) end diff --git a/src/prob/ne.jl b/src/prob/ne.jl index 17307fb..8d4a4aa 100644 --- a/src/prob/ne.jl +++ b/src/prob/ne.jl @@ -24,6 +24,6 @@ function build_ne(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel) constraint_heat_rate_curve(pm, gm, i) end - # This objective function minimizes demand and pressure cost. + # This objective function minimizes cost of network expansion. objective_min_ne_cost(pm, gm) end diff --git a/src/prob/ne_ogpf.jl b/src/prob/ne_opf.jl similarity index 71% rename from src/prob/ne_ogpf.jl rename to src/prob/ne_opf.jl index a061a85..73744b0 100644 --- a/src/prob/ne_ogpf.jl +++ b/src/prob/ne_opf.jl @@ -1,17 +1,17 @@ -# Definitions for solving an optimal joint gas and power flow with network expansion. +# Definitions for solving an optimal joint power flow problem with network expansion. "Entry point for running gas and electric power expansion planning with demand-based pricing and a pressure penalty (in TPS paper)." -function run_ne_ogpf(g_file, p_file, g_type, p_type, optimizer; kwargs...) +function run_ne_opf(g_file, p_file, g_type, p_type, optimizer; kwargs...) gm_ref_extensions = [_GM.ref_add_ne!, ref_add_price_zones!] pm_ref_extensions = [_PM.ref_add_on_off_va_bounds!, _PM.ref_add_ne_branch!] - return run_model(g_file, p_file, g_type, p_type, optimizer, build_ne_ogpf; + return run_model(g_file, p_file, g_type, p_type, optimizer, build_ne_opf; gm_ref_extensions=gm_ref_extensions, pm_ref_extensions=pm_ref_extensions, kwargs...) end -"Construct the gas flow feasbility problem with demand being the cost model." -function build_ne_ogpf(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel) +"Construct the expansion planning with optimal power flow problem." +function build_ne_opf(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel) # Gas-only-related variables and constraints. _GM.build_nels(gm) @@ -23,7 +23,7 @@ function build_ne_ogpf(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel) constraint_heat_rate_curve(pm, gm, i) end - # Variables related to the ne_ogpf problem. + # Variables related to the NE OGPF problem. variable_zone_demand(gm) variable_zone_demand_price(gm) variable_zone_pressure(gm) @@ -37,6 +37,6 @@ function build_ne_ogpf(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel) constraint_pressure_price(gm, i) end - # Objective function minimizes demand and pressure cost. - objective_min_ne_ogpf_cost(pm, gm) + # Objective function minimizes network expansion, demand, and pressure cost. + objective_min_ne_opf_cost(pm, gm) end diff --git a/src/prob/ogpf.jl b/src/prob/opf.jl similarity index 63% rename from src/prob/ogpf.jl rename to src/prob/opf.jl index 3204900..7b7fa13 100644 --- a/src/prob/ogpf.jl +++ b/src/prob/opf.jl @@ -1,14 +1,14 @@ -# Definitions for solving an optimal joint gas and power flow problem. +# Definitions for solving an optimal joint power flow problem. -"Entry point into running the optimal gas-power flow problem." -function run_ogpf(g_file, p_file, g_type, p_type, optimizer; kwargs...) +"Entry point into running the optimal power flow problem." +function run_opf(g_file, p_file, g_type, p_type, optimizer; kwargs...) return run_model( - g_file, p_file, g_type, p_type, optimizer, build_ogpf; + g_file, p_file, g_type, p_type, optimizer, build_opf; gm_ref_extensions=[ref_add_price_zones!], kwargs...) end -"Construct the optimal gas-power flow problem." -function build_ogpf(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel) +"Construct the optimal power flow problem." +function build_opf(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel) # Gas-only related variables and constraints _GM.build_gf(gm) @@ -20,7 +20,7 @@ function build_ogpf(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel) constraint_heat_rate_curve(pm, gm, i) end - # Variables related to the ogpf problem. + # Variables related to the OGPF problem. variable_zone_demand(gm) variable_zone_demand_price(gm) variable_zone_pressure(gm) @@ -35,5 +35,5 @@ function build_ogpf(pm::_PM.AbstractPowerModel, gm::_GM.AbstractGasModel) end # This objective function minimizes operation cost. - objective_min_ogpf_cost(gm, pm) + objective_min_opf_cost(gm, pm) end diff --git a/test/base.jl b/test/base.jl index 0046698..4212659 100644 --- a/test/base.jl +++ b/test/base.jl @@ -21,6 +21,7 @@ @testset "run_model (with network inputs)" begin g_data, p_data = _GM.parse_file(g_file), _PM.parse_file(p_file) + resolve_units!(g_data, p_data) result = run_model(g_data, p_data, g_type, p_type, juniper, build_gpf) @test result["termination_status"] == LOCALLY_SOLVED end diff --git a/test/ne_ogpf.jl b/test/ne_opf.jl similarity index 92% rename from test/ne_ogpf.jl rename to test/ne_opf.jl index 2c15614..5358c8f 100644 --- a/test/ne_ogpf.jl +++ b/test/ne_opf.jl @@ -6,7 +6,7 @@ g_type, p_type = MISOCPGasModel, SOCWRPowerModel # Solve the joint network expansion, optimal gas-power flow problem. - result = run_ne_ogpf(g_file, p_file, g_type, p_type, juniper; + result = run_ne_opf(g_file, p_file, g_type, p_type, juniper; gm_solution_processors=[_GM.sol_psqr_to_p!], pm_solution_processors=[_PM.sol_data_model!]) @@ -24,7 +24,7 @@ g_type, p_type = MINLPGasModel, SOCWRPowerModel # Solve the joint network expansion, optimal gas-power flow problem. - result = run_ne_ogpf(g_file, p_file, g_type, p_type, juniper; + result = run_ne_opf(g_file, p_file, g_type, p_type, juniper; gm_solution_processors=[_GM.sol_psqr_to_p!], pm_solution_processors=[_PM.sol_data_model!]) diff --git a/test/ogpf.jl b/test/opf.jl similarity index 91% rename from test/ogpf.jl rename to test/opf.jl index b7c3ee2..5849eb8 100644 --- a/test/ogpf.jl +++ b/test/opf.jl @@ -6,7 +6,7 @@ g_type, p_type = MISOCPGasModel, SOCWRPowerModel # Solve the optimal gas-power flow problem. - result = run_ogpf(g_file, p_file, g_type, p_type, juniper; + result = run_opf(g_file, p_file, g_type, p_type, juniper; gm_solution_processors=[_GM.sol_psqr_to_p!], pm_solution_processors=[_PM.sol_data_model!]) @@ -23,7 +23,7 @@ g_type, p_type = MINLPGasModel, SOCWRPowerModel # Solve the optimal gas-power flow problem. - result = run_ogpf(g_file, p_file, g_type, p_type, juniper; + result = run_opf(g_file, p_file, g_type, p_type, juniper; gm_solution_processors=[_GM.sol_psqr_to_p!], pm_solution_processors=[_PM.sol_data_model!]) diff --git a/test/runtests.jl b/test/runtests.jl index a65cd15..8e2cfe5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -34,10 +34,10 @@ juniper = JuMP.optimizer_with_attributes(Juniper.Optimizer, "nl_solver"=>ipopt, include("gpf.jl") - include("ogpf.jl") + include("opf.jl") include("ne.jl") - include("ne_ogpf.jl") + include("ne_opf.jl") end