Showing preview only (2,887K chars total). Download the full file or copy to clipboard to get everything.
Repository: NREL-SIIP/PowerSimulations.jl
Branch: main
Commit: f801e64fbc98
Files: 259
Total size: 2.7 MB
Directory structure:
gitextract_1kk9e1p9/
├── .claude/
│ ├── Sienna.md
│ └── claude.md
├── .devcontainer/
│ └── devcontainer.json
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ ├── TagBot.yml
│ ├── cross-package-test.yml
│ ├── doc-preview-cleanup.yml
│ ├── docs.yml
│ ├── format-check.yml
│ ├── main-tests.yml
│ ├── performance_comparison.yml
│ └── pr_testing.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── LICENSE
├── Project.toml
├── README.md
├── codecov.yml
├── docs/
│ ├── Makefile
│ ├── Project.toml
│ ├── make.jl
│ ├── make_tutorials.jl
│ └── src/
│ ├── api/
│ │ ├── PowerSimulations.md
│ │ ├── developer.md
│ │ ├── glossary.md
│ │ └── internal.md
│ ├── code_base_developer_guide/
│ │ └── extending_powersimulations.md
│ ├── explanation/
│ │ ├── chronologies.md
│ │ ├── feedforward.md
│ │ ├── psi_structure.md
│ │ └── sequencing.md
│ ├── formulation_library/
│ │ ├── Branch.md
│ │ ├── DCModels.md
│ │ ├── Feedforward.md
│ │ ├── General.md
│ │ ├── Introduction.md
│ │ ├── Load.md
│ │ ├── Network.md
│ │ ├── Piecewise.md
│ │ ├── README.md
│ │ ├── RenewableGen.md
│ │ ├── Service.md
│ │ ├── Source.md
│ │ └── ThermalGen.md
│ ├── get_test_data.jl
│ ├── how_to/
│ │ ├── adding_new_problem_model.md
│ │ ├── debugging_infeasible_models.md
│ │ ├── logging.md
│ │ ├── parallel_simulations.md
│ │ ├── problem_templates.md
│ │ ├── read_results.md
│ │ ├── register_variable.md
│ │ └── simulation_recorder.md
│ ├── index.md
│ └── tutorials/
│ ├── decision_problem.jl
│ └── pcm_simulation.jl
├── scripts/
│ └── formatter/
│ ├── Project.toml
│ └── formatter_code.jl
├── src/
│ ├── PowerSimulations.jl
│ ├── contingency_model/
│ │ ├── contingency.jl
│ │ ├── contingency_arguments.jl
│ │ └── contingency_constraints.jl
│ ├── core/
│ │ ├── abstract_feedforward.jl
│ │ ├── abstract_simulation_store.jl
│ │ ├── auxiliary_variables.jl
│ │ ├── cache_utils.jl
│ │ ├── constraints.jl
│ │ ├── dataset.jl
│ │ ├── dataset_container.jl
│ │ ├── definitions.jl
│ │ ├── device_model.jl
│ │ ├── dual_processing.jl
│ │ ├── event_keys.jl
│ │ ├── event_model.jl
│ │ ├── expressions.jl
│ │ ├── formulations.jl
│ │ ├── initial_conditions.jl
│ │ ├── model_store_params.jl
│ │ ├── network_formulations.jl
│ │ ├── network_model.jl
│ │ ├── network_reductions.jl
│ │ ├── operation_model_abstract_types.jl
│ │ ├── optimization_container.jl
│ │ ├── parameters.jl
│ │ ├── power_flow_data_wrapper.jl
│ │ ├── results_by_time.jl
│ │ ├── service_model.jl
│ │ ├── settings.jl
│ │ ├── store_common.jl
│ │ └── variables.jl
│ ├── devices_models/
│ │ ├── device_constructors/
│ │ │ ├── branch_constructor.jl
│ │ │ ├── hvdcsystems_constructor.jl
│ │ │ ├── load_constructor.jl
│ │ │ ├── reactivepowerdevice_constructor.jl
│ │ │ ├── regulationdevice_constructor.jl
│ │ │ ├── renewablegeneration_constructor.jl
│ │ │ ├── source_constructor.jl
│ │ │ └── thermalgeneration_constructor.jl
│ │ └── devices/
│ │ ├── AC_branches.jl
│ │ ├── HVDCsystems.jl
│ │ ├── TwoTerminalDC_branches.jl
│ │ ├── area_interchange.jl
│ │ ├── common/
│ │ │ ├── add_auxiliary_variable.jl
│ │ │ ├── add_constraint_dual.jl
│ │ │ ├── add_pwl_methods.jl
│ │ │ ├── add_to_expression.jl
│ │ │ ├── add_variable.jl
│ │ │ ├── duration_constraints.jl
│ │ │ ├── get_time_series.jl
│ │ │ ├── objective_function/
│ │ │ │ ├── common.jl
│ │ │ │ ├── import_export.jl
│ │ │ │ ├── linear_curve.jl
│ │ │ │ ├── market_bid.jl
│ │ │ │ ├── piecewise_linear.jl
│ │ │ │ └── quadratic_curve.jl
│ │ │ ├── range_constraint.jl
│ │ │ ├── rateofchange_constraints.jl
│ │ │ └── set_expression.jl
│ │ ├── default_interface_methods.jl
│ │ ├── electric_loads.jl
│ │ ├── reactivepower_device.jl
│ │ ├── regulation_device.jl
│ │ ├── renewable_generation.jl
│ │ ├── source.jl
│ │ └── thermal_generation.jl
│ ├── feedforward/
│ │ ├── feedforward_arguments.jl
│ │ ├── feedforward_constraints.jl
│ │ └── feedforwards.jl
│ ├── initial_conditions/
│ │ ├── add_initial_condition.jl
│ │ ├── calculate_initial_condition.jl
│ │ ├── initial_condition_chronologies.jl
│ │ ├── initialization.jl
│ │ └── update_initial_conditions.jl
│ ├── network_models/
│ │ ├── area_balance_model.jl
│ │ ├── copperplate_model.jl
│ │ ├── hvdc_network_constructor.jl
│ │ ├── hvdc_networks.jl
│ │ ├── network_constructor.jl
│ │ ├── network_slack_variables.jl
│ │ ├── pm_translator.jl
│ │ ├── power_flow_evaluation.jl
│ │ └── powermodels_interface.jl
│ ├── operation/
│ │ ├── decision_model.jl
│ │ ├── decision_model_store.jl
│ │ ├── emulation_model.jl
│ │ ├── emulation_model_store.jl
│ │ ├── initial_conditions_update_in_memory_store.jl
│ │ ├── model_numerical_analysis_utils.jl
│ │ ├── operation_model_interface.jl
│ │ ├── operation_model_simulation_interface.jl
│ │ ├── operation_model_types.jl
│ │ ├── operation_problem_templates.jl
│ │ ├── optimization_debugging.jl
│ │ ├── problem_results.jl
│ │ ├── problem_template.jl
│ │ ├── template_validation.jl
│ │ └── time_series_interface.jl
│ ├── parameters/
│ │ ├── add_parameters.jl
│ │ ├── update_container_parameter_values.jl
│ │ ├── update_cost_parameters.jl
│ │ └── update_parameters.jl
│ ├── services_models/
│ │ ├── agc.jl
│ │ ├── reserve_group.jl
│ │ ├── reserves.jl
│ │ ├── service_slacks.jl
│ │ ├── services_constructor.jl
│ │ └── transmission_interface.jl
│ ├── simulation/
│ │ ├── decision_model_simulation_results.jl
│ │ ├── emulation_model_simulation_results.jl
│ │ ├── get_components_interface.jl
│ │ ├── hdf_simulation_store.jl
│ │ ├── in_memory_simulation_store.jl
│ │ ├── initial_condition_update_simulation.jl
│ │ ├── optimization_output_cache.jl
│ │ ├── optimization_output_caches.jl
│ │ ├── realized_meta.jl
│ │ ├── simulation.jl
│ │ ├── simulation_events.jl
│ │ ├── simulation_info.jl
│ │ ├── simulation_internal.jl
│ │ ├── simulation_models.jl
│ │ ├── simulation_partition_results.jl
│ │ ├── simulation_partitions.jl
│ │ ├── simulation_problem_results.jl
│ │ ├── simulation_results.jl
│ │ ├── simulation_results_export.jl
│ │ ├── simulation_sequence.jl
│ │ ├── simulation_state.jl
│ │ ├── simulation_store_params.jl
│ │ └── simulation_store_requirements.jl
│ └── utils/
│ ├── dataframes_utils.jl
│ ├── datetime_utils.jl
│ ├── file_utils.jl
│ ├── generate_valid_formulations.jl
│ ├── indexing.jl
│ ├── jump_utils.jl
│ ├── logging.jl
│ ├── powersystems_utils.jl
│ ├── print_pt_v2.jl
│ ├── print_pt_v3.jl
│ ├── recorder_events.jl
│ └── time_series_utils.jl
└── test/
├── Project.toml
├── includes.jl
├── performance/
│ └── performance_test.jl
├── run_partitioned_simulation.jl
├── runtests.jl
├── test_basic_model_structs.jl
├── test_data/
│ └── results_export.json
├── test_device_branch_constructors.jl
├── test_device_hvdc.jl
├── test_device_lcc.jl
├── test_device_load_constructors.jl
├── test_device_renewable_generation_constructors.jl
├── test_device_source_constructors.jl
├── test_device_synchronous_condenser_constructors.jl
├── test_device_thermal_generation_constructors.jl
├── test_events.jl
├── test_formulation_combinations.jl
├── test_import_export_cost.jl
├── test_initialization_problem.jl
├── test_jump_utils.jl
├── test_market_bid_cost.jl
├── test_mbc_sanity_check.jl
├── test_model_decision.jl
├── test_model_emulation.jl
├── test_multi_interval.jl
├── test_network_constructors.jl
├── test_network_constructors_with_dlr.jl
├── test_parallel_branch_parameter_multipliers.jl
├── test_power_flow_in_the_loop.jl
├── test_print.jl
├── test_problem_template.jl
├── test_recorder_events.jl
├── test_services_constructor.jl
├── test_simulation_build.jl
├── test_simulation_execute.jl
├── test_simulation_models.jl
├── test_simulation_partitions.jl
├── test_simulation_results.jl
├── test_simulation_results_export.jl
├── test_simulation_sequence.jl
├── test_simulation_store.jl
├── test_utils/
│ ├── add_components_to_system.jl
│ ├── add_dlr_ts.jl
│ ├── add_market_bid_cost.jl
│ ├── common_operation_model.jl
│ ├── events_simulation_utils.jl
│ ├── iec_simulation_utils.jl
│ ├── mbc_simulation_utils.jl
│ ├── mbc_system_utils.jl
│ ├── mock_operation_models.jl
│ ├── model_checks.jl
│ ├── operations_problem_templates.jl
│ ├── run_simulation.jl
│ └── solver_definitions.jl
└── test_utils.jl
================================================
FILE CONTENTS
================================================
================================================
FILE: .claude/Sienna.md
================================================
# Sienna Programming Practices
This document describes general programming practices and conventions that apply across all Sienna packages (PowerSystems.jl, PowerSimulations.jl, PowerFlows.jl, PowerNetworkMatrices.jl, InfrastructureSystems.jl, etc.).
## Performance Requirements
**Priority:** Critical. See the [Julia Performance Tips](https://docs.julialang.org/en/v1/manual/performance-tips/).
### Anti-Patterns to Avoid
#### Type instability
Functions must return consistent concrete types. Check with `@code_warntype`.
- Bad: `f(x) = x > 0 ? 1 : 1.0`
- Good: `f(x) = x > 0 ? 1.0 : 1.0`
#### Abstract field types
Struct fields must have concrete types or be parameterized.
- Bad: `struct Foo; data::AbstractVector; end`
- Good: `struct Foo{T<:AbstractVector}; data::T; end`
#### Untyped containers
- Bad: `Vector{Any}()`, `Vector{Real}()`
- Good: `Vector{Float64}()`, `Vector{Int}()`
#### Non-const globals
- Bad: `THRESHOLD = 0.5`
- Good: `const THRESHOLD = 0.5`
#### Unnecessary allocations
- Use views instead of copies (`@view`, `@views`)
- Pre-allocate arrays instead of `push!` in loops
- Use in-place operations (functions ending with `!`)
#### Captured variables
Avoid closures that capture mutable or reassigned variables, as these cause boxing. Captured variables that do not change type (especially if never reassigned) do not incur boxing — see [Julia docs on captured variables](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured).
#### Splatting penalty
Avoid splatting (`...`) in performance-critical code. Splatting containers with known length at compile time (e.g., `Tuple`) is acceptable.
#### Abstract return types
In performance-critical code, avoid returning abstract types. Returning `Union{T, Nothing}` is acceptable for functions that may fail or return nothing. Factory functions that return one of several concrete subtypes are also fine.
#### Using `isa` in function logic
**ABSOLUTELY FORBIDDEN unless the user explicitly asks for it.** Never write code that uses `isa` checks for type-based branching. This is always wrong — use multiple dispatch instead.
- Bad: `if x isa Float64 ... elseif x isa Int ... end`
- Good: Use multiple dispatch with specific type signatures
- Bad: `function f(x); if x isa AbstractVector return sum(x) else return x end; end`
- Good: `f(x::AbstractVector) = sum(x); f(x::Number) = x`
**Why this matters:** `isa` checks force the compiler to handle multiple code paths at runtime, losing type information and preventing specialization. Multiple dispatch allows the compiler to generate optimized code for each type. Using `isa` is an anti-pattern that defeats Julia's core design.
### Best Practices
- Use `@inbounds` when bounds are verified
- Use broadcasting (dot syntax) for element-wise operations
- Avoid `try-catch` in hot paths
- Use function barriers to isolate type instability
> Apply these guidelines with judgment. Not every function is performance-critical. Focus optimization efforts on hot paths and frequently called code.
## Code Conventions
Style guide: [https://sienna-platform.github.io/InfrastructureSystems.jl/stable/style/](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/style/)
Formatter (JuliaFormatter): Use the formatter script provided in each package.
Key rules:
- Constructors: use `function Foo()` not `Foo() = ...`
- Asserts: prefer `InfrastructureSystems.@assert_op` over `@assert`
- Globals: `UPPER_CASE` for constants
- Exports: all exports in main module file
- Comments: complete sentences, describe why not how
## Documentation Practices and Requirements
Framework: [Diataxis](https://diataxis.fr/)
Sienna guide: [https://sienna-platform.github.io/InfrastructureSystems.jl/stable/docs_best_practices/explanation/](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/docs_best_practices/explanation/)
Docstring requirements:
- Scope: all elements of public interface (IS is selective about exports)
- Include: function signatures and arguments list
- Automation: `DocStringExtensions.TYPEDSIGNATURES` (`TYPEDFIELDS` used sparingly in IS)
- See also: add links for functions with same name (multiple dispatch)
API docs:
- Public: typically in `docs/src/api/public.md` using `@autodocs` with `Public=true, Private=false`
- Internals: typically in `docs/src/api/internals.md`
## Design Principles
- Elegance and concision in both interface and implementation
- Fail fast with actionable error messages rather than hiding problems
- Validate invariants explicitly in subtle cases
- Avoid over-adherence to backwards compatibility for internal helpers
## Contribution Workflow
Branch naming: `feature/description` or `fix/description`
1. Create feature branch
2. Follow style guide and run formatter
3. Ensure tests pass
4. Submit pull request
## AI Agent Guidance
**Key priorities:** Read existing patterns first, maintain consistency, use concrete types in hot paths, run formatter, add docstrings to public API, ensure tests pass.
**Critical rules:**
- Always use `julia --project=<env>` (never bare `julia`)
- **NEVER use `isa` in function logic** — use multiple dispatch instead. This is absolutely forbidden unless the user explicitly asks for it.
- Never edit auto-generated files directly
- Verify type stability with `@code_warntype` for performance-critical code
- Consider downstream package impact
## Julia Environment Best Practices
**CRITICAL:** Always use `julia --project=<env>` when running Julia code in Sienna repositories. **NEVER** use bare `julia` or `julia --project` without specifying the environment. Each package typically defines dependencies in `test/Project.toml` for testing.
Common patterns:
```sh
# Run tests (using test environment)
julia --project=test test/runtests.jl
# Run specific test
julia --project=test test/runtests.jl test_file_name
# Run expression
julia --project=test -e 'using PackageName; ...'
# Instantiate environment
julia --project=test -e 'using Pkg; Pkg.instantiate()'
# Build docs (using docs environment)
julia --project=docs docs/make.jl
```
**Why this matters:** Running without `--project=<env>` will fail because required packages won't be available in the default environment. The test/docs environments contain all necessary dependencies for their respective tasks.
## Troubleshooting
**Type instability**
- Symptom: Poor performance, many allocations
- Diagnosis: `@code_warntype` on suspect function
- Solution: See performance anti-patterns above
**Formatter fails**
- Symptom: Formatter command returns error
- Solution: Run the formatter script provided in the package (e.g., `julia -e 'include("scripts/formatter/formatter_code.jl")'`)
**Test failures**
- Symptom: Tests fail unexpectedly
- Solution: `julia --project=test -e 'using Pkg; Pkg.instantiate()'`
================================================
FILE: .claude/claude.md
================================================
# PowerSimulations.jl
Power system optimization and simulation framework. Builds and solves large-scale optimization problems for operations modeling across multiple time scales (planning, day-ahead, real-time). Julia compat: `^1.10`.
> **General Sienna Programming Practices:** For performance requirements, code conventions, documentation practices, and contribution workflows that apply across all Sienna packages, see [Sienna.md](Sienna.md). Always load [Sienna.md](Sienna.md) before any change or code execution.
## Core Architecture
### Operation Models
The central abstraction is `OperationModel`, with two concrete types:
- **`DecisionModel{M <: DecisionProblem}`** — Solves optimization problems over a specified horizon (e.g., 24h unit commitment, 1h economic dispatch). Contains a `ProblemTemplate`, an `OptimizationContainer` (JuMP model wrapper), and a `System` from PowerSystems.jl.
- **`EmulationModel{M <: EmulationProblem}`** — Simulates real-time operation with a single time-step horizon. Used for AGC, reserve deployment, and similar fast-timescale problems.
Built-in problem types: `GenericOpProblem`, `UnitCommitmentProblem`, `EconomicDispatchProblem`, `AGCReserveDeployment`.
### ProblemTemplate
Defines what a model contains — its network representation and which device/service formulations to use:
```julia
template = ProblemTemplate(NetworkModel(CopperPlatePowerModel))
set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment)
set_device_model!(template, RenewableDispatch, RenewableFullDispatch)
set_service_model!(template, VariableReserve{ReserveUp}, RangeReserve)
```
### Device, Service, and Network Models
These types bind a PowerSystems component type to a formulation:
- **`DeviceModel{D <: PSY.Device, B <: AbstractDeviceFormulation}`** — Specifies how a device type is modeled. The formulation determines which variables, constraints, and parameters are added. Also carries feedforward specifications, time series mappings, and attributes.
- **`ServiceModel{D <: PSY.Service, B <: AbstractServiceFormulation}`** — Same pattern for ancillary services (reserves, AGC).
- **`NetworkModel{T <: PM.AbstractPowerModel}`** — Specifies the power flow formulation. Options include `CopperPlatePowerModel` (single node), `PTDFPowerModel` (linearized with PTDF matrix), `AreaBalancePowerModel` (zonal), and full AC/DC from PowerModels.jl.
### Formulation Hierarchy
Formulations are organized by device category. The formulation type controls what gets built:
- **Thermal**: `ThermalBasicUnitCommitment`, `ThermalStandardUnitCommitment`, `ThermalBasicDispatch`, `ThermalCompactUnitCommitment`, etc. UC formulations add binary on/off variables and min up/down time constraints; dispatch formulations use continuous variables only.
- **Renewable**: `RenewableFullDispatch`, `RenewableConstantPowerFactor`
- **Load**: `StaticPowerLoad`, `PowerLoadInterruption`, `PowerLoadDispatch`
- **Storage**: `BookKeeping`, `BatteryAncillaryServices`
- **Branches**: `StaticBranch`, `StaticBranchBounds`, `StaticBranchUnbounded`, `HVDCTwoTerminalDispatch`
### OptimizationContainer
Wraps the JuMP model and holds all optimization artifacts in typed containers:
- **Variables** — decision variables indexed by device and time
- **Constraints** — constraint references
- **Parameters** — time-varying data (time series, feedforward values) stored as parameter containers
- **Expressions** — reusable expressions (e.g., nodal balance) that multiple devices contribute to
- **Objective function** — cost components
## Simulation Architecture
### Simulation
Orchestrates multi-model runs across time. A `Simulation` contains:
- **`SimulationModels`** — Container holding a vector of `DecisionModel`s and an optional `EmulationModel`
- **`SimulationSequence`** — Defines execution order, feedforward connections between models, and initial condition chronologies
- **`SimulationState`** — Tracks evolving state across the simulation timeline
### SimulationState
Maintains state that flows between models and across time steps:
```
SimulationState
├── current_time::Ref{DateTime} # Current simulation clock
├── last_decision_model::Ref{Symbol} # Which model ran last
├── decision_states::DatasetContainer # Outputs from decision models
└── system_states::DatasetContainer # Actual system state evolution
```
After each model solves, its results update the relevant datasets in `SimulationState`. The next model in sequence reads from these datasets via feedforwards and initial conditions.
### Feedforward Mechanism
Feedforwards transfer values between models in a simulation sequence. They parameterize a downstream model using results from an upstream model:
- **`UpperBoundFeedforward`** — Constrains variables with upper bounds from source
- **`LowerBoundFeedforward`** — Constrains variables with lower bounds from source
- **`SemiContinuousFeedforward`** — Passes binary on/off status
- **`FixValueFeedforward`** — Fixes variable values from source results
Each feedforward specifies a source model, source variable, and affected component/variable in the target model.
### Initial Conditions
State carried between time steps within or across models:
- `DevicePower` — Previous generation level
- `DeviceStatus` — On/off status
- `InitialTimeDurationOn/Off` — Time in current state
- `InitialEnergyLevel` — Storage state-of-charge
- `AreaControlError` — AGC error state
Chronologies control how initial conditions are sourced: `InterProblemChronology` (from a different model's results) or `IntraProblemChronology` (from the same model's previous solve).
### Simulation Execution Loop
1. Read current state from `SimulationState`
2. Update feedforward parameters in the current model from upstream results
3. Update initial conditions from state
4. Solve the model (`JuMP.optimize!`)
5. Write results to `SimulationState` and results store (HDF5 or in-memory)
6. Advance to next model in sequence; repeat
## Directory Structure
```
src/
├── core/ # Core types: OptimizationContainer, DeviceModel,
│ # NetworkModel, ServiceModel, formulations,
│ # variable/constraint/parameter type definitions
├── operation/ # DecisionModel, EmulationModel, ProblemTemplate,
│ # built-in problem templates, model build/solve logic
├── simulation/ # Simulation, SimulationModels, SimulationSequence,
│ # SimulationState, results storage (HDF5, in-memory)
├── devices_models/
│ ├── devices/ # Per-device-type implementations (thermal, renewable,
│ │ # loads, branches, HVDC, storage)
│ └── device_constructors/ # Build functions that add variables, constraints,
│ # parameters to OptimizationContainer per formulation
├── network_models/ # CopperPlate, PTDF, AreaBalance, PowerModels interface
├── services_models/ # Reserve and transmission interface implementations
├── feedforward/ # Feedforward types, argument setup, constraint builders
├── initial_conditions/ # IC types, chronologies, update logic
└── parameters/ # Parameter update mechanisms for time series and state
```
## Build Flow
When `build!(model, system)` is called:
1. Template specifies device models, service models, and network model
2. For each `DeviceModel`, the formulation type dispatches to device-specific constructors that add variables, constraints, parameters, and expressions to the `OptimizationContainer`
3. Network model adds power balance and flow constraints; devices contribute to shared nodal balance expressions
4. Service models add reserve variables and participation constraints
5. Feedforwards (if in simulation context) add linking constraints/parameters
6. Objective function assembled from cost components
7. Result: a complete JuMP optimization model ready to solve
================================================
FILE: .devcontainer/devcontainer.json
================================================
{
"extensions": [
"julialang.language-julia"
],
"image": "ghcr.io/julia-vscode/julia-devcontainer"
}
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: code bug
assignees: ''
---
**If this is a question, something isn't working or an idea please start a Q&A discussion in the [Discussion tab](https://github.com/Sienna-Platform/PowerSimulations.jl/discussions)**
Open a bug report only if you can provide the details below
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
Paste the code we can run to reproduce the error you are seeing
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature request
assignees: ''
---
**If this is a question or an idea please start a Q&A discussion in the [Discussion tab](https://github.com/Sienna-Platform/PowerSimulations.jl/discussions)**
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I want to represent problem X [...] please be as specific as possible, including the mathematical formulations where appropriate.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/workflows/TagBot.yml
================================================
name: TagBot
on:
issue_comment:
types:
- created
workflow_dispatch:
jobs:
TagBot:
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
runs-on: ubuntu-latest
steps:
- uses: JuliaRegistries/TagBot@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
ssh: ${{ secrets.DOCUMENTER_KEY }}
================================================
FILE: .github/workflows/cross-package-test.yml
================================================
name: CrossPackageTest
on:
push:
branches: [main]
tags: [v*]
pull_request:
jobs:
test:
name: Julia v${{ matrix.julia-version }} - ${{ matrix.package_name }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
julia-version: [1]
os: [ubuntu-latest]
package_name: [HydroPowerSimulations, StorageSystemsSimulations, PowerAnalytics]
continue-on-error: true
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.julia-version }}
arch: x64
- uses: julia-actions/julia-buildpkg@latest
- name: Clone ${{matrix.package_name}}
uses: actions/checkout@v2
with:
repository: Sienna-Platform/${{matrix.package_name}}.jl
path: downstream
- name: Run the tests
shell: julia --project=downstream {0}
run: |
using Pkg
try
# Force it to use this PR's version of the package
Pkg.develop(PackageSpec(path=".")) # resolver may fail with main deps
Pkg.update()
Pkg.test() # resolver may fail with test time deps
catch err
err isa Pkg.Resolve.ResolverError || rethrow()
# If we can't resolve that means this is incompatible by SemVer, and this is fine.
# It means we marked this as a breaking change, so we don't need to worry about
# mistakenly introducing a breaking change as we have intentionally made one.
@info "Not compatible with this release. No problem." exception=err
exit(0) # Exit immediately, as a success
end
================================================
FILE: .github/workflows/doc-preview-cleanup.yml
================================================
name: Doc Preview Cleanup
on:
pull_request:
types: [closed]
# Ensure that only one "Doc Preview Cleanup" workflow is force pushing at a time
concurrency:
group: doc-preview-cleanup
cancel-in-progress: false
jobs:
doc-preview-cleanup:
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.fork == false
# This workflow pushes to gh-pages; permissions are per-job and independent of docs.yml
permissions:
contents: write
steps:
- name: Checkout gh-pages branch
uses: actions/checkout@v4
with:
ref: gh-pages
- name: Delete preview and history + push changes
run: |
if [ -d "${preview_dir}" ]; then
git config user.name "Documenter.jl"
git config user.email "documenter@juliadocs.github.io"
git rm -rf "${preview_dir}"
git commit -m "delete preview"
git branch gh-pages-new "$(echo "delete history" | git commit-tree "HEAD^{tree}")"
git push --force origin gh-pages-new:gh-pages
fi
env:
preview_dir: previews/PR${{ github.event.number }}
================================================
FILE: .github/workflows/docs.yml
================================================
name: Documentation
on:
push:
branches:
- main
- 'release-'
tags: '*'
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: '1'
- name: Install dependencies
run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
- name: Set DOCUMENTER_CURRENT_VERSION for tutorial download links
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "DOCUMENTER_CURRENT_VERSION=previews/PR${{ github.event.pull_request.number }}" >> "$GITHUB_ENV"
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "DOCUMENTER_CURRENT_VERSION=${GITHUB_REF_NAME}" >> "$GITHUB_ENV"
elif [[ "${{ github.ref }}" == "refs/heads/main" ]] || [[ "${{ github.ref }}" =~ ^refs/heads/release- ]]; then
echo "DOCUMENTER_CURRENT_VERSION=dev" >> "$GITHUB_ENV"
fi
- name: Build and deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
run: julia --project=docs --color=yes docs/make.jl
================================================
FILE: .github/workflows/format-check.yml
================================================
name: Format Check
on:
push:
branches:
- 'main'
- 'release-'
tags: '*'
pull_request:
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
julia-version: [1]
julia-arch: [x86]
os: [ubuntu-latest]
steps:
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.julia-version }}
- uses: actions/checkout@v2
- name: Install JuliaFormatter and format
run: |
julia -e 'include("scripts/formatter/formatter_code.jl")'
- uses: reviewdog/action-suggester@v1
if: github.event_name == 'pull_request'
with:
tool_name: JuliaFormatter
fail_on_error: true
- name: Format check
run: |
julia -e '
out = Cmd(`git diff --name-only`) |> read |> String
if out == ""
exit(0)
else
@error "Some files have not been formatted !!!"
write(stdout, out)
exit(1)
end'
================================================
FILE: .github/workflows/main-tests.yml
================================================
name: Main - CI
on:
push:
branches:
- main
schedule:
- cron: 0 * * * *
jobs:
test:
name: Julia ${{ matrix.julia-version }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
julia-version: ['1', 'nightly']
julia-arch: [x64]
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@latest
continue-on-error: true
with:
version: ${{ matrix.julia-version }}
arch: ${{ matrix.julia-arch }}
- uses: julia-actions/julia-buildpkg@latest
env:
PYTHON: ""
- uses: julia-actions/julia-runtest@latest
continue-on-error: ${{ matrix.julia-version == 'nightly' }}
env:
PYTHON: ""
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v5
with:
file: ./lcov.info
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
================================================
FILE: .github/workflows/performance_comparison.yml
================================================
name: 'Performance Comparison'
on:
pull_request:
jobs:
comparison:
runs-on: ubuntu-latest
steps:
- uses: julia-actions/setup-julia@latest
- uses: actions/checkout@v5
- name: Run Perfomance Test Main
run: |
julia --project=test -e 'using Pkg; Pkg.add(PackageSpec(name="PowerSimulations", rev="main")); Pkg.instantiate()'
julia -t 4 --project=test test/performance/performance_test.jl "Main"
- name: Run Perfomance Test Branch
run: |
julia --project=test -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
julia -t 4 --project=test test/performance/performance_test.jl "This Branch"
- name: Read precompile results
id: precompile_results
run: |
body="$(cat precompile_time.txt)"
body="${body//'%'/'%25'}"
body="${body//$'\n'/'%0A'}"
body="${body//$'\r'/'%0D'}"
echo "::set-output name=body::$body"
- name: Read build results
id: build_results
run: |
body="$(cat build_time.txt)"
body="${body//'%'/'%25'}"
body="${body//$'\n'/'%0A'}"
body="${body//$'\r'/'%0D'}"
echo "::set-output name=body::$body"
- name: Read solve results
id: solve_results
run: |
body="$(cat solve_time.txt)"
body="${body//'%'/'%25'}"
body="${body//$'\n'/'%0A'}"
body="${body//$'\r'/'%0D'}"
echo "::set-output name=body::$body"
- name: Find Comment
uses: peter-evans/find-comment@v4
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: Performance Results
- name: Create comment
if: steps.fc.outputs.comment-id == ''
uses: peter-evans/create-or-update-comment@v5
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
Performance Results
| Version | Precompile Time |
| :--- | :----: |
${{ steps.precompile_results.outputs.body }}
| Version | Build Time |
| :--- | :----: |
${{ steps.build_results.outputs.body }}
| Version | Solve Time |
| :--- | :----: |
${{ steps.solve_results.outputs.body }}
- name: Update comment
if: steps.fc.outputs.comment-id != ''
uses: peter-evans/create-or-update-comment@v5
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
body: |
Performance Results
| Version | Precompile Time |
| :--- | :----: |
${{ steps.precompile_results.outputs.body }}
| Version | Build Time |
| :--- | :----: |
${{ steps.build_results.outputs.body }}
| Version | Build Time |
| :--- | :----: |
${{ steps.solve_results.outputs.body }}
edit-mode: replace
================================================
FILE: .github/workflows/pr_testing.yml
================================================
name: Test-CI
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
test:
name: Julia ${{ matrix.julia-version }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
julia-version: ['1']
julia-arch: [x64]
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v5
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.julia-version }}
arch: ${{ matrix.julia-arch }}
- uses: julia-actions/julia-buildpkg@latest
env:
PYTHON: ""
- uses: julia-actions/julia-runtest@latest
env:
PYTHON: ""
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v5
with:
file: ./lcov.info
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
================================================
FILE: .gitignore
================================================
test_simulation_results/*
# Claude
settings.json
#Files generated by invoking Julia with --code-coverage
*.jl.cov
*.jl.*.cov
*.log
_*.jl
# Files generated by invoking Julia with --track-allocation
*.jl.mem
# System-specific files and directories generated by the BinaryProvider and BinDeps packages
# They contain absolute paths specific to the host computer, and so should not be committed
deps/deps.jl
deps/build.log
deps/downloads/
deps/usr/
deps/src/
# Build artifacts for creating documentation generated by the Documenter package
docs/build/
docs/site/
## Autogenerated code during the documentation process
generated*.md
#Jupyter Ignores
.ipynb_checkpoints/
.ipynb_checkpoints
#Mac temp ignores
.DS_Store
#Figures
*.pdf
*.ipynb
Manifest.toml
.vscode
*.h5
data
# profiling results
**/build_time.txt
**/precompile_time.txt
**/solve_time.txt
################################################################################
# Operating systems #
################################################################################
########################################
# Linux #
########################################
*~
# temporary files which can be created if a process still has a handle open of
# a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
########################################
# macOS #
########################################
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
########################################
# Windows #
########################################
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
## Acknowledgements
# Many thanks to `https://gitignore.io/`, written and maintained by Joe Blau, which contributed much material to this gitignore file.
# Claude
hooks
settings.*.json
settings.json
================================================
FILE: .pre-commit-config.yaml
================================================
repos:
- repo: local
hooks:
- id: julia-formatter
name: Run Julia formatter
entry: julia scripts/formatter/formatter_code.jl
language: system
types: [file]
pass_filenames: false
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Community driven development of this package is encouraged. To maintain code quality standards, please adhere to the following guidelines when contributing:
- To get started, <a href="https://www.clahub.com/agreements/NREL/PowerSimulations.jl">sign the Contributor License Agreement</a>.
- Please do your best to adhere to the lengthy [Julia style guide](https://docs.julialang.org/en/latest/manual/style-guide/).
- To submit code contributions, [fork](https://help.github.com/articles/fork-a-repo/) the repository, commit your changes, and [submit a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
================================================
FILE: LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2018, 2023 Alliance for Sustainable Energy, LLC and The Regents of the University of California
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: Project.toml
================================================
name = "PowerSimulations"
uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4"
authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"]
version = "0.34.2"
[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
DataFramesMeta = "1313f7d8-7da2-5740-9ea0-a2ca25f37964"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
PowerFlows = "94fada2c-fd9a-4e89-8d82-81405f5cb4f6"
PowerModels = "c36e90e8-916a-50a6-bd94-075b64ef4655"
PowerNetworkMatrices = "bed98974-b02a-5e2f-9fe0-a103f5c450dd"
PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
TimeSeries = "9e3dc215-6440-5c97-bce1-76c03772f85e"
TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
[compat]
CSV = "~0.10"
DataFrames = "1"
DataFramesMeta = "~0.15"
DataStructures = "~0.18, ~0.19"
Dates = "1"
Distributed = "1"
Distributions = "^0.25"
DocStringExtensions = "~v0.9"
HDF5 = "~0.17"
InfrastructureSystems = "^3.5"
InteractiveUtils = "1"
JSON3 = "1"
JuMP = "^1.28"
LinearAlgebra = "1"
Logging = "1"
MathOptInterface = "1"
PowerFlows = "^0.16"
PowerModels = "^0.21.5"
PowerNetworkMatrices = "^0.20"
PowerSystems = "^5.8"
PrettyTables = "2.4, 3.1"
ProgressMeter = "^1.5"
Random = "^1.10"
Serialization = "1"
SparseArrays = "1"
TimeSeries = "~0.25"
TimerOutputs = "~0.5"
julia = "^1.10"
================================================
FILE: README.md
================================================
# PowerSimulations.jl
[](https://github.com/Sienna-Platform/PowerSimulations.jl/actions/workflows/main-tests.yml)
[](https://codecov.io/gh/Sienna-Platform/PowerSimulations.jl)
[](https://sienna-platform.github.io/PowerSimulations.jl/latest)
[](https://zenodo.org/badge/latestdoi/109443246)
[<img src="https://img.shields.io/badge/slack-@Sienna/PSI-sienna.svg?logo=slack">](https://join.slack.com/t/nrel-sienna/shared_invite/zt-glam9vdu-o8A9TwZTZqqNTKHa7q3BpQ)
[](http://juliapkgstats.com/pkg/PowerSimulations)
`PowerSimulations.jl` is a Julia package for power system modeling and simulation of Power Systems operations. The objectives of the package are:
- Provide a flexible modeling framework that can accommodate problems of different complexity and at different time-scales.
- Streamline the construction of large scale optimization problems to avoid repetition of work when adding/modifying model details.
- Exploit Julia's capabilities to improve computational performance of large scale power system quasi-static simulations.
The flexible modeling framework is enabled through a modular set of capabilities that enable scalable power system analysis and exploration of new analysis methods. The modularity of PowerSimulations results from the structure of the simulations enabled by the package:
- _Simulations_ define a set of problems that can be solved using numerical techniques.
For example, an annual production cost modeling simulation can be created by formulating a unit commitment model against system data to assemble a set of 365 daily time-coupled scheduling problems.
## Simulations enabled by PowerSimulations
- Integrated Resource Planning
- Production Cost Modeling
- Market Simulations
## Installation
```julia
julia> ]
(v1.9) pkg> add PowerSystems
(v1.9) pkg> add PowerSimulations
```
## Usage
`PowerSimulations.jl` uses [PowerSystems.jl](https://github.com/Sienna-Platform/PowerSystems.jl) to handle the data used in the simulations.
```julia
using PowerSimulations
using PowerSystems
```
For information on using the package, see the [stable documentation](https://sienna-platform.github.io/PowerSimulations.jl/stable/). Use the [in-development documentation](https://sienna-platform.github.io/PowerSimulations.jl/dev/) for the version of the documentation which contains the unreleased features.
## Development
Contributions to the development and enhancement of PowerSimulations is welcome. Please see [CONTRIBUTING.md](https://github.com/Sienna-Platform/PowerSimulations.jl/blob/main/CONTRIBUTING.md) for code contribution guidelines.
## License
PowerSimulations is released under a BSD [license](https://github.com/Sienna-Platform/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) initiative at the U.S. Department of Energy's National Renewable Energy Laboratory ([NREL](https://www.nrel.gov/)) Software Record SWR-23-104.
================================================
FILE: codecov.yml
================================================
codecov:
require_ci_to_pass: yes
coverage:
precision: 2
round: down
range: "70...100"
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: auto # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
threshold: 5 # allowed to drop X% and still result in a "success" commit status
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure
patch:
default:
target: 70
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "reach,diff,flags,tree"
behavior: default
require_changes: no
================================================
FILE: docs/Makefile
================================================
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
html:
julia make.jl
github: html
-git branch -D gh-pages
-git push origin --delete gh-pages
ghp-import -n -b gh-pages -m "Update documentation" ./build
git checkout gh-pages
git push --set-upstream origin gh-pages
git checkout ${BRANCH}
all: github
================================================
FILE: docs/Project.toml
================================================
[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656"
DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8"
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
HydroPowerSimulations = "fc1677e0-6ad7-4515-bf3a-bd6bf20a0b1b"
InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
PowerNetworkMatrices = "bed98974-b02a-5e2f-9fe0-a103f5c450dd"
PowerSimulations = "e690365d-45e2-57bb-ac84-44ba829e73c4"
PowerSystemCaseBuilder = "f00506e0-b84f-492a-93c2-c0a9afc4364e"
PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
TimeSeries = "9e3dc215-6440-5c97-bce1-76c03772f85e"
[compat]
Documenter = "^1.7"
InfrastructureSystems = "3"
julia = "^1.6"
================================================
FILE: docs/make.jl
================================================
using Documenter
using PowerSystems
using PowerSimulations
using DataStructures
using DocumenterInterLinks
using Literate
links = InterLinks(
"Julia" => "https://docs.julialang.org/en/v1/",
"InfrastructureSystems" => "https://sienna-platform.github.io/InfrastructureSystems.jl/stable/",
"PowerSystems" => "https://sienna-platform.github.io/PowerSystems.jl/stable/",
"PowerSimulations" => "https://sienna-platform.github.io/PowerSimulations.jl/stable/",
"StorageSystemsSimulations" => "https://sienna-platform.github.io/StorageSystemsSimulations.jl/stable/",
"HydroPowerSimulations" => "https://sienna-platform.github.io/HydroPowerSimulations.jl/dev/",
)
include(joinpath(@__DIR__, "make_tutorials.jl"))
make_tutorials()
pages = OrderedDict(
"Welcome Page" => "index.md",
"Tutorials" => Any[
"Single-step Problem" => "tutorials/generated_decision_problem.md",
"Multi-stage Production Cost Simulation" => "tutorials/generated_pcm_simulation.md",
],
"How to..." => Any[
"...register a variable in a custom operation model" => "how_to/register_variable.md",
"...create a problem template" => "how_to/problem_templates.md",
"...read the simulation results" => "how_to/read_results.md",
"...debug an infeasible model" => "how_to/debugging_infeasible_models.md",
"...configure logging" => "how_to/logging.md",
"...inspect simulation events using the recorder" => "how_to/simulation_recorder.md",
"...run a parallel simulation" => "how_to/parallel_simulations.md",
],
"Explanation" => Any[
"explanation/psi_structure.md",
"explanation/feedforward.md",
"explanation/chronologies.md",
"explanation/sequencing.md",
],
"Reference" => Any[
"Glossary and Acronyms" => "api/glossary.md",
"Public API" => "api/PowerSimulations.md",
"Developers" => ["Developer Guidelines" => "api/developer.md",
"Internals" => "api/internal.md"],
],
"Formulation Library" => Any[
"Introduction" => "formulation_library/Introduction.md",
"General" => "formulation_library/General.md",
"Network" => "formulation_library/Network.md",
"Thermal Generation" => "formulation_library/ThermalGen.md",
"Renewable Generation" => "formulation_library/RenewableGen.md",
"Load" => "formulation_library/Load.md",
"Branch" => "formulation_library/Branch.md",
"Source" => "formulation_library/Source.md",
"Services" => "formulation_library/Service.md",
"Feedforwards" => "formulation_library/Feedforward.md",
"Piecewise Linear Cost" => "formulation_library/Piecewise.md",
],
)
makedocs(;
modules = [PowerSimulations],
format = Documenter.HTML(;
prettyurls = haskey(ENV, "GITHUB_ACTIONS"),
size_threshold = nothing),
sitename = "PowerSimulations.jl",
authors = "Jose Daniel Lara, Daniel Thom, Kate Doubleday, Rodrigo Henriquez-Auba, and Clayton Barrows",
pages = Any[p for p in pages],
plugins = [links],
)
deploydocs(;
repo = "github.com/Sienna-Platform/PowerSimulations.jl.git",
target = "build",
branch = "gh-pages",
devbranch = "main",
devurl = "dev",
push_preview = true,
versions = ["stable" => "v^", "v#.#"],
)
================================================
FILE: docs/make_tutorials.jl
================================================
using Pkg
using Literate
using DataFrames
using PrettyTables
# Limit DataFrame rendering during docs generation to avoid huge literal outputs.
# Notes:
# - Environment-variable approaches tested (`DATAFRAMES_ROWS`, `DATAFRAMES_COLUMNS`,
# `LINES`, `COLUMNS`) did not constrain DataFrames output in this pipeline.
# - We keep a docs-local Base.show override as a fallback and accept `kwargs...`
# so explicit show(...; kwargs) calls do not error on unsupported keywords.
function _env_int(name::String, default::Int)
parsed = tryparse(Int, get(ENV, name, string(default)))
return something(parsed, default)
end
const _DF_MAX_ROWS = _env_int("SIENNA_DOCS_DF_MAX_ROWS", 10)
const _DF_MAX_COLS = _env_int("SIENNA_DOCS_DF_MAX_COLS", 80)
function Base.show(io::IO, mime::MIME"text/plain", df::DataFrame; kwargs...)
# Keep docs output bounded while allowing explicit caller kwargs.
PrettyTables.pretty_table(io, df;
backend = :text,
maximum_number_of_rows = _DF_MAX_ROWS,
maximum_number_of_columns = _DF_MAX_COLS,
show_omitted_cell_summary = true,
compact_printing = false,
limit_printing = true,
kwargs...)
end
function Base.show(io::IO, mime::MIME"text/html", df::DataFrame; kwargs...)
PrettyTables.pretty_table(io, df;
backend = :html,
maximum_number_of_rows = _DF_MAX_ROWS,
maximum_number_of_columns = _DF_MAX_COLS,
show_omitted_cell_summary = true,
compact_printing = false,
limit_printing = true,
kwargs...)
end
# Remove previously generated tutorial artifacts so a docs build only reflects
# current source tutorials.
#
# Input:
# - dir: tutorial output directory that can contain generated_*.md/ipynb.
# Output:
# - Deletes matching files in-place and logs each deletion.
function clean_old_generated_files(dir::String)
if !isdir(dir)
@warn "Directory does not exist: $dir"
return
end
generated_files = filter(
f ->
startswith(f, "generated_") &&
(endswith(f, ".md") || endswith(f, ".ipynb")),
readdir(dir),
)
for file in generated_files
rm(joinpath(dir, file); force = true)
@info "Removed old generated file: $file"
end
end
#########################################################
# Literate post-processing functions for tutorial generation
#########################################################
# Compute docs base URL from Documenter deploy context.
#
# Behavior:
# - previews/PR123 -> .../previews/PR123
# - dev (or custom DOCUMENTER_DEVURL) -> .../dev
# - tagged versions like v0.9 -> .../v0.9
# - fallback -> .../stable
#
# This keeps generated download/view-online links correct across preview, dev,
# tagged, and stable deployments.
function _compute_docs_base_url()
base = "https://sienna-platform.github.io/PowerSimulations.jl"
current_version = get(ENV, "DOCUMENTER_CURRENT_VERSION", "")
# Preview builds (e.g. "previews/PR123")
if startswith(current_version, "previews/PR")
return "$base/$current_version"
end
# Dev builds
if current_version == "dev"
dev_suffix = get(ENV, "DOCUMENTER_DEVURL", "dev")
return "$base/$dev_suffix"
end
# Tagged/versioned builds (e.g. "v0.9", "v1.2.3")
if !isempty(current_version) && current_version != "stable"
return "$base/$current_version"
end
# Default to stable
return "$base/stable"
end
const _DOCS_BASE_URL = _compute_docs_base_url()
"""
Choose how tutorial download links are written in generated markdown.
- **Absolute** (under `_DOCS_BASE_URL/tutorials/`): CI / Documenter context (`GITHUB_ACTIONS` or
non-empty `DOCUMENTER_CURRENT_VERSION`) so previews, `dev`, and versioned URLs match
`_compute_docs_base_url()`.
- **Relative** (bare filenames): local/offline builds; files sit next to `generated_*.md`
under `docs/src/tutorials/`.
Override: `SIENNA_DOCS_DOWNLOAD_LINKS`=`absolute` or `relative`.
"""
function _downloads_use_absolute_urls()
o = get(ENV, "SIENNA_DOCS_DOWNLOAD_LINKS", "")
o == "absolute" && return true
o == "relative" && return false
haskey(ENV, "GITHUB_ACTIONS") && return true
!isempty(get(ENV, "DOCUMENTER_CURRENT_VERSION", "")) && return true
return false
end
# Replace APPEND_MARKDOWN("path/to/file.md") placeholders with file contents.
#
# Sample input:
# "Before\nAPPEND_MARKDOWN(\"docs/src/tutorials/_snippet.md\")\nAfter"
# Sample output:
# "Before\n<contents of _snippet.md>\nAfter"
#
# Notes:
# - Uses a non-greedy-safe capture (`[^\"]*`) so multiple placeholders can be
# replaced independently.
function insert_md(content)
pattern = r"APPEND_MARKDOWN\(\"([^\"]*)\"\)"
if occursin(pattern, content)
content = replace(content, pattern => m -> read(m.captures[1], String))
end
return content
end
# Default display titles for Documenter admonition types when no custom title is given.
# See https://documenter.juliadocs.org/stable/showcase/#Admonitions
const _ADMONITION_DISPLAY_NAMES = Dict{String, String}(
"note" => "Note",
"info" => "Info",
"tip" => "Tip",
"warning" => "Warning",
"danger" => "Danger",
"compat" => "Compat",
"todo" => "TODO",
"details" => "Details",
)
# Preprocess Literate source to convert Documenter-style admonitions into Jupyter-friendly
# blockquotes. Used only for notebook output; markdown keeps `!!! type` and is rendered by
# Documenter. Admonitions are not recognized by common mark or Jupyter; see
# https://fredrikekre.github.io/Literate.jl/v2/tips/#admonitions-compatibility
function preprocess_admonitions_for_notebook(str::AbstractString)
lines = split(str, '\n'; keepempty = true)
out = String[]
i = 1
n = length(lines)
admonition_start =
r"^# !!! (note|info|tip|warning|danger|compat|todo|details)(?:\s+\"([^\"]*)\")?\s*$"
content_line = r"^# (.*)$" # Documenter admonition body: # then 4 spaces
blank_comment = r"^#\s*$" # # or # with only spaces
while i <= n
line = lines[i]
m = match(admonition_start, line)
if m !== nothing
typ = lowercase(m.captures[1])
custom_title = m.captures[2]
title = if custom_title !== nothing && !isempty(custom_title)
custom_title
else
get(_ADMONITION_DISPLAY_NAMES, typ, titlecase(typ))
end
push!(out, "# > *$(title)*")
push!(out, "# >")
i += 1
# Consume blank comment lines and content lines
while i <= n
l = lines[i]
if match(blank_comment, l) !== nothing
push!(out, "# >")
i += 1
elseif (cm = match(content_line, l)) !== nothing
push!(out, "# > " * cm.captures[1])
i += 1
else
break
end
end
continue
end
push!(out, line)
i += 1
end
return join(out, '\n')
end
# Inject a short "download tutorial files" sentence after the first markdown
# heading in generated tutorial pages.
#
# Sample input:
# "# Title\nBody..."
# Sample output (conceptual):
# "# Title\n\n*To follow along... [Julia script](.../tutorial.jl)...*\n\nBody..."
#
# Download links:
# - **Deployed / CI**: absolute URLs under `_DOCS_BASE_URL` when `_downloads_use_absolute_urls()` is true.
# - **Local**: bare filenames (siblings of `generated_*.md` in `docs/src/tutorials/`).
function add_download_links(content, jl_file, ipynb_file)
script_link, notebook_link = if _downloads_use_absolute_urls()
("$_DOCS_BASE_URL/tutorials/$(jl_file)", "$_DOCS_BASE_URL/tutorials/$(ipynb_file)")
else
(jl_file, ipynb_file)
end
download_section = """
*To follow along, you can download this tutorial as a [Julia script (.jl)]($(script_link)) or [Jupyter notebook (.ipynb)]($(notebook_link)).*
"""
# Insert after the first heading (which should be the title)
# Match the first heading line and replace it with heading + download section
m = match(r"^(#+ .+)$"m, content)
if m !== nothing
heading = m.match
content = replace(content, r"^(#+ .+)$"m => heading * download_section; count = 1)
end
return content
end
# Insert a setup preface and captured `Pkg.status()` into the first markdown
# cell of a generated notebook, immediately after the first heading.
#
# Sample effect:
# - First markdown cell gains a "Set up" blockquote and an embedded code block
# containing package versions from the docs build environment.
function add_pkg_status_to_notebook(nb::Dict)
cells = get(nb, "cells", [])
if isempty(cells)
return nb
end
# Find the first markdown cell
first_markdown_idx = nothing
for (i, cell) in enumerate(cells)
if get(cell, "cell_type", "") == "markdown"
first_markdown_idx = i
break
end
end
if first_markdown_idx === nothing
return nb # No markdown cell found, return unchanged
end
first_cell = cells[first_markdown_idx]
cell_source = get(first_cell, "source", [])
# Convert source array to string to find the first heading
source_text = join(cell_source)
# Find the first heading (lines starting with #)
heading_pattern = r"^(#+\s+.+?)$"m
heading_match = match(heading_pattern, source_text)
if heading_match === nothing
return nb # No heading found, return unchanged
end
# Capture Pkg.status() output at build time
io = IOBuffer()
Pkg.status(; io = io)
pkg_status_output = String(take!(io))
# Create the content to insert: blockquote "Set up" with setup instructions and pkg.status()
# Blockquote title and body; hyperlinks for IJulia and create an environment
preface_lines = [
"\n",
"> **Set up**\n",
">\n",
"> To run this notebook, first install the Julia kernel for Jupyter Notebooks using [IJulia](https://julialang.github.io/IJulia.jl/stable/manual/installation/), then [create an environment](https://pkgdocs.julialang.org/v1/environments/) for this tutorial with the packages listed with `using <PackageName>` further down.\n",
">\n",
"> This tutorial has demonstrated compatibility with these package versions. If you run into any errors, first check your package versions for consistency using `Pkg.status()`.\n",
">\n",
]
# Format Pkg.status() output as a code block inside the blockquote
pkg_status_lines = split(pkg_status_output, '\n'; keepempty = true)
pkg_status_block = [" > ```\n"]
for line in pkg_status_lines
push!(pkg_status_block, " > " * line * "\n")
end
push!(pkg_status_block, " > ```\n", "\n")
# Find the first heading line in the source array
heading_line_idx = nothing
for (i, line) in enumerate(cell_source)
if match(heading_pattern, line) !== nothing
heading_line_idx = i
break
end
end
if heading_line_idx === nothing
return nb # Couldn't find heading line
end
# Build new source array
new_source = String[]
# Add all lines up to and including the heading line
for i in 1:heading_line_idx
push!(new_source, cell_source[i])
end
# Add the preface and pkg.status content right after the heading
append!(new_source, preface_lines)
append!(new_source, pkg_status_block)
# Add all remaining lines after the heading
for i in (heading_line_idx + 1):length(cell_source)
push!(new_source, cell_source[i])
end
# Update the cell source
first_cell["source"] = new_source
cells[first_markdown_idx] = first_cell
nb["cells"] = cells
return nb
end
# Add italicized "view online" comment after each image from ```@raw html ... ``` (or
# the raw HTML / markdown form Literate writes). Used as a postprocess in Literate.notebook.
# Literate strips the backtick wrapper and outputs raw HTML; we match that multi-line block.
# Sample effect:
# - If a markdown cell contains one or more image fragments, append exactly one
# "view online" fallback note at the end of that cell.
# - If the note already exists in the cell, no change is applied.
function add_image_links(nb::Dict, outputfile_base::AbstractString)
tutorial_url = "$_DOCS_BASE_URL/tutorials/$(outputfile_base)/"
msg = "_If image is not available when viewing in a Jupyter notebook, view the tutorial online [here]($tutorial_url)._"
cells = get(nb, "cells", [])
for (idx, cell) in enumerate(cells)
get(cell, "cell_type", "") != "markdown" && continue
source = get(cell, "source", [])
isempty(source) && continue
text = join(source)
# Check if this cell already has the "view online" message to avoid duplicates
contains(text, "If image is not available when viewing in a Jupyter notebook") &&
continue
suffix = "\n\n" * msg * "\n"
# If the cell has any of the image shapes below, we append one "view online" note.
# We build one alternation pattern from sub-patterns (each line is one case).
#
# HTML paragraph wrapping an <img> (Literate often emits <p>…<img>…</p>).
# <p[^>]*> — opening <p> and attributes
# [\s\S]*? — any chars, non-greedy, up to the first <img
# <img…</p> — from <img through closing </p>
p_with_img_pattern = r"<p[^>]*>[\s\S]*?<img[\s\S]*?</p>"
# Documenter @raw html chunk that Literate inlines in the notebook (backticks removed in output).
# ```@raw html — start marker
# [\s\S]*? — block body, non-greedy
# ``` — end fence
raw_html_block_pattern = r"```@raw html[\s\S]*?```"
# Standard markdown image: 
# !\[…\] — alt in brackets; \(…\) — path in parens
markdown_image_pattern = r"!\[[^\]]*\]\([^\)]*\)"
# A bare <img ...> not already covered by the <p>…<img>…</p> case above.
# <img — tag start; [^>]*? — attributes; /?> — self-closing or >
standalone_img_pattern = r"<img[^>]*?/?>"
# Union of the four cases: (?: A | B | C | D )
image_fragment_pattern = Regex(
"(?:" *
p_with_img_pattern.pattern * "|" *
raw_html_block_pattern.pattern * "|" *
markdown_image_pattern.pattern * "|" *
standalone_img_pattern.pattern * ")",
)
if occursin(image_fragment_pattern, text)
text *= suffix
end
# Convert back to notebook source array (lines, last without trailing \n if non-empty)
lines = split(text, "\n"; keepempty = true)
new_source = String[]
for i in 1:length(lines)
if i < length(lines)
push!(new_source, lines[i] * "\n")
else
isempty(lines[i]) || push!(new_source, lines[i])
end
end
cell["source"] = new_source
cells[idx] = cell
end
nb["cells"] = cells
return nb
end
#########################################################
# Process tutorials with Literate
#########################################################
# Generate tutorial markdown + notebook artifacts from literate .jl sources.
#
# Pipeline:
# 1) discover tutorial .jl files (excluding helper files starting with "_")
# 2) generate Documenter-flavored markdown with injected download links
# 3) generate notebook with admonition conversion, setup preface, and image note
function make_tutorials()
tutorials_dir = abspath(joinpath(@__DIR__, "src", "tutorials"))
# Exclude helper scripts that start with "_"
if isdir(tutorials_dir)
tutorial_files =
filter(
x -> endswith(x, ".jl") && !startswith(x, "_"),
readdir(tutorials_dir),
)
if !isempty(tutorial_files)
# Clean up old generated tutorial files
tutorial_outputdir = tutorials_dir
clean_old_generated_files(tutorial_outputdir)
for file in tutorial_files
@show file
infile_path = joinpath(tutorials_dir, file)
execute =
if occursin("EXECUTE = TRUE", uppercase(readline(infile_path)))
true
else
false
end
outputfile = string("generated_", replace("$file", ".jl" => ""))
# Generate markdown
Literate.markdown(infile_path,
tutorial_outputdir;
name = outputfile,
credit = false,
flavor = Literate.DocumenterFlavor(),
documenter = true,
postprocess = (
content -> add_download_links(
insert_md(content),
file,
string(outputfile, ".ipynb"),
)
),
execute = execute)
# Generate notebook (chain add_image_links after add_pkg_status_to_notebook).
# preprocess_admonitions_for_notebook converts Documenter admonitions to blockquotes
# so they render in Jupyter; markdown output keeps !!! style for Documenter.
Literate.notebook(infile_path,
tutorial_outputdir;
name = outputfile,
credit = false,
execute = false,
preprocess = preprocess_admonitions_for_notebook,
postprocess = nb ->
add_image_links(add_pkg_status_to_notebook(nb), outputfile))
end
end
end
end
================================================
FILE: docs/src/api/PowerSimulations.md
================================================
```@meta
CurrentModule = PowerSimulations
DocTestSetup = quote
using PowerSimulations
end
```
# API Reference
```@contents
Pages = ["PowerSimulations.md"]
Depth = 3
```
```@raw html
```
## Device Models
List of structures and methods for Device models
```@docs
DeviceModel
```
### Formulations
Refer to the [Formulations Page](@ref formulation_library) for each Abstract Device Formulation.
HVDC formulations will be moved to its own section in future releases
### HVDC Formulations
```@docs
TransportHVDCNetworkModel
VoltageDispatchHVDCNetworkModel
HVDCTwoTerminalLCC
```
### Converter Formulations
```@docs
QuadraticLossConverter
```
### DC Lines Formulations
```@docs
DCLossyLine
```
### Synchronous Condenser Formulations
```@docs
SynchronousCondenserBasicDispatch
```
### Problem Templates
```@autodocs
Modules = [PowerSimulations]
Pages = ["problem_template.jl",
"operation_problem_templates.jl",
]
Order = [:type, :function]
Public = true
Private = false
```
```@raw html
```
* * *
## Decision Models
```@autodocs
Modules = [PowerSimulations]
Pages = ["decision_model.jl",
]
Order = [:type, :function]
Public = true
Private = false
```
```@raw html
```
```@docs
GenericOpProblem
```
```@raw html
```
* * *
## Emulation Models
```@docs
EmulationModel
EmulationModel(::Type{M} where {M <: EmulationProblem}, ::ProblemTemplate, ::PSY.System, ::Union{Nothing, JuMP.Model})
build!(::EmulationModel)
run!(::EmulationModel)
solve!(::Int, ::EmulationModel{<:EmulationProblem}, ::Dates.DateTime, ::SimulationStore)
```
```@raw html
```
* * *
## Service Models
List of structures and methods for Service models
```@docs
ServiceModel
```
```@raw html
```
* * *
## Simulation Models
```@docs
InitialCondition
SimulationModels
SimulationSequence
Simulation
build!(::Simulation)
execute!(::Simulation)
```
```@autodocs
Modules = [PowerSimulations]
Pages = ["simulation_partitions.jl",
]
Order = [:type, :function]
Public = true
Private = false
```
```@raw html
```
## Chronology Models
```@autodocs
Modules = [PowerSimulations]
Pages = ["initial_condition_chronologies.jl",
]
Order = [:type, :function]
Public = true
Private = false
```
* * *
## Variables
For a list of variables for each device refer to its Formulations page.
### Common Variables
```@docs
ActivePowerVariable
ReactivePowerVariable
PiecewiseLinearCostVariable
RateofChangeConstraintSlackUp
RateofChangeConstraintSlackDown
PostContingencyActivePowerChangeVariable
```
### Thermal Unit Variables
```@docs
OnVariable
StartVariable
StopVariable
HotStartVariable
WarmStartVariable
ColdStartVariable
PowerAboveMinimumVariable
```
### Storage Unit Variables
```@docs
ReservationVariable
EnergyVariable
ActivePowerOutVariable
ActivePowerInVariable
```
### Load Variables
```@docs
ShiftUpActivePowerVariable
ShiftDownActivePowerVariable
```
### Branches and Network Variables
```@docs
FlowActivePowerVariable
FlowActivePowerSlackUpperBound
FlowActivePowerSlackLowerBound
FlowActivePowerFromToVariable
FlowActivePowerToFromVariable
FlowReactivePowerFromToVariable
FlowReactivePowerToFromVariable
PhaseShifterAngle
HVDCLosses
HVDCFlowDirectionVariable
VoltageMagnitude
VoltageAngle
```
### Two Terminal and Multi-Terminal HVDC Variables
```@docs
InterpolationBinarySquaredCurrentVariable
SquaredDCVoltage
DCLineCurrent
InterpolationSquaredVoltageVariable
InterpolationBinarySquaredVoltageVariable
AuxBilinearConverterVariable
AuxBilinearSquaredConverterVariable
InterpolationSquaredBilinearVariable
InterpolationBinarySquaredBilinearVariable
InterpolationSquaredCurrentVariable
DCVoltage
ConverterCurrent
SquaredConverterCurrent
ConverterPositiveCurrent
ConverterNegativeCurrent
ConverterPowerDirection
```
### Services Variables
```@docs
ActivePowerReserveVariable
ServiceRequirementVariable
SystemBalanceSlackUp
SystemBalanceSlackDown
ReserveRequirementSlack
InterfaceFlowSlackUp
InterfaceFlowSlackDown
PostContingencyActivePowerReserveDeploymentVariable
```
### Feedforward Variables
```@docs
UpperBoundFeedForwardSlack
LowerBoundFeedForwardSlack
```
```@raw html
```
* * *
## Auxiliary Variables
### Thermal Unit Auxiliary Variables
```@docs
TimeDurationOn
TimeDurationOff
PowerOutput
```
### Bus Auxiliary Variables
```@docs
PowerFlowVoltageAngle
PowerFlowVoltageMagnitude
PowerFlowLossFactors
PowerFlowVoltageStabilityFactors
```
### Branch Auxiliary Variables
```@docs
PowerFlowBranchReactivePowerFromTo
PowerFlowBranchReactivePowerToFrom
PowerFlowBranchActivePowerFromTo
PowerFlowBranchActivePowerToFrom
PowerFlowBranchActivePowerLoss
```
```@raw html
```
* * *
## Constraints
### Common Constraints
```@docs
PiecewiseLinearCostConstraint
```
### Network Constraints
```@docs
CopperPlateBalanceConstraint
NodalBalanceActiveConstraint
NodalBalanceReactiveConstraint
AreaParticipationAssignmentConstraint
```
### Power Variable Limit Constraints
```@docs
ActivePowerVariableLimitsConstraint
ReactivePowerVariableLimitsConstraint
ActivePowerVariableTimeSeriesLimitsConstraint
InputActivePowerVariableLimitsConstraint
OutputActivePowerVariableLimitsConstraint
ActivePowerInVariableTimeSeriesLimitsConstraint
ActivePowerOutVariableTimeSeriesLimitsConstraint
```
### Services Constraints
```@docs
RequirementConstraint
ParticipationFractionConstraint
ReservePowerConstraint
```
### Thermal Unit Constraints
```@docs
ActiveRangeICConstraint
CommitmentConstraint
DurationConstraint
RampConstraint
StartupInitialConditionConstraint
StartupTimeLimitTemperatureConstraint
```
### Renewable Unit Constraints
```@docs
EqualityConstraint
```
## Source Constraints
```@docs
ImportExportBudgetConstraint
```
## Load Constraints
```@docs
ShiftDownActivePowerVariableLimitsConstraint
NonAnticipativityConstraint
ShiftUpActivePowerVariableLimitsConstraint
RealizedShiftedLoadMinimumBoundConstraint
ShiftedActivePowerBalanceConstraint
```
### Branches Constraints
```@docs
FlowLimitConstraint
FlowRateConstraint
FlowRateConstraintFromTo
FlowRateConstraintToFrom
HVDCPowerBalance
NetworkFlowConstraint
PhaseAngleControlLimit
```
### Two Terminal and Multi-Terminal HVDC Constraints
```@docs
ConverterLossConstraint
InterpolationVoltageConstraints
InterpolationCurrentConstraints
InterpolationBilinearConstraints
CurrentAbsoluteValueConstraint
ConverterPowerCalculationConstraint
ConverterMcCormickEnvelopes
DCLineCurrentConstraint
DCCurrentBalance
```
### Contingency Constraints
```@docs
PostContingencyGenerationBalanceConstraint
PostContingencyActivePowerVariableLimitsConstraint
PostContingencyActivePowerReserveDeploymentVariableLimitsConstraint
```
### Market Bid Cost Constraints
```@docs
PiecewiseLinearBlockIncrementalOfferConstraint
PiecewiseLinearBlockDecrementalOfferConstraint
```
### Feedforward Constraints
```@docs
FeedforwardSemiContinuousConstraint
FeedforwardUpperBoundConstraint
FeedforwardLowerBoundConstraint
```
```@raw html
```
* * *
## Parameters
### Time Series Parameters
```@docs
ActivePowerTimeSeriesParameter
ReactivePowerTimeSeriesParameter
RequirementTimeSeriesParameter
ReactivePowerOffsetParameter
ActivePowerOutTimeSeriesParameter
ActivePowerInTimeSeriesParameter
FuelCostParameter
FromToFlowLimitParameter
ToFromFlowLimitParameter
```
### Variable Value Parameters
```@docs
UpperBoundValueParameter
LowerBoundValueParameter
OnStatusParameter
FixValueParameter
```
### Objective Function Parameters
```@docs
CostFunctionParameter
```
### Events Parameters
```@docs
AvailableStatusChangeCountdownParameter
AvailableStatusParameter
ActivePowerOffsetParameter
DynamicBranchRatingTimeSeriesParameter
PostContingencyDynamicBranchRatingTimeSeriesParameter
```
## Results
### Acessing Optimization Model
```@autodocs
Modules = [PowerSimulations]
Pages = ["optimization_container.jl",
"optimization_debugging.jl"
]
Order = [:type, :function]
Public = true
Private = false
```
### Accessing Problem Results
```@autodocs
Modules = [PowerSimulations]
Pages = ["operation/problem_results.jl",
]
Order = [:type, :function]
Public = true
Private = false
```
### Accessing Simulation Results
```@autodocs
Modules = [PowerSimulations]
Pages = ["simulation_results.jl",
"simulation_problem_results.jl",
"simulation_partition_results.jl",
"hdf_simulation_store.jl"
]
Order = [:type, :function]
Public = true
Private = false
```
## Simulation Recorder
```@autodocs
Modules = [PowerSimulations]
Pages = ["utils/recorder_events.jl",
]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/api/developer.md
================================================
# Guidelines for Developers
In order to contribute to `PowerSimulations.jl` repository please read the following sections of
[`InfrastructureSystems.jl`](https://github.com/Sienna-Platform/InfrastructureSystems.jl)
documentation in detail:
1. [Style Guide](https://nrel-Sienna.github.io/InfrastructureSystems.jl/stable/style/)
2. [Contributing Guidelines](https://github.com/Sienna-Platform/PowerSimulations.jl/blob/main/CONTRIBUTING.md)
Pull requests are always welcome to fix bugs or add additional modeling capabilities.
**All the code contributions need to include tests with a minimum coverage of 70%**
================================================
FILE: docs/src/api/glossary.md
================================================
# Definitions
## A
- *Attributes*: Certain device formulations can be customized by specifying attributes that will include/remove certain variables, expressions and/or constraints. For example, in `StorageSystemsSimulations.jl`, the device formulation of `StorageDispatchWithReserves` can be specified with the following dictionary of attributes:
```julia
set_device_model!(
template,
DeviceModel(
GenericBattery,
StorageDispatchWithReserves;
attributes = Dict{String, Any}(
"reservation" => false,
"cycling_limits" => false,
"energy_target" => false,
"complete_coverage" => false,
"regularization" => false,
),
),
)
```
Changing the attributes between `true` or `false` can enable/disable multiple aspects of the formulation.
## C
- *Chronologies:* In `PowerSimulations.jl`, chronologies define where information is flowing. There are two types of chronologies. 1) **inter-stage chronologies** (`InterProblemChronology`) that define how information flows between stages. e.g. day-ahead solutions are used to inform economic dispatch problems; and 2) **intra-stage chronologies** (`IntraProblemChronology`) that define how information flows between multiple executions of a single stage. e.g. the dispatch setpoints of the first period of an economic dispatch problem are constrained by the ramping limits from setpoints in the final period of the previous problem.
## D
- *Decision Problem*: A decision problem calculates the desired system operation based on forecasts of uncertain inputs and information about the state of the system. The output of a decision problem represents the policies used to drive the set-points of the system's devices, like generators or switches, and depends on the purpose of the problem. See the tutorial on [Running a Single-Step Problem](@ref) to learn more about solving individual problems.
- *Device Formulation*: The model of a device that is incorporated into a large system optimization models. For instance, the storage device model used inside of a Unit Commitment (UC) problem. A device model needs to follow some requirements to be integrated into operation problems. For more information about valid `DeviceModel`s and their mathematical representations, check out the [Formulation Library](@ref formulation_intro).
## E
- *Emulation Problem*: An emulation problem is used to mimic the system's behavior subject to an incoming decision and the realization of a forecasted inputs. The solution of the emulator produces outputs representative of the system performance when operating subject the policies resulting from the decision models.
## F
- *FeedForward*: The definition of exactly what information is passed using the defined chronologies is accomplished using FeedForwards. Specifically, a FeedForward is used to define what to do with information being passed with an inter-stage chronology in a Simulation. The most common FeedForward is the `SemiContinuousFeedForward` that affects the semi-continuous range constraints of thermal generators in the economic dispatch problems based on the value of the (already solved) unit-commitment variables.
## H
- *Horizon*: The number of steps in the look-ahead of a decision problem. For instance, a Day-Ahead problem usually has a 48 step horizon. Check the time [Time Series Data Section in PowerSystems.jl](https://sienna-platform.github.io/PowerSystems.jl/stable/modeler_guide/time_series/)
## I
- *Interval*: The amount of time between updates to the decision problem. For instance, Day-Ahead problems usually have a 24-hour intervals and Real-Time problems have 5-minute intervals. Check the time [Time Series Data Section in PowerSystems.jl](https://sienna-platform.github.io/PowerSystems.jl/stable/modeler_guide/time_series/)
## R
- *Resolution*: The amount of time between time steps in a simulation. For instance 1-hour or 5-minutes. In Julia these are defined using the syntax `Hour(1)` and `Minute(5)`. Check the time [Time Series Data Section in PowerSystems.jl](https://sienna-platform.github.io/PowerSystems.jl/stable/modeler_guide/time_series/)
- *Results vs Realized Results*: In `PowerSimulations.jl` the term *results* is used to refer to the solution of all optimization problems in a *Simulation*. When using `read_variable(results, Variable)` in a `DecisionModel` of a simulation, the output is a dictionary with the values of such variable for every optimization problem solved, while `read_realized_variable(results, Variable)` will return the values of the specified interval and number of steps in the simulation. See the [Read Results page](@ref read_results) for more details.
## S
- *Service Formulation*: The model of a service that is incorporated into a large system optimization models. `Services` (or ancillary services) are models used to ensure that there is necessary support to the power grid from generators to consumers, in order to ensure reliable operation of the system. The most common application for ancillary services are reserves, i.e., generation (or load) that is not currently being used, but can be quickly made available in case of unexpected changes of grid conditions, for example a sudden loss of load or generation. A service model needs to follow some requirements to be integrated into operation problems. For more information about valid `ServiceModel`s and their mathematical representations, check out the [Formulation Library](@ref service_formulations).
- *Simulation*: A simulation is a pre-determined sequence of decision problems in a way that solving it, resembles the solution procedures commonly used by operators. The most common simulation model is the solution of a Unit Commitment and Economic Dispatch sequence of problems.
- *Solver*: A solver is a software package that incorporates algorithms for finding solutions to one or more classes of optimization problem. For example, FICO Xpress is a commercial optimization solver for linear programming (LP), convex quadratic programming (QP) problems, convex quadratically constrained quadratic programming (QCQP), second-order cone programming (SOCP) and their mixed integer counterparts. **A solver is required to be specified** in order to solve any computer optimization problem.
## T
- *Template*: A `ProblemTemplate` is just a collection of `DeviceModel`s that allows the user to specify the formulations of each set of devices (by device type) independently so that the modeler can adjust the level of detail according to the question of interest and the available data. For more information about valid `DeviceModel`s and their mathematical representations, check out the [Formulation Library](@ref formulation_intro).
================================================
FILE: docs/src/api/internal.md
================================================
```@meta
CollapsedDocStrings = true
```
# Internal API
```@autodocs
Modules = [PowerSimulations]
Public = false
```
================================================
FILE: docs/src/code_base_developer_guide/extending_powersimulations.md
================================================
# Extending Source Code Functionalities
## Enable other recorder events
Other types of recorder events can be enabled with a possible performance impact. To do this
pass in the specific recorder names to be enabled when you call build.
```julia
sim = Simulation(...)
recorders = [:execution]
build!(sim; recorders = recorders)
execute!(sim)
```
Now we can examine InitialConditionUpdateEvents for specific steps and stages.
```julia
show_simulation_events(
PSI.InitialConditionUpdateEvent,
"./output/aggregation/1",
x -> x.initial_condition_type == "DeviceStatus";
step = 2,
stage = 1
)
┌─────────────────────────────┬─────────────────────┬────────────────────────┬─────────────────┬─────────────┬─────┬──────────────┐
│ name │ simulation_time │ initial_condition_type │ device_type │ device_name │ val │ stage_number │
├─────────────────────────────┼─────────────────────┼────────────────────────┼─────────────────┼─────────────┼─────┼──────────────┤
│ InitialConditionUpdateEvent │ 2024-01-02T00:00:00 │ DeviceStatus │ ThermalStandard │ Solitude │ 0.0 │ 1 │
│ InitialConditionUpdateEvent │ 2024-01-02T00:00:00 │ DeviceStatus │ ThermalStandard │ Park City │ 1.0 │ 1 │
│ InitialConditionUpdateEvent │ 2024-01-02T00:00:00 │ DeviceStatus │ ThermalStandard │ Alta │ 1.0 │ 1 │
│ InitialConditionUpdateEvent │ 2024-01-02T00:00:00 │ DeviceStatus │ ThermalStandard │ Brighton │ 1.0 │ 1 │
│ InitialConditionUpdateEvent │ 2024-01-02T00:00:00 │ DeviceStatus │ ThermalStandard │ Sundance │ 0.0 │ 1 │
└─────────────────────────────┴─────────────────────┴────────────────────────┴─────────────────┴─────────────┴─────┴──────────────┘
```
## Show the wall time with your events
Sometimes you might want to see how the events line up with the wall time.
```julia
show_simulation_events(
PSI.InitialConditionUpdateEvent,
"./output/aggregation/1",
x -> x.initial_condition_type == "DeviceStatus";
step = 2,
stage = 1,
wall_time = true
)
┌─────────────────────────┬─────────────────────────────┬─────────────────────┬────────────────────────┬─────────────────┬─────────────┬─────┬──────────────┐
│ timestamp │ name │ simulation_time │ initial_condition_type │ device_type │ device_name │ val │ stage_number │
├─────────────────────────┼─────────────────────────────┼─────────────────────┼────────────────────────┼─────────────────┼─────────────┼─────┼──────────────┤
│ 2020-04-07T15:08:32.711 │ InitialConditionUpdateEvent │ 2024-01-02T00:00:00 │ DeviceStatus │ ThermalStandard │ Solitude │ 0.0 │ 1 │
│ 2020-04-07T15:08:32.711 │ InitialConditionUpdateEvent │ 2024-01-02T00:00:00 │ DeviceStatus │ ThermalStandard │ Park City │ 1.0 │ 1 │
│ 2020-04-07T15:08:32.711 │ InitialConditionUpdateEvent │ 2024-01-02T00:00:00 │ DeviceStatus │ ThermalStandard │ Alta │ 1.0 │ 1 │
│ 2020-04-07T15:08:32.711 │ InitialConditionUpdateEvent │ 2024-01-02T00:00:00 │ DeviceStatus │ ThermalStandard │ Brighton │ 1.0 │ 1 │
│ 2020-04-07T15:08:32.711 │ InitialConditionUpdateEvent │ 2024-01-02T00:00:00 │ DeviceStatus │ ThermalStandard │ Sundance │ 0.0 │ 1 │
└─────────────────────────┴─────────────────────────────┴─────────────────────┴────────────────────────┴─────────────────┴─────────────┴─────┴──────────────┘
```
================================================
FILE: docs/src/explanation/chronologies.md
================================================
# [Chronologies](@id chronologies)
In PowerSimulations, chronologies define where information is flowing. There are two types
of chronologies.
- inter-stage chronologies: Define how information flows between stages. e.g. day-ahead solutions are used to inform economic dispatch problems
- intra-stage chronologies: Define how information flows between multiple executions of a single stage. e.g. the dispatch setpoints of the first period of an economic dispatch problem are constrained by the ramping limits from setpoints in the final period of the previous problem.
================================================
FILE: docs/src/explanation/feedforward.md
================================================
# [Feedforward](@id feedforward)
The definition of exactly what information is passed using the defined chronologies is accomplished using FeedForwards.
Specifically, a FeedForward is used to define what to do with information being passed with an inter-stage chronology in a Simulation. The most common FeedForward is the `SemiContinuousFeedForward` that affects the semi-continuous range constraints of thermal generators in the economic dispatch problems based on the value of the (already solved) unit-commitment variables.
The creation of a FeedForward requires at least to specify the `component_type` on which the FeedForward will be applied. The `source` variable specify which variable will be taken from the problem solved, for example the commitment variable of the thermal unit in the unit commitment problem. Finally, the `affected_values` specify which variables will be affected in the problem to be solved, for example the next economic dispatch problem.
================================================
FILE: docs/src/explanation/psi_structure.md
================================================
# [PowerSimulations.jl Modeling Structure](@id psi_structure)
PowerSimulations enables the simulation of a sequence of power systems optimization problems and provides user control over each aspect of the simulation configuration. Specifically:
- mathematical formulations can be selected for each component with [`DeviceModel`](@ref) and [`ServiceModel`](@ref)
- a problem can be defined by creating model entries in a [Operations `ProblemTemplate`s](@ref op_problem_template)
- models ([`DecisionModel`](@ref) or [`EmulationModel`](@ref)) can be built by applying a `ProblemTemplate` to a `System` and can be executed/solved in isolation or as part of a [`Simulation`](@ref Simulation(::SimulationSequence,::String,::Int,::SimulationModels,::AbstractString, ::Any))
- [`Simulation`](@ref Simulation(::SimulationSequence,::String,::Int,::SimulationModels,::AbstractString, ::Any))s can be defined and executed by sequencing one or more models and defining how and when data flows between models.
!!! question "What is the difference between a Model and a Problem?"
A "Problem" is an abstract mathematical description of how to represent power system behavior, whereas a "Model" is a concrete representation of a "Problem" applied to a dataset. I.e. once a Problem is populated with data describing all the loads, generators, lines, etc., it becomes a Model.
================================================
FILE: docs/src/explanation/sequencing.md
================================================
# [Sequencing](@id sequencing)
In a typical simulation pipeline, we want to connect daily (24-hours) day-ahead unit commitment problems, with multiple economic dispatch problems. Usually, our day-ahead unit commitment problem will have an hourly (1-hour) resolution, while the economic dispatch will have a 5-minute resolution.
Depending on your problem, it is common to use a 2-day look-ahead for unit commitment problems, so in this case, the Day-Ahead problem will have: resolution = Hour(1) with interval = Hour(24) and horizon = Hour(48). In the case of the economic dispatch problem, it is common to use a look-ahead of two hours. Thus, the Real-Time problem will have: resolution = Minute(5), with interval = Minute(5) (we only store the first operating point) and horizon = 24 (24 time steps of 5 minutes are 120 minutes, that is 2 hours).
================================================
FILE: docs/src/formulation_library/Branch.md
================================================
# `PowerSystems.Branch` Formulations
!!! note
The use of reactive power variables and constraints will depend on the network model used, i.e., whether it uses (or does not use) reactive power. If the network model is purely active power-based, reactive power variables and related constraints are not created.
### Table of contents
1. [`StaticBranch`](#StaticBranch)
2. [`StaticBranchBounds`](#StaticBranchBounds)
3. [`StaticBranchUnbounded`](#StaticBranchUnbounded)
4. [`HVDCTwoTerminalUnbounded`](#HVDCTwoTerminalUnbounded)
5. [`HVDCTwoTerminalLossless`](#HVDCTwoTerminalLossless)
6. [`HVDCTwoTerminalDispatch`](#HVDCTwoTerminalDispatch)
7. [`PhaseAngleControl`](#PhaseAngleControl)
8. [`TwoTerminalLCCLine`](#TwoTerminalLCCLine)
9. [Valid configurations](#Valid-configurations)
## `StaticBranch`
Formulation valid for `PTDFPowerModel` Network model
```@docs
StaticBranch
```
**Variables:**
- [`FlowActivePowerVariable`](@ref):
+ Bounds: ``(-\infty,\infty)``
+ Symbol: ``f``
If Slack variables are enabled:
- [`FlowActivePowerSlackUpperBound`](@ref):
+ Bounds: [0.0, ]
+ Default proportional cost: 2e5
+ Symbol: ``f^\text{sl,up}``
- [`FlowActivePowerSlackLowerBound`](@ref):
+ Bounds: [0.0, ]
+ Default proportional cost: 2e5
+ Symbol: ``f^\text{sl,lo}``
**Static Parameters**
- ``R^\text{max}`` = `PowerSystems.get_rating(branch)`
**Objective:**
Add a large proportional cost to the objective function if rate constraint slack variables are used ``+ (f^\text{sl,up} + f^\text{sl,lo}) \cdot 2 \cdot 10^5``
**Expressions:**
No expressions are used.
**Constraints:**
For each branch ``b \in \{1,\dots, B\}`` (in a system with ``N`` buses) the constraints are given by:
```math
\begin{aligned}
& f_t = \sum_{i=1}^N \text{PTDF}_{i,b} \cdot \text{Bal}_{i,t}, \quad \forall t \in \{1,\dots, T\}\\
& f_t - f_t^\text{sl,up} \le R^\text{max},\quad \forall t \in \{1,\dots, T\} \\
& f_t + f_t^\text{sl,lo} \ge -R^\text{max},\quad \forall t \in \{1,\dots, T\}
\end{aligned}
```
on which ``\text{PTDF}`` is the ``N \times B`` system Power Transfer Distribution Factors (PTDF) matrix, and ``\text{Bal}_{i,t}`` is the active power bus balance expression (i.e. ``\text{Generation}_{i,t} - \text{Demand}_{i,t}``) at bus ``i`` at time-step ``t``.
* * *
## `StaticBranchBounds`
Formulation valid for `PTDFPowerModel` Network model
```@docs
StaticBranchBounds
```
**Variables:**
- [`FlowActivePowerVariable`](@ref):
+ Bounds: ``\left[-R^\text{max},R^\text{max}\right]``
+ Symbol: ``f``
**Static Parameters**
- ``R^\text{max}`` = `PowerSystems.get_rating(branch)`
**Objective:**
No cost is added to the objective function.
**Expressions:**
No expressions are used.
**Constraints:**
For each branch ``b \in \{1,\dots, B\}`` (in a system with ``N`` buses) the constraints are given by:
```math
\begin{aligned}
& f_t = \sum_{i=1}^N \text{PTDF}_{i,b} \cdot \text{Bal}_{i,t}, \quad \forall t \in \{1,\dots, T\}
\end{aligned}
```
on which ``\text{PTDF}`` is the ``N \times B`` system Power Transfer Distribution Factors (PTDF) matrix, and ``\text{Bal}_{i,t}`` is the active power bus balance expression (i.e. ``\text{Generation}_{i,t} - \text{Demand}_{i,t}``) at bus ``i`` at time-step ``t``.
* * *
## `StaticBranchUnbounded`
Formulation valid for `PTDFPowerModel` Network model
```@docs
StaticBranchUnbounded
```
- [`FlowActivePowerVariable`](@ref):
+ Bounds: ``(-\infty,\infty)``
+ Symbol: ``f``
**Objective:**
No cost is added to the objective function.
**Expressions:**
No expressions are used.
**Constraints:**
For each branch ``b \in \{1,\dots, B\}`` (in a system with ``N`` buses) the constraints are given by:
```math
\begin{aligned}
& f_t = \sum_{i=1}^N \text{PTDF}_{i,b} \cdot \text{Bal}_{i,t}, \quad \forall t \in \{1,\dots, T\}
\end{aligned}
```
on which ``\text{PTDF}`` is the ``N \times B`` system Power Transfer Distribution Factors (PTDF) matrix, and ``\text{Bal}_{i,t}`` is the active power bus balance expression (i.e. ``\text{Generation}_{i,t} - \text{Demand}_{i,t}``) at bus ``i`` at time-step ``t``.
* * *
## `HVDCTwoTerminalUnbounded`
Formulation valid for `PTDFPowerModel` Network model
```@docs
HVDCTwoTerminalUnbounded
```
This model assumes that it can transfer power from two AC buses without losses and no limits.
**Variables:**
- [`FlowActivePowerVariable`](@ref):
+ Bounds: ``\left(-\infty,\infty\right)``
+ Symbol: ``f``
**Objective:**
No cost is added to the objective function.
**Expressions:**
The variable `FlowActivePowerVariable` ``f`` is added to the nodal balance expression `ActivePowerBalance`, by adding the flow ``f`` in the receiving bus and subtracting it from the sending bus. This is used then to compute the AC flows using the PTDF equation.
**Constraints:**
No constraints are added.
* * *
## `HVDCTwoTerminalLossless`
Formulation valid for `PTDFPowerModel` Network model
```@docs
HVDCTwoTerminalLossless
```
This model assumes that it can transfer power from two AC buses without losses.
**Variables:**
- [`FlowActivePowerVariable`](@ref):
+ Bounds: ``\left(-\infty,\infty\right)``
+ Symbol: ``f``
**Static Parameters**
- ``R^\text{from,min}`` = `PowerSystems.get_active_power_limits_from(branch).min`
- ``R^\text{from,max}`` = `PowerSystems.get_active_power_limits_from(branch).max`
- ``R^\text{to,min}`` = `PowerSystems.get_active_power_limits_to(branch).min`
- ``R^\text{to,max}`` = `PowerSystems.get_active_power_limits_to(branch).max`
**Objective:**
No cost is added to the objective function.
**Expressions:**
The variable `FlowActivePowerVariable` ``f`` is added to the nodal balance expression `ActivePowerBalance`, by adding the flow ``f`` in the receiving bus and subtracting it from the sending bus. This is used then to compute the AC flows using the PTDF equation.
**Constraints:**
```math
\begin{align*}
& R^\text{min} \le f_t \le R^\text{max},\quad \forall t \in \{1,\dots, T\} \\
\end{align*}
```
where:
```math
\begin{align*}
& R^\text{min} = \begin{cases}
\min\left(R^\text{from,min}, R^\text{to,min}\right), & \text{if } R^\text{from,min} \ge 0 \text{ and } R^\text{to,min} \ge 0 \\
\max\left(R^\text{from,min}, R^\text{to,min}\right), & \text{if } R^\text{from,min} \le 0 \text{ and } R^\text{to,min} \le 0 \\
R^\text{from,min},& \text{if } R^\text{from,min} \le 0 \text{ and } R^\text{to,min} \ge 0 \\
R^\text{to,min},& \text{if } R^\text{from,min} \ge 0 \text{ and } R^\text{to,min} \le 0
\end{cases}
\end{align*}
```
and
```math
\begin{align*}
& R^\text{max} = \begin{cases}
\min\left(R^\text{from,max}, R^\text{to,max}\right), & \text{if } R^\text{from,max} \ge 0 \text{ and } R^\text{to,max} \ge 0 \\
\max\left(R^\text{from,max}, R^\text{to,max}\right), & \text{if } R^\text{from,max} \le 0 \text{ and } R^\text{to,max} \le 0 \\
R^\text{from,max},& \text{if } R^\text{from,max} \le 0 \text{ and } R^\text{to,max} \ge 0 \\
R^\text{to,max},& \text{if } R^\text{from,max} \ge 0 \text{ and } R^\text{to,max} \le 0
\end{cases}
\end{align*}
```
* * *
## `HVDCTwoTerminalDispatch`
Formulation valid for `PTDFPowerModel` Network model
```@docs
HVDCTwoTerminalDispatch
```
**Variables**
- [`FlowActivePowerToFromVariable`](@ref):
+ Symbol: ``f^\text{to-from}``
- [`FlowActivePowerFromToVariable`](@ref):
+ Symbol: ``f^\text{from-to}``
- [`HVDCLosses`](@ref):
+ Symbol: ``\ell``
- [`HVDCFlowDirectionVariable`](@ref)
+ Bounds: ``\{0,1\}``
+ Symbol: ``u^\text{dir}``
**Static Parameters**
- ``R^\text{from,min}`` = `PowerSystems.get_active_power_limits_from(branch).min`
- ``R^\text{from,max}`` = `PowerSystems.get_active_power_limits_from(branch).max`
- ``R^\text{to,min}`` = `PowerSystems.get_active_power_limits_to(branch).min`
- ``R^\text{to,max}`` = `PowerSystems.get_active_power_limits_to(branch).max`
- ``L_0`` = `PowerSystems.get_loss(branch).l0`
- ``L_1`` = `PowerSystems.get_loss(branch).l1`
**Objective:**
No cost is added to the objective function.
**Expressions:**
Each `FlowActivePowerToFromVariable` ``f^\text{to-from}`` and `FlowActivePowerFromToVariable` ``f^\text{from-to}`` is added to the nodal balance expression `ActivePowerBalance`, by adding the respective flow in the receiving bus and subtracting it from the sending bus. That is, ``f^\text{to-from}`` adds the flow to the `from` bus, and subtracts the flow from the `to` bus, while ``f^\text{from-to}`` adds the flow to the `to` bus, and subtracts the flow from the `from` bus This is used then to compute the AC flows using the PTDF equation.
In addition, the `HVDCLosses` are subtracted to the `from` bus in the `ActivePowerBalance` expression.
**Constraints:**
```math
\begin{align*}
& R^\text{from,min} \le f_t^\text{from-to} \le R^\text{from,max}, \forall t \in \{1,\dots, T\} \\
& R^\text{to,min} \le f_t^\text{to-from} \le R^\text{to,max},\quad \forall t \in \{1,\dots, T\} \\
& f_t^\text{to-from} - f_t^\text{from-to} \le L_1 \cdot f_t^\text{to-from} - L_0,\quad \forall t \in \{1,\dots, T\} \\
& f_t^\text{from-to} - f_t^\text{to-from} \ge L_1 \cdot f_t^\text{from-to} + L_0,\quad \forall t \in \{1,\dots, T\} \\
& f_t^\text{from-to} - f_t^\text{to-from} \ge - M^\text{big} (1 - u^\text{dir}_t),\quad \forall t \in \{1,\dots, T\} \\
& f_t^\text{to-from} - f_t^\text{from-to} \ge - M^\text{big} u^\text{dir}_t,\quad \forall t \in \{1,\dots, T\} \\
& f_t^\text{to-from} - f_t^\text{from-to} \le \ell_t,\quad \forall t \in \{1,\dots, T\} \\
& f_t^\text{from-to} - f_t^\text{to-from} \le \ell_t,\quad \forall t \in \{1,\dots, T\}
\end{align*}
```
* * *
## `PhaseAngleControl`
Formulation valid for `PTDFPowerModel` Network model
```@docs
PhaseAngleControl
```
**Variables:**
- [`FlowActivePowerVariable`](@ref):
+ Bounds: ``(-\infty,\infty)``
+ Symbol: ``f``
- [`PhaseShifterAngle`](@ref):
+ Symbol: ``\theta^\text{shift}``
**Static Parameters**
- ``R^\text{max}`` = `PowerSystems.get_rating(branch)`
- ``\Theta^\text{min}`` = `PowerSystems.get_phase_angle_limits(branch).min`
- ``\Theta^\text{max}`` = `PowerSystems.get_phase_angle_limits(branch).max`
- ``X`` = `PowerSystems.get_x(branch)` (series reactance)
**Objective:**
No changes to objective function
**Expressions:**
Adds to the `ActivePowerBalance` expression the term ``-\theta^\text{shift} /X`` to the `from` bus and ``+\theta^\text{shift} /X`` to the `to` bus, that the `PhaseShiftingTransformer` is connected.
**Constraints:**
For each branch ``b \in \{1,\dots, B\}`` (in a system with ``N`` buses) the constraints are given by:
```math
\begin{aligned}
& f_t = \sum_{i=1}^N \text{PTDF}_{i,b} \cdot \text{Bal}_{i,t} + \frac{\theta^\text{shift}_t}{X}, \quad \forall t \in \{1,\dots, T\}\\
& -R^\text{max} \le f_t \le R^\text{max},\quad \forall t \in \{1,\dots, T\}
\end{aligned}
```
on which ``\text{PTDF}`` is the ``N \times B`` system Power Transfer Distribution Factors (PTDF) matrix, and ``\text{Bal}_{i,t}`` is the active power bus balance expression (i.e. ``\text{Generation}_{i,t} - \text{Demand}_{i,t}``) at bus ``i`` at time-step ``t``.
* * *
## `TwoTerminalLCCLine`
Formulation valid for `ACPPowerModel` Network model
**Variables:**
- [`HVDCRectifierDelayAngleVariable`]:
+ Bounds: ``(-\alpha_{r,t}^\text{min},\alpha_{r,t}^\text{max})``
+ Symbol: ``\alpha_{r,t}``
- [`HVDCInverterExtinctionAngleVariable`]:
+ Bounds: ``(-\gamma_{i,t}^\text{min},\gamma_{i,t}^\text{max})``
+ Symbol: ``\gamma_{i,t}``
- [`HVDCRectifierPowerFactorAngleVariable`]:
+ Bounds: ``\{0,1\}``
+ Symbol: ``\phi_{r,t}``
- [`HVDCInverterPowerFactorAngleVariable`]:
+ Bounds: ``\{0,1\}``
+ Symbol: ``\phi_{i,t}``
- [`HVDCRectifierOverlapAngleVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``\mu_{r,t}``
- [`HVDCInverterOverlapAngleVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``\mu_{i,t}``
- [`HVDCRectifierTapSettingVariable`]:
+ Bounds: ``(t_{r,t}^\text{min},t_{r,t}^\text{max})``
+ Symbol: ``t_{r,t}``
- [`HVDCInverterTapSettingVariable`]:
+ Bounds: ``(t_{i,t}^\text{min},t_{i,t}^\text{max})``
+ Symbol: ``t_{i,t}``
- [`HVDCRectifierDCVoltageVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``v_{r,t}^\text{dc}``
- [`HVDCInverterDCVoltageVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``v_{i,t}^\text{dc}``
- [`HVDCRectifierACCurrentVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``I_{r,t}^\text{ac}``
- [`HVDCInverterACCurrentVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``I_{i,t}^\text{ac}``
- [`DCLineCurrentFlowVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``I^\text{dc}``
- [`HVDCActivePowerReceivedFromVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``p_{r,t}^\text{ac}``
- [`HVDCActivePowerReceivedToVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``p_{i,t}^\text{ac}``
- [`HVDCReactivePowerReceivedFromVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``q_{r,t}^\text{ac}``
- [`HVDCReactivePowerReceivedToVariable`]:
+ Bounds: [0.0, ]
+ Symbol: ``q_{i,t}^\text{ac}``
**Static Parameters**
- ``R^\text{dc}`` = `PowerSystems.get_r(lcc)`
- ``N_r`` = `PowerSystems.get_rectifier_bridges(lcc)`
- ``N_i`` = `PowerSystems.get_inverter_bridges(lcc)`
- ``X_r`` = `PowerSystems.get_rectifier_xc(lcc)`
- ``X_i`` = `PowerSystems.get_inverter_xc(lcc)`
- ``a_r`` = `PowerSystems.get_rectifier_transformer_ratio(lcc)`
- ``a_i`` = `PowerSystems.get_inverter_transformer_ratio(lcc)`
- ``t_r`` = `PowerSystems.get_rectifier_tap_setting(lcc)`
- ``t_i`` = `PowerSystems.get_inverter_tap_setting(lcc)`
- ``t^\text{min}_r`` = `PowerSystems.get_rectifier_tap_setting(lcc).min`
- ``t^\text{max}_r`` = `PowerSystems.get_rectifier_tap_setting(lcc).max`
- ``t^\text{min}_i`` = `PowerSystems.get_inverter_tap_setting(lcc).min`
- ``t^\text{max}_i`` = `PowerSystems.get_inverter_tap_setting(lcc).max`
**Objective:**
No changes to objective function
**Expressions:**
The variable `HVDCActivePowerReceivedFromVariable` ``p_{r,t}^\text{ac}`` is added to the nodal balance expression `ActivePowerBalance` as a negative load, since the rectifier takes power from the AC system and to injects it into the DC system. On the other hand, the variable `HVDCActivePowerReceivedToVariable` ``p_{i,t}^\text{ac}`` is added to the nodal balance expression `ActivePowerBalance` as a positive load, since it takes the power from the DC system and injects it back into the AC system.
The variables `HVDCReactivePowerReceivedFromVariable` ``q_{r,t}^\text{ac}`` and `HVDCReactivePowerReceivedToVariable` ``q_{i,t}^\text{ac}`are added to the nodal balance expression`ActivePowerBalance` as positive loads, since they consume reactive power from the AC system to allow current transfer in converters during commutation.
**Constraints:**
- **Rectifier:**
```math
\begin{aligned}
& v^\text{dc}_{r,t} = \frac{3}{\pi}N_r \left( \sqrt{2}\frac{a_r v^\text{ac}_{r,t}}{t_{r,t}}\\cos{\alpha_{r,t}}-X_r I^\text{dc}_t \right)\\
& \mu_{r,t} = \arccos \left( \cos\alpha_{r,t} - \frac{\sqrt{2} I^\text{dc}_t X_r t_{r,t}}{a_r v^\text{ac}_{r,t}} \right) - \alpha_{r,t}\\
& \phi_{r,t} = \arctan \left( \frac{2\mu_{r,t} + \sin(2\alpha_{r,t}) - \sin(2\mu_{r,t} + 2\alpha_{r,t})}{\cos(2\alpha_{r,t}) - \cos(2\mu_{r,t} + 2\alpha_{r,t})} \right)\\
\end{aligned}
```
Which can be approximated as:
```math
\begin{aligned}
& \phi_{r,t} = arccos(\frac{1}{2}\cos\alpha_{r,t} + \frac{1}{2}\cos(\alpha_{r,t} + \mu_{r,t}))
\end{aligned}
```
```math
\begin{aligned}
& I^\text{ac}_{r,t} = \sqrt{6} \frac{N_r}{\pi} I^\text{dc}_t\\
& p^\text{ac}_{r,t} = \sqrt{3} I^\text{ac}_{r,t} \frac{a_r v^\text{ac}_{r,t}}{t_{r,t}}\cos{\phi_{r,t}} \\
& q^\text{ac}_{r,t} = \sqrt{3} I^\text{ac}_{r,t} \frac{a_r v^\text{ac}_{r,t}}{t_{r,t}}\sin{\phi_{r,t}} \\
\end{aligned}
```
- **Inverter:**
```math
\begin{aligned}
& v^\text{dc}_{i,t} = \frac{3}{\pi}N_i \left( \sqrt{2}\frac{a_i v^\text{ac}_{i,t}}{t_{i,t}}\\cos{\gamma_{i,t}}-X_i I^\text{dc}_t \right)\\
& \mu_{i,t} = \arccos \left( \cos\gamma_{i,t} - \frac{\sqrt{2} I^\text{dc}_t X_i t_{i,t}}{a_i v^\text{ac}_{i,t}} \right) - \gamma_{i,t}\\
& \phi_{i,t} = \arctan \left( \frac{2\mu_{i,t} + \sin(2\gamma_{i,t}) - \sin(2\mu_{i,t} + 2\gamma_{i,t})}{\cos(2\gamma_{i,t}) - \cos(2\mu_{r,t} + 2\gamma_{i,t})} \right)\\
\end{aligned}
```
Which can be approximated as:
```math
\begin{aligned}
& \phi_{i,t} = arccos(\frac{1}{2}\cos\gamma_{i,t} + \frac{1}{2}\cos(\gamma_{i,t} + \mu_{i,t}))
\end{aligned}
```
```math
\begin{aligned}
& I^\text{ac}_{i,t} = \sqrt{6} \frac{N_i}{\pi} I^\text{dc}_t\\
& p^\text{ac}_{i,t} = \sqrt{3} I^\text{ac}_{i,t} \frac{a_i v^\text{ac}_{i,t}}{t_{i,t}}\cos{\phi_{i,t}} \\
& q^\text{ac}_{i,t} = \sqrt{3} I^\text{ac}_{i,t} \frac{a_i v^\text{ac}_{i,t}}{t_{i,t}}\sin{\phi_{i,t}} \\
\end{aligned}
```
- **DC Transmission Line:**
```math
\begin{aligned}
& v^\text{dc}_{i,t} = v^\text{dc}_{r,t} - R_\text{dc}I^\text{dc}_t
\end{aligned}
```
* * *
## Valid configurations
Valid [`DeviceModel`](@ref)s for subtypes of `Branch` include the following:
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.generate_device_formulation_combinations()
filter!(x -> (x["device_type"] <: Branch) && (x["device_type"] != TModelHVDCLine), combos)
combo_table = DataFrame(
"Valid DeviceModel" =>
["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos],
"Device Type" => [
"[$(c["device_type"])](https://nrel-Sienna.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)"
for c in combos
],
"Formulation" => ["[$(c["formulation"])](@ref)" for c in combos],
)
mdtable(combo_table; latex = false)
```
================================================
FILE: docs/src/formulation_library/DCModels.md
================================================
# DC Models formulations
!!! note
Multi-terminal DC models are still in early stages of development and future versions will add a more comprehensive list of formulations
* * *
## LosslessLine
`LosslessLine` models are used with `PSY.DCBranch` models.
```@docs
LosslessLine
```
**Variables:**
- [`FlowActivePowerVariable`](@ref):
+ Bounds: ``(R^\text{min},R^\text{max})``
+ Symbol: ``f``
**Static Parameters**
- ``R^\text{from,min}`` = `PowerSystems.get_active_power_limits_from(branch).min`
- ``R^\text{from,max}`` = `PowerSystems.get_active_power_limits_from(branch).max`
- ``R^\text{to,min}`` = `PowerSystems.get_active_power_limits_to(branch).min`
- ``R^\text{to,max}`` = `PowerSystems.get_active_power_limits_to(branch).max`
Then, the minimum and maximum are computed as `R^\text{min} = \min(R^\text{from,min}, R^\text{to,min})` and `R^\text{max} = \min(R^\text{from,max}, R^\text{to,max})`
**Objective:**
No cost is added to the objective function.
**Expressions:**
The variable `FlowActivePowerVariable` ``f`` is added to the nodal balance expression `ActivePowerBalance` for DC Buses, by adding the flow ``f`` in the receiving DC bus and subtracting it from the sending DC bus.
**Constraints:**
No constraints are added to the function.
* * *
## LosslessConverter
Converters are used to interface the AC Buses with DC Buses.
```@docs
LosslessConverter
```
**Variables:**
- [`ActivePowerVariable`](@ref):
+ Bounds: ``(P^\text{min},P^\text{max})``
+ Symbol: ``p``
**Static Parameters:**
- ``P^\text{min}`` = `PowerSystems.get_active_power_limits(device).min`
- ``P^\text{max}`` = `PowerSystems.get_active_power_limits(device).max`
**Objective:**
No cost is added to the objective function.
**Expressions:**
The variable `ActivePowerVariable` ``p`` is added positive to the AC balance expression `ActivePowerBalance` for AC Buses, and added negative to `ActivePowerBalance` for DC Buses, balancing both sides.
**Constraints:**
No constraints are added to the function.
================================================
FILE: docs/src/formulation_library/Feedforward.md
================================================
# [FeedForward Formulations](@id ff_formulations)
**FeedForwards** are the mechanism to define how information is shared between models. Specifically, a FeedForward defines what to do with information passed with an inter-stage chronology in a Simulation. The most common FeedForward is the `SemiContinuousFeedForward` that affects the semi-continuous range constraints of thermal generators in the economic dispatch problems based on the value of the (already solved) unit-commitment variables.
The creation of a FeedForward requires at least specifying the `component_type` on which the FeedForward will be applied. The `source` variable specifies which variable will be taken from the problem solved, for example, the commitment variable of the thermal unit in the unit commitment problem. Finally, the `affected_values` specify which variables will be affected in the problem to be solved, for example, the next economic dispatch problem.
### Table of contents
1. [`SemiContinuousFeedforward`](#SemiContinuousFeedForward)
2. [`FixValueFeedforward`](#FixValueFeedforward)
3. [`UpperBoundFeedforward`](#UpperBoundFeedforward)
4. [`LowerBoundFeedforward`](#LowerBoundFeedforward)
* * *
## `SemiContinuousFeedforward`
```@docs
SemiContinuousFeedforward
```
**Variables:**
No variables are created
**Parameters:**
- ``\text{on}^\text{th}`` = `OnStatusParameter` obtained from the source variable, typically the commitment variable of the unit commitment problem ``u^\text{th}``.
**Objective:**
No changes to the objective function.
**Expressions:**
Adds ``-\text{on}^\text{th}P^\text{th,max}`` to the `ActivePowerRangeExpressionUB` expression and ``-\text{on}^\text{th}P^\text{th,min}`` to the `ActivePowerRangeExpressionLB` expression.
**Constraints:**
Limits the `ActivePowerRangeExpressionUB` and `ActivePowerRangeExpressionLB` by zero as:
```math
\begin{align*}
& \text{ActivePowerRangeExpressionUB}_t := p_t^\text{th} - \text{on}_t^\text{th}P^\text{th,max} \le 0, \quad \forall t\in \{1, \dots, T\} \\
& \text{ActivePowerRangeExpressionLB}_t := p_t^\text{th} - \text{on}_t^\text{th}P^\text{th,min} \ge 0, \quad \forall t\in \{1, \dots, T\}
\end{align*}
```
Thus, if the commitment parameter is zero, the dispatch is limited to zero, forcing to turn off the generator without introducing binary variables in the economic dispatch problem.
* * *
## `FixValueFeedforward`
```@docs
FixValueFeedforward
```
**Variables:**
No variables are created
**Parameters:**
The parameter `FixValueParameter` is used to match the result obtained from the source variable (from the simulation state).
**Objective:**
No changes to the objective function.
**Expressions:**
No changes on expressions.
**Constraints:**
Set the `VariableType` from the `affected_values` to be equal to the source parameter store in `FixValueParameter`
```math
\begin{align*}
& \text{AffectedVariable}_t = \text{SourceVariableParameter}_t, \quad \forall t \in \{1,\dots, T\}
\end{align*}
```
* * *
## `UpperBoundFeedforward`
```@docs
UpperBoundFeedforward
```
**Variables:**
If slack variables are enabled:
- [`UpperBoundFeedForwardSlack`](@ref)
+ Bounds: [0.0, ]
+ Default proportional cost: 1e6
+ Symbol: ``p^\text{ff,ubsl}``
**Parameters:**
The parameter `UpperBoundValueParameter` stores the result obtained from the source variable (from the simulation state) that will be used as an upper bound to the affected variable.
**Objective:**
The slack variable is added to the objective function using its large default cost ``+ p^\text{ff,ubsl} \cdot 10^6``
**Expressions:**
No changes on expressions.
**Constraints:**
Set the `VariableType` from the `affected_values` to be lower than the source parameter store in `UpperBoundValueParameter`.
```math
\begin{align*}
& \text{AffectedVariable}_t - p_t^\text{ff,ubsl} \le \text{SourceVariableParameter}_t, \quad \forall t \in \{1,\dots, T\}
\end{align*}
```
* * *
## `LowerBoundFeedforward`
```@docs
LowerBoundFeedforward
```
**Variables:**
If slack variables are enabled:
- [`LowerBoundFeedForwardSlack`](@ref)
+ Bounds: [0.0, ]
+ Default proportional cost: 1e6
+ Symbol: ``p^\text{ff,lbsl}``
**Parameters:**
The parameter `LowerBoundValueParameter` stores the result obtained from the source variable (from the simulation state) that will be used as a lower bound to the affected variable.
**Objective:**
The slack variable is added to the objective function using its large default cost ``+ p^\text{ff,lbsl} \cdot 10^6``
**Expressions:**
No changes on expressions.
**Constraints:**
Set the `VariableType` from the `affected_values` to be greater than the source parameter store in `LowerBoundValueParameter`.
```math
\begin{align*}
& \text{AffectedVariable}_t + p_t^\text{ff,lbsl} \ge \text{SourceVariableParameter}_t, \quad \forall t \in \{1,\dots, T\}
\end{align*}
```
================================================
FILE: docs/src/formulation_library/General.md
================================================
# [Formulations](@id formulation_library)
Modeling formulations are created by dispatching on abstract subtypes of `PowerSimulations.AbstractDeviceFormulation`
## `FixedOutput`
```@docs
FixedOutput
```
**Variables:**
No variables are created for `DeviceModel(<:DeviceType, FixedOutput)`
**Static Parameters:**
- ThermalGen:
+ ``P^\text{th,max}`` = `PowerSystems.get_max_active_power(device)`
+ ``Q^\text{th,max}`` = `PowerSystems.get_max_reactive_power(device)`
- Storage:
+ ``P^\text{st,max}`` = `PowerSystems.get_max_active_power(device)`
+ ``Q^\text{st,max}`` = `PowerSystems.get_max_reactive_power(device)`
**Time Series Parameters:**
```@eval
using PowerSimulations
using HydroPowerSimulations
using PowerSystems
using DataFrames
using Latexify
combo_tables = []
for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad]
combos = PowerSimulations.get_default_time_series_names(t, FixedOutput)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
insertcols!(combo_table, 1, "Device Type" => fill(string(t), length(combos)))
push!(combo_tables, combo_table)
end
mdtable(vcat(combo_tables...); latex = false)
```
**Objective:**
No objective terms are created for `DeviceModel(<:DeviceType, FixedOutput)`
**Expressions:**
Adds the active and reactive parameters listed for specific device types above to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations).
**Constraints:**
No constraints are created for `DeviceModel(<:DeviceType, FixedOutput)`
* * *
## `FunctionData` Options
PowerSimulations can represent variable costs using a variety of different methods depending on the data available in each device. The following describes the objective function terms that are populated for each variable cost option.
### `LinearFunctionData`
`variable_cost = LinearFunctionData(c)`: creates a fixed marginal cost term in the objective function
```math
\begin{aligned}
& \text{min} \sum_{t} c * G_t
\end{aligned}
```
### `QuadraticFunctionData` and `PolynomialFunctionData`
`variable_cost::QuadraticFunctionData` and `variable_cost::PolynomialFunctionData`: create a polynomial cost term in the objective function
```math
\begin{aligned}
& \text{min} \sum_{t} \sum_{n} C_n * G_t^n
\end{aligned}
```
where
- For `QuadraticFunctionData`:
+ ``C_0`` = `get_constant_term(variable_cost)`
+ ``C_1`` = `get_proportional_term(variable_cost)`
+ ``C_2`` = `get_quadratic_term(variable_cost)`
- For `PolynomialFunctionData`:
+ ``C_n`` = `get_coefficients(variable_cost)[n]`
### `` and `PiecewiseLinearSlopeData`
`variable_cost::PiecewiseLinearData` and `variable_cost::PiecewiseLinearSlopeData`: create a piecewise linear cost term in the objective function
```math
\begin{aligned}
& \text{min} \sum_{t} f(G_t)
\end{aligned}
```
where
- For `variable_cost::PiecewiseLinearData`, ``f(x)`` is the piecewise linear function obtained by connecting the `(x, y)` points `get_points(variable_cost)` in order.
- For `variable_cost = PiecewiseLinearSlopeData([x0, x1, x2, ...], y0, [s0, s1, s2, ...])`, ``f(x)`` is the piecewise linear function obtained by starting at `(x0, y0)`, drawing a segment at slope `s0` to `x=x1`, drawing a segment at slope `s1` to `x=x2`, etc.
* * *
## `StorageCost`
Adds an objective function cost term according to:
```math
\begin{aligned}
& \text{min} \sum_{t} \quad [E^{surplus}_t * C^{penalty} - E^{shortage}_t * C^{value}]
\end{aligned}
```
**Impact of different cost configurations:**
The following table describes all possible configurations of the `StorageCost` with the target constraint in hydro or storage device models. Cases 1(a) & 2(a) will not impact the model's operations, and the target constraint will be rendered useless. In most cases that have no energy target and a non-zero value for ``C^{value}``, if this cost is too high (``C^{value} >> 0``) or too low (``C^{value} <<0``) can result in either the model holding on to stored energy till the end of the model not storing any energy in the device. This is caused by the fact that when the energy target is zero, we have ``E_t = - E^{shortage}_t``, and ``- E^{shortage}_t * C^{value}`` in the objective function is replaced by ``E_t * C^{value}``, thus resulting in ``C^{value}`` to be seen as the cost of stored energy.
| Case | Energy Target | Energy Shortage Cost | Energy Value / Energy Surplus cost | Effect |
|:--------- |:------------- |:-------------------- |:---------------------------------- |:------------------------------------------------- |
| Case 1(a) | $\hat{E}=0$ | $C^{penalty}=0$ | $C^{value}=0$ | no change |
| Case 1(b) | $\hat{E}=0$ | $C^{penalty}=0$ | $C^{value}<0$ | penalty for storing energy |
| Case 1(c) | $\hat{E}=0$ | $C^{penalty}>0$ | $C^{value}=0$ | no penalties or incentives applied |
| Case 1(d) | $\hat{E}=0$ | $C^{penalty}=0$ | $C^{value}>0$ | incentive for storing energy |
| Case 1(e) | $\hat{E}=0$ | $C^{penalty}>0$ | $C^{value}<0$ | penalty for storing energy |
| Case 1(f) | $\hat{E}=0$ | $C^{penalty}>0$ | $C^{value}>0$ | incentive for storing energy |
| Case 2(a) | $\hat{E}>0$ | $C^{penalty}=0$ | $C^{value}=0$ | no change |
| Case 2(b) | $\hat{E}>0$ | $C^{penalty}=0$ | $C^{value}<0$ | penalty on energy storage in excess of target |
| Case 2(c) | $\hat{E}>0$ | $C^{penalty}>0$ | $C^{value}=0$ | penalty on energy storage short of target |
| Case 2(d) | $\hat{E}>0$ | $C^{penalty}=0$ | $C^{value}>0$ | incentive on excess energy |
| Case 2(e) | $\hat{E}>0$ | $C^{penalty}>0$ | $C^{value}<0$ | penalty on both excess/shortage of energy |
| Case 2(f) | $\hat{E}>0$ | $C^{penalty}>0$ | $C^{value}>0$ | penalty for shortage, incentive for excess energy |
================================================
FILE: docs/src/formulation_library/Introduction.md
================================================
# [Formulations Introduction](@id formulation_intro)
PowerSimulations.jl enables modularity in its formulations by assigning a [`DeviceModel`](@ref) to each `PowerSystems.jl` component type existing in a defined system.
`PowerSimulations.jl` has a multiple `AbstractDeviceFormulation` subtypes that can be applied to different `PowerSystems.jl` device types, each dispatching to different methods for populating the optimization problem **variables**, **objective function**, **expressions** and **constraints**.
## Example Formulation
For example a typical optimization problem in a [`DecisionModel`](@ref) in `PowerSimulations.jl` with three [`DeviceModel`](@ref) has the abstract form of:
```math
\begin{align*}
&\min_{\boldsymbol{x}}~ \text{Objective\_DeviceModelA} + \text{Objective\_DeviceModelB} + \text{Objective\_DeviceModelC} \\
& ~~\text{s.t.} \\
& \hspace{0.9cm} \text{Constraints\_NetworkModel} \\
& \hspace{0.9cm} \text{Constraints\_DeviceModelA} \\
& \hspace{0.9cm} \text{Constraints\_DeviceModelB} \\
& \hspace{0.9cm} \text{Constraints\_DeviceModelC}
\end{align*}
```
Suppose this is a system with the following characteristics:
- Horizon: 48 hours
- Interval: 24 hours
- Resolution: 1 hour
- Three Buses: 1, 2 and 3
- One `ThermalStandard` (device A) unit at bus 1
- One `RenewableDispatch` (device B) unit at bus 2
- One `PowerLoad` (device C) at bus 3
- Three `Line` that connects all the buses
Now, we assign the following [`DeviceModel`](@ref) to each `PowerSystems.jl` with:
| Type | Formulation |
|:------------------- |:----------------------- |
| Network | `CopperPlatePowerModel` |
| `ThermalStandard` | `ThermalDispatchNoMin` |
| `RenewableDispatch` | `RenewableFullDispatch` |
| `PowerLoad` | `StaticPowerLoad` |
Note that we did not assign any [`DeviceModel`](@ref) to `Line` since the `CopperPlatePowerModel` used for the network assumes that everything is lumped in the same node (like a copper plate with infinite capacity), and hence there are no flows between buses that branches can limit.
Each [`DeviceModel`](@ref) formulation is described in specific in their respective page, but the overall optimization problem will end-up as:
```math
\begin{align*}
&\min_{\boldsymbol{p}^\text{th}, \boldsymbol{p}^\text{re}}~ \sum_{t=1}^{48} C^\text{th} p_t^\text{th} - C^\text{re} p_t^\text{re} \\
& ~~\text{s.t.} \\
& \hspace{0.9cm} p_t^\text{th} + p_t^\text{re} = P_t^\text{load}, \quad \forall t \in {1,\dots, 48} \\
& \hspace{0.9cm} 0 \le p_t^\text{th} \le P^\text{th,max} \\
& \hspace{0.9cm} 0 \le p_t^\text{re} \le \text{ActivePowerTimeSeriesParameter}_t
\end{align*}
```
Note that the `StaticPowerLoad` does not impose any cost to the objective function or constraint but adds its power demand to the supply-balance demand of the `CopperPlatePowerModel` used. Since we are using the `ThermalDispatchNoMin` formulation for the thermal generation, the lower bound for the power is 0, instead of ``P^\text{th,min}``. In addition, we are assuming a linear cost ``C^\text{th}``. Finally, the `RenewableFullDispatch` formulation allows the dispatch of the renewable unit between 0 and its maximum injection time series ``p_t^\text{re,param}``.
# Nomenclature
In the formulations described in the other pages, the nomenclature is as follows:
- Lowercase letters are used for variables, e.g., ``p`` for power.
- Uppercase letters are used for parameters, e.g., ``C`` for costs.
- Subscripts are used for indexing, e.g., ``(\cdot)_t`` for indexing at time ``t``.
- Superscripts are used for descriptions, e.g., ``(\cdot)^\text{th}`` to describe a thermal (th) variable/parameter.
- Bold letters are used for vectors, e.g., ``\boldsymbol{p} = \{p\}_{1,\dots,24}``.
================================================
FILE: docs/src/formulation_library/Load.md
================================================
# `PowerSystems.ElectricLoad` Formulations
Electric load formulations define the optimization models that describe load units (demand) mathematical model in different operational settings, such as economic dispatch and unit commitment.
!!! note
The use of reactive power variables and constraints will depend on the network model used, i.e., whether it uses (or does not use) reactive power. If the network model is purely active power-based, reactive power variables and related constraints are not created.
### Table of contents
1. [`StaticPowerLoad`](#StaticPowerLoad)
2. [`PowerLoadInterruption`](#PowerLoadInterruption)
3. [`PowerLoadDispatch`](#PowerLoadDispatch)
4. [`PowerLoadShift`](#PowerLoadShift)
5. [Valid configurations](#Valid-configurations)
* * *
## `StaticPowerLoad`
```@docs
StaticPowerLoad
```
**Variables:**
No variables are created
**Time Series Parameters:**
Uses the `max_active_power` timeseries parameter to determine the demand value at each time-step
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.get_default_time_series_names(ElectricLoad, StaticPowerLoad)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Expressions:**
Subtracts the parameters listed above from the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations).
**Constraints:**
No constraints are created
* * *
## `PowerLoadInterruption`
```@docs
PowerLoadInterruption
```
**Variables:**
- [`ActivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Symbol: ``p^\text{ld}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Symbol: ``q^\text{ld}``
- [`OnVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Default initial value: 1
+ Symbol: ``u^\text{ld}``
**Static Parameters:**
- ``P^\text{ld,max}`` = `PowerSystems.get_max_active_power(device)`
- ``Q^\text{ld,max}`` = `PowerSystems.get_max_reactive_power(device)`
**Time Series Parameters:**
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.get_default_time_series_names(ElectricLoad, PowerLoadInterruption)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Objective:**
Creates an objective function term based on the [`FunctionData` Options](@ref) where the quantity term is defined as ``p^\text{ld}``.
**Expressions:**
- Subtract``p^\text{ld}`` and ``q^\text{ld}`` terms and to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations)
**Constraints:**
```math
\begin{aligned}
& p_t^\text{ld} \le u_t^\text{ld} \cdot \text{ActivePowerTimeSeriesParameter}_t, \quad \forall t \in \{1,\dots, T\} \\
& q_t^\text{re} = \text{pf} \cdot p_t^\text{re}, \quad \forall t \in \{1,\dots, T\}
\end{aligned}
```
on which ``\text{pf} = \sin(\arctan(Q^\text{ld,max}/P^\text{ld,max}))``.
* * *
## `PowerLoadDispatch`
```@docs
PowerLoadDispatch
```
**Variables:**
- [`ActivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: `PowerSystems.get_active_power(device)`
+ Symbol: ``p^\text{ld}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: `PowerSystems.get_reactive_power(device)`
+ Symbol: ``q^\text{ld}``
**Static Parameters:**
- ``P^\text{ld,max}`` = `PowerSystems.get_max_active_power(device)`
- ``Q^\text{ld,max}`` = `PowerSystems.get_max_reactive_power(device)`
**Time Series Parameters:**
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.get_default_time_series_names(ElectricLoad, PowerLoadDispatch)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Objective:**
Creates an objective function term based on the [`FunctionData` Options](@ref) where the quantity term is defined as ``p^\text{ld}``.
**Expressions:**
- Subtract``p^\text{ld}`` and ``q^\text{ld}`` terms and to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations)
**Constraints:**
```math
\begin{aligned}
& p_t^\text{ld} \le \text{ActivePowerTimeSeriesParameter}_t, \quad \forall t \in \{1,\dots, T\}\\
& q_t^\text{ld} = \text{pf} \cdot p_t^\text{ld}, \quad \forall t \in \{1,\dots, T\}\\
\end{aligned}
```
on which ``\text{pf} = \sin(\arctan(Q^\text{ld,max}/P^\text{ld,max}))``.
* * *
## `PowerLoadShift`
```@docs
PowerLoadShift
```
**Variables:**
- [`ShiftUpActivePowerVariable`](@ref):
+ Bounds: [0.0, `ShiftUpActivePowerTimeSeriesParameter`]
+ Default initial value: 0.0
+ Symbol: ``p^\text{shift,up}``
- [`ShiftDownActivePowerVariable`](@ref):
+ Bounds: [0.0, `ShiftDownActivePowerTimeSeriesParameter`]
+ Default initial value: 0.0
+ Symbol: ``p^\text{shift,dn}``
- [`ReactivePowerVariable`](@ref) *(AC network models only)*:
+ Bounds: [0.0, ]
+ Default initial value: `PowerSystems.get_reactive_power(device)`
+ Symbol: ``q^\text{ld}``
**Static Parameters:**
- ``P^\text{ld,max}`` = `PowerSystems.get_max_active_power(device)`
- ``Q^\text{ld,max}`` = `PowerSystems.get_max_reactive_power(device)`
**Time Series Parameters:**
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.get_default_time_series_names(ShiftablePowerLoad, PowerLoadShift)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Expressions:**
- Defines the `RealizedShiftedLoad` expression per device per time step:
```math
p_t^\text{realized} = \text{ActivePowerTimeSeriesParameter}_t + p_t^\text{shift,up} - p_t^\text{shift,dn}, \quad \forall t \in \{1,\dots,T\}
```
- Subtracts ``p_t^\text{realized}`` from the active power balance expression of the selected [Network Formulations](@ref network_formulations).
**Objective:**
Creates objective function terms based on the [`FunctionData` Options](@ref) for both shift variables:
- A cost term on ``p^\text{shift,up}`` (typically zero or negative, rewarding shifting up)
- A cost term on ``p^\text{shift,dn}`` (typically positive, penalizing shifting down)
**Constraints:**
```math
\begin{aligned}
& \sum_{t=1}^{T} \left( p_t^\text{shift,up} - p_t^\text{shift,dn} \right) = 0 \\
& \sum_{t=1}^{T_\text{sub}} \left( p_t^\text{shift,up} - p_t^\text{shift,dn} \right) = 0 \quad \text{(if \texttt{additional\_balance\_interval} is set)}
\end{aligned}
```
```math
p_t^\text{realized} \ge 0, \quad \forall t \in \{1,\dots,T\}
```
```math
p_t^\text{shift,up} \le \text{ShiftUpActivePowerTimeSeriesParameter}_t, \quad \forall t \in \{1,\dots,T\}
```
```math
p_t^\text{shift,dn} \le \text{ShiftDownActivePowerTimeSeriesParameter}_t, \quad \forall t \in \{1,\dots,T\}
```
```math
\sum_{\tau=1}^{t} \left( p_\tau^\text{shift,dn} - p_\tau^\text{shift,up} \right) \ge 0, \quad \forall t \in \{1,\dots,T\}
```
```math
q_t^\text{ld} = \text{pf} \cdot p_t^\text{realized}, \quad \forall t \in \{1,\dots,T\}
```
## Valid configurations
Valid [`DeviceModel`](@ref)s for subtypes of `ElectricLoad` include the following:
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.generate_device_formulation_combinations()
filter!(x -> x["device_type"] <: ElectricLoad, combos)
combo_table = DataFrame(
"Valid DeviceModel" =>
["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos],
"Device Type" => [
"[$(c["device_type"])](https://nrel-Sienna.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)"
for c in combos
],
"Formulation" => ["[$(c["formulation"])](@ref)" for c in combos],
)
mdtable(combo_table; latex = false)
```
================================================
FILE: docs/src/formulation_library/Network.md
================================================
# [Network Formulations](@id network_formulations)
Network formulations are used to describe how the network and buses are handled when constructing constraints. The most common constraint decided by the network formulation is the supply-demand balance constraint.
```@docs
NetworkModel
```
Available Network Models are:
| Formulation | Description |
|:----------------------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CopperPlatePowerModel` | Copper plate connection between all components, i.e. infinite transmission capacity |
| `AreaBalancePowerModel` | Network model approximation to represent inter-area flow with each area represented as a single node |
| `PTDFPowerModel` | Uses the PTDF factor matrix to compute the fraction of power transferred in the network across the branches |
| `AreaPTDFPowerModel` | Uses the PTDF factor matrix to compute the fraction of power transferred in the network across the branches and balances power by Area instead of system-wide |
[`PowerModels.jl`](https://github.com/lanl-ansi/PowerModels.jl) available formulations:
- Exact non-convex models: `ACPPowerModel`, `ACRPowerModel`, `ACTPowerModel`.
- Linear approximations: `DCPPowerModel`, `NFAPowerModel`.
- Quadratic approximations: `DCPLLPowerModel`, `LPACCPowerModel`
- Quadratic relaxations: `SOCWRPowerModel`, `SOCWRConicPowerModel`, `SOCBFPowerModel`, `SOCBFConicPowerModel`, `QCRMPowerModel`, `QCLSPowerModel`.
- SDP relaxations: `SDPWRMPowerModel`.
All of these formulations are described in the [PowerModels.jl documentation](https://lanl-ansi.github.io/PowerModels.jl/stable/formulation-details/) and will not be described here.
* * *
## `CopperPlatePowerModel`
```@docs
CopperPlatePowerModel
```
**Variables:**
If Slack variables are enabled:
- [`SystemBalanceSlackUp`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Default proportional cost: 1e6
+ Symbol: ``p^\text{sl,up}``
- [`SystemBalanceSlackDown`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Default proportional cost: 1e6
+ Symbol: ``p^\text{sl,dn}``
**Objective:**
Add a large proportional cost to the objective function if slack variables are used ``+ (p^\text{sl,up} + p^\text{sl,dn}) \cdot 10^6``
**Expressions:**
Adds ``p^\text{sl,up}`` and ``p^\text{sl,dn}`` terms to the respective active power balance expressions `ActivePowerBalance` created by this `CopperPlatePowerModel` network formulation.
**Constraints:**
Adds the `CopperPlateBalanceConstraint` to balance the active power of all components available in the system
```math
\begin{align}
& \sum_{c \in \text{components}} p_t^c = 0, \quad \forall t \in \{1, \dots, T\}
\end{align}
```
* * *
## `AreaBalancePowerModel`
```@docs
AreaBalancePowerModel
```
**Variables:**
If Slack variables are enabled:
- [`SystemBalanceSlackUp`](@ref) by area:
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Default proportional cost: 1e6
+ Symbol: ``p^\text{sl,up}``
- [`SystemBalanceSlackDown`](@ref) by area:
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Default proportional cost: 1e6
+ Symbol: ``p^\text{sl,dn}``
**Objective:**
Adds ``p^\text{sl,up}`` and ``p^\text{sl,dn}`` terms to the respective active power balance expressions `ActivePowerBalance` per area.
**Expressions:**
Creates `ActivePowerBalance` expressions for each area that then are used to balance active power for all buses within a single area.
**Constraints:**
Adds the `CopperPlateBalanceConstraint` to balance the active power of all components available in an area.
```math
\begin{align}
& \sum_{c \in \text{components}_a} p_t^c = 0, \quad \forall a\in \{1,\dots, A\}, t \in \{1, \dots, T\}
\end{align}
```
* * *
## `PTDFPowerModel`
```@docs
PTDFPowerModel
```
**Variables:**
If Slack variables are enabled:
- [`SystemBalanceSlackUp`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Default proportional cost: 1e6
+ Symbol: ``p^\text{sl,up}``
- [`SystemBalanceSlackDown`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Default proportional cost: 1e6
+ Symbol: ``p^\text{sl,dn}``
**Objective:**
Add a large proportional cost to the objective function if slack variables are used ``+ (p^\text{sl,up} + p^\text{sl,dn}) \cdot 10^6``
**Expressions:**
Adds ``p^\text{sl,up}`` and ``p^\text{sl,dn}`` terms to the respective system-wide active power balance expressions `ActivePowerBalance` created by this `CopperPlatePowerModel` network formulation. In addition, it creates `ActivePowerBalance` expressions for each bus to be used in the calculation of branch flows.
**Constraints:**
Adds the `CopperPlateBalanceConstraint` to balance the active power of all components available in the system
```math
\begin{align}
& \sum_{c \in \text{components}} p_t^c = 0, \quad \forall t \in \{1, \dots, T\}
\end{align}
```
In addition creates `NodalBalanceActiveConstraint` for HVDC buses balance, if DC components are connected to an HVDC network.
## `AreaPTDFPowerModel`
```@docs
AreaPTDFPowerModel
```
**Variables**
Slack variables are not supported.
**Objective Function**
No changes to the objective function.
**Expressions**
Creates the area-wide and nodal-wide active power balance expressions `ActivePowerBalance` to balance power based on each area independently. The flows across areas are computed based on the PTDF factors of lines connecting areas.
**Constraints:**
Adds the `ActivePowerBalance` constraint to balance the active power of all components available for each area.
```math
\begin{align}
& \sum_{c \in \text{components}_a} p_t^c = 0, \quad \forall a\in \{1,\dots, A\}, t \in \{1, \dots, T\}
\end{align}
```
This includes the flows of lines based on the PTDF factors.
================================================
FILE: docs/src/formulation_library/Piecewise.md
================================================
# [Piecewise linear cost functions](@id pwl_cost)
The choice for piecewise-linear (PWL) cost representation in `PowerSimulations.jl` is equivalent to the so-called λ-model from the paper [_The Impacts of Convex Piecewise Linear Cost Formulations on AC Optimal Power Flow_](https://www.sciencedirect.com/science/article/pii/S0378779621001723). The SOS constraints in each model are only implemented if the data for PWL is not convex.
## Special Ordered Set (SOS) Constraints
A special ordered set (SOS) is an ordered set of variables used as an additional way to specify integrality conditions in an optimization model.
- Special Ordered Sets of type 1 (SOS1) are a set of variables, at most one of which can take a non-zero value, all others being at 0. They most frequently applications is in a a set of variables that are actually binary variables: in other words, we have to choose at most one from a set of possibilities.
- Special Ordered Sets of type 2 (SOS2) are an ordered set of non-negative variables, of which at most two can be non-zero, and if two are non-zero these must be consecutive in their ordering. Special Ordered Sets of type 2 are typically used to model non-linear functions of a variable in a linear model, such as non-convex quadratic functions using PWL functions.
## Standard representation of PWL costs
Piecewise-linear costs are defined by a sequence of points representing the line segments for each generator: ``(P_k^\text{max}, C_k)`` on which we assume ``C_k`` is the cost of generating ``P_k^\text{max}`` power, and ``k \in \{1,\dots, K\}`` are the number of segments each generator cost function has.
!!! note
`PowerSystems` has more options to specify cost functions for each thermal unit. Independent of which form of the cost data is provided, `PowerSimulations.jl` will internally transform the data to use the λ-model formulation. See **TODO: ADD PSY COST DOCS** for more information.
### Commitment formulation
With this the standard representation of PWL costs for a thermal unit commitment is given by:
```math
\begin{align*}
\min_{\substack{p_{t}, \delta_{k,t}}}
& \sum_{t \in \mathcal{T}} \left(\sum_{k \in \mathcal{K}} C_{k,t} \delta_{k,t} \right) \Delta t\\
& \sum_{k \in \mathcal{K}} P_{k}^{\text{max}} \delta_{k,t} = p_{t} & \forall t \in \mathcal{T}\\
& \sum_{k \in \mathcal{K}} \delta_{k,t} = u_{t} & \forall t \in \mathcal{T}\\
& P^{\text{min}} u_{t} \leq p_{t} \leq P^{\text{max}} u_{t} & \forall t \in \mathcal{T}\\
&\left \{\delta_{1,t}, \dots, \delta_{K,t} \right \} \in \text{SOS}_{2} & \forall t \in \mathcal{T}
\end{align*}
```
on which ``\delta_{k,t} \in [0,1]`` is the interpolation variable, ``p`` is the active power of the generator and ``u \in \{0,1\}`` is the commitment variable of the generator. In the case of a PWL convex costs, i.e. increasing slopes, the SOS constraint is omitted.
### Dispatch formulation
```math
\begin{align*}
\min_{\substack{p_{t}, \delta_{k,t}}}
& \sum_{t \in \mathcal{T}} \left(\sum_{k \in \mathcal{K}} C_{k,t} \delta_{k,t} \right) \Delta t\\
& \sum_{k \in \mathcal{K}} P_{k}^{\text{max}} \delta_{k,t} = p_{t} & \forall t \in \mathcal{T}\\
& \sum_{k \in \mathcal{K}} \delta_{k,t} = \text{on}_{t} & \forall t \in \mathcal{T}\\
& P^{\text{min}} \text{on}_{t} \leq p_{t} \leq P^{\text{max}} \text{on}_{t} & \forall t \in \mathcal{T}\\
&\left \{\delta_{i,t}, \dots, \delta_{k,t} \right \} \in \text{SOS}_{2} & \forall t \in \mathcal{T}
\end{align*}
```
on which ``\delta_{k,t} \in [0,1]`` is the interpolation variable, ``p`` is the active power of the generator and ``\text{on} \in \{0,1\}`` is the parameter that decides if the generator is available or not. In the case of a PWL convex costs, i.e. increasing slopes, the SOS constraint is omitted.
## Compact representation of PWL costs
### Commitment Formulation
```math
\begin{align*}
\min_{\substack{p_{t}, \delta_{k,t}}}
& \sum_{t \in \mathcal{T}} \left(\sum_{k \in \mathcal{K}} C_{k,t} \delta_{k,t} \right) \Delta t\\
& \sum_{k \in \mathcal{K}} P_{k}^{\text{max}} \delta_{k,t} = P^{\text{min}} u_{t} + \Delta p_{t} & \forall t \in \mathcal{T}\\
& \sum_{k \in \mathcal{K}} \delta_{k,t} = u_{t} & \forall t \in \mathcal{T}\\
& 0 \leq \Delta p_{t} \leq \left( P^{\text{max}} - P^{\text{min}} \right)u_{t} & \forall t \in \mathcal{T}\\
&\left \{\delta_{i,t} \dots \delta_{k,t} \right \} \in \text{SOS}_{2} & \forall t \in \mathcal{T}
\end{align*}
```
on which ``\delta_{k,t} \in [0,1]`` is the interpolation variable, ``\Delta p`` is the active power of the generator above the minimum power and ``u \in \{0,1\}`` is the commitment variable of the generator. In the case of a PWL convex costs, i.e. increasing slopes, the SOS constraint is omitted.
### Dispatch formulation
```math
\begin{align*}
\min_{\substack{p_{t}, \delta_{k,t}}}
& \sum_{t \in \mathcal{T}} \left(\sum_{k \in \mathcal{K}} C_{k,t} \delta_{k,t} \right) \Delta t\\
& \sum_{k \in \mathcal{K}} P_{k}^{\text{max}} \delta_{k,t} = P^{\text{min}} \text{on}_{t} + \Delta p_{t} & \forall t \in \mathcal{T}\\
& \sum_{k \in \mathcal{K}} \delta_{k,t} = \text{on}_{t} & \forall t \in \mathcal{T}\\
& 0 \leq \Delta p_{t} \leq \left( P^{\text{max}} - P^{\text{min}} \right)\text{on}_{t} & \forall t \in \mathcal{T}\\
&\left \{\delta_{i,t} \dots \delta_{k,t} \right \} \in \text{SOS}_{2} & \forall t \in \mathcal{T}
\end{align*}
```
on which ``\delta_{k,t} \in [0,1]`` is the interpolation variable, ``\Delta p`` is the active power of the generator above the minimum power and ``u \in \{0,1\}`` is the commitment variable of the generator. In the case of a PWL convex costs, i.e. increasing slopes, the SOS constraint is omitted.
================================================
FILE: docs/src/formulation_library/README.md
================================================
# Formulation documentation guide
Formulation documentation should *roughly* follow the template established by RenewableGen.md
## Auto generated items
- Valid DeviceModel table: just change the device category in the filter function
- Time Series Parameters: just change the device category and formulation in the `get_default_time_series_names` method call
## Linked items
- Formulations in the Valid DeviceModel table must have a docstring in src/core/formulations.jl
- The Formulation in the @docs block must have a docstring in src/core/formulations.jl
- The Variables must have docstrings in src/core/variables.jl
- The Time Series Parameters must have docstrings in src/core/parameters.jl
================================================
FILE: docs/src/formulation_library/RenewableGen.md
================================================
# `PowerSystems.RenewableGen` Formulations
Renewable generation formulations define the optimization models that describe renewable units mathematical model in different operational settings, such as economic dispatch and unit commitment.
!!! note
The use of reactive power variables and constraints will depend on the network model used, i.e., whether it uses (or does not use) reactive power. If the network model is purely active power-based, reactive power variables and related constraints are not created.
!!! note
Reserve variables for services are not included in the formulation, albeit their inclusion change the variables, expressions, constraints and objective functions created. A detailed description of the implications in the optimization models is described in the [Service formulation](@ref service_formulations) section.
### Table of contents
1. [`RenewableFullDispatch`](#RenewableFullDispatch)
2. [`RenewableConstantPowerFactor`](#RenewableConstantPowerFactor)
3. [Valid configurations](#Valid-configurations)
* * *
## `RenewableFullDispatch`
```@docs
RenewableFullDispatch
```
**Variables:**
- [`ActivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``p^\text{re}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``q^\text{re}``
**Static Parameters:**
- ``P^\text{re,min}`` = `PowerSystems.get_active_power_limits(device).min`
- ``Q^\text{re,min}`` = `PowerSystems.get_reactive_power_limits(device).min`
- ``Q^\text{re,max}`` = `PowerSystems.get_reactive_power_limits(device).max`
**Time Series Parameters:**
Uses the `max_active_power` timeseries parameter to limit the available active power at each time-step.
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.get_default_time_series_names(RenewableGen, RenewableFullDispatch)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Objective:**
Creates an objective function term based on the [`FunctionData` Options](@ref) where the quantity term is defined as ``- p^\text{re}`` to incentivize generation from `RenewableGen` devices.
**Expressions:**
Adds ``p^\text{re}`` and ``q^\text{re}`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations).
**Constraints:**
```math
\begin{aligned}
& P^\text{re,min} \le p_t^\text{re} \le \text{ActivePowerTimeSeriesParameter}_t, \quad \forall t \in \{1,\dots, T\} \\
& Q^\text{re,min} \le q_t^\text{re} \le Q^\text{re,max}, \quad \forall t \in \{1,\dots, T\}
\end{aligned}
```
* * *
## `RenewableConstantPowerFactor`
```@docs
RenewableConstantPowerFactor
```
**Variables:**
- [`ActivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: `PowerSystems.get_active_power(device)`
+ Symbol: ``p^\text{re}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: `PowerSystems.get_reactive_power(device)`
+ Symbol: ``q^\text{re}``
**Static Parameters:**
- ``P^\text{re,min}`` = `PowerSystems.get_active_power_limits(device).min`
- ``Q^\text{re,min}`` = `PowerSystems.get_reactive_power_limits(device).min`
- ``Q^\text{re,max}`` = `PowerSystems.get_reactive_power_limits(device).max`
- ``\text{pf}`` = `PowerSystems.get_power_factor(device)`
**Time Series Parameters:**
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.get_default_time_series_names(
RenewableGen,
RenewableConstantPowerFactor,
)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Objective:**
Creates an objective function term based on the [`FunctionData` Options](@ref) where the quantity term is defined as ``- p_t^\text{re}`` to incentivize generation from `RenewableGen` devices.
**Expressions:**
Adds ``p^\text{re}`` and ``q^\text{re}`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations)
**Constraints:**
```math
\begin{aligned}
& P^\text{re,min} \le p_t^\text{re} \le \text{ActivePowerTimeSeriesParameter}_t, \quad \forall t \in \{1,\dots, T\} \\
& q_t^\text{re} = \text{pf} \cdot p_t^\text{re}, \quad \forall t \in \{1,\dots, T\}
\end{aligned}
```
* * *
## Valid configurations
Valid [`DeviceModel`](@ref)s for subtypes of `RenewableGen` include the following:
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.generate_device_formulation_combinations()
filter!(x -> x["device_type"] <: RenewableGen, combos)
combo_table = DataFrame(
"Valid DeviceModel" =>
["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos],
"Device Type" => [
"[$(c["device_type"])](https://nrel-Sienna.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)"
for c in combos
],
"Formulation" => ["[$(c["formulation"])](@ref)" for c in combos],
)
mdtable(combo_table; latex = false)
```
================================================
FILE: docs/src/formulation_library/Service.md
================================================
# [`PowerSystems.Service` Formulations](@id service_formulations)
`Services` (or ancillary services) are models used to ensure that there is necessary support to the power grid from generators to consumers, in order to ensure reliable operation of the system.
The most common application for ancillary services are reserves, i.e., generation (or load) that is not currently being used, but can be quickly made available in case of unexpected changes of grid conditions, for example a sudden loss of load or generation.
A key challenge of adding services to a system, from a mathematical perspective, is specifying which units contribute to the specified requirement of a service, that implies the creation of new variables (such as reserve variables) and modification of constraints.
In this documentation, we first specify the available `Services` in the grid, and what requirements impose in the system, and later we discuss the implication on device formulations for specific units.
### Table of contents
1. [`RangeReserve`](#RangeReserve)
2. [`StepwiseCostReserve`](#StepwiseCostReserve)
3. [`GroupReserve`](#GroupReserve)
4. [`RampReserve`](#RampReserve)
5. [`NonSpinningReserve`](#NonSpinningReserve)
6. [`ConstantMaxInterfaceFlow`](#ConstantMaxInterfaceFlow)
7. [`VariableMaxInterfaceFlow`](#VariableMaxInterfaceFlow)
8. [Changes on Expressions](#Changes-on-Expressions-due-to-Service-models)
* * *
## `RangeReserve`
```@docs
RangeReserve
```
For each service ``s`` of the model type `RangeReserve` the following variables are created:
**Variables**:
- [`ActivePowerReserveVariable`](@ref):
+ Bounds: [0.0, ]
+ Default proportional cost: ``1.0 / \text{SystemBasePower}``
+ Symbol: ``r_{d}`` for ``d`` in contributing devices to the service ``s``
If slacks are enabled:
- [`ReserveRequirementSlack`](@ref):
+ Bounds: [0.0, ]
+ Default proportional cost: 1e5
+ Symbol: ``r^\text{sl}``
Depending on the `PowerSystems.jl` type associated to the `RangeReserve` formulation model, the parameters are:
**Static Parameters**
- ``\text{PF}`` = `PowerSystems.get_max_participation_factor(service)`
For a `ConstantReserve` `PowerSystems` type:
- ``\text{Req}`` = `PowerSystems.get_requirement(service)`
**Time Series Parameters**
For a `VariableReserve` `PowerSystems` type:
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.get_default_time_series_names(VariableReserve, RangeReserve)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Relevant Methods:**
- ``\mathcal{D}_s`` = `PowerSystems.get_contributing_devices(system, service)`: Set (vector) of all contributing devices to the service ``s`` in the system.
**Objective:**
Add a large proportional cost to the objective function if slack variables are used ``+ r^\text{sl} \cdot 10^5``. In addition adds the default cost for `ActivePowerReserveVariables` as a proportional cost.
**Expressions:**
Adds the `ActivePowerReserveVariable` for upper/lower bound expressions of contributing devices.
For `ReserveUp` types, the variable is added to `ActivePowerRangeExpressionUB`, such that this expression considers both the `ActivePowerVariable` and its reserve variable. Similarly, For `ReserveDown` types, the variable is added to `ActivePowerRangeExpressionLB`, such that this expression considers both the `ActivePowerVariable` and its reserve variable
*Example*: for a thermal unit ``d`` contributing to two different `ReserveUp` ``s_1, s_2`` services (e.g. Reg-Up and Spin):
```math
\text{ActivePowerRangeExpressionUB}_{t} = p_t^\text{th} + r_{s_1,t} + r_{s_2, t} \le P^\text{th,max}
```
similarly if ``s_3`` is a `ReserveDown` service (e.g. Reg-Down):
```math
\text{ActivePowerRangeExpressionLB}_{t} = p_t^\text{th} - r_{s_3,t} \ge P^\text{th,min}
```
**Constraints:**
A RangeReserve implements two fundamental constraints. The first is that the sum of all reserves of contributing devices must be larger than the `RangeReserve` requirement. Thus, for a service ``s``:
```math
\sum_{d\in\mathcal{D}_s} r_{d,t} + r_t^\text{sl} \ge \text{Req},\quad \forall t\in \{1,\dots, T\} \quad \text{(for a ConstantReserve)} \\
\sum_{d\in\mathcal{D}_s} r_{d,t} + r_t^\text{sl} \ge \text{RequirementTimeSeriesParameter}_{t},\quad \forall t\in \{1,\dots, T\} \quad \text{(for a VariableReserve)}
```
In addition, there is a restriction on how much each contributing device ``d`` can contribute to the requirement, based on the max participation factor allowed.
```math
r_{d,t} \le \text{Req} \cdot \text{PF} ,\quad \forall d\in \mathcal{D}_s, \forall t\in \{1,\dots, T\} \quad \text{(for a ConstantReserve)} \\
r_{d,t} \le \text{RequirementTimeSeriesParameter}_{t} \cdot \text{PF}\quad \forall d\in \mathcal{D}_s, \forall t\in \{1,\dots, T\}, \quad \text{(for a VariableReserve)}
```
* * *
## `StepwiseCostReserve`
Service must be used with `ReserveDemandCurve` `PowerSystems.jl` type. This service model is used to model ORDC (Operating Reserve Demand Curve) in ERCOT.
```@docs
StepwiseCostReserve
```
For each service ``s`` of the model type `ReserveDemandCurve` the following variables are created:
**Variables**:
- [`ActivePowerReserveVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``r_{d}`` for ``d`` in contributing devices to the service ``s``
- [`ServiceRequirementVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``\text{req}``
**Time Series Parameters**
For a `ReserveDemandCurve` `PowerSystems` type:
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos =
PowerSimulations.get_default_time_series_names(ReserveDemandCurve, StepwiseCostReserve)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Relevant Methods:**
- ``\mathcal{D}_s`` = `PowerSystems.get_contributing_devices(system, service)`: Set (vector) of all contributing devices to the service ``s`` in the system.
**Objective:**
The `ServiceRequirementVariable` is added as a piecewise linear cost based on the decreasing offers listed in the `variable_cost` time series. These decreasing cost represent the scarcity prices of not having sufficient reserves. For example, if the variable ``\text{req} = 0``, then a really high cost is paid for not having enough reserves, and if ``\text{req}`` is larger, then a lower cost (or even zero) is paid.
**Expressions:**
Adds the `ActivePowerReserveVariable` for upper/lower bound expressions of contributing devices.
For `ReserveUp` types, the variable is added to `ActivePowerRangeExpressionUB`, such that this expression considers both the `ActivePowerVariable` and its reserve variable. Similarly, For `ReserveDown` types, the variable is added to `ActivePowerRangeExpressionLB`, such that this expression considers both the `ActivePowerVariable` and its reserve variable
*Example*: for a thermal unit ``d`` contributing to two different `ReserveUp` ``s_1, s_2`` services (e.g. Reg-Up and Spin):
```math
\text{ActivePowerRangeExpressionUB}_{t} = p_t^\text{th} + r_{s_1,t} + r_{s_2, t} \le P^\text{th,max}
```
similarly if ``s_3`` is a `ReserveDown` service (e.g. Reg-Down):
```math
\text{ActivePowerRangeExpressionLB}_{t} = p_t^\text{th} - r_{s_3,t} \ge P^\text{th,min}
```
**Constraints:**
A `StepwiseCostReserve` implements a single constraint, such that the sum of all reserves of contributing devices must be larger than the `ServiceRequirementVariable` variable. Thus, for a service ``s``:
```math
\sum_{d\in\mathcal{D}_s} r_{d,t} \ge \text{req}_t,\quad \forall t\in \{1,\dots, T\}
```
## `GroupReserve`
Service must be used with `ConstantReserveGroup` `PowerSystems.jl` type. This service model is used to model an aggregation of services.
```@docs
GroupReserve
```
For each service ``s`` of the model type `GroupReserve` the following variables are created:
**Variables**:
No variables are created, but the services associated with the `GroupReserve` must have created variables.
**Static Parameters**
- ``\text{Req}`` = `PowerSystems.get_requirement(service)`
**Relevant Methods:**
- ``\mathcal{S}_s`` = `PowerSystems.get_contributing_services(system, service)`: Set (vector) of all contributing services to the group service ``s`` in the system.
- ``\mathcal{D}_{s_i}`` = `PowerSystems.get_contributing_devices(system, service_aux)`: Set (vector) of all contributing devices to the service ``s_i`` in the system.
**Objective:**
Does not modify the objective function, besides the changes to the objective function due to the other services associated to the group service.
**Expressions:**
No changes, besides the changes to the expressions due to the other services associated to the group service.
**Constraints:**
A GroupReserve implements that the sum of all reserves of contributing devices, of all contributing services, must be larger than the `GroupReserve` requirement. Thus, for a `GroupReserve` service ``s``:
```math
\sum_{d\in\mathcal{D}_{s_i}} \sum_{i \in \mathcal{S}_s} r_{d,t} \ge \text{Req},\quad \forall t\in \{1,\dots, T\}
```
* * *
## `RampReserve`
```@docs
RampReserve
```
For each service ``s`` of the model type `RampReserve` the following variables are created:
**Variables**:
- [`ActivePowerReserveVariable`](@ref):
+ Bounds: [0.0, ]
+ Default proportional cost: ``1.0 / \text{SystemBasePower}``
+ Symbol: ``r_{d}`` for ``d`` in contributing devices to the service ``s``
If slacks are enabled:
- [`ReserveRequirementSlack`](@ref):
+ Bounds: [0.0, ]
+ Default proportional cost: 1e5
+ Symbol: ``r^\text{sl}``
`RampReserve` only accepts `VariableReserve` `PowerSystems.jl` type. With that, the parameters are:
**Static Parameters**
- ``\text{TF}`` = `PowerSystems.get_time_frame(service)`
- ``R^\text{th,up}`` = `PowerSystems.get_ramp_limits(device).up` for thermal contributing devices
- ``R^\text{th,dn}`` = `PowerSystems.get_ramp_limits(device).down` for thermal contributing devices
**Time Series Parameters**
For a `VariableReserve` `PowerSystems` type:
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.get_default_time_series_names(VariableReserve, RampReserve)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Relevant Methods:**
- ``\mathcal{D}_s`` = `PowerSystems.get_contributing_devices(system, service)`: Set (vector) of all contributing devices to the service ``s`` in the system.
**Objective:**
Add a large proportional cost to the objective function if slack variables are used ``+ r^\text{sl} \cdot 10^5``. In addition adds the default cost for `ActivePowerReserveVariables` as a proportional cost.
**Expressions:**
Adds the `ActivePowerReserveVariable` for upper/lower bound expressions of contributing devices.
For `ReserveUp` types, the variable is added to `ActivePowerRangeExpressionUB`, such that this expression considers both the `ActivePowerVariable` and its reserve variable. Similarly, For `ReserveDown` types, the variable is added to `ActivePowerRangeExpressionLB`, such that this expression considers both the `ActivePowerVariable` and its reserve variable
*Example*: for a thermal unit ``d`` contributing to two different `ReserveUp` ``s_1, s_2`` services (e.g. Reg-Up and Spin):
```math
\text{ActivePowerRangeExpressionUB}_{t} = p_t^\text{th} + r_{s_1,t} + r_{s_2, t} \le P^\text{th,max}
```
similarly if ``s_3`` is a `ReserveDown` service (e.g. Reg-Down):
```math
\text{ActivePowerRangeExpressionLB}_{t} = p_t^\text{th} - r_{s_3,t} \ge P^\text{th,min}
```
**Constraints:**
A RampReserve implements three fundamental constraints. The first is that the sum of all reserves of contributing devices must be larger than the `RampReserve` requirement. Thus, for a service ``s``:
```math
\sum_{d\in\mathcal{D}_s} r_{d,t} + r_t^\text{sl} \ge \text{RequirementTimeSeriesParameter}_{t},\quad \forall t\in \{1,\dots, T\}
```
Finally, there is a restriction based on the ramp limits of the contributing devices:
```math
r_{d,t} \le R^\text{th,up} \cdot \text{TF}\quad \forall d\in \mathcal{D}_s, \forall t\in \{1,\dots, T\}, \quad \text{(for ReserveUp)} \\
r_{d,t} \le R^\text{th,dn} \cdot \text{TF}\quad \forall d\in \mathcal{D}_s, \forall t\in \{1,\dots, T\}, \quad \text{(for ReserveDown)}
```
* * *
## `NonSpinningReserve`
```@docs
NonSpinningReserve
```
For each service ``s`` of the model type `NonSpinningReserve`, the following variables are created:
**Variables**:
- [`ActivePowerReserveVariable`](@ref):
+ Bounds: [0.0, ]
+ Default proportional cost: ``1.0 / \text{SystemBasePower}``
+ Symbol: ``r_{d}`` for ``d`` in contributing devices to the service ``s``
If slacks are enabled:
- [`ReserveRequirementSlack`](@ref):
+ Bounds: [0.0, ]
+ Default proportional cost: 1e5
+ Symbol: ``r^\text{sl}``
`NonSpinningReserve` only accepts `VariableReserve` `PowerSystems.jl` type. With that, the parameters are:
**Static Parameters**
- ``\text{PF}`` = `PowerSystems.get_max_participation_factor(service)`
- ``\text{TF}`` = `PowerSystems.get_time_frame(service)`
- ``P^\text{th,min}`` = `PowerSystems.get_active_power_limits(device).min` for thermal contributing devices
- ``T^\text{st,up}`` = `PowerSystems.get_time_limits(d).up` for thermal contributing devices
- ``R^\text{th,up}`` = `PowerSystems.get_ramp_limits(device).down` for thermal contributing devices
Other parameters:
- ``\Delta T``: Resolution of the problem in minutes.
**Time Series Parameters**
For a `VariableReserve` `PowerSystems` type:
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.get_default_time_series_names(VariableReserve, NonSpinningReserve)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Relevant Methods:**
- ``\mathcal{D}_s`` = `PowerSystems.get_contributing_devices(system, service)`: Set (vector) of all contributing devices to the service ``s`` in the system.
**Objective:**
Add a large proportional cost to the objective function if slack variables are used ``+ r^\text{sl} \cdot 10^5``. In addition adds the default cost for `ActivePowerReserveVariables` as a proportional cost.
**Expressions:**
Adds the `ActivePowerReserveVariable` for upper/lower bound expressions of contributing devices.
For `ReserveUp` types, the variable is added to `ActivePowerRangeExpressionUB`, such that this expression considers both the `ActivePowerVariable` and its reserve variable. Similarly, For `ReserveDown` types, the variable is added to `ActivePowerRangeExpressionLB`, such that this expression considers both the `ActivePowerVariable` and its reserve variable
*Example*: for a thermal unit ``d`` contributing to two different `ReserveUp` ``s_1, s_2`` services (e.g. Reg-Up and Spin):
```math
\text{ActivePowerRangeExpressionUB}_{t} = p_t^\text{th} + r_{s_1,t} + r_{s_2, t} \le P^\text{th,max}
```
similarly if ``s_3`` is a `ReserveDown` service (e.g. Reg-Down):
```math
\text{ActivePowerRangeExpressionLB}_{t} = p_t^\text{th} - r_{s_3,t} \ge P^\text{th,min}
```
**Constraints:**
A NonSpinningReserve implements three fundamental constraints. The first is that the sum of all reserves of contributing devices must be larger than the `NonSpinningReserve` requirement. Thus, for a service ``s``:
```math
\sum_{d\in\mathcal{D}_s} r_{d,t} + r_t^\text{sl} \ge \text{RequirementTimeSeriesParameter}_{t},\quad \forall t\in \{1,\dots, T\}
```
In addition, there is a restriction on how much each contributing device ``d`` can contribute to the requirement, based on the max participation factor allowed.
```math
r_{d,t} \le \text{RequirementTimeSeriesParameter}_{t} \cdot \text{PF}\quad \forall d\in \mathcal{D}_s, \forall t\in \{1,\dots, T\},
```
Finally, there is a restriction based on the reserve response time for the non-spinning reserve if the unit is off. To do so, compute ``R^\text{limit}_d`` as the reserve response limit as:
```math
R^\text{limit}_d = \begin{cases}
0 & \text{ if TF } \le T^\text{st,up}_d \\
P^\text{th,min}_d + (\text{TF}_s - T^\text{st,up}_d) \cdot R^\text{th,up}_d \Delta T \cdot R^\text{th,up}_d & \text{ if TF } > T^\text{st,up}_d
\end{cases}, \quad \forall d\in \mathcal{D}_s
```
Then, the constraint depends on the commitment variable ``u_t^\text{th}`` as:
```math
r_{d,t} \le (1 - u_{d,t}^\text{th}) \cdot R^\text{limit}_d, \quad \forall d \in \mathcal{D}_s, \forall t \in \{1,\dots, T\}
```
* * *
## `ConstantMaxInterfaceFlow`
This Service model only accepts the `PowerSystems.jl` `TransmissionInterface` type to properly function. It is used to model a collection of branches that make up an interface or corridor with a maximum transfer of power.
```@docs
ConstantMaxInterfaceFlow
```
**Variables**
If slacks are used:
- [`InterfaceFlowSlackUp`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``f^\text{sl,up}``
- [`InterfaceFlowSlackDown`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``f^\text{sl,dn}``
**Static Parameters**
- ``F^\text{max}`` = `PowerSystems.get_active_power_flow_limits(service).max`
- ``F^\text{min}`` = `PowerSystems.get_active_power_flow_limits(service).min`
- ``C^\text{flow}`` = `PowerSystems.get_violation_penalty(service)`
- ``\mathcal{M}_s`` = `PowerSystems.get_direction_mapping(service)`. Dictionary of contributing branches with its specified direction (``\text{Dir}_d = 1`` or ``\text{Dir}_d = -1``) with respect to the interface.
**Relevant Methods**
- ``\mathcal{D}_s`` = `PowerSystems.get_contributing_devices(system, service)`: Set (vector) of all contributing branches to the service ``s`` in the system.
**Objective:**
Add the violation penalty proportional cost to the objective function if slack variables are used ``+ (f^\text{sl,up} + f^\text{sl,dn}) \cdot C^\text{flow}``.
**Expressions:**
Creates the expression `InterfaceTotalFlow` to keep track of all `FlowActivePowerVariable` of contributing branches to the transmission interface.
**Constraints:**
It adds the constraint to limit the `InterfaceTotalFlow` by the specified bounds of the service ``s``:
```math
F^\text{min} \le f^\text{sl,up}_t - f^\text{sl,dn}_t + \sum_{d\in\mathcal{D}_s} \text{Dir}_d f_{d,t} \le F^\text{max}, \quad \forall t \in \{1,\dots,T\}
```
## `VariableMaxInterfaceFlow`
This Service model only accepts the `PowerSystems.jl` `TransmissionInterface` type to properly function. It is used to model a collection of branches that make up an interface or corridor with a maximum transfer of power.
```@docs
VariableMaxInterfaceFlow
```
**Variables**
If slacks are used:
- [`InterfaceFlowSlackUp`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``f^\text{sl,up}``
- [`InterfaceFlowSlackDown`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``f^\text{sl,dn}``
**Static Parameters**
- ``F^\text{max}`` = `PowerSystems.get_active_power_flow_limits(service).max`
- ``F^\text{min}`` = `PowerSystems.get_active_power_flow_limits(service).min`
- ``C^\text{flow}`` = `PowerSystems.get_violation_penalty(service)`
- ``\mathcal{M}_s`` = `PowerSystems.get_direction_mapping(service)`. Dictionary of contributing branches with its specified direction (``\text{Dir}_d = 1`` or ``\text{Dir}_d = -1``) with respect to the interface.
**Time Series Parameters**
For a `TransmissionInterface` `PowerSystems` type:
```@eval
using PowerSimulations
using PowerSystems
using DataFrames
using Latexify
combos = PowerSimulations.get_default_time_series_names(
TransmissionInterface,
VariableMaxInterfaceFlow,
)
combo_table = DataFrame(
"Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))),
"Default Time Series Name" => map(x -> "`$x`", collect(values(combos))),
)
mdtable(combo_table; latex = false)
```
**Relevant Methods**
- ``\mathcal{D}_s`` = `PowerSystems.get_contributing_devices(system, service)`: Set (vector) of all contributing branches to the service ``s`` in the system.
**Objective:**
Add the violation penalty proportional cost to the objective function if slack variables are used ``+ (f^\text{sl,up} + f^\text{sl,dn}) \cdot C^\text{flow}``.
**Expressions:**
Creates the expression `InterfaceTotalFlow` to keep track of all `FlowActivePowerVariable` of contributing branches to the transmission interface.
**Constraints:**
It adds the constraint to limit the `InterfaceTotalFlow` by the specified bounds of the service ``s``:
```math
F^\text{min} \cdot \text{MinInterfaceFlowLimitParameter}_t \le f^\text{sl,up}_t - f^\text{sl,dn}_t + \sum_{d\in\mathcal{D}_s} \text{Dir}_d f_{d,t} \le F^\text{max}\cdot \text{MaxInterfaceFlowLimitParameter}_t, \quad \forall t \in \{1,\dots,T\}
```
## Changes on Expressions due to Service models
It is important to note that by adding a service to a Optimization Problem, variables for each contributing device must be created. For example, for every contributing generator ``d \in \mathcal{D}`` that is participating in services ``s_1,s_2,s_3``, it is required to create three set of `ActivePowerReserveVariable` variables:
```math
r_{s_1,d,t},~ r_{s_2,d,t},~ r_{s_3,d,t},\quad \forall d \in \mathcal{D}, \forall t \in \{1,\dots, T\}
```
### Changes on UpperBound (UB) and LowerBound (LB) limits
Each contributing generator ``d`` has active power limits that the reserve variables affect. In simple terms, the limits are implemented using expressions `ActivePowerRangeExpressionUB` and `ActivePowerRangeExpressionLB` as:
```math
\text{ActivePowerRangeExpressionUB}_t \le P^\text{max} \\
\text{ActivePowerRangeExpressionLB}_t \ge P^\text{min}
```
`ReserveUp` type variables contribute to the upper bound expression, while `ReserveDown` variables contribute to the lower bound expressions. So if ``s_1,s_2`` are `ReserveUp` services, and ``s_3`` is a `ReserveDown` service, then for a thermal generator ``d`` using a `ThermalStandardDispatch`:
```math
\begin{align*}
& p_{d,t}^\text{th} + r_{s_1,d,t} + r_{s_2,d,t} \le P^\text{th,max},\quad \forall d\in \mathcal{D}^\text{th}, \forall t \in \{1,\dots,T\} \\
& p_{d,t}^\text{th} - r_{s_3,d,t} \ge P^\text{th,min},\quad \forall d\in \mathcal{D}^\text{th}, \forall t \in \{1,\dots,T\}
\end{align*}
```
while for a renewable generator ``d`` using a `RenewableFullDispatch`:
```math
\begin{align*}
& p_{d,t}^\text{re} + r_{s_1,d,t} + r_{s_2,d,t} \le \text{ActivePowerTimeSeriesParameter}_t,\quad \forall d\in \mathcal{D}^\text{re}, \forall t \in \{1,\dots,T\}\\
& p_{d,t}^\text{re} - r_{s_3,d,t} \ge 0,\quad \forall d\in \mathcal{D}^\text{re}, \forall t \in \{1,\dots,T\}
\end{align*}
```
### Changes in Ramp limits
For the case of Ramp Limits (of formulation that model these limits), the reserve variables only affect the current time, and not the previous time. Then, for the same example as before:
```math
\begin{align*}
& p_{d,t}^\text{th} + r_{s_1,d,t} + r_{s_2,d,t} - p_{d,t-1}^\text{th}\le R^\text{th,up},\quad \forall d\in \mathcal{D}^\text{th}, \forall t \in \{1,\dots,T\}\\
& p_{d,t}^\text{th} - r_{s_3,d,t} - p_{d,t-1}^\text{th} \ge -R^\text{th,dn},\quad \forall d\in \mathcal{D}^\text{th}, \forall t \in \{1,\dots,T\}
\end{align*}
```
================================================
FILE: docs/src/formulation_library/Source.md
================================================
# `Source` Formulations
Source formulations define the optimization models that describe source or infinite bus units mathematical model in different operational settings, such as economic dispatch and unit commitment.
!!! note
The use of reactive power variables and constraints will depend on the network model used, i.e., whether it uses (or does not use) reactive power. If the network model is purely active power-based, reactive power variables and related constraints are not created.
!!! note
Reserve variables for services are not included in the formulation, albeit their inclusion change the variables, expressions, constraints and objective functions created. A detailed description of the implications in the optimization models is described in the [Service formulation](@ref service_formulations) section.
### Table of Contents
1. [`ImportExportSourceModel`](#ImportExportSourceModel)
* * *
## `ImportExportSourceModel`
```@docs
ImportExportSourceModel
```
TODO
================================================
FILE: docs/src/formulation_library/ThermalGen.md
================================================
# `ThermalGen` Formulations
Thermal generation formulations define the optimization models that describe thermal units mathematical model in different operational settings, such as economic dispatch and unit commitment.
!!! note
Thermal units can include multiple terms added to the objective function, such as no-load cost, turn-on/off cost, fixed cost and variable cost. In addition, variable costs can be linear, quadratic or piecewise-linear formulations. These methods are properly described in the [cost function page](@ref pwl_cost).
!!! note
The use of reactive power variables and constraints will depend on the network model used, i.e., whether it uses (or does not use) reactive power. If the network model is purely active power-based, reactive power variables and related constraints are not created.
!!! note
Reserve variables for services are not included in the formulation, albeit their inclusion change the variables, expressions, constraints and objective functions created. A detailed description of the implications in the optimization models is described in the [Service formulation](@ref service_formulations) section.
### Table of Contents
1. [`ThermalBasicDispatch`](#ThermalBasicDispatch)
2. [`ThermalDispatchNoMin`](#ThermalDispatchNoMin)
3. [`ThermalCompactDispatch`](#ThermalCompactDispatch)
4. [`ThermalStandardDispatch`](#ThermalStandardDispatch)
5. [`ThermalBasicUnitCommitment`](#ThermalBasicUnitCommitment)
6. [`ThermalBasicCompactUnitCommitment`](#ThermalBasicCompactUnitCommitment)
7. [`ThermalStandardUnitCommitment`](#ThermalStandardUnitCommitment)
8. [`ThermalMultiStartUnitCommitment`](#ThermalMultiStartUnitCommitment)
9. [Valid configurations](#Valid-configurations)
* * *
## `ThermalBasicDispatch`
```@docs
ThermalBasicDispatch
```
**Variables:**
- [`ActivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``p^\text{th}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``q^\text{th}``
**Static Parameters:**
- ``P^\text{th,min}`` = `PowerSystems.get_active_power_limits(device).min`
- ``P^\text{th,max}`` = `PowerSystems.get_active_power_limits(device).max`
- ``Q^\text{th,min}`` = `PowerSystems.get_reactive_power_limits(device).min`
- ``Q^\text{th,max}`` = `PowerSystems.get_reactive_power_limits(device).max`
**Objective:**
Add a cost to the objective function depending on the defined cost structure of the thermal unit by adding it to its `ProductionCostExpression`.
**Expressions:**
Adds ``p^\text{th}`` to the `ActivePowerBalance` expression and ``q^\text{th}`` to the `ReactivePowerBalance`, to be used in the supply-balance constraint depending on the network model used.
**Constraints:**
For each thermal unit creates the range constraints for its active and reactive power depending on its static parameters.
```math
\begin{align*}
& P^\text{th,min} \le p^\text{th}_t \le P^\text{th,max}, \quad \forall t\in \{1, \dots, T\} \\
& Q^\text{th,min} \le q^\text{th}_t \le Q^\text{th,max}, \quad \forall t\in \{1, \dots, T\}
\end{align*}
```
* * *
## `ThermalDispatchNoMin`
```@docs
ThermalDispatchNoMin
```
**Variables:**
- [`ActivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``p^\text{th}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``q^\text{th}``
**Static Parameters:**
- ``P^\text{th,max}`` = `PowerSystems.get_active_power_limits(device).max`
- ``Q^\text{th,min}`` = `PowerSystems.get_reactive_power_limits(device).min`
- ``Q^\text{th,max}`` = `PowerSystems.get_reactive_power_limits(device).max`
**Objective:**
Add a cost to the objective function depending on the defined cost structure of the thermal unit by adding it to its `ProductionCostExpression`.
**Expressions:**
Adds ``p^\text{th}`` to the `ActivePowerBalance` expression and ``q^\text{th}`` to the `ReactivePowerBalance`, to be used in the supply-balance constraint depending on the network model used.
**Constraints:**
For each thermal unit creates the range constraints for its active and reactive power depending on its static parameters.
```math
\begin{align}
& 0 \le p^\text{th}_t \le P^\text{th,max}, \quad \forall t\in \{1, \dots, T\} \\
& Q^\text{th,min} \le q^\text{th}_t \le Q^\text{th,max}, \quad \forall t\in \{1, \dots, T\}
\end{align}
```
* * *
## `ThermalCompactDispatch`
```@docs
ThermalCompactDispatch
```
**Variables:**
- [`PowerAboveMinimumVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``\Delta p^\text{th}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``q^\text{th}``
**Auxiliary Variables:**
- [`PowerOutput`](@ref):
+ Symbol: ``P^\text{th}``
+ Definition: ``P^\text{th} = \text{on}^\text{th}P^\text{min} + \Delta p^\text{th}``
**Static Parameters:**
- ``P^\text{th,min}`` = `PowerSystems.get_active_power_limits(device).min`
- ``P^\text{th,max}`` = `PowerSystems.get_active_power_limits(device).max`
- ``Q^\text{th,min}`` = `PowerSystems.get_reactive_power_limits(device).min`
- ``Q^\text{th,max}`` = `PowerSystems.get_reactive_power_limits(device).max`
- ``R^\text{th,up}`` = `PowerSystems.get_ramp_limits(device).up`
- ``R^\text{th,dn}`` = `PowerSystems.get_ramp_limits(device).down`
**Variable Value Parameters:**
- ``\text{on}^\text{th}``: Used in feedforwards to define if the unit is on/off at each time-step from another problem. If no feedforward is used, the parameter takes a {0,1} value if the unit is available or not.
**Objective:**
Add a cost to the objective function depending on the defined cost structure of the thermal unit by adding it to its `ProductionCostExpression`.
**Expressions:**
Adds ``\text{on}^\text{th}P^\text{th,min} + \Delta p^\text{th}`` to the `ActivePowerBalance` expression and ``q^\text{th}`` to the `ReactivePowerBalance`, to be used in the supply-balance constraint depending on the network model used.
**Constraints:**
For each thermal unit creates the range constraints for its active and reactive power depending on its static parameters. It also implements ramp constraints for the active power variable.
```math
\begin{align*}
& 0 \le \Delta p^\text{th}_t \le \text{on}^\text{th}_t\left(P^\text{th,max} - P^\text{th,min}\right), \quad \forall t\in \{1, \dots, T\} \\
& \text{on}^\text{th}_t Q^\text{th,min} \le q^\text{th}_t \le \text{on}^\text{th}_t Q^\text{th,max}, \quad \forall t\in \{1, \dots, T\} \\
& -R^\text{th,dn} \le \Delta p_1^\text{th} - \Delta p^\text{th, init} \le R^\text{th,up} \\
& -R^\text{th,dn} \le \Delta p_t^\text{th} - \Delta p_{t-1}^\text{th} \le R^\text{th,up}, \quad \forall t\in \{2, \dots, T\}
\end{align*}
```
* * *
## `ThermalStandardDispatch`
```@docs
ThermalStandardDispatch
```
**Variables:**
- [`ActivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``p^\text{th}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``q^\text{th}``
If Slack variables are enabled (`use_slacks = true`):
- [`RateofChangeConstraintSlackUp`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Default proportional cost: 2e5
+ Symbol: ``p^\text{sl,up}``
- [`RateofChangeConstraintSlackDown`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Default proportional cost: 2e5
+ Symbol: ``p^\text{sl,dn}``
**Static Parameters:**
- ``P^\text{th,min}`` = `PowerSystems.get_active_power_limits(device).min`
- ``P^\text{th,max}`` = `PowerSystems.get_active_power_limits(device).max`
- ``Q^\text{th,min}`` = `PowerSystems.get_reactive_power_limits(device).min`
- ``Q^\text{th,max}`` = `PowerSystems.get_reactive_power_limits(device).max`
- ``R^\text{th,up}`` = `PowerSystems.get_ramp_limits(device).up`
- ``R^\text{th,dn}`` = `PowerSystems.get_ramp_limits(device).down`
**Objective:**
Add a cost to the objective function depending on the defined cost structure of the thermal unit by adding it to its `ProductionCostExpression`.
**Expressions:**
Adds ``p^\text{th}`` to the `ActivePowerBalance` expression and ``q^\text{th}`` to the `ReactivePowerBalance`, to be used in the supply-balance constraint depending on the network model used.
**Constraints:**
For each thermal unit creates the range constraints for its active and reactive power depending on its static parameters.
```math
\begin{align*}
& P^\text{th,min} \le p^\text{th}_t \le P^\text{th,max}, \quad \forall t\in \{1, \dots, T\} \\
& Q^\text{th,min} \le q^\text{th}_t \le Q^\text{th,max}, \quad \forall t\in \{1, \dots, T\} \\
& p_1^\text{th} - p^\text{th, init} - p_1^\text{sl,up} \le R^\text{th,up} \\
& p_t^\text{th} - p_{t-1}^\text{th} - p_t^\text{sl,up}\le R^\text{th,up}, \quad \forall t\in \{2, \dots, T\} \\
& -R^\text{th,dn} \le p_1^\text{th} - p^\text{th, init} + p_1^\text{sl,dn} \\
& -R^\text{th,dn} \le p_t^\text{th} - p_{t-1}^\text{th} + p_t^\text{sl,dn}, \quad \forall t\in \{2, \dots, T\} \\
\end{align*}
```
* * *
## `ThermalBasicUnitCommitment`
```@docs
ThermalBasicUnitCommitment
```
**Variables:**
- [`ActivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``p^\text{th}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``q^\text{th}``
- [`OnVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``u_t^\text{th}``
- [`StartVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``v_t^\text{th}``
- [`StopVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``w_t^\text{th}``
**Static Parameters:**
- ``P^\text{th,min}`` = `PowerSystems.get_active_power_limits(device).min`
- ``P^\text{th,max}`` = `PowerSystems.get_active_power_limits(device).max`
- ``Q^\text{th,min}`` = `PowerSystems.get_reactive_power_limits(device).min`
- ``Q^\text{th,max}`` = `PowerSystems.get_reactive_power_limits(device).max`
**Objective:**
Add a cost to the objective function depending on the defined cost structure of the thermal unit by adding it to its `ProductionCostExpression`.
**Expressions:**
Adds ``p^\text{th}`` to the `ActivePowerBalance` expression and ``q^\text{th}`` to the `ReactivePowerBalance`, to be used in the supply-balance constraint depending on the network model used.
**Constraints:**
For each thermal unit creates the range constraints for its active and reactive power depending on its static parameters. In addition, it creates the commitment constraint to turn on/off the device.
```math
\begin{align*}
& u_t^\text{th} P^\text{th,min} \le p^\text{th}_t \le u_t^\text{th} P^\text{th,max}, \quad \forall t\in \{1, \dots, T\} \\
& u_t^\text{th} Q^\text{th,min} \le q^\text{th}_t \le u_t^\text{th} Q^\text{th,max}, \quad \forall t\in \{1, \dots, T\} \\
& u_1^\text{th} = u^\text{th,init} + v_1^\text{th} - w_1^\text{th} \\
& u_t^\text{th} = u_{t-1}^\text{th} + v_t^\text{th} - w_t^\text{th}, \quad \forall t \in \{2,\dots,T\} \\
& v_t^\text{th} + w_t^\text{th} \le 1, \quad \forall t \in \{1,\dots,T\}
\end{align*}
```
* * *
## `ThermalBasicCompactUnitCommitment`
```@docs
ThermalBasicCompactUnitCommitment
```
**Variables:**
- [`PowerAboveMinimumVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``\Delta p^\text{th}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``q^\text{th}``
- [`OnVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``u_t^\text{th}``
- [`StartVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``v_t^\text{th}``
- [`StopVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``w_t^\text{th}``
**Auxiliary Variables:**
- [`PowerOutput`](@ref):
+ Symbol: ``P^\text{th}``
+ Definition: ``P^\text{th} = u^\text{th}P^\text{min} + \Delta p^\text{th}``
**Static Parameters:**
- ``P^\text{th,min}`` = `PowerSystems.get_active_power_limits(device).min`
- ``P^\text{th,max}`` = `PowerSystems.get_active_power_limits(device).max`
- ``Q^\text{th,min}`` = `PowerSystems.get_reactive_power_limits(device).min`
- ``Q^\text{th,max}`` = `PowerSystems.get_reactive_power_limits(device).max`
**Objective:**
Add a cost to the objective function depending on the defined cost structure of the thermal unit by adding it to its `ProductionCostExpression`.
**Expressions:**
Adds ``u^\text{th}P^\text{th,min} + \Delta p^\text{th}`` to the `ActivePowerBalance` expression and ``q^\text{th}`` to the `ReactivePowerBalance`, to be used in the supply-balance constraint depending on the network model used.
**Constraints:**
For each thermal unit creates the range constraints for its active and reactive power depending on its static parameters. In addition, it creates the commitment constraint to turn on/off the device.
```math
\begin{align*}
& 0 \le \Delta p^\text{th}_t \le u^\text{th}_t\left(P^\text{th,max} - P^\text{th,min}\right), \quad \forall t\in \{1, \dots, T\} \\
& u_t^\text{th} Q^\text{th,min} \le q^\text{th}_t \le u_t^\text{th} Q^\text{th,max}, \quad \forall t\in \{1, \dots, T\} \\
& u_1^\text{th} = u^\text{th,init} + v_1^\text{th} - w_1^\text{th} \\
& u_t^\text{th} = u_{t-1}^\text{th} + v_t^\text{th} - w_t^\text{th}, \quad \forall t \in \{2,\dots,T\} \\
& v_t^\text{th} + w_t^\text{th} \le 1, \quad \forall t \in \{1,\dots,T\}
\end{align*}
```
* * *
## `ThermalCompactUnitCommitment`
```@docs
ThermalCompactUnitCommitment
```
**Variables:**
- [`PowerAboveMinimumVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``\Delta p^\text{th}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``q^\text{th}``
- [`OnVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``u_t^\text{th}``
- [`StartVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``v_t^\text{th}``
- [`StopVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``w_t^\text{th}``
**Auxiliary Variables:**
- [`PowerOutput`](@ref):
+ Symbol: ``P^\text{th}``
+ Definition: ``P^\text{th} = u^\text{th}P^\text{min} + \Delta p^\text{th}``
- [`TimeDurationOn`](@ref):
+ Symbol: ``V_t^\text{th}``
+ Definition: Computed post optimization by adding consecutive turned on variable ``u_t^\text{th}``
- [`TimeDurationOff`](@ref):
+ Symbol: ``W_t^\text{th}``
+ Definition: Computed post optimization by adding consecutive turned off variable ``1 - u_t^\text{th}``
**Static Parameters:**
- ``P^\text{th,min}`` = `PowerSystems.get_active_power_limits(device).min`
- ``P^\text{th,max}`` = `PowerSystems.get_active_power_limits(device).max`
- ``Q^\text{th,min}`` = `PowerSystems.get_reactive_power_limits(device).min`
- ``Q^\text{th,max}`` = `PowerSystems.get_reactive_power_limits(device).max`
- ``R^\text{th,up}`` = `PowerSystems.get_ramp_limits(device).up`
- ``R^\text{th,dn}`` = `PowerSystems.get_ramp_limits(device).down`
- ``D^\text{min,up}`` = `PowerSystems.get_time_limits(device).up`
- ``D^\text{min,dn}`` = `PowerSystems.get_time_limits(device).down`
**Objective:**
Add a cost to the objective function depending on the defined cost structure of the thermal unit by adding it to its `ProductionCostExpression`.
**Expressions:**
Adds ``u^\text{th}P^\text{th,min} + \Delta p^\text{th}`` to the `ActivePowerBalance` expression and ``q^\text{th}`` to the `ReactivePowerBalance`, to be used in the supply-balance constraint depending on the network model used.
**Constraints:**
For each thermal unit creates the range constraints for its active and reactive power depending on its static parameters. It also creates the commitment constraint to turn on/off the device.
```math
\begin{align*}
& 0 \le \Delta p^\text{th}_t \le u^\text{th}_t\left(P^\text{th,max} - P^\text{th,min}\right), \quad \forall t\in \{1, \dots, T\} \\
& u_t^\text{th} Q^\text{th,min} \le q^\text{th}_t \le u_t^\text{th} Q^\text{th,max}, \quad \forall t\in \{1, \dots, T\} \\
& -R^\text{th,dn} \le \Delta p_1^\text{th} - \Delta p^\text{th, init} \le R^\text{th,up} \\
& -R^\text{th,dn} \le \Delta p_t^\text{th} - \Delta p_{t-1}^\text{th} \le R^\text{th,up}, \quad \forall t\in \{2, \dots, T\} \\
& u_1^\text{th} = u^\text{th,init} + v_1^\text{th} - w_1^\text{th} \\
& u_t^\text{th} = u_{t-1}^\text{th} + v_t^\text{th} - w_t^\text{th}, \quad \forall t \in \{2,\dots,T\} \\
& v_t^\text{th} + w_t^\text{th} \le 1, \quad \forall t \in \{1,\dots,T\}
\end{align*}
```
In addition, this formulation adds duration constraints, i.e. minimum-up time and minimum-down time constraints. The duration constraints are added over the start times looking backwards.
The duration times ``D^\text{min,up}`` and ``D^\text{min,dn}`` are processed to be used in multiple of the time-steps, given the resolution of the specific problem. In addition, parameters ``D^\text{init,up}`` and ``D^\text{init,dn}`` are used to identify how long the unit was on or off, respectively, before the simulation started.
Minimum up-time constraint for ``t \in \{1,\dots T\}``:
```math
\begin{align*}
& \text{If } t \leq D^\text{min,up} - D^\text{init,up} \text{ and } D^\text{init,up} > 0: \\
& 1 + \sum_{i=t-D^\text{min,up} + 1}^t v_i^\text{th} \leq u_t^\text{th} \quad \text{(for } i \text{ in the set of time steps).} \\
& \text{Otherwise:} \\
& \sum_{i=t-D^\text{min,up} + 1}^t v_i^\text{th} \leq u_t^\text{th}
\end{align*}
```
Minimum down-time constraint for ``t \in \{1,\dots T\}``:
```math
\begin{align*}
& \text{If } t \leq D^\text{min,dn} - D^\text{init,dn} \text{ and } D^\text{init,up} > 0: \\
& 1 + \sum_{i=t-D^\text{min,dn} + 1}^t w_i^\text{th} \leq 1 - u_t^\text{th} \quad \text{(for } i \text{ in the set of time steps).} \\
& \text{Otherwise:} \\
& \sum_{i=t-D^\text{min,dn} + 1}^t w_i^\text{th} \leq 1 - u_t^\text{th}
\end{align*}
```
* * *
## `ThermalStandardUnitCommitment`
```@docs
ThermalStandardUnitCommitment
```
**Variables:**
- [`ActivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``p^\text{th}``
- [`ReactivePowerVariable`](@ref):
+ Bounds: [0.0, ]
+ Symbol: ``q^\text{th}``
- [`OnVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``u_t^\text{th}``
- [`StartVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``v_t^\text{th}``
- [`StopVariable`](@ref):
+ Bounds: ``\{0,1\}``
+ Symbol: ``w_t^\text{th}``
If Slack variables are enabled (`use_slacks = true`):
- [`RateofChangeConstraintSlackUp`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Default proportional cost: 2e5
+ Symbol: ``p^\text{sl,up}``
- [`RateofChangeConstraintSlackDown`](@ref):
+ Bounds: [0.0, ]
+ Default initial value: 0.0
+ Default proportional cost: 2e5
+ Symbol: ``p^\text{sl,dn}``
**Auxiliary Variables:**
- [`TimeDurationOn`](@ref):
+ Symbol: ``V_t^\text{th}``
+ Definition: Computed post optimization by adding consecutive turned on variable ``u_t^\text{th}``
- [`TimeDurationOff`](@ref):
+ Symbol: ``W_t^\text{th}``
+ Definition: Computed post optimization by adding consecutive turned off variable ``1 - u_t^\text{th}``
**Static Parameters:**
- ``P^\text{th,min}`` = `PowerSystems.get_active_power_limits(device).min`
- ``P^\text{th,max}`` = `PowerSystems.get_active_power_limits(device).max`
- ``Q^\text{th,min}`` = `PowerSystems.get_reactive_power_limits(device).min`
- ``Q^\text{th,max}`` = `PowerSystems.get_reactive_power_limits(device).max`
- ``R^\text{th,up}`` = `PowerSystems.get_ramp_limits(device).up`
- ``R^\text{th,dn}`` = `PowerSystems.get_ramp_limits(device).down`
- ``D^\text{min,up}`` = `PowerSystems.get_time_limits(device).up`
- ``D^\text{min,dn}`` = `PowerSystems.get_time_limits(device).down`
**Objective:**
Add a cost to the objective function depending on the defined cost structure of the thermal unit by adding it to its `ProductionCostExpression`.
**Expressions:**
Adds ``p^\text{th}`` to the `ActivePowerBalance` expression and ``q^\text{th}`` to the `ReactivePowerBalance`, to be used in the supply-balance constraint depending on the network model used.
**Constraints:**
For each thermal unit creates the range constraints for its active and reactive power depending on its static parameters. It also creates the commitment constraint to turn on/off the device.
```math
\begin{align*}
& u^\text{th}_t P^\text
gitextract_1kk9e1p9/
├── .claude/
│ ├── Sienna.md
│ └── claude.md
├── .devcontainer/
│ └── devcontainer.json
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ ├── TagBot.yml
│ ├── cross-package-test.yml
│ ├── doc-preview-cleanup.yml
│ ├── docs.yml
│ ├── format-check.yml
│ ├── main-tests.yml
│ ├── performance_comparison.yml
│ └── pr_testing.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── LICENSE
├── Project.toml
├── README.md
├── codecov.yml
├── docs/
│ ├── Makefile
│ ├── Project.toml
│ ├── make.jl
│ ├── make_tutorials.jl
│ └── src/
│ ├── api/
│ │ ├── PowerSimulations.md
│ │ ├── developer.md
│ │ ├── glossary.md
│ │ └── internal.md
│ ├── code_base_developer_guide/
│ │ └── extending_powersimulations.md
│ ├── explanation/
│ │ ├── chronologies.md
│ │ ├── feedforward.md
│ │ ├── psi_structure.md
│ │ └── sequencing.md
│ ├── formulation_library/
│ │ ├── Branch.md
│ │ ├── DCModels.md
│ │ ├── Feedforward.md
│ │ ├── General.md
│ │ ├── Introduction.md
│ │ ├── Load.md
│ │ ├── Network.md
│ │ ├── Piecewise.md
│ │ ├── README.md
│ │ ├── RenewableGen.md
│ │ ├── Service.md
│ │ ├── Source.md
│ │ └── ThermalGen.md
│ ├── get_test_data.jl
│ ├── how_to/
│ │ ├── adding_new_problem_model.md
│ │ ├── debugging_infeasible_models.md
│ │ ├── logging.md
│ │ ├── parallel_simulations.md
│ │ ├── problem_templates.md
│ │ ├── read_results.md
│ │ ├── register_variable.md
│ │ └── simulation_recorder.md
│ ├── index.md
│ └── tutorials/
│ ├── decision_problem.jl
│ └── pcm_simulation.jl
├── scripts/
│ └── formatter/
│ ├── Project.toml
│ └── formatter_code.jl
├── src/
│ ├── PowerSimulations.jl
│ ├── contingency_model/
│ │ ├── contingency.jl
│ │ ├── contingency_arguments.jl
│ │ └── contingency_constraints.jl
│ ├── core/
│ │ ├── abstract_feedforward.jl
│ │ ├── abstract_simulation_store.jl
│ │ ├── auxiliary_variables.jl
│ │ ├── cache_utils.jl
│ │ ├── constraints.jl
│ │ ├── dataset.jl
│ │ ├── dataset_container.jl
│ │ ├── definitions.jl
│ │ ├── device_model.jl
│ │ ├── dual_processing.jl
│ │ ├── event_keys.jl
│ │ ├── event_model.jl
│ │ ├── expressions.jl
│ │ ├── formulations.jl
│ │ ├── initial_conditions.jl
│ │ ├── model_store_params.jl
│ │ ├── network_formulations.jl
│ │ ├── network_model.jl
│ │ ├── network_reductions.jl
│ │ ├── operation_model_abstract_types.jl
│ │ ├── optimization_container.jl
│ │ ├── parameters.jl
│ │ ├── power_flow_data_wrapper.jl
│ │ ├── results_by_time.jl
│ │ ├── service_model.jl
│ │ ├── settings.jl
│ │ ├── store_common.jl
│ │ └── variables.jl
│ ├── devices_models/
│ │ ├── device_constructors/
│ │ │ ├── branch_constructor.jl
│ │ │ ├── hvdcsystems_constructor.jl
│ │ │ ├── load_constructor.jl
│ │ │ ├── reactivepowerdevice_constructor.jl
│ │ │ ├── regulationdevice_constructor.jl
│ │ │ ├── renewablegeneration_constructor.jl
│ │ │ ├── source_constructor.jl
│ │ │ └── thermalgeneration_constructor.jl
│ │ └── devices/
│ │ ├── AC_branches.jl
│ │ ├── HVDCsystems.jl
│ │ ├── TwoTerminalDC_branches.jl
│ │ ├── area_interchange.jl
│ │ ├── common/
│ │ │ ├── add_auxiliary_variable.jl
│ │ │ ├── add_constraint_dual.jl
│ │ │ ├── add_pwl_methods.jl
│ │ │ ├── add_to_expression.jl
│ │ │ ├── add_variable.jl
│ │ │ ├── duration_constraints.jl
│ │ │ ├── get_time_series.jl
│ │ │ ├── objective_function/
│ │ │ │ ├── common.jl
│ │ │ │ ├── import_export.jl
│ │ │ │ ├── linear_curve.jl
│ │ │ │ ├── market_bid.jl
│ │ │ │ ├── piecewise_linear.jl
│ │ │ │ └── quadratic_curve.jl
│ │ │ ├── range_constraint.jl
│ │ │ ├── rateofchange_constraints.jl
│ │ │ └── set_expression.jl
│ │ ├── default_interface_methods.jl
│ │ ├── electric_loads.jl
│ │ ├── reactivepower_device.jl
│ │ ├── regulation_device.jl
│ │ ├── renewable_generation.jl
│ │ ├── source.jl
│ │ └── thermal_generation.jl
│ ├── feedforward/
│ │ ├── feedforward_arguments.jl
│ │ ├── feedforward_constraints.jl
│ │ └── feedforwards.jl
│ ├── initial_conditions/
│ │ ├── add_initial_condition.jl
│ │ ├── calculate_initial_condition.jl
│ │ ├── initial_condition_chronologies.jl
│ │ ├── initialization.jl
│ │ └── update_initial_conditions.jl
│ ├── network_models/
│ │ ├── area_balance_model.jl
│ │ ├── copperplate_model.jl
│ │ ├── hvdc_network_constructor.jl
│ │ ├── hvdc_networks.jl
│ │ ├── network_constructor.jl
│ │ ├── network_slack_variables.jl
│ │ ├── pm_translator.jl
│ │ ├── power_flow_evaluation.jl
│ │ └── powermodels_interface.jl
│ ├── operation/
│ │ ├── decision_model.jl
│ │ ├── decision_model_store.jl
│ │ ├── emulation_model.jl
│ │ ├── emulation_model_store.jl
│ │ ├── initial_conditions_update_in_memory_store.jl
│ │ ├── model_numerical_analysis_utils.jl
│ │ ├── operation_model_interface.jl
│ │ ├── operation_model_simulation_interface.jl
│ │ ├── operation_model_types.jl
│ │ ├── operation_problem_templates.jl
│ │ ├── optimization_debugging.jl
│ │ ├── problem_results.jl
│ │ ├── problem_template.jl
│ │ ├── template_validation.jl
│ │ └── time_series_interface.jl
│ ├── parameters/
│ │ ├── add_parameters.jl
│ │ ├── update_container_parameter_values.jl
│ │ ├── update_cost_parameters.jl
│ │ └── update_parameters.jl
│ ├── services_models/
│ │ ├── agc.jl
│ │ ├── reserve_group.jl
│ │ ├── reserves.jl
│ │ ├── service_slacks.jl
│ │ ├── services_constructor.jl
│ │ └── transmission_interface.jl
│ ├── simulation/
│ │ ├── decision_model_simulation_results.jl
│ │ ├── emulation_model_simulation_results.jl
│ │ ├── get_components_interface.jl
│ │ ├── hdf_simulation_store.jl
│ │ ├── in_memory_simulation_store.jl
│ │ ├── initial_condition_update_simulation.jl
│ │ ├── optimization_output_cache.jl
│ │ ├── optimization_output_caches.jl
│ │ ├── realized_meta.jl
│ │ ├── simulation.jl
│ │ ├── simulation_events.jl
│ │ ├── simulation_info.jl
│ │ ├── simulation_internal.jl
│ │ ├── simulation_models.jl
│ │ ├── simulation_partition_results.jl
│ │ ├── simulation_partitions.jl
│ │ ├── simulation_problem_results.jl
│ │ ├── simulation_results.jl
│ │ ├── simulation_results_export.jl
│ │ ├── simulation_sequence.jl
│ │ ├── simulation_state.jl
│ │ ├── simulation_store_params.jl
│ │ └── simulation_store_requirements.jl
│ └── utils/
│ ├── dataframes_utils.jl
│ ├── datetime_utils.jl
│ ├── file_utils.jl
│ ├── generate_valid_formulations.jl
│ ├── indexing.jl
│ ├── jump_utils.jl
│ ├── logging.jl
│ ├── powersystems_utils.jl
│ ├── print_pt_v2.jl
│ ├── print_pt_v3.jl
│ ├── recorder_events.jl
│ └── time_series_utils.jl
└── test/
├── Project.toml
├── includes.jl
├── performance/
│ └── performance_test.jl
├── run_partitioned_simulation.jl
├── runtests.jl
├── test_basic_model_structs.jl
├── test_data/
│ └── results_export.json
├── test_device_branch_constructors.jl
├── test_device_hvdc.jl
├── test_device_lcc.jl
├── test_device_load_constructors.jl
├── test_device_renewable_generation_constructors.jl
├── test_device_source_constructors.jl
├── test_device_synchronous_condenser_constructors.jl
├── test_device_thermal_generation_constructors.jl
├── test_events.jl
├── test_formulation_combinations.jl
├── test_import_export_cost.jl
├── test_initialization_problem.jl
├── test_jump_utils.jl
├── test_market_bid_cost.jl
├── test_mbc_sanity_check.jl
├── test_model_decision.jl
├── test_model_emulation.jl
├── test_multi_interval.jl
├── test_network_constructors.jl
├── test_network_constructors_with_dlr.jl
├── test_parallel_branch_parameter_multipliers.jl
├── test_power_flow_in_the_loop.jl
├── test_print.jl
├── test_problem_template.jl
├── test_recorder_events.jl
├── test_services_constructor.jl
├── test_simulation_build.jl
├── test_simulation_execute.jl
├── test_simulation_models.jl
├── test_simulation_partitions.jl
├── test_simulation_results.jl
├── test_simulation_results_export.jl
├── test_simulation_sequence.jl
├── test_simulation_store.jl
├── test_utils/
│ ├── add_components_to_system.jl
│ ├── add_dlr_ts.jl
│ ├── add_market_bid_cost.jl
│ ├── common_operation_model.jl
│ ├── events_simulation_utils.jl
│ ├── iec_simulation_utils.jl
│ ├── mbc_simulation_utils.jl
│ ├── mbc_system_utils.jl
│ ├── mock_operation_models.jl
│ ├── model_checks.jl
│ ├── operations_problem_templates.jl
│ ├── run_simulation.jl
│ └── solver_definitions.jl
└── test_utils.jl
Condensed preview — 259 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,954K chars).
[
{
"path": ".claude/Sienna.md",
"chars": 6950,
"preview": "# Sienna Programming Practices\n\nThis document describes general programming practices and conventions that apply across "
},
{
"path": ".claude/claude.md",
"chars": 8178,
"preview": "# PowerSimulations.jl\n\nPower system optimization and simulation framework. Builds and solves large-scale optimization pr"
},
{
"path": ".devcontainer/devcontainer.json",
"chars": 121,
"preview": "{\n \"extensions\": [\n \"julialang.language-julia\"\n ],\n \"image\": \"ghcr.io/julia-vscode/julia-devcontainer\"\n}"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 778,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: code bug\nassignees: ''\n\n---\n\n**If this "
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 865,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: feature request\nassignees: ''\n\n---\n\n"
},
{
"path": ".github/workflows/TagBot.yml",
"chars": 362,
"preview": "name: TagBot\non:\n issue_comment:\n types:\n - created\n workflow_dispatch:\njobs:\n TagBot:\n if: github.event_n"
},
{
"path": ".github/workflows/cross-package-test.yml",
"chars": 1674,
"preview": "name: CrossPackageTest\n\non:\n push:\n branches: [main]\n tags: [v*]\n pull_request:\n\njobs:\n test:\n name: Julia v"
},
{
"path": ".github/workflows/doc-preview-cleanup.yml",
"chars": 1152,
"preview": "name: Doc Preview Cleanup\n\non:\n pull_request:\n types: [closed]\n\n# Ensure that only one \"Doc Preview Cleanup\" workflo"
},
{
"path": ".github/workflows/docs.yml",
"chars": 1248,
"preview": "name: Documentation\n\non:\n push:\n branches:\n - main\n - 'release-'\n tags: '*'\n pull_request:\n\njobs:\n bu"
},
{
"path": ".github/workflows/format-check.yml",
"chars": 1040,
"preview": "name: Format Check\n\non:\n push:\n branches:\n - 'main'\n - 'release-'\n tags: '*'\n pull_request:\n\njobs:\n b"
},
{
"path": ".github/workflows/main-tests.yml",
"chars": 1090,
"preview": "name: Main - CI\n\non:\n push:\n branches:\n - main\n schedule:\n - cron: 0 * * * *\njobs:\n test:\n name: Ju"
},
{
"path": ".github/workflows/performance_comparison.yml",
"chars": 3159,
"preview": "name: 'Performance Comparison'\n\non:\n pull_request:\n\njobs:\n comparison:\n runs-on: ubuntu-latest\n steps:\n - u"
},
{
"path": ".github/workflows/pr_testing.yml",
"chars": 964,
"preview": "name: Test-CI\n\non:\n pull_request:\n types: [opened, synchronize, reopened]\n\njobs:\n test:\n name: Julia ${{ matrix."
},
{
"path": ".gitignore",
"chars": 2663,
"preview": "test_simulation_results/*\n# Claude\nsettings.json\n\n#Files generated by invoking Julia with --code-coverage\n*.jl.cov\n*.jl."
},
{
"path": ".pre-commit-config.yaml",
"chars": 230,
"preview": "repos:\n - repo: local\n hooks:\n - id: julia-formatter\n name: Run Julia formatter\n entry: julia scr"
},
{
"path": "CONTRIBUTING.md",
"chars": 660,
"preview": "# Contributing\n\nCommunity driven development of this package is encouraged. To maintain code quality standards, please a"
},
{
"path": "LICENSE",
"chars": 1589,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2018, 2023 Alliance for Sustainable Energy, LLC and The Regents of the University of"
},
{
"path": "Project.toml",
"chars": 2243,
"preview": "name = \"PowerSimulations\"\nuuid = \"e690365d-45e2-57bb-ac84-44ba829e73c4\"\nauthors = [\"Jose Daniel Lara\", \"Clayton Barrows\""
},
{
"path": "README.md",
"chars": 3537,
"preview": "# PowerSimulations.jl\n\n[\n\nhtml:\n\tjulia make.jl\n\ngithub: html\n\t-git branch -D gh-pages\n\t-git pu"
},
{
"path": "docs/Project.toml",
"chars": 1067,
"preview": "[deps]\nCSV = \"336ed68f-0bac-5ca0-87d4-7b16caf5d00b\"\nDataFrames = \"a93c6f00-e57d-5684-b7b6-d8193f3e46c0\"\nDataStructures ="
},
{
"path": "docs/make.jl",
"chars": 3336,
"preview": "using Documenter\nusing PowerSystems\nusing PowerSimulations\nusing DataStructures\nusing DocumenterInterLinks\nusing Literat"
},
{
"path": "docs/make_tutorials.jl",
"chars": 18000,
"preview": "using Pkg\nusing Literate\nusing DataFrames\nusing PrettyTables\n\n# Limit DataFrame rendering during docs generation to avoi"
},
{
"path": "docs/src/api/PowerSimulations.md",
"chars": 8769,
"preview": "```@meta\nCurrentModule = PowerSimulations\nDocTestSetup = quote\n using PowerSimulations\nend\n```\n\n# API Reference\n\n```"
},
{
"path": "docs/src/api/developer.md",
"chars": 614,
"preview": "# Guidelines for Developers\n\nIn order to contribute to `PowerSimulations.jl` repository please read the following sectio"
},
{
"path": "docs/src/api/glossary.md",
"chars": 6805,
"preview": "# Definitions\n\n## A\n\n - *Attributes*: Certain device formulations can be customized by specifying attributes that will "
},
{
"path": "docs/src/api/internal.md",
"chars": 118,
"preview": "```@meta\nCollapsedDocStrings = true\n```\n\n# Internal API\n\n```@autodocs\nModules = [PowerSimulations]\nPublic = false\n```\n"
},
{
"path": "docs/src/code_base_developer_guide/extending_powersimulations.md",
"chars": 3552,
"preview": "# Extending Source Code Functionalities\n\n## Enable other recorder events\n\nOther types of recorder events can be enabled "
},
{
"path": "docs/src/explanation/chronologies.md",
"chars": 575,
"preview": "# [Chronologies](@id chronologies)\n\nIn PowerSimulations, chronologies define where information is flowing. There are two"
},
{
"path": "docs/src/explanation/feedforward.md",
"chars": 974,
"preview": "# [Feedforward](@id feedforward)\n\nThe definition of exactly what information is passed using the defined chronologies is"
},
{
"path": "docs/src/explanation/psi_structure.md",
"chars": 1379,
"preview": "# [PowerSimulations.jl Modeling Structure](@id psi_structure)\n\nPowerSimulations enables the simulation of a sequence of "
},
{
"path": "docs/src/explanation/sequencing.md",
"chars": 850,
"preview": "# [Sequencing](@id sequencing)\n\nIn a typical simulation pipeline, we want to connect daily (24-hours) day-ahead unit com"
},
{
"path": "docs/src/formulation_library/Branch.md",
"chars": 18123,
"preview": "# `PowerSystems.Branch` Formulations\n\n!!! note\n \n The use of reactive power variables and constraints will depend "
},
{
"path": "docs/src/formulation_library/DCModels.md",
"chars": 2063,
"preview": "# DC Models formulations\n\n!!! note\n \n Multi-terminal DC models are still in early stages of development and future"
},
{
"path": "docs/src/formulation_library/Feedforward.md",
"chars": 4916,
"preview": "# [FeedForward Formulations](@id ff_formulations)\n\n**FeedForwards** are the mechanism to define how information is share"
},
{
"path": "docs/src/formulation_library/General.md",
"chars": 6544,
"preview": "# [Formulations](@id formulation_library)\n\nModeling formulations are created by dispatching on abstract subtypes of `Pow"
},
{
"path": "docs/src/formulation_library/Introduction.md",
"chars": 3832,
"preview": "# [Formulations Introduction](@id formulation_intro)\n\nPowerSimulations.jl enables modularity in its formulations by assi"
},
{
"path": "docs/src/formulation_library/Load.md",
"chars": 8622,
"preview": "# `PowerSystems.ElectricLoad` Formulations\n\nElectric load formulations define the optimization models that describe load"
},
{
"path": "docs/src/formulation_library/Network.md",
"chars": 6340,
"preview": "# [Network Formulations](@id network_formulations)\n\nNetwork formulations are used to describe how the network and buses "
},
{
"path": "docs/src/formulation_library/Piecewise.md",
"chars": 5692,
"preview": "# [Piecewise linear cost functions](@id pwl_cost)\n\nThe choice for piecewise-linear (PWL) cost representation in `PowerS"
},
{
"path": "docs/src/formulation_library/README.md",
"chars": 703,
"preview": "# Formulation documentation guide\n\nFormulation documentation should *roughly* follow the template established by Renewab"
},
{
"path": "docs/src/formulation_library/RenewableGen.md",
"chars": 5443,
"preview": "# `PowerSystems.RenewableGen` Formulations\n\nRenewable generation formulations define the optimization models that descri"
},
{
"path": "docs/src/formulation_library/Service.md",
"chars": 23873,
"preview": "# [`PowerSystems.Service` Formulations](@id service_formulations)\n\n`Services` (or ancillary services) are models used to"
},
{
"path": "docs/src/formulation_library/Source.md",
"chars": 1005,
"preview": "# `Source` Formulations\n\nSource formulations define the optimization models that describe source or infinite bus units m"
},
{
"path": "docs/src/formulation_library/ThermalGen.md",
"chars": 29967,
"preview": "# `ThermalGen` Formulations\n\nThermal generation formulations define the optimization models that describe thermal units "
},
{
"path": "docs/src/get_test_data.jl",
"chars": 1249,
"preview": "using Cbc\nusing PowerSimulations\nusing PowerSystems\nusing DataStructures\nusing InfrastructureSystems\nimport Infrastructu"
},
{
"path": "docs/src/how_to/adding_new_problem_model.md",
"chars": 8901,
"preview": "# Adding an Operations Problem Model\n\nThis tutorial will show how to create a custom decision problem model. These cases"
},
{
"path": "docs/src/how_to/debugging_infeasible_models.md",
"chars": 10859,
"preview": "# Debugging infeasible models\n\nGetting infeasible solutions to models is a common occurrence in operations simulations, "
},
{
"path": "docs/src/how_to/logging.md",
"chars": 1962,
"preview": "# Logging\n\n`PowerSimulations.jl` will output many log messages when building systems and\nrunning simulations. You may wa"
},
{
"path": "docs/src/how_to/parallel_simulations.md",
"chars": 9585,
"preview": "# Parallel Simulations\n\nThis section contains instructions to:\n\n - [Run a Simulation in Parallel on a local computer](@"
},
{
"path": "docs/src/how_to/problem_templates.md",
"chars": 1586,
"preview": "# [Operations `ProblemTemplate`s](@id op_problem_template)\n\nTemplates are used to specify the modeling properties of the"
},
{
"path": "docs/src/how_to/read_results.md",
"chars": 11202,
"preview": "# [Read results](@id read_results)\n\nOnce a [`DecisionModel`](@ref) is solved via `solve!(model)` or a Simulation is exec"
},
{
"path": "docs/src/how_to/register_variable.md",
"chars": 2855,
"preview": "# Register a variable in a custom operation model\n\nIn most cases, operation problem models are optimization models. Alth"
},
{
"path": "docs/src/how_to/simulation_recorder.md",
"chars": 3501,
"preview": "# Simulation Recorder\n\nPowerSimulations.jl provides the ability to record structured data as events\nduring a simulation."
},
{
"path": "docs/src/index.md",
"chars": 3717,
"preview": "# PowerSimulations.jl\n\n```@meta\nCurrentModule = PowerSimulations\n```\n\n## Overview\n\n`PowerSimulations.jl` is a power syst"
},
{
"path": "docs/src/tutorials/decision_problem.jl",
"chars": 6395,
"preview": "#!nb # ```@meta\n#!nb # EditURL = \"decision_problem.jl\"\n#!nb # ```\n#!nb #\n# # Running a Single-Step Problem\n#\n# ## Introd"
},
{
"path": "docs/src/tutorials/pcm_simulation.jl",
"chars": 9056,
"preview": "#!nb # ```@meta\n#!nb # EditURL = \"pcm_simulation.jl\"\n#!nb # ```\n#!nb #\n# # Running a Multi-Stage Production Cost Simulat"
},
{
"path": "scripts/formatter/Project.toml",
"chars": 256,
"preview": "uuid = \"c6367ca8-164d-4469-afe3-c91cf8860505\"\nauthors = [\"Jose Daniel Lara <jdlara@berkeley.edu>\"]\n\n[deps]\nJuliaFormatte"
},
{
"path": "scripts/formatter/formatter_code.jl",
"chars": 1231,
"preview": "using Pkg\nPkg.activate(@__DIR__)\nPkg.instantiate()\nPkg.update()\n\nusing JuliaFormatter\n\nmain_paths = [\".\"]\nfor main_path "
},
{
"path": "src/PowerSimulations.jl",
"chars": 25408,
"preview": "isdefined(Base, :__precompile__) && __precompile__()\nmodule PowerSimulations\n\n##########################################"
},
{
"path": "src/contingency_model/contingency.jl",
"chars": 942,
"preview": "#! format: off\n# This value could change depending on the event modeling choices\nget_parameter_multiplier(::EventParamet"
},
{
"path": "src/contingency_model/contingency_arguments.jl",
"chars": 12881,
"preview": "function add_event_arguments!(\n container::OptimizationContainer,\n devices::T,\n device_model::DeviceModel{U, V}"
},
{
"path": "src/contingency_model/contingency_constraints.jl",
"chars": 9316,
"preview": "function add_event_constraints!(\n container::OptimizationContainer,\n devices::T,\n device_model::DeviceModel{U, "
},
{
"path": "src/core/abstract_feedforward.jl",
"chars": 107,
"preview": "abstract type AbstractAffectFeedforward end\n\nget_device_type(x::AbstractAffectFeedforward) = x.device_type\n"
},
{
"path": "src/core/abstract_simulation_store.jl",
"chars": 848,
"preview": "\"\"\"\nProvides storage of simulation data\n\"\"\"\nabstract type SimulationStore end\n\n# Required methods:\n# - open_store\n# - Ba"
},
{
"path": "src/core/auxiliary_variables.jl",
"chars": 3134,
"preview": "\"\"\"\nAuxiliary Variable for Thermal Generation Models to keep track of time elapsed on\n\"\"\"\nstruct TimeDurationOn <: AuxVa"
},
{
"path": "src/core/cache_utils.jl",
"chars": 1586,
"preview": "\nstruct OptimizationResultCacheKey\n model::Symbol\n key::OptimizationContainerKey\nend\n\nstruct CacheFlushRule\n ke"
},
{
"path": "src/core/constraints.jl",
"chars": 29206,
"preview": "abstract type PostContingencyConstraintType <: ConstraintType end\n\nstruct AbsoluteValueConstraint <: ConstraintType end\n"
},
{
"path": "src/core/dataset.jl",
"chars": 8805,
"preview": "abstract type AbstractDataset end\n\nget_data_resolution(s::AbstractDataset)::Dates.Millisecond = s.resolution\nget_last_re"
},
{
"path": "src/core/dataset_container.jl",
"chars": 6295,
"preview": "struct DatasetContainer{T}\n duals::Dict{ConstraintKey, T}\n aux_variables::Dict{AuxVarKey, T}\n variables::Dict{V"
},
{
"path": "src/core/definitions.jl",
"chars": 5542,
"preview": "#################################################################################\n# Type Alias for long type signatures\n"
},
{
"path": "src/core/device_model.jl",
"chars": 4616,
"preview": "\"\"\"\nFormulation type to augment the power balance constraint expression with a time series parameter\n\"\"\"\nstruct FixedOut"
},
{
"path": "src/core/dual_processing.jl",
"chars": 3619,
"preview": "struct VarRestoreInfo{A <: AbstractArray}\n lb::Union{Nothing, A}\n ub::Union{Nothing, A}\n fixed_int_value::Union"
},
{
"path": "src/core/event_keys.jl",
"chars": 557,
"preview": "struct EventKey{T <: PSY.Contingency, U <: Union{PSY.Component, PSY.System}}\n meta::String\nend\n\nfunction EventKey(\n "
},
{
"path": "src/core/event_model.jl",
"chars": 3667,
"preview": "abstract type AbstractEventCondition end\n\n\"\"\"\n ContinuousCondition()\n\nEstablishes an event condition that is triggere"
},
{
"path": "src/core/expressions.jl",
"chars": 3135,
"preview": "abstract type SystemBalanceExpressions <: ExpressionType end\nabstract type RangeConstraintLBExpressions <: ExpressionTyp"
},
{
"path": "src/core/formulations.jl",
"chars": 9792,
"preview": "\"\"\"\nAbstract type for Device Formulations (a.k.a Models)\n\n# Example\n\nimport PowerSimulations as PSI\nstruct MyCustomDevic"
},
{
"path": "src/core/initial_conditions.jl",
"chars": 5206,
"preview": "\"\"\"\nContainer for the initial condition data\n\"\"\"\nmutable struct InitialCondition{\n T <: InitialConditionType,\n U <"
},
{
"path": "src/core/model_store_params.jl",
"chars": 1829,
"preview": "struct ModelStoreParams <: ISOPT.AbstractModelStoreParams\n num_executions::Int\n horizon_count::Int\n interval::D"
},
{
"path": "src/core/network_formulations.jl",
"chars": 2716,
"preview": "############################## Network Model Formulations ##################################\n# These formulations are ta"
},
{
"path": "src/core/network_model.jl",
"chars": 17298,
"preview": "const DeviceModelForBranches = DeviceModel{<:PSY.Branch, <:AbstractDeviceFormulation}\nconst BranchModelContainer = Dict{"
},
{
"path": "src/core/network_reductions.jl",
"chars": 9045,
"preview": "mutable struct BranchReductionOptimizationTracker\n variable_dict::Dict{\n Type{<:ISOPT.VariableType},\n D"
},
{
"path": "src/core/operation_model_abstract_types.jl",
"chars": 583,
"preview": "\"\"\"\nAbstract type for Decision Model and Emulation Model. OperationModel structs are parameterized with DecisionProblem "
},
{
"path": "src/core/optimization_container.jl",
"chars": 70318,
"preview": "struct PrimalValuesCache\n variables_cache::Dict{VariableKey, AbstractArray}\n expressions_cache::Dict{ExpressionKey"
},
{
"path": "src/core/parameters.jl",
"chars": 20416,
"preview": "abstract type ParameterAttributes end\n\nstruct NoAttributes end\n\nstruct TimeSeriesAttributes{T <: PSY.TimeSeriesData} <: "
},
{
"path": "src/core/power_flow_data_wrapper.jl",
"chars": 1651,
"preview": "mutable struct PowerFlowEvaluationData{T <: PFS.PowerFlowContainer}\n power_flow_data::T\n \"\"\"\n Records which PSI"
},
{
"path": "src/core/results_by_time.jl",
"chars": 5290,
"preview": "mutable struct ResultsByTime{T, N}\n key::OptimizationContainerKey\n data::SortedDict{Dates.DateTime, T}\n resolut"
},
{
"path": "src/core/service_model.jl",
"chars": 4766,
"preview": "function _check_service_formulation(\n ::Type{D},\n) where {D <: Union{AbstractServiceFormulation, PSY.Service}}\n if"
},
{
"path": "src/core/settings.jl",
"chars": 5661,
"preview": "struct Settings\n horizon::Base.RefValue{Dates.Millisecond}\n resolution::Base.RefValue{Dates.Millisecond}\n inter"
},
{
"path": "src/core/store_common.jl",
"chars": 8505,
"preview": "# Aliases used for clarity in the method dispatches so it is possible to know if writing to\n# DecisionModel data or Emul"
},
{
"path": "src/core/variables.jl",
"chars": 19562,
"preview": "abstract type AbstractContingencyVariableType <: VariableType end\nabstract type SparseVariableType <: VariableType end\na"
},
{
"path": "src/devices_models/device_constructors/branch_constructor.jl",
"chars": 50030,
"preview": "################################# Generic AC Branch Models ################################\n# These 3 methods are defin"
},
{
"path": "src/devices_models/device_constructors/hvdcsystems_constructor.jl",
"chars": 8062,
"preview": "function construct_device!(\n container::OptimizationContainer,\n sys::PSY.System,\n ::ArgumentConstructStage,\n "
},
{
"path": "src/devices_models/device_constructors/load_constructor.jl",
"chars": 20957,
"preview": "# AbstractPowerModel + ControllableLoad device model\nfunction construct_device!(\n container::OptimizationContainer,\n "
},
{
"path": "src/devices_models/device_constructors/reactivepowerdevice_constructor.jl",
"chars": 1502,
"preview": "function construct_device!(\n container::OptimizationContainer,\n sys::PSY.System,\n ::ArgumentConstructStage,\n "
},
{
"path": "src/devices_models/device_constructors/regulationdevice_constructor.jl",
"chars": 4353,
"preview": "function construct_device!(\n container::OptimizationContainer,\n sys::PSY.System,\n ::ArgumentConstructStage,\n "
},
{
"path": "src/devices_models/device_constructors/renewablegeneration_constructor.jl",
"chars": 8249,
"preview": "function construct_device!(\n container::OptimizationContainer,\n sys::PSY.System,\n ::ArgumentConstructStage,\n "
},
{
"path": "src/devices_models/device_constructors/source_constructor.jl",
"chars": 9995,
"preview": "\"\"\"\nThis function creates the arguments for the model for an import/export formulation for Source devices\n\"\"\"\nfunction c"
},
{
"path": "src/devices_models/device_constructors/thermalgeneration_constructor.jl",
"chars": 68694,
"preview": "# TODO: Security constrained models implement the correct functions for the model\nfunction has_security_arguments(device"
},
{
"path": "src/devices_models/devices/AC_branches.jl",
"chars": 44643,
"preview": "\n# Note: Any future concrete formulation requires the definition of\n\n# construct_device!(\n# ::OptimizationContainer,"
},
{
"path": "src/devices_models/devices/HVDCsystems.jl",
"chars": 35193,
"preview": "#! format: off\nget_variable_binary(::ActivePowerVariable, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormu"
},
{
"path": "src/devices_models/devices/TwoTerminalDC_branches.jl",
"chars": 55824,
"preview": "#################################### Branch Variables ##################################################\n#! format: off\n"
},
{
"path": "src/devices_models/devices/area_interchange.jl",
"chars": 8962,
"preview": "#! format: off\nget_multiplier_value(::FromToFlowLimitParameter, d::PSY.AreaInterchange, ::AbstractBranchFormulation) = -"
},
{
"path": "src/devices_models/devices/common/add_auxiliary_variable.jl",
"chars": 935,
"preview": "\"\"\"\nAdd variables to the OptimizationContainer for any component.\n\"\"\"\nfunction add_variables!(\n container::Optimizati"
},
{
"path": "src/devices_models/devices/common/add_constraint_dual.jl",
"chars": 4821,
"preview": "function add_constraint_dual!(\n container::OptimizationContainer,\n sys::PSY.System,\n model::DeviceModel{T, D},\n"
},
{
"path": "src/devices_models/devices/common/add_pwl_methods.jl",
"chars": 13457,
"preview": "\"\"\"\n _get_breakpoints_for_pwl_function(min_val, max_val, f; num_segments = DEFAULT_INTERPOLATION_LENGTH)\n\nGenerate br"
},
{
"path": "src/devices_models/devices/common/add_to_expression.jl",
"chars": 95407,
"preview": "_system_expression_type(::Type{PTDFPowerModel}) = PSY.System\n_system_expression_type(::Type{CopperPlatePowerModel}) = PS"
},
{
"path": "src/devices_models/devices/common/add_variable.jl",
"chars": 5524,
"preview": "\"\"\"\nAdd variables to the OptimizationContainer for any component.\n\"\"\"\nfunction add_variables!(\n container::Optimizati"
},
{
"path": "src/devices_models/devices/common/duration_constraints.jl",
"chars": 16465,
"preview": "@doc raw\"\"\"\nThis formulation of the duration constraints adds over the start times looking backwards.\n\n# LaTeX\n\n* Minimu"
},
{
"path": "src/devices_models/devices/common/get_time_series.jl",
"chars": 1366,
"preview": "function _get_time_series(\n container::OptimizationContainer,\n component::PSY.Component,\n attributes::TimeSerie"
},
{
"path": "src/devices_models/devices/common/objective_function/common.jl",
"chars": 18002,
"preview": "##################################\n######## Helper Functions ########\n##################################\n\nget_output_off"
},
{
"path": "src/devices_models/devices/common/objective_function/import_export.jl",
"chars": 2278,
"preview": "_include_min_gen_power_in_constraint(\n ::PSY.Source,\n ::ActivePowerOutVariable,\n ::AbstractDeviceFormulation,\n)"
},
{
"path": "src/devices_models/devices/common/objective_function/linear_curve.jl",
"chars": 8112,
"preview": "# Add proportional terms to objective function and expression\nfunction _add_linearcurve_variable_term_to_model!(\n con"
},
{
"path": "src/devices_models/devices/common/objective_function/market_bid.jl",
"chars": 36261,
"preview": "##################################################\n################ PWL Parameters #################\n##################"
},
{
"path": "src/devices_models/devices/common/objective_function/piecewise_linear.jl",
"chars": 23677,
"preview": "##################################################\n################# SOS Methods ####################\n##################"
},
{
"path": "src/devices_models/devices/common/objective_function/quadratic_curve.jl",
"chars": 8806,
"preview": "# Add proportional terms to objective function and expression\nfunction _add_quadraticcurve_variable_term_to_model!(\n "
},
{
"path": "src/devices_models/devices/common/range_constraint.jl",
"chars": 29284,
"preview": "######## CONSTRAINTS ############\n\n_add_lb(::RangeConstraintLBExpressions) = true\n_add_ub(::RangeConstraintLBExpressions"
},
{
"path": "src/devices_models/devices/common/rateofchange_constraints.jl",
"chars": 16407,
"preview": "function _get_minutes_per_period(container::OptimizationContainer)\n resolution = get_resolution(container)\n if res"
},
{
"path": "src/devices_models/devices/common/set_expression.jl",
"chars": 558,
"preview": "\"\"\"\nReplaces an expression value in the expression container if the key exists\n\"\"\"\nfunction set_expression!(\n contain"
},
{
"path": "src/devices_models/devices/default_interface_methods.jl",
"chars": 2298,
"preview": "########################### Interfaces ########################################################\nget_variable_key(variabl"
},
{
"path": "src/devices_models/devices/electric_loads.jl",
"chars": 20239,
"preview": "#! format: off\n########################### ElectricLoad ####################################\n\nget_variable_multiplier(_,"
},
{
"path": "src/devices_models/devices/reactivepower_device.jl",
"chars": 1641,
"preview": "#! format: off\n\nrequires_initialization(::AbstractReactivePowerDeviceFormulation) = false\nget_variable_multiplier(_, ::T"
},
{
"path": "src/devices_models/devices/regulation_device.jl",
"chars": 10297,
"preview": "#! format: off\nget_variable_multiplier(_, ::Type{PSY.RegulationDevice{PSY.ThermalStandard}}, ::DeviceLimitedRegulation) "
},
{
"path": "src/devices_models/devices/renewable_generation.jl",
"chars": 6716,
"preview": "#! format: off\nget_variable_multiplier(_, ::Type{<:PSY.RenewableGen}, ::AbstractRenewableFormulation) = 1.0\nget_expressi"
},
{
"path": "src/devices_models/devices/source.jl",
"chars": 8279,
"preview": "#! format: off\n\nrequires_initialization(::ImportExportSourceModel) = false\n\n\nget_variable_multiplier(::ActivePowerOutVar"
},
{
"path": "src/devices_models/devices/thermal_generation.jl",
"chars": 60159,
"preview": "#! format: off\n\nrequires_initialization(::AbstractThermalFormulation) = false\nrequires_initialization(::AbstractThermalU"
},
{
"path": "src/feedforward/feedforward_arguments.jl",
"chars": 7760,
"preview": "function add_feedforward_arguments!(\n container::OptimizationContainer,\n model::DeviceModel,\n devices::IS.Flatt"
},
{
"path": "src/feedforward/feedforward_constraints.jl",
"chars": 18627,
"preview": "function add_feedforward_constraints!(\n container::OptimizationContainer,\n model::DeviceModel,\n devices::IS.Fla"
},
{
"path": "src/feedforward/feedforwards.jl",
"chars": 10918,
"preview": "function get_affected_values(ff::AbstractAffectFeedforward)\n return ff.affected_values\nend\n\nfunction attach_feedforwa"
},
{
"path": "src/initial_conditions/add_initial_condition.jl",
"chars": 9088,
"preview": "function _get_initial_conditions_value(\n ::Vector{T},\n component::W,\n ::U,\n ::V,\n container::Optimization"
},
{
"path": "src/initial_conditions/calculate_initial_condition.jl",
"chars": 828,
"preview": "\"\"\"\nDefault implementation of set_initial_condition_value\n\"\"\"\nfunction set_ic_quantity!(\n ic::InitialCondition{T, JuM"
},
{
"path": "src/initial_conditions/initial_condition_chronologies.jl",
"chars": 871,
"preview": "\"\"\" Supertype for initial condition chronologies \"\"\"\nabstract type InitialConditionChronology end\n\n\"\"\"\n InterProblemC"
},
{
"path": "src/initial_conditions/initialization.jl",
"chars": 5136,
"preview": "function get_initial_conditions_template(model::OperationModel, number_of_steps::Int)\n # This is done to avoid passin"
},
{
"path": "src/initial_conditions/update_initial_conditions.jl",
"chars": 1772,
"preview": "function _update_initial_conditions!(\n model::OperationModel,\n key::InitialConditionKey{T, U},\n source, # Store"
},
{
"path": "src/network_models/area_balance_model.jl",
"chars": 2504,
"preview": "function add_constraints!(\n container::OptimizationContainer,\n ::Type{CopperPlateBalanceConstraint},\n sys::PSY."
},
{
"path": "src/network_models/copperplate_model.jl",
"chars": 1385,
"preview": "function add_constraints!(\n container::OptimizationContainer,\n ::Type{T},\n sys::U,\n model::NetworkModel{V},\n"
},
{
"path": "src/network_models/hvdc_network_constructor.jl",
"chars": 1183,
"preview": "function construct_hvdc_network!(\n container::OptimizationContainer,\n sys::PSY.System,\n transmission_model::Net"
},
{
"path": "src/network_models/hvdc_networks.jl",
"chars": 2192,
"preview": "## To add method of upper_bounds and lower_bounds for DCVoltage\nget_variable_binary(::DCVoltage, ::Type{PSY.DCBus}, ::Ab"
},
{
"path": "src/network_models/network_constructor.jl",
"chars": 8645,
"preview": "function construct_network!(\n container::OptimizationContainer,\n sys::PSY.System,\n model::NetworkModel{CopperPl"
},
{
"path": "src/network_models/network_slack_variables.jl",
"chars": 6738,
"preview": "#! format: off\nget_variable_multiplier(::SystemBalanceSlackUp, ::Type{<: Union{PSY.ACBus, PSY.Area, PSY.System}}, _) = 1"
},
{
"path": "src/network_models/pm_translator.jl",
"chars": 26896,
"preview": "const PM_MAP_TUPLE =\n NamedTuple{(:from_to, :to_from), Tuple{Tuple{Int, Int, Int}, Tuple{Int, Int, Int}}}\n\nconst PM_B"
},
{
"path": "src/network_models/power_flow_evaluation.jl",
"chars": 43013,
"preview": "# Defines the order of precedence for each type of information that could be sent to PowerFlows.jl\nconst PF_INPUT_KEY_PR"
},
{
"path": "src/network_models/powermodels_interface.jl",
"chars": 17730,
"preview": "#################################################################################\n# Comments\n#\n# - Ideally the net_injec"
},
{
"path": "src/operation/decision_model.jl",
"chars": 25325,
"preview": "mutable struct DecisionModel{M <: DecisionProblem} <: OperationModel\n name::Symbol\n template::AbstractProblemTempl"
},
{
"path": "src/operation/decision_model_store.jl",
"chars": 6044,
"preview": "\"\"\"\nStores results data for one DecisionModel\n\"\"\"\nmutable struct DecisionModelStore <: ISOPT.AbstractModelStore\n # Al"
},
{
"path": "src/operation/emulation_model.jl",
"chars": 24419,
"preview": "\"\"\"\n EmulationModel{M}(\n template::AbstractProblemTemplate,\n sys::PSY.System,\n jump_model::Union"
},
{
"path": "src/operation/emulation_model_store.jl",
"chars": 7066,
"preview": "\"\"\"\nStores results data for one EmulationModel\n\"\"\"\nmutable struct EmulationModelStore <: ISOPT.AbstractModelStore\n da"
},
{
"path": "src/operation/initial_conditions_update_in_memory_store.jl",
"chars": 4954,
"preview": "\n################## ic updates from store for emulation problems simulation #################\n\nfunction update_initial_c"
},
{
"path": "src/operation/model_numerical_analysis_utils.jl",
"chars": 5192,
"preview": "# The Numerical stability checks code in this file is based on the code from the SDDP.jl package,\n# from the below menti"
},
{
"path": "src/operation/operation_model_interface.jl",
"chars": 16470,
"preview": "# Default implementations of getter/setter functions for OperationModel.\nis_built(model::OperationModel) =\n ISOPT.get"
},
{
"path": "src/operation/operation_model_simulation_interface.jl",
"chars": 1068,
"preview": "function update_model!(model::OperationModel, source::SimulationState, ini_cond_chronology)\n TimerOutputs.@timeit RUN"
},
{
"path": "src/operation/operation_model_types.jl",
"chars": 689,
"preview": "\"\"\"\nAbstract type for models than employ PowerSimulations methods. For custom decision problems\n use DecisionProblem "
},
{
"path": "src/operation/operation_problem_templates.jl",
"chars": 4296,
"preview": "\nstruct EconomicDispatchProblem <: DefaultDecisionProblem end\nstruct UnitCommitmentProblem <: DefaultDecisionProblem end"
},
{
"path": "src/operation/optimization_debugging.jl",
"chars": 3905,
"preview": "\"\"\"\nEach Tuple corresponds to (con_name, internal_index, moi_index)\n\"\"\"\nfunction get_all_constraint_index(model::Operati"
},
{
"path": "src/operation/problem_results.jl",
"chars": 3050,
"preview": "\"\"\"\nConstruct OptimizationProblemResults from a solved DecisionModel.\n\"\"\"\nfunction OptimizationProblemResults(model::Dec"
},
{
"path": "src/operation/problem_template.jl",
"chars": 11612,
"preview": "\nconst DevicesModelContainer = Dict{Symbol, DeviceModel}\nconst ServicesModelContainer = Dict{Tuple{String, Symbol}, Serv"
},
{
"path": "src/operation/template_validation.jl",
"chars": 4113,
"preview": "function _check_branch_network_compatibility(\n ::NetworkModel{T},\n unmodeled_branch_types::Vector{DataType},\n) whe"
},
{
"path": "src/operation/time_series_interface.jl",
"chars": 2775,
"preview": "function get_time_series_values!(\n time_series_type::Type{T},\n model::DecisionModel,\n component,\n name::Stri"
},
{
"path": "src/parameters/add_parameters.jl",
"chars": 37471,
"preview": "function add_parameters!(\n container::OptimizationContainer,\n ::Type{T},\n devices::U,\n model::DeviceModel{D,"
},
{
"path": "src/parameters/update_container_parameter_values.jl",
"chars": 31946,
"preview": "function _update_parameter_values!(\n ::AbstractArray{T},\n ::ParameterType,\n ::NoAttributes,\n args...,\n) wher"
},
{
"path": "src/parameters/update_cost_parameters.jl",
"chars": 11948,
"preview": "function _update_parameter_values!(\n parameter_array::DenseAxisArray,\n ::T,\n parameter_multiplier::JuMPFloatArr"
},
{
"path": "src/parameters/update_parameters.jl",
"chars": 3198,
"preview": "\"\"\"\nUpdate parameter function an OperationModel\n\"\"\"\nfunction update_parameter_values!(\n model::OperationModel,\n ke"
},
{
"path": "src/services_models/agc.jl",
"chars": 11787,
"preview": "#! format: off\nget_variable_multiplier(_, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = NaN\n########################## "
},
{
"path": "src/services_models/reserve_group.jl",
"chars": 2405,
"preview": "function get_default_time_series_names(\n ::Type{PSY.ConstantReserveGroup{T}},\n ::Type{GroupReserve}) where {T <: P"
},
{
"path": "src/services_models/reserves.jl",
"chars": 21333,
"preview": "#! format: off\n############################### Reserve Variables #########################################\n\nget_variable"
},
{
"path": "src/services_models/service_slacks.jl",
"chars": 1615,
"preview": "function reserve_slacks!(\n container::OptimizationContainer,\n service::T,\n) where {T <: Union{PSY.Reserve, PSY.Res"
},
{
"path": "src/services_models/services_constructor.jl",
"chars": 27819,
"preview": "function get_incompatible_devices(devices_template::Dict)\n incompatible_device_types = Set{DataType}()\n for model "
},
{
"path": "src/services_models/transmission_interface.jl",
"chars": 5398,
"preview": "#! format: off\nget_variable_binary(_, ::Type{PSY.TransmissionInterface}, ::ConstantMaxInterfaceFlow) = false\nget_variabl"
},
{
"path": "src/simulation/decision_model_simulation_results.jl",
"chars": 25969,
"preview": "struct DecisionModelSimulationResults <: OperationModelSimulationResults\n variables::ResultsByKeyAndTime\n duals::R"
},
{
"path": "src/simulation/emulation_model_simulation_results.jl",
"chars": 11587,
"preview": "struct EmulationModelSimulationResults <: OperationModelSimulationResults\n variables::Dict{OptimizationContainerKey, "
},
{
"path": "src/simulation/get_components_interface.jl",
"chars": 2285,
"preview": "# Analogous to `src/get_components_interface.jl` in PowerSystems.jl, see comments there.\n\n# get_components\n\"\"\"\nCalling `"
},
{
"path": "src/simulation/hdf_simulation_store.jl",
"chars": 40821,
"preview": "const HDF_FILENAME = \"simulation_store.h5\"\nconst HDF_SIMULATION_ROOT_PATH = \"simulation\"\nconst EMULATION_MODEL_PATH = \"$"
},
{
"path": "src/simulation/in_memory_simulation_store.jl",
"chars": 7577,
"preview": "\"\"\"\nStores simulation data in memory\n\"\"\"\nmutable struct InMemorySimulationStore <: SimulationStore\n params::Simulatio"
},
{
"path": "src/simulation/initial_condition_update_simulation.jl",
"chars": 7094,
"preview": "function update_initial_conditions!(\n model::OperationModel,\n state::SimulationState,\n ::InterProblemChronology"
},
{
"path": "src/simulation/optimization_output_cache.jl",
"chars": 4486,
"preview": "\"\"\"\nCache for a single parameter/variable/dual.\nStores arrays chronologically by simulation timestamp.\n\"\"\"\nmutable struc"
},
{
"path": "src/simulation/optimization_output_caches.jl",
"chars": 3748,
"preview": "\"\"\"\nCache for all model results\n\"\"\"\nstruct OptimizationOutputCaches\n data::Dict{OptimizationResultCacheKey, Optimizat"
},
{
"path": "src/simulation/realized_meta.jl",
"chars": 6025,
"preview": "struct RealizedMeta\n start_time::Dates.DateTime\n resolution::Dates.TimePeriod\n len::Int\n start_offset::Int\n "
},
{
"path": "src/simulation/simulation.jl",
"chars": 48530,
"preview": "\"\"\"\n Simulation(\n sequence::SimulationSequence,\n name::String,\n steps::Int\n models::Simul"
},
{
"path": "src/simulation/simulation_events.jl",
"chars": 9624,
"preview": "function apply_simulation_events!(simulation::Simulation)\n sequence = get_sequence(simulation)\n events = get_event"
},
{
"path": "src/simulation/simulation_info.jl",
"chars": 579,
"preview": "mutable struct SimulationInfo\n number::Union{Nothing, Int}\n sequence_uuid::Union{Nothing, Base.UUID}\n run_statu"
},
{
"path": "src/simulation/simulation_internal.jl",
"chars": 4455,
"preview": "mutable struct SimulationInternal\n sim_files_dir::String\n partitions::Union{Nothing, SimulationPartitions}\n sto"
},
{
"path": "src/simulation/simulation_models.jl",
"chars": 6123,
"preview": "\"\"\"\n SimulationModels(\n decision_models::Vector{<:DecisionModel},\n emulation_models::Union{Nothing, Emu"
},
{
"path": "src/simulation/simulation_partition_results.jl",
"chars": 6731,
"preview": "const _TEMP_WRITE_POSITION = \"__write_position__\"\n\n\"\"\"\nHandles merging of simulation partitions\n\"\"\"\nstruct SimulationPar"
},
{
"path": "src/simulation/simulation_partitions.jl",
"chars": 10208,
"preview": "\"\"\"\nDefines how a simulation can be partition into partitions and run in parallel.\n\"\"\"\nstruct SimulationPartitions <: IS"
},
{
"path": "src/simulation/simulation_problem_results.jl",
"chars": 22961,
"preview": "abstract type OperationModelSimulationResults end\n# Subtypes need to implement the following methods for SimulationProbl"
},
{
"path": "src/simulation/simulation_results.jl",
"chars": 16030,
"preview": "function check_folder_integrity(folder::String)\n folder_files = readdir(folder)\n alien_files = setdiff(folder_file"
},
{
"path": "src/simulation/simulation_results_export.jl",
"chars": 5664,
"preview": "\nconst _SUPPORTED_FORMATS = (\"csv\",)\n\nmutable struct SimulationResultsExport\n models::Dict{Symbol, OptimizationProble"
},
{
"path": "src/simulation/simulation_sequence.jl",
"chars": 15021,
"preview": "function check_simulation_chronology(\n horizons::OrderedDict{Symbol, Dates.Millisecond},\n intervals::OrderedDict{S"
},
{
"path": "src/simulation/simulation_state.jl",
"chars": 43083,
"preview": "struct SimulationState\n current_time::Base.RefValue{Dates.DateTime}\n last_decision_model::Base.RefValue{Symbol}\n "
},
{
"path": "src/simulation/simulation_store_params.jl",
"chars": 1821,
"preview": "struct SimulationStoreParams\n initial_time::Dates.DateTime\n step_resolution::Dates.Millisecond\n num_steps::Int\n"
},
{
"path": "src/simulation/simulation_store_requirements.jl",
"chars": 653,
"preview": "struct SimulationModelStoreRequirements\n duals::Dict{ConstraintKey, Dict{String, Any}}\n parameters::Dict{Parameter"
},
{
"path": "src/utils/dataframes_utils.jl",
"chars": 200,
"preview": "\nfunction to_matrix(df::DataFrame)\n return Matrix{Float64}(df)\nend\n\nfunction to_matrix(df_row::DataFrameRow{DataFrame"
},
{
"path": "src/utils/datetime_utils.jl",
"chars": 795,
"preview": "\"\"\"\ncalculates the index in the time series corresponding to the data. Assumes that the dates vector is sorted.\n\"\"\"\nfunc"
},
{
"path": "src/utils/file_utils.jl",
"chars": 1819,
"preview": "\"\"\"\nReturn a decoded JSON file.\n\"\"\"\nfunction read_json(filename::AbstractString)\n open(filename, \"r\") do io\n J"
},
{
"path": "src/utils/generate_valid_formulations.jl",
"chars": 3564,
"preview": "\"\"\"\nGenerate valid combinations of device_type/formulation and service_type/formulation.\nReturn vectors of dictionaries "
},
{
"path": "src/utils/indexing.jl",
"chars": 2489,
"preview": "# Pad `ixs` with `:` for any unindexed middle dimensions of `dest` (Python `...`-style).\n# Fast path for AbstractArrays "
},
{
"path": "src/utils/jump_utils.jl",
"chars": 22187,
"preview": "const IntegerAxis = Union{Vector{Int}, UnitRange{Int}}\n\nfunction get_hinted_aff_expr(size::Int)\n expr = JuMP.AffExpr("
},
{
"path": "src/utils/logging.jl",
"chars": 658,
"preview": "\nLOG_GROUP_COST_FUNCTIONS = :CostFunctionsConstructor\nLOG_GROUP_OPTIMZATION_CONTAINER = :OptimizationContainer\nLOG_GROUP"
},
{
"path": "src/utils/powersystems_utils.jl",
"chars": 15527,
"preview": "\"\"\"\nConvert the internal `Dates.Millisecond` interval (where `UNSET_INTERVAL` means\nunset) to the `Union{Nothing, Dates."
}
]
// ... and 59 more files (download for full content)
About this extraction
This page contains the full source code of the NREL-SIIP/PowerSimulations.jl GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 259 files (2.7 MB), approximately 719.9k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.