Repository: NREL-SIIP/PowerSystems.jl
Branch: main
Commit: 667b5762ce2f
Files: 365
Total size: 3.9 MB
Directory structure:
gitextract_d2nxsq6e/
├── .claude/
│ ├── Sienna.md
│ └── claude.md
├── .devcontainer/
│ └── devcontainer.json
├── .editorconfig
├── .github/
│ ├── copilot-setup-steps.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── TagBot.yml
│ ├── cross-package-test.yml
│ ├── doc-preview-cleanup.yml
│ ├── docs.yml
│ ├── fix-docs-on-failure.yml
│ ├── format-check.yml
│ ├── main-tests.yml
│ └── pr_testing.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CHANGELOG.md
├── CITATION.cff
├── CONTRIBUTING.md
├── LICENSE
├── Project.toml
├── README.md
├── codecov.yml
├── docs/
│ ├── Makefile
│ ├── Project.toml
│ ├── make.jl
│ ├── make_model_library.jl
│ ├── make_tutorials.jl
│ └── src/
│ ├── api/
│ │ ├── citation.md
│ │ ├── developer_guidelines.md
│ │ ├── enumerated_types.md
│ │ ├── glossary.md
│ │ ├── internal.md
│ │ ├── psse_models.md
│ │ ├── public.md
│ │ ├── static_injection_subtypes.md
│ │ ├── type_tree.md
│ │ └── valuecurve_options.md
│ ├── explanation/
│ │ ├── buses_type_explanation.md
│ │ ├── conforming_and_non_conforming_loads.md
│ │ ├── dynamic_data.md
│ │ ├── per_unit.md
│ │ ├── plant_attributes.md
│ │ ├── power_concepts.md
│ │ ├── supplemental_attributes.md
│ │ ├── system.md
│ │ ├── time_series.md
│ │ ├── transformer_per_unit_models.md
│ │ └── type_structure.md
│ ├── generate_input_config_table.jl
│ ├── generate_validation_table.jl
│ ├── how_to/
│ │ ├── add_component_natural_units.md
│ │ ├── add_cost_curve.md
│ │ ├── add_fuel_curve_timeseries.md
│ │ ├── add_new_types.md
│ │ ├── adding_additional_fields.md
│ │ ├── build_system_with_files.md
│ │ ├── create_hydro_datasets.md
│ │ ├── create_system_with_source_import_export_cost.md
│ │ ├── handle_3W_transformers.md
│ │ ├── improve_ts_performance.md
│ │ ├── jump.md
│ │ ├── market_bid_cost.md
│ │ ├── migrating_to_psy5.md
│ │ ├── parse_dynamic_data.md
│ │ ├── parse_matpower_psse.md
│ │ ├── parse_ts_from_csvs.md
│ │ ├── reduce_repl_printing.md
│ │ ├── serialize_data.md
│ │ └── use_context_managers.md
│ ├── index.md
│ ├── model_library/
│ │ ├── dynamic_branch.md
│ │ ├── dynamic_generator.md
│ │ ├── dynamic_inverter.md
│ │ ├── hybrid_system.md
│ │ ├── hydro_generation_cost.md
│ │ ├── hydro_reservoir.md
│ │ ├── hydro_reservoir_cost.md
│ │ ├── import_export_cost.md
│ │ ├── load_cost.md
│ │ ├── market_bid_cost.md
│ │ ├── offer_curve_cost.md
│ │ ├── outer_control.md
│ │ ├── renewable_generation_cost.md
│ │ ├── reserves.md
│ │ ├── storage_cost.md
│ │ └── thermal_generation_cost.md
│ └── tutorials/
│ ├── add_dynamic_data.jl
│ ├── creating_system.jl
│ ├── manipulating_datasets.jl
│ ├── tutorials_data/
│ │ ├── RTS-GMLC.RAW
│ │ ├── RTS_GMLC.m
│ │ ├── TestGENCLS.dyr
│ │ ├── case5.m
│ │ └── case5_re.m
│ ├── utils/
│ │ └── docs_utils.jl
│ └── working_with_time_series.jl
├── scripts/
│ ├── formatter/
│ │ ├── Project.toml
│ │ └── formatter_code.jl
│ ├── generate_config_file.py
│ └── generate_validation_config_file.py
├── src/
│ ├── PowerSystems.jl
│ ├── base.jl
│ ├── component_selector.jl
│ ├── component_selector_interface.jl
│ ├── contingencies.jl
│ ├── data_format_conversions.jl
│ ├── definitions.jl
│ ├── deprecated.jl
│ ├── descriptors/
│ │ ├── power_system_inputs.json
│ │ └── power_system_structs.json
│ ├── get_components_interface.jl
│ ├── impedance_correction.jl
│ ├── models/
│ │ ├── HybridSystem.jl
│ │ ├── OuterControl.jl
│ │ ├── RoundRotorExponential.jl
│ │ ├── RoundRotorQuadratic.jl
│ │ ├── SalientPoleExponential.jl
│ │ ├── SalientPoleQuadratic.jl
│ │ ├── branches.jl
│ │ ├── components.jl
│ │ ├── cost_function_timeseries.jl
│ │ ├── cost_functions/
│ │ │ ├── HydroGenerationCost.jl
│ │ │ ├── HydroReservoirCost.jl
│ │ │ ├── ImportExportCost.jl
│ │ │ ├── LoadCost.jl
│ │ │ ├── MarketBidCost.jl
│ │ │ ├── OfferCurveCost.jl
│ │ │ ├── RenewableGenerationCost.jl
│ │ │ ├── StorageCost.jl
│ │ │ ├── ThermalGenerationCost.jl
│ │ │ └── operational_cost.jl
│ │ ├── devices.jl
│ │ ├── dynamic_branch.jl
│ │ ├── dynamic_generator.jl
│ │ ├── dynamic_generator_components.jl
│ │ ├── dynamic_inverter.jl
│ │ ├── dynamic_inverter_components.jl
│ │ ├── dynamic_loads.jl
│ │ ├── dynamic_machines.jl
│ │ ├── dynamic_models.jl
│ │ ├── generated/
│ │ │ ├── ACBus.jl
│ │ │ ├── AGC.jl
│ │ │ ├── AVRFixed.jl
│ │ │ ├── AVRSimple.jl
│ │ │ ├── AVRTypeI.jl
│ │ │ ├── AVRTypeII.jl
│ │ │ ├── ActiveConstantPowerLoad.jl
│ │ │ ├── ActivePowerDroop.jl
│ │ │ ├── ActivePowerPI.jl
│ │ │ ├── ActiveRenewableControllerAB.jl
│ │ │ ├── ActiveVirtualOscillator.jl
│ │ │ ├── AggregateDistributedGenerationA.jl
│ │ │ ├── AndersonFouadMachine.jl
│ │ │ ├── Arc.jl
│ │ │ ├── Area.jl
│ │ │ ├── AreaInterchange.jl
│ │ │ ├── AverageConverter.jl
│ │ │ ├── BaseMachine.jl
│ │ │ ├── CSVGN1.jl
│ │ │ ├── ConstantReserve.jl
│ │ │ ├── ConstantReserveGroup.jl
│ │ │ ├── ConstantReserveNonSpinning.jl
│ │ │ ├── CurrentModeControl.jl
│ │ │ ├── DCBus.jl
│ │ │ ├── DEGOV.jl
│ │ │ ├── DEGOV1.jl
│ │ │ ├── DiscreteControlledACBranch.jl
│ │ │ ├── DynamicExponentialLoad.jl
│ │ │ ├── ESAC1A.jl
│ │ │ ├── ESAC6A.jl
│ │ │ ├── ESAC8B.jl
│ │ │ ├── ESDC1A.jl
│ │ │ ├── ESDC2A.jl
│ │ │ ├── ESST1A.jl
│ │ │ ├── ESST4B.jl
│ │ │ ├── EX4VSA.jl
│ │ │ ├── EXAC1.jl
│ │ │ ├── EXAC1A.jl
│ │ │ ├── EXAC2.jl
│ │ │ ├── EXPIC1.jl
│ │ │ ├── EXST1.jl
│ │ │ ├── EnergyReservoirStorage.jl
│ │ │ ├── ExponentialLoad.jl
│ │ │ ├── FACTSControlDevice.jl
│ │ │ ├── FiveMassShaft.jl
│ │ │ ├── FixedAdmittance.jl
│ │ │ ├── FixedDCSource.jl
│ │ │ ├── FixedFrequency.jl
│ │ │ ├── FullMachine.jl
│ │ │ ├── GasTG.jl
│ │ │ ├── GeneralGovModel.jl
│ │ │ ├── GenericArcImpedance.jl
│ │ │ ├── GenericDER.jl
│ │ │ ├── HybridOutputCurrentLimiter.jl
│ │ │ ├── HydroDispatch.jl
│ │ │ ├── HydroPumpTurbine.jl
│ │ │ ├── HydroReservoir.jl
│ │ │ ├── HydroTurbine.jl
│ │ │ ├── HydroTurbineGov.jl
│ │ │ ├── IEEEST.jl
│ │ │ ├── IEEET1.jl
│ │ │ ├── IEEETurbineGov1.jl
│ │ │ ├── InstantaneousOutputCurrentLimiter.jl
│ │ │ ├── InterconnectingConverter.jl
│ │ │ ├── InterruptiblePowerLoad.jl
│ │ │ ├── InterruptibleStandardLoad.jl
│ │ │ ├── KauraPLL.jl
│ │ │ ├── LCFilter.jl
│ │ │ ├── LCLFilter.jl
│ │ │ ├── Line.jl
│ │ │ ├── LoadZone.jl
│ │ │ ├── MagnitudeOutputCurrentLimiter.jl
│ │ │ ├── MarconatoMachine.jl
│ │ │ ├── MonitoredLine.jl
│ │ │ ├── MotorLoad.jl
│ │ │ ├── OneDOneQMachine.jl
│ │ │ ├── PIDGOV.jl
│ │ │ ├── PSS2A.jl
│ │ │ ├── PSS2B.jl
│ │ │ ├── PSS2C.jl
│ │ │ ├── PSSFixed.jl
│ │ │ ├── PSSSimple.jl
│ │ │ ├── PeriodicVariableSource.jl
│ │ │ ├── PhaseShiftingTransformer.jl
│ │ │ ├── PhaseShiftingTransformer3W.jl
│ │ │ ├── PowerLoad.jl
│ │ │ ├── PriorityOutputCurrentLimiter.jl
│ │ │ ├── RECurrentControlB.jl
│ │ │ ├── RLFilter.jl
│ │ │ ├── ReactivePowerDroop.jl
│ │ │ ├── ReactivePowerPI.jl
│ │ │ ├── ReactiveRenewableControllerAB.jl
│ │ │ ├── ReactiveVirtualOscillator.jl
│ │ │ ├── ReducedOrderPLL.jl
│ │ │ ├── RenewableDispatch.jl
│ │ │ ├── RenewableEnergyConverterTypeA.jl
│ │ │ ├── RenewableEnergyVoltageConverterTypeA.jl
│ │ │ ├── RenewableNonDispatch.jl
│ │ │ ├── ReserveDemandCurve.jl
│ │ │ ├── RoundRotorMachine.jl
│ │ │ ├── SCRX.jl
│ │ │ ├── SEXS.jl
│ │ │ ├── ST6B.jl
│ │ │ ├── ST8C.jl
│ │ │ ├── STAB1.jl
│ │ │ ├── SalientPoleMachine.jl
│ │ │ ├── SaturationOutputCurrentLimiter.jl
│ │ │ ├── SauerPaiMachine.jl
│ │ │ ├── ShiftablePowerLoad.jl
│ │ │ ├── SimpleAFMachine.jl
│ │ │ ├── SimpleFullMachine.jl
│ │ │ ├── SimpleMarconatoMachine.jl
│ │ │ ├── SimplifiedSingleCageInductionMachine.jl
│ │ │ ├── SingleCageInductionMachine.jl
│ │ │ ├── SingleMass.jl
│ │ │ ├── Source.jl
│ │ │ ├── StandardLoad.jl
│ │ │ ├── SteamTurbineGov1.jl
│ │ │ ├── SwitchedAdmittance.jl
│ │ │ ├── SynchronousCondenser.jl
│ │ │ ├── TGFixed.jl
│ │ │ ├── TGSimple.jl
│ │ │ ├── TGTypeI.jl
│ │ │ ├── TGTypeII.jl
│ │ │ ├── TModelHVDCLine.jl
│ │ │ ├── TapTransformer.jl
│ │ │ ├── ThermalMultiStart.jl
│ │ │ ├── ThermalStandard.jl
│ │ │ ├── Transformer2W.jl
│ │ │ ├── Transformer3W.jl
│ │ │ ├── TransmissionInterface.jl
│ │ │ ├── TwoTerminalGenericHVDCLine.jl
│ │ │ ├── TwoTerminalLCCLine.jl
│ │ │ ├── TwoTerminalVSCLine.jl
│ │ │ ├── VariableReserve.jl
│ │ │ ├── VariableReserveNonSpinning.jl
│ │ │ ├── VirtualInertia.jl
│ │ │ ├── VoltageModeControl.jl
│ │ │ ├── WPIDHY.jl
│ │ │ ├── ZeroOrderBESS.jl
│ │ │ └── includes.jl
│ │ ├── generation.jl
│ │ ├── injection.jl
│ │ ├── loads.jl
│ │ ├── reserves.jl
│ │ ├── serialization.jl
│ │ ├── services.jl
│ │ ├── static_injection_subsystem.jl
│ │ ├── static_models.jl
│ │ ├── storage.jl
│ │ ├── supplemental_accessors.jl
│ │ ├── supplemental_constructors.jl
│ │ ├── supplemental_setters.jl
│ │ └── topological_elements.jl
│ ├── outages.jl
│ ├── parsers/
│ │ ├── common.jl
│ │ ├── enums.jl
│ │ ├── generator_mapping_cdm.yaml
│ │ ├── generator_mapping_pm.yaml
│ │ ├── im_io/
│ │ │ ├── LICENSE.md
│ │ │ ├── common.jl
│ │ │ ├── data.jl
│ │ │ └── matlab.jl
│ │ ├── im_io.jl
│ │ ├── pm_io/
│ │ │ ├── LICENSE.md
│ │ │ ├── common.jl
│ │ │ ├── data.jl
│ │ │ ├── matpower.jl
│ │ │ ├── psse.jl
│ │ │ └── pti.jl
│ │ ├── pm_io.jl
│ │ ├── power_models_data.jl
│ │ ├── power_system_table_data.jl
│ │ ├── powerflowdata_data.jl
│ │ ├── psse_dynamic_data.jl
│ │ ├── psse_dynamic_mapping.yaml
│ │ └── psse_metadata_reimport.jl
│ ├── plant_attribute.jl
│ ├── subsystems.jl
│ └── utils/
│ ├── IO/
│ │ ├── base_checks.jl
│ │ ├── branchdata_checks.jl
│ │ └── system_checks.jl
│ ├── conversion.jl
│ ├── generate_struct_files.jl
│ ├── logging.jl
│ ├── print.jl
│ ├── print_pt_v2.jl
│ └── print_pt_v3.jl
└── test/
├── Project.toml
├── common.jl
├── runtests.jl
├── test_base_checks.jl
├── test_base_power.jl
├── test_branchchecks_testing.jl
├── test_busnumberchecks.jl
├── test_component_selector.jl
├── test_constructors.jl
├── test_cost_functions.jl
├── test_devices.jl
├── test_dynamic_generator.jl
├── test_dynamic_inverter.jl
├── test_dynamic_loads.jl
├── test_dynamics_source.jl
├── test_generate_structs.jl
├── test_hybrid_system.jl
├── test_hydro_reservoir.jl
├── test_internal.jl
├── test_logging.jl
├── test_outages.jl
├── test_parse_dynamics.jl
├── test_parse_matpower.jl
├── test_parse_psse.jl
├── test_plant_attributes.jl
├── test_power_system_table_data.jl
├── test_powersystemconstructors.jl
├── test_printing.jl
├── test_read_time_series.jl
├── test_serialization.jl
├── test_services.jl
├── test_subsystems.jl
├── test_supplemental_accessors.jl
├── test_system.jl
├── test_topology.jl
└── test_validation.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 variables causing boxing. Pass variables as function arguments instead.
#### Splatting penalty
Avoid splatting (`...`) in performance-critical code.
#### Abstract return types
Avoid returning `Union` types or abstract types.
#### 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:
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:
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=` (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=` 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=` 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
================================================
# PowerSystems.jl
Data model library for power system simulation and optimization. Julia compat: `^1.10`.
> **General Sienna Programming Practices:** For information on performance requirements, code conventions, documentation practices, and contribution workflows that apply across all Sienna packages, see [Sienna.md](Sienna.md).
## Design Objectives
**Primary goal:** Performance and expressiveness.
Comprehensive data model library for power system simulation, optimization, and dynamics analysis. Provides the `System` container and all component types (generators, loads, branches, storage, dynamic models). Consumed by PowerSimulations.jl, PowerFlows.jl, PowerNetworkMatrices.jl, and other Sienna packages. All code must be written with performance in mind.
## File Structure
### `src/`
Key files:
- `PowerSystems.jl` -- main module, exports, and includes
- `base.jl` -- `System` type definition and core methods
- `definitions.jl` -- core type definitions and enums
- `deprecated.jl` -- deprecated function warnings
- `subsystems.jl` -- subsystem management
- `contingencies.jl` -- contingency definitions
- `outages.jl` -- outage modeling
- `component_selector.jl` -- component selection utilities
- `data_format_conversions.jl` -- format conversion methods
#### `models/`
Core component models and definitions:
- `components.jl` -- base component methods
- `devices.jl` -- device implementations
- `branches.jl` -- branch/transmission line definitions
- `topological_elements.jl` -- buses and topology
- `generation.jl` -- generation component definitions
- `storage.jl` -- storage/battery definitions
- `loads.jl` -- load component definitions
- `reserves.jl` -- reserve ancillary services
- `services.jl` -- all kinds of ancillary services (supertype to reserves)
- `static_models.jl` -- static component definitions
- `dynamic_generator.jl` -- dynamic generator models
- `dynamic_inverter.jl` -- dynamic inverter models
- `dynamic_branch.jl` -- dynamic branch models
- `dynamic_loads.jl` -- dynamic load models
- `HybridSystem.jl` -- hybrid renewable + storage systems
- `serialization.jl` -- component serialization
- `supplemental_constructors.jl` -- additional constructors
- `supplemental_accessors.jl` -- getter methods
- `supplemental_setters.jl` -- setter methods
- `generated/` -- auto-generated component type files (**DO NOT EDIT directly**)
- `cost_functions/` -- operational cost types (ThermalGenerationCost, StorageCost, etc.)
#### `parsers/`
Data parsing and import functionality:
- `common.jl` -- shared parsing utilities
- `power_system_table_data.jl` -- CSV/table-based data parsing
- `power_models_data.jl` -- PowerModels.jl format support
- `psse_dynamic_data.jl` -- PSS/E dynamic data parsing
- `pm_io/` -- PowerModels I/O (matpower.jl, psse.jl, pti.jl)
- `im_io/` -- InteractiveModels I/O (matlab.jl)
#### `utils/`
Utility functions:
- `print.jl` -- enhanced console display
- `generate_struct_files.jl` -- generate component definitions
- `logging.jl` -- logging configuration
- `conversion.jl` -- unit and format conversions
- `IO/` -- data validation (system_checks.jl, branchdata_checks.jl, base_checks.jl)
#### `descriptors/`
JSON schema and metadata:
- `power_system_structs.json` -- component structure definitions
- `power_system_inputs.json` -- input specifications
### Other top-level directories
- `test/` -- test suite
- `docs/` -- documentation source
- `scripts/` -- utility scripts (formatter)
## Auto-Generation
Component structs are auto-generated from JSON descriptors (`src/descriptors/power_system_structs.json`). Generated files are in `src/models/generated/` and should **NOT** be edited directly. Over 140 component types are auto-generated.
Generator: `src/utils/generate_struct_files.jl`
Workflow:
1. Edit `src/descriptors/power_system_structs.json` to define/modify struct fields
2. Run the generation script
3. Generated files include docstrings, constructors, and accessors automatically
## Downstream Packages
- **PowerSimulations.jl** -- production cost modeling and unit commitment
- **PowerFlows.jl** -- power flow analysis
- **PowerNetworkMatrices.jl** -- network matrix calculations
- **PowerSystemsInvestmentsPortfolios.jl** -- capacity expansion portfolios
## Dependencies
- **InfrastructureSystems.jl** -- base types, system data management, time series
- **PowerFlowData.jl** -- power flow data handling
- **DataFrames.jl** -- tabular data processing
- **TimeSeries.jl** -- time series data management
- **PrettyTables.jl** -- enhanced console output
## Core Abstractions
### System
Main container for power system data. Defined in `src/base.jl`.
Fields:
- `data` -- `IS.SystemData` for storing components and time series
- `frequency` -- system frequency (Hz)
- `bus_numbers` -- set of bus numbers for validation
- `runchecks` -- flag for data validation
- `units_settings` -- unit system settings (`SYSTEM_BASE`, `DEVICE_BASE`, `NATURAL_UNITS`)
Key methods: `add_component!`, `remove_component!`, `get_component`, `get_components`, `get_bus`, `set_units_base_system!`
### Component
Abstract base type for all power system elements.
Hierarchy:
- **Topology** -- network topology elements: `Bus` (`ACBus`, `DCBus`), `Arc`, `Area`, `LoadZone`
- **Device** -- physical equipment: `StaticInjection` (generators, loads, storage), `Branch` (lines, transformers)
- **Service** -- ancillary services (reserves, AGC)
- **DynamicComponent** -- dynamic models for stability analysis
### StaticInjection
Static injection devices (generators, loads, storage).
- **Generator:** `ThermalStandard`, `ThermalMultiStart`, `HydroDispatch`, `RenewableDispatch`, `RenewableNonDispatch`
- **Storage:** `EnergyReservoirStorage`, `HybridSystem`
- **ElectricLoad:** `PowerLoad`, `StandardLoad`, `InterruptiblePowerLoad`, `ControllableLoad`
- **StaticInjectionSubsystem:** grouped injection components
### Branch
Transmission elements connecting buses. Branches that contain Arcs with ACBuses are AC Branches and branches with DCBuses are DC Branches.
- **ACBranch:** `Line`, `TwoWindingTransformer`, `PhaseShiftingTransformer`, `TapTransformer`, `TwoTerminalHVDCLine`, `MonitoredLine`
- **DCBranch:** `TModelHVDCLine`
- **ControlledBranch:** `DiscreteControlledACBranch`
### DynamicInjection
Dynamic models for transient stability.
- **DynamicGenerator** -- synchronous machines with AVR, PSS, TurbineGovernor
- **DynamicInverter** -- inverter-based resources with converter, filter, controls
### Service
Ancillary services and system requirements.
- **Reserve:** `ConstantReserve`, `VariableReserve`, `ReserveDemandCurve`
- **AGC** -- automatic generation control
- **TransmissionInterface** -- interface flow limits
### OperationalCost
Cost structures for component operations.
- **ThermalGenerationCost** -- thermal unit costs with fuel, startup, variable O&M
- **HydroGenerationCost** -- hydro unit costs
- **RenewableGenerationCost** -- renewable unit costs
- **StorageCost** -- storage operation costs
- **MarketBidCost** -- market bid/offer curves
### TimeSeriesData
Time-varying data attached to components.
- **SingleTimeSeries** -- single scenario time series
- **Deterministic** -- deterministic forecast
- **Probabilistic** -- probabilistic forecast with scenarios
## Common Tasks
```sh
# Dev local copy
julia --project=test -e 'using Pkg; Pkg.develop(path = ".")'
# Run all tests
julia --project=test test/runtests.jl
# Run specific tests (without extension)
julia --project=test test/runtests.jl
# Example:
julia --project=test test/runtests.jl test_plant_attributes
# Build docs
julia --project=docs docs/make.jl
# Format code
julia -e 'include("scripts/formatter/formatter_code.jl")'
# Check formatting
git diff --exit-code
# Instantiate test environment
julia --project=test -e 'using Pkg; Pkg.instantiate()'
# Generate structs
julia --project=test -e "using InfrastructureSystems; InfrastructureSystems.generate_structs(\"./src/descriptors/power_system_structs.json\", \"./src/models/generated\")"
```
## PowerSystems.jl Specific Guidelines
### Julia Environment
**Always use `julia --project=test`** when running Julia code in this repository. See [Sienna.md](Sienna.md) for general Julia environment best practices. The `test/Project.toml` defines all required dependencies including PowerSystems, PowerSystemCaseBuilder, and InfrastructureSystems.
### Working with Auto-Generated Code
Component structs are auto-generated from `src/descriptors/power_system_structs.json`. Over 140 component types are auto-generated.
**DO NOT** edit files in `src/models/generated/` directly. Instead:
1. Edit `src/descriptors/power_system_structs.json` to define/modify struct fields
2. Run the generation script: `julia --project=test -e "using InfrastructureSystems; InfrastructureSystems.generate_structs(\"./src/descriptors/power_system_structs.json\", \"./src/models/generated\")"`
3. Generated files include docstrings, constructors, and accessors automatically
### PowerSystems-Specific Patterns
- **Component addition:** Use `add_component!(sys, component)` not direct insertion
- **Component retrieval:** Use `get_component(Type, sys, name)` or `get_components(Type, sys)`
- **Time series:** Always attach to components, never store standalone
- **Units:** Be mindful of `SYSTEM_BASE`, `DEVICE_BASE`, `NATURAL_UNITS` settings
- **Validation:** Use `runchecks=true` during development to catch issues early
- **Bus numbers:** Must be unique across system; validated on add
================================================
FILE: .devcontainer/devcontainer.json
================================================
{
"extensions": [
"julialang.language-julia"
],
"image": "ghcr.io/julia-vscode/julia-devcontainer"
}
================================================
FILE: .editorconfig
================================================
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Julia files
[*.jl]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
================================================
FILE: .github/copilot-setup-steps.yml
================================================
name: "Copilot Setup Steps"
on: workflow_dispatch
jobs:
copilot-setup:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Julia
uses: julia-actions/setup-julia@v2
with:
version: "1"
- name: Install documentation dependencies
run: |
julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
================================================
FILE: .github/pull_request_template.md
================================================
Thanks for opening a PR to PowerSystems.jl, please take note of the following when making a PR:
Check the [contributor guidelines](https://sienna-platform.github.io/PowerSystems.jl/stable/api/developer_guidelines/)
1. Add a description of the changes proposed in the pull request.
2. Is my PR fixing an open issue? Add the reference to the related issue
3. If you are contributing a new struct: please refer to the [testing requirements for new structs](https://sienna-platform.github.io/PowerSystems.jl/stable/how_to/add_new_types/#Testing-the-addition-of-new-struct-to-the-code-base)
================================================
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: [PowerSimulations, PowerSystemCaseBuilder, PowerNetworkMatrices, PowerFlows]
continue-on-error: true
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v2
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@v2
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/fix-docs-on-failure.yml
================================================
name: Auto-fix Documentation Failures
on:
workflow_run:
workflows: ["Documentation"]
types:
- completed
branches:
- main
permissions:
issues: write
actions: read
pull-requests: read
jobs:
open-copilot-issue:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
steps:
- name: Create or update Copilot issue for docs failure
uses: actions/github-script@v7
with:
script: |
const runId = context.payload.workflow_run.id;
const runUrl = context.payload.workflow_run.html_url;
const headSha = context.payload.workflow_run.head_sha;
const owner = context.repo.owner;
const repo = context.repo.repo;
// --- Gather failure logs ---
const { data: jobsData } = await github.rest.actions.listJobsForWorkflowRun({
owner, repo, run_id: runId, filter: 'latest',
});
let failureSummary = '';
for (const job of jobsData.jobs) {
if (job.conclusion === 'failure') {
failureSummary += `### Job: ${job.name}\n`;
failureSummary += `- **Status:** ${job.conclusion}\n`;
failureSummary += `- **URL:** ${job.html_url}\n\n`;
try {
const logResponse = await github.rest.actions.downloadJobLogsForWorkflowRun({
owner, repo, job_id: job.id,
});
const logLines = logResponse.data.split('\n');
const tail = logLines.slice(-200).join('\n');
failureSummary += 'Log tail (last 200 lines)\n\n```\n' + tail + '\n```\n\n\n';
} catch (e) {
failureSummary += `_Could not fetch logs: ${e.message}_\n\n`;
}
}
}
// --- Check for an existing open issue ---
const { data: issues } = await github.rest.issues.listForRepo({
owner, repo,
labels: 'documentation,copilot',
state: 'open',
per_page: 5,
});
const existingIssue = issues.find(i =>
i.title.startsWith('[Copilot] Fix documentation build failure')
);
// --- Check for open PRs (including drafts) already addressing docs failures ---
const { data: openPRs } = await github.rest.pulls.list({
owner, repo,
state: 'open',
per_page: 30,
});
const docFixPRs = openPRs.filter(pr => {
const title = pr.title.toLowerCase();
const body = (pr.body || '').toLowerCase();
const labels = pr.labels.map(l => l.name.toLowerCase());
return (
labels.includes('documentation') ||
title.includes('documentation') ||
/\bdocs?\b/.test(title) ||
body.includes('documentation build failure') ||
body.includes('docs/make.jl')
);
});
let prSection = '';
if (docFixPRs.length > 0) {
prSection = '### Existing PRs that may address this failure\n\n';
prSection += 'Check these open PRs (including drafts) before starting work — they may already fix some or all of the errors:\n\n';
for (const pr of docFixPRs) {
const draft = pr.draft ? ' (draft)' : '';
prSection += `- #${pr.number}${draft}: ${pr.title}\n`;
}
prSection += '\nIf an existing PR already resolves the failure, close this issue. Otherwise, coordinate with or build on the existing PR.\n\n';
}
// --- Build issue body ---
const body = [
'## Documentation build failed on `main`',
'',
`The [Documentation workflow run](${runUrl}) (run ID: \`${runId}\`) failed at commit \`${headSha}\`.`,
'',
prSection,
'### Task',
'Please investigate the documentation build failure and open a PR to fix it.',
"The documentation is built with Julia's Documenter.jl package. The build script is at `docs/make.jl`.",
'',
'### Cross-repo documentation context',
'',
'PowerSystems.jl docs are linked to other Sienna packages via [DocumenterInterLinks.jl](https://github.com/JuliaDocumenter/DocumenterInterLinks.jl).',
'The `docs/make.jl` file configures `InterLinks` to resolve `@extref` cross-references to other repos in the **Sienna-Platform** (and **NLR-Sienna**) GitHub orgs.',
'',
'**Common cross-repo causes of documentation failures:**',
'- Missing or renamed docstrings in a dependency (e.g., `InfrastructureSystems.jl`) that are referenced via `@extref`',
'- Ambiguous docstrings that are imported from another package and re-exported by PowerSystems.jl — these need disambiguation in the `@autodocs` or `@docs` blocks',
'- Broken `InterLinks` URLs when a dependency has reorganized or redeployed its documentation',
'- `ExternalFallbacks` in `docs/make.jl` that reference symbols no longer present in the upstream package',
'',
'**If the fix belongs in another repository:**',
'- Open a PR in the appropriate **Sienna-Platform/** or **NLR-Sienna/** repo (e.g., `InfrastructureSystems.jl`) to fix the upstream docstring or export',
'- Link the upstream PR in this issue and in any PowerSystems.jl PR',
'- If a temporary workaround is possible in PowerSystems.jl (e.g., updating `ExternalFallbacks`), include it and note the upstream PR that provides the permanent fix',
'',
'### Other common causes',
'- Docstring errors or missing exports in this repo',
'- Broken cross-references or links',
'- Literate.jl script errors in `docs/src/`',
'- Dependency issues in `docs/Project.toml`',
'',
'### Documentation guidelines',
'',
'Follow these guidelines when making documentation changes:',
'- [Sienna documentation practices](https://github.com/Sienna-Platform/InfrastructureSystems.jl/blob/main/.claude/Sienna.md) (see "Documentation Practices and Requirements")',
'- [Sienna docs best practices](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/docs_best_practices/explanation/)',
'- [Diataxis framework](https://diataxis.fr/)',
'',
'### Failure Details',
failureSummary,
].join('\n');
if (existingIssue) {
// Update the existing issue with new failure info
const comment = [
'## New documentation build failure',
'',
`A new failure occurred at commit \`${headSha}\`.`,
'',
`[Workflow run](${runUrl})`,
'',
prSection,
failureSummary,
].join('\n');
await github.rest.issues.createComment({
owner, repo,
issue_number: existingIssue.number,
body: comment,
});
console.log(`Updated existing issue #${existingIssue.number}`);
} else if (docFixPRs.length > 0) {
// There are already open PRs that may fix this — don't create a duplicate issue,
// just add a comment on the most recent relevant PR
const targetPR = docFixPRs[0];
await github.rest.issues.createComment({
owner, repo,
issue_number: targetPR.number,
body: [
'## Documentation build still failing on `main`',
'',
`The [Documentation workflow](${runUrl}) failed at commit \`${headSha}\`.`,
'This PR may already address the failure — please verify.',
'',
failureSummary,
].join('\n'),
});
console.log(`Commented on existing docs PR #${targetPR.number}`);
} else {
// Ensure labels exist
for (const label of ['documentation', 'copilot']) {
try {
await github.rest.issues.getLabel({ owner, repo, name: label });
} catch {
const colors = { documentation: '0075ca', copilot: 'c2e0c6' };
const descriptions = {
documentation: 'Improvements or additions to documentation',
copilot: 'Copilot agent task',
};
await github.rest.issues.createLabel({
owner, repo, name: label,
color: colors[label],
description: descriptions[label],
});
}
}
// Create a new issue
const { data: issue } = await github.rest.issues.create({
owner, repo,
title: `[Copilot] Fix documentation build failure (${headSha.slice(0, 7)})`,
body: body,
labels: ['documentation', 'copilot'],
});
// Assign the issue to Copilot to trigger the coding agent
try {
await github.rest.issues.addAssignees({
owner, repo,
issue_number: issue.number,
assignees: ['copilot'],
});
console.log(`Created issue #${issue.number} and assigned to Copilot`);
} catch (e) {
// If assigning fails, mention @copilot in a comment as fallback
console.log(`Could not assign to copilot: ${e.message}`);
await github.rest.issues.createComment({
owner, repo,
issue_number: issue.number,
body: '@copilot',
});
console.log(`Created issue #${issue.number} and mentioned @copilot in comment`);
}
}
================================================
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@v4
- 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:
schedule:
- cron: "0 0 * * 1-5"
push:
branches:
- main
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
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@v1
with:
file: ./lcov.info
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
================================================
FILE: .github/workflows/pr_testing.yml
================================================
name: Test-CI
on:
pull_request:
types: [opened, synchronize, reopened]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
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@v2
- 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@v4
with:
file: ./lcov.info
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
================================================
FILE: .gitignore
================================================
#Files generated by invoking Julia with --code-coverage
*.jl.cov
*.jl.*.cov
*.log
_*.jl
# Files generated by invoking Julia with --track-allocation
*.jl.mem
## Autogenerated code during the documentation process
generated*.md
docs/src/tutorials/generated/
*.raw
# Test data
data
# 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/
#Jupyter Ignores
.ipynb_checkpoints/
.ipynb_checkpoints
#Mac temp ignores
.DS_Store
#Figures
*.pdf
*.ipynb
Manifest.toml
.vscode
*.h5
################################################################################
# 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.
================================================
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: CHANGELOG.md
================================================
# PowerSystems Change Log
## 1.0.0 Announcement
After 1.0.0 release, the manual Changelog will no longer be maintained. Please refer to the [releases page](https://github.com/Sienna-Platform/PowerSystems.jl/releases) to follow up with the changes.
## 0.28.0
- Export additional methods
- Change System constructor that takes iterable arguments
## 0.27.0
- Change errors to warnings when validating impedance values in AC Branches
- Add Support for non-spinning reserve (Thanks @andrewrosemberg)
- Add costs to reserve products (Thanks @andrewrosemberg)
- Improvements to documentation
- Extend parsing of PSS/e dyr files
- Modifications to dynamic structs to support (min, max) tuples
## 0.26.0
- Add conversion field to HydroStorage
- Bug fix in add_component for RegulationDevice
- Add StaticReserveGroup object (Thanks @andrewrosemberg)
## 0.25.0
- Bug fix in units settings when parsing TableData
- Add defaults for ThermalStandard Fuel and Prime Mover (Thanks @raphaelsaavedra)
- Bug Fix cost data in TableData Parsing
- Bump IS version and remove type inputs to setter functions
## 0.24.1
- Add pss/e .dyr file parsing support
- Bug fixes in staturation data GENROU and GENROE
- Bug fixes in TableData parsing
## 0.24.0
- Change the use of @forward macros to avoid world of age errors
- Change DynamicMachines constructors to avoid de-serialization errors
- Change implementation of DynamicBranches
- Change implementation of RegulatioDevices
## 0.23.3
- Bug fixes in TableDataParsing
- Improvements in RegulationDevice getter functions
- Addition of get_max_reactive_power for RenewableDispatch
## 0.23.2
- Bug fixes in TableDataParsing
- Add get_max_reactive_power for RenewableGeneration with PowerFactor
## 0.23.1
- Fix bug in DynamicGenerator constructor
- Add additional get_value methods for ThermalStandard ramps
- Improve testing
## 0.23.0
- Addition of get_max_active_power, get_max_reactive_power accessor functions
- Enable serialization of DynamicLines
- Islanding detection in PTDF, LODF and Ybus calculations
- Remove MVABase field from DynamicInverter
## 0.22.0
- Addition of DynamicLines Struct
- Renames of Fields in Structs to match code guidelines
- Store RAW Electric Source Data (Z) in Thermal Generators
- Implement UnitsInfo to return data in different bases accordingly
- Update Autogeneration of structs.
## 0.21.0
- Improvements to Power Flow solve: Add Jacobian Function, add a method that modifies the system and one that returns results
- Improvements to TableData Parsing
- Add new methods to get admittance from branches
- Add Monitored Line to PTDF
## 0.20.1
- Add AC1A, ST1A, GasTG structs for dynamic modeling.
- Implement heuristic in pwl data to avoid NaN
- Bug fixes with Regulation Devices
- Improved testing.
## 0.20.0
- Add Support for MultiStart Thermal Generation (a.k.a. PGLIB Model)
- Performance updates to Power Flow.
- Remove Make PF function.
- Fixin forecast handling of composed structs
- Update to IS v0.11
- Add SalientPoleGenerator and RoundRotorGenerator with saturation variants
- Add regulation device composed with generators
- Add Basepower field to InjectionDevices in system's per unit
- Add readonly option for seralization of time series
## 0.19.0
- Update for IS 0.9
- Change behaviour of get_component
## 0.18.5
- Bug fix for serialization
## 0.18.4
- Add deepcopy method for system
## 0.18.3
- Bug fix in serialization to folder
## 0.18.2
- Fix potential miscalculation of PWL upper bound limits
## 0.18.1
- Remove warning PWL get_slope function
## 0.18.0
- Add functions to to get breakpoints and slopes from PWL cost functions
- Add getter function support for generated structs
- Enable addition of DynamicInjections to StaticInjection components and associated methods
## 0.17.2
- Add DemandCurveReserve
- Add functions to manipilate pwl cost functions
## 0.17.1
- Fix bug with frequency de-serialization
## 0.17.0
- Fix Serialization of DynamicInverter
- Fix remove_component for Area
- Add available fields for Reserves
## 0.16.0
- Changes to DynamicInverter and DynamicGenerator structs
- Bugfix in solve_powerflow!
- add option to set store location of hdf5 file
## v0.15.2
- add get_available_components method
## v0.15.1
- add has_forecasts method
## v0.15.0
- Add filtering function to get_components
- Add Parser for Texas A&M models
- Add tiime_at_status field in ThermalStandard
## v0.14.1
- Update InfrastructureSystems dependency
## v0.14.0
- Update names and contents of Dynamic Structs, RenewableGen, HydroGen and ThermalGen
## v0.13.1
- Update CSV dependency to v0.6
## v0.13.0
- Change uses of Load Zone and Area
- Add AGC service
- Remove unnecessary fields in transfer service
- Add participation factor field in TechThermal
## v0.12.0
- Make LoadZone and Area optional Bus Inputs
## v0.11.2
- Reduce warning print for unsupported columns outs when parsing data
## v0.11.1
- Change device internal forecasts field name
## v0.11.0
- Add support for Load Zones and Areas
- Add return status for power flows
- Change behavior of Matpower and PTI files parsing
## v0.10.0
- Update PTI parsing code from PM and IM
- Modify the user's interface for enums
## v0.9.1
- Update Struct autogeneration code
## v0.9.0
- Update Hydropower structs naming
## v0.8.6
- Add missing getter functions for DynamicInverter and DynamicGenerator
- Add missing getter functions for System fields.
- Add frequency field to System and DEFAULT_SYSTEM_FREQUENCY
## v0.8.5
- Add functions to handle DynamicInjection components
## v0.8.4
- Fix 7z error in Julia 1.3 and Windows
- Bugfix in pu conversion in HVDC Table Data
- Improve testing
## v0.8.3
- Update DynamicGenerator and DynamicInverter to comply with PSY
- Change get_components to support parametrized structs
- Improve testing of dynamic structs
## v0.8.2
- Update package dependencies compatibility
- Add range to struct docstrings
- Hydropower data parsing improvements
## v0.8.1
- Bugfix TableData HydroStorage
## v0.8.0
- Updated HydroDispatch and removed HydroStorage
## v0.7.1
- Bugfix services removal
## v0.7.0
- Make codebase consistent with the style guides.
- Add Dynamic Data capabilities.
- Change the use of services and store them inside of devices.
- Add ext field to devices
- Add ext field to the system
## v0.6.2
- Downgrade compatible version of CSV to 0.5.13 to avoid tab-complete hang.
- Bug Fix in docstrings autogeneration code
- Contiguous forecasts function added
## v0.6.1
- Remove bin from auto-generation code
- Updated docstrings
## v0.6.0
- Use accessor functions instead of labels to get forecasts
- Bug Fix in code autogeneration
## v0.5.2
- Enforce unique bus numbers
- Set min version of IS to 0.2.4
## v0.5.1
- Bugfix in generate_initial_times
- Bug fixes on SystemTable Data
## v0.5.0
- Store and access forecast data from Disk
## v0.4.3
- Fix Parsing bug in Table data #362
- Enable custom validation descriptors when parsing PSS/e and MATPOWER files
- Enable multiple loads per bus when parsing PSS/e and MATPOWER files
- Support multiple generators per bus and non-sequential bus indexing in power flow
## v0.4.2
- Fix printing of forecasts #350 fixing #343
## v0.1.1
- Update to Julia-v0.7
## v0.1.0
- Initial implementation
================================================
FILE: CITATION.cff
================================================
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
- family-names: "Lara"
given-names: "José Daniel"
- family-names: "Barrows"
given-names: "Clayton"
- family-names: "Thom"
given-names: "Daniel"
- family-names: "Krishnamurthy"
given-names: "Dheepak"
- family-names: "Callaway"
given-names: "Duncan"
title: "PowerSystems.jl — A power system data management package for large scale modeling"
version: 1.0.0
doi: 10.5281/zenodo.1234
date-released: 2021-09-21
url: "https://github.com/Sienna-Platform/PowerSystems.jl"
preferred-citation:
type: article
authors:
- family-names: "Lara"
given-names: "José Daniel"
- family-names: "Barrows"
given-names: "Clayton"
- family-names: "Thom"
given-names: "Daniel"
- family-names: "Krishnamurthy"
given-names: "Dheepak"
- family-names: "Callaway"
given-names: "Duncan"
title: "PowerSystems.jl — A power system data management package for large scale modeling"
journal: "SoftwareX"
volume: 15
month: 7
doi: "https://doi.org/10.1016/j.softx.2021.100747"
url: "https://www.sciencedirect.com/science/article/pii/S2352711021000765"
year: 2021
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Community driven development of this package is encouraged. To maintain code quality standards, please adhere to the following guidlines when contributing:
- To get started, sign the Contributor License Agreement.
- Please do your best to adhere to our [coding style guide](https://sienna-platform.github.io/InfrastructureSystems.jl/latest/style).
- 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 = "PowerSystems"
uuid = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd"
authors = ["Jose Daniel Lara", "Daniel Thom", "Rodrigo Henriquez-Auba", "Gabriel Konar-Steenberg", "Clayton Barrows"]
version = "5.9.1"
[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
PowerFlowData = "dd99e9e3-7471-40fc-b48d-a10501125371"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
TimeSeries = "9e3dc215-6440-5c97-bce1-76c03772f85e"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
[compat]
CSV = "~0.10"
DataFrames = "1"
DataStructures = "^0.19"
Dates = "1"
DocStringExtensions = "0.8, 0.9.2"
InfrastructureSystems = "^3.5"
InteractiveUtils = "1"
JSON3 = "1"
LinearAlgebra = "1"
Logging = "1"
PowerFlowData = "^1.5"
PrettyTables = "2.4, 3.1"
TimeSeries = "0.25"
UUIDs = "1"
Unicode = "1"
YAML = "~0.4"
julia = "^1.10"
================================================
FILE: README.md
================================================
# PowerSystems.jl
[](https://github.com/Sienna-Platform/PowerSystems.jl/actions/workflows/main-tests.yml)
[](https://codecov.io/gh/Sienna-Platform/PowerSystems.jl)
[](https://github.com/Sienna-Platform/PowerSystems.jl/actions/workflows/docs.yml)
[](https://doi.org/10.5281/zenodo.17703517)
[](https://join.slack.com/t/core-sienna/shared_invite/zt-glam9vdu-o8A9TwZTZqqNTKHa7q3BpQ)
[](http://juliapkgstats.com/pkg/PowerSystems)
The `PowerSystems.jl` package provides a rigorous data model using Julia structures to enable power systems analysis and modeling. In addition to stand-alone system analysis tools and data model building, the `PowerSystems.jl` package is used as the foundational data container for the [PowerSimulations.jl](https://github.com/Sienna-Platform/PowerSimulations.jl) and [PowerSimulationsDynamics.jl](https://github.com/Sienna-Platform/PowerSimulationsDynamics.jl) packages. `PowerSystems.jl` supports a limited number of data file formats for parsing.
## Version Advisory
- PowerSystems will work with Julia v1.6+.
## Device data enabled in PowerSystems
- Generators (Thermal, Renewable and Hydro)
- Transmission (Lines, and Transformers)
- Active Flow control devices (DC Lines and Phase Shifting Transformers)
- TwoTerminal and Multiterminal HVDC
- Topological elements (Buses, Arcs, Areas)
- Storage (Batteries)
- Load (Static, and Curtailable)
- Services (Reserves, Transfers)
- TimeSeries (Deterministic, Scenarios, Probabilistic)
- Dynamic Generators Models
- Dynamic Inverter Models
For information on using the package and a more extensive list of device data enabled, see the [stable documentation](https://sienna-platform.github.io/PowerSystems.jl/stable/). Use the [in-development documentation](https://sienna-platform.github.io/PowerSystems.jl/dev/) for the version of the documentation which contains the unreleased features.
## Parsing capabilities in PowerSystems
- MATPOWER CaseFormat
- PSS/e - PTI Format v30 (partial support), v33, v35 (.raw and .dyr files)
- [RTS-GMLC](https://github.com/GridMod/RTS-GMLC/tree/master/RTS_Data/SourceData) table data format
## Development
Contributions to the development and enhancement of PowerSystems are welcome. Please see
[CONTRIBUTING.md](https://github.com/NREL/PowerSystems.jl/blob/main/CONTRIBUTING.md) for
code contribution guidelines.
## Citing PowerSystems.jl
[Paper describing `PowerSystems.jl`](https://www.sciencedirect.com/science/article/pii/S2352711021000765)
```bibtex
@article{LARA2021100747,
title = {PowerSystems.jl — A power system data management package for large scale modeling},
journal = {SoftwareX},
volume = {15},
pages = {100747},
year = {2021},
issn = {2352-7110},
doi = {https://doi.org/10.1016/j.softx.2021.100747},
url = {https://www.sciencedirect.com/science/article/pii/S2352711021000765},
author = {José Daniel Lara and Clayton Barrows and Daniel Thom and Dheepak Krishnamurthy and Duncan Callaway},
keywords = {Power Systems, Julia, Energy}
}
```
## License
PowerSystems is released under a BSD [license](https://github.com/NREL/PowerSystems.jl/blob/main/LICENSE).
PowerSystems has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP)
initiative at the U.S. Department of Energy's National Laboratory of the Rockies ([NLR](https://www.nlr.gov/), formerly NREL) Software Record SWR-23-105.
================================================
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
ignore:
- "src/parsers/pm_io/"
- "src/parsers/im_io/"
================================================
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"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656"
DocumenterMermaid = "a078cd44-4d9c-4618-b545-3ab9d77f9177"
InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1"
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
PowerSystemCaseBuilder = "f00506e0-b84f-492a-93c2-c0a9afc4364e"
PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
TimeSeries = "9e3dc215-6440-5c97-bce1-76c03772f85e"
TypeTree = "04da0e3b-1cad-4b2c-a963-fc1602baf1af"
[compat]
CSV = "~0.10"
Documenter = "=1.15.0"
julia = "^1.10"
================================================
FILE: docs/make.jl
================================================
using Documenter, PowerSystems
import DataStructures: OrderedDict
using Literate
using DocumenterInterLinks
using DocumenterMermaid
links = InterLinks(
"InfrastructureSystems" => "https://sienna-platform.github.io/InfrastructureSystems.jl/stable/",
# Sometimes IS docstrings @extref to PSY, and sometimes those IS docstrings are included
# in the PSY reference, so we can have PSY @extref-ing to itself:
"PowerSystems" => "https://sienna-platform.github.io/PowerSystems.jl/stable/",
)
# This is a fallback for the docstrings that are referenced within IS docstrings
fallbacks = ExternalFallbacks(
"ComponentContainer" => "@extref InfrastructureSystems.ComponentContainer",
"InfrastructureSystemsComponent" => "@extref InfrastructureSystems.InfrastructureSystemsComponent"
)
# This is commented out because the output is not user-friendly. Deliberation on how to best
# communicate this information to users is ongoing.
#include(joinpath(@__DIR__, "src", "generate_validation_table.jl"))
include(joinpath(@__DIR__, "make_model_library.jl"))
include(joinpath(@__DIR__, "make_tutorials.jl"))
pages = OrderedDict(
"Welcome Page" => "index.md",
"Tutorials" => Any[
"Create and Explore a Power `System`" => "tutorials/generated_creating_system.md",
"Manipulating Data Sets" => "tutorials/generated_manipulating_datasets.md",
"Working with Time Series" => "tutorials/generated_working_with_time_series.md",
"Adding Data for Dynamic Simulations" => "tutorials/generated_add_dynamic_data.md",
],
"How to..." => Any[
"...import data" => Any[
"Parse a MATPOWER or PSS/e file" => "how_to/parse_matpower_psse.md",
"Parse PSS/e dynamic data" => "how_to/parse_dynamic_data.md",
"Build a `System` using .csv files" => "how_to/build_system_with_files.md",
"Save and read data with a JSON" => "how_to/serialize_data.md",
],
"...add a component using natural units (MW)" => "how_to/add_component_natural_units.md",
"...use context managers for bulk operations" => "how_to/use_context_managers.md",
"...add additional data to a component" => "how_to/adding_additional_fields.md",
"...add time-series data" => Any[
"Parse time series data from .csv files" => "how_to/parse_ts_from_csvs.md",
"Improve performance with time series data" => "how_to/improve_ts_performance.md",
],
"...add cost data" => Any[
"Add an Operating Cost" => "how_to/add_cost_curve.md",
"Add a market bid" => "how_to/market_bid_cost.md",
"Add costs for imported/exported power" => "how_to/create_system_with_source_import_export_cost.md",
"Add time series fuel costs" => "how_to/add_fuel_curve_timeseries.md",
],
"...customize or add a new Type" => "how_to/add_new_types.md",
"...define hydro generators with reservoirs" => "how_to/create_hydro_datasets.md",
"...handle 3-Winding Transformers" => "how_to/handle_3W_transformers.md",
"...use PowerSystems.jl with JuMP.jl" => "how_to/jump.md",
"...reduce REPL printing" => "how_to/reduce_repl_printing.md",
"...update to a new `PowerSystems.jl` version" => Any[
"Migrate from version 4.0 to 5.0" => "how_to/migrating_to_psy5.md",
],
],
"Explanation" =>
Any[
"explanation/system.md",
"explanation/type_structure.md",
"explanation/buses_type_explanation.md",
"explanation/per_unit.md",
"explanation/power_concepts.md",
"explanation/conforming_and_non_conforming_loads.md",
"explanation/transformer_per_unit_models.md",
"explanation/time_series.md",
"explanation/dynamic_data.md",
"explanation/supplemental_attributes.md",
"explanation/plant_attributes.md",
],
"Model Library" => Any[],
"Reference" =>
Any["Public API" => "api/public.md",
"Glossary and Acronyms" => "api/glossary.md",
"Type Tree" => "api/type_tree.md",
"`ValueCurve` Options" => "api/valuecurve_options.md",
"Specifying the category of..." => "api/enumerated_types.md",
"Supported PSS/e Models" => "api/psse_models.md",
"Comparison of Load, Generator, and Storage Types" => "api/static_injection_subtypes.md",
"Citation" => "api/citation.md",
"Developers" => ["Developer Guidelines" => "api/developer_guidelines.md",
"Internals" => "api/internal.md"]
]
)
pages["Model Library"] = make_model_library(
categories = [
Topology,
StaticInjection,
Service,
Branch,
DynamicInjection,
],
exceptions = [PSY.DynamicComponent,
PSY.ActivePowerControl,
PSY.ReactivePowerControl,
PSY.DynamicBranch,
PSY.HybridSystem,
PSY.OperationalCost,
PSY.DynamicInverter,
PSY.DynamicGenerator,
],
manual_additions =
Dict("Service" => ["Reserves" => "model_library/reserves.md"],
"StaticInjection" => ["HybridSystem" => "model_library/hybrid_system.md"],
"DynamicInjection" => ["Dynamic Inverter" => "model_library/dynamic_inverter.md",
"Dynamic Generator" => "model_library/dynamic_generator.md",
],
"Branch" => ["Dynamic Lines" => "model_library/dynamic_branch.md"],
"Operating Costs" => ["ThermalGenerationCost" =>"model_library/thermal_generation_cost.md",
"HydroGenerationCost" =>"model_library/hydro_generation_cost.md",
"HydroReservoirCost" =>"model_library/hydro_reservoir_cost.md",
"RenewableGenerationCost" =>"model_library/renewable_generation_cost.md",
"StorageCost" =>"model_library/storage_cost.md",
"LoadCost" =>"model_library/load_cost.md",
"MarketBidCost" =>"model_library/market_bid_cost.md",
"ImportExportCost" =>"model_library/import_export_cost.md",
"OfferCurveCost" =>"model_library/offer_curve_cost.md"],
"HydroReservoir" => "model_library/hydro_reservoir.md",
)
)
# clean_old_generated_files and insert_md are now defined in make_tutorials.jl
# They are used here for other sections (Model Library, Explanation, How to...)
# This code performs the automated addition of Literate - Generated Markdowns. The desired
# section name should be the name of the file for instance network_matrices.jl -> Network Matrices
julia_file_filter = x -> occursin(".jl", x)
folders = Dict(
"Model Library" => filter(julia_file_filter, readdir("docs/src/model_library")),
"Explanation" => filter(julia_file_filter, readdir("docs/src/explanation")),
"How to..." => filter(julia_file_filter, readdir("docs/src/how_to")),
)
# Clean up old generated files in folders before Literate generates new ones
# Note: model_library is cleaned by make_model_library.jl before it generates files,
# so we only clean explanation and how_to directories here
for (section, folder) in folders
# Skip model_library as it's already cleaned by make_model_library()
section == "Model Library" && continue
section_folder_name = lowercase(replace(section, " " => "_"))
outputdir = joinpath(pwd(), "docs", "src", "$section_folder_name")
clean_old_generated_files(outputdir)
end
# Process other sections (Model Library, Explanation, How to...)
for (section, folder) in folders
for file in folder
@show file
section_folder_name = lowercase(replace(section, " " => "_"))
inputfile = joinpath("$section_folder_name", "$file")
infile_path = joinpath(pwd(), "docs", "src", inputfile)
execute = occursin("EXECUTE = TRUE", uppercase(readline(infile_path))) ? true : false
execute && include(infile_path)
outputdir = joinpath(pwd(), "docs", "src", "$section_folder_name")
outputfile = string("generated_", replace("$file", ".jl" => ""))
# Generate markdown
Literate.markdown(infile_path,
outputdir;
name = outputfile,
credit = false,
flavor = Literate.DocumenterFlavor(),
documenter = true,
postprocess = insert_md,
execute = execute)
subsection = titlecase(replace(split(file, ".")[1], "_" => " "))
push!(pages[section], ("$subsection" => joinpath("$section_folder_name", "$(outputfile).md")))
end
end
# Process tutorials separately with Literate
make_tutorials()
makedocs(
modules = [PowerSystems],
format = Documenter.HTML(
prettyurls = haskey(ENV, "GITHUB_ACTIONS"),
size_threshold = nothing,),
sitename = "PowerSystems.jl",
authors = "Jose Daniel Lara, Daniel Thom, Kate Doubleday, Rodrigo Henriquez-Auba, and Clayton Barrows",
pages = Any[p for p in pages],
draft = false,
plugins = [links, fallbacks],
)
deploydocs(
repo = "github.com/Sienna-Platform/PowerSystems.jl.git",
target = "build",
branch = "gh-pages",
devbranch = "main",
devurl = "dev",
push_preview=true,
versions = ["stable" => "v^", "v#.#"],
)
================================================
FILE: docs/make_model_library.jl
================================================
using InteractiveUtils
import InfrastructureSystems as IS
import PowerSystems as PSY
function _clean_old_generated_files(dir::String)
# Remove old generated_*.md files before creating new ones
if !isdir(dir)
@warn "Directory does not exist: $dir"
return
end
generated_files = filter(f -> startswith(f, "generated_") && endswith(f, ".md"), readdir(dir))
for file in generated_files
rm(joinpath(dir, file), force=true)
@info "Removed old generated file: $file"
end
end
function _check_exception(T, exceptions::Vector)
for type_exception in exceptions
if T <: type_exception
return true
end
end
return false
end
function _write_first_level_markdown(c::String)
file_name = "model_library/generated_$(c).md"
open(joinpath("docs/src", file_name), "w") do io
print(
io,
"""
# $(c)
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/$(c).jl"]
Order = [:type, :function]
Public = true
Private = false
```
""",
)
end
return file_name
end
function _write_second_level_markdown(input::DataType, subtypes::Vector{DataType}, exceptions)
c = string(nameof(input))
file_name = "model_library/generated_$(c).md"
open(joinpath("docs/src", file_name), "w") do io
print(io, "# $input\n\n")
for T_ in subtypes
_check_exception(T_, exceptions) && continue
T = string(nameof(T_))
print(
io,
"""
## $(T)
```@autodocs
Modules = [PowerSystems]
Pages = ["/$(T).jl"]
Order = [:type, :function]
Public = true
Private = false
```
""",
)
end
end
return file_name
end
function make_dynamics_library!(model_library;
dyn_categories =[
PSY.DynamicGeneratorComponent,
PSY.DynamicInverterComponent,
],
exceptions = [PSY.OuterControl,
PSY.ActivePowerControl,
PSY.ReactivePowerControl,],
manual_additions = Dict{String, Any}("DynamicInverterComponent" => Any["OuterControl" => "model_library/outer_control.md"])
)
for abstract_type in dyn_categories
@info "Making entries for subtypes of $abstract_type"
abstract_type_string = string(nameof(abstract_type))
addition = Dict{String, Any}()
internal_index = Any[]
for c_ in subtypes(abstract_type)
c_string = string(nameof(c_))
_check_exception(c_, exceptions) && continue
concretes = IS.get_all_concrete_subtypes(c_)
file_name = _write_second_level_markdown(c_,
concretes, exceptions)
push!(internal_index, c_string => file_name)
end
push!(model_library, abstract_type_string => internal_index)
if haskey(manual_additions, abstract_type_string)
addition = get(manual_additions, abstract_type_string, nothing)
push!(model_library[abstract_type_string], addition...)
end
end
end
function make_model_library(;
categories = [],
exceptions = [],
manual_additions = Dict{String, Any}()
)
# Clean up old generated files before creating new ones
_clean_old_generated_files(joinpath("docs", "src", "model_library"))
model_library = Dict{String, Any}()
for abstract_type in categories
@info "Making entries for subtypes of $abstract_type"
internal_index = Any[]
concrete = IS.get_all_concrete_subtypes(abstract_type)
for c_ in concrete
_check_exception(c_, exceptions) && continue
c = string(nameof(c_))
file_name = _write_first_level_markdown(c)
push!(internal_index, c => file_name)
end
isempty(internal_index) && continue
model_library[string(nameof(abstract_type))] = internal_index
end
make_dynamics_library!(model_library)
for (k, v) in manual_additions
if haskey(model_library, k)
push!(model_library[k], v...)
else
model_library[k] = v
end
end
return Any[p for p in model_library]
end
================================================
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/PowerSystems.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\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 ` 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 (Literate often emits
……
).
#
]*> — opening
and attributes
# [\s\S]*? — any chars, non-greedy, up to the first — from
p_with_img_pattern = r"
]*>[\s\S]*?"
# 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 not already covered by the
……
case above.
# ]*? — attributes; /?> — self-closing or >
standalone_img_pattern = r"]*?/?>"
# 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/citation.md
================================================
### Citation
Users are requested to please cite the
[following paper:](https://www.sciencedirect.com/science/article/pii/S2352711021000765)
```bibtex
@article{LARA2021100747,
title = {PowerSystems.jl — A power system data management package for large scale modeling},
journal = {SoftwareX},
volume = {15},
pages = {100747},
year = {2021},
issn = {2352-7110},
doi = {https://doi.org/10.1016/j.softx.2021.100747},
url = {https://www.sciencedirect.com/science/article/pii/S2352711021000765},
author = {José Daniel Lara and Clayton Barrows and Daniel Thom and Dheepak Krishnamurthy and Duncan Callaway},
keywords = {Power Systems, Julia, Energy},
```
PowerSystems has been developed as part of the [Sienna platform](https://www.nlr.gov/analysis/sienna.html)
by the U.S. Department of Energy's National Laboratory of the Rockies
([NLR](https://www.nlr.gov/), formerly NREL).
================================================
FILE: docs/src/api/developer_guidelines.md
================================================
# Developer Guidelines
In order to contribute to `PowerSystems.jl` repository please read the following sections of
[`InfrastructureSystems.jl`](https://github.com/Sienna-Platform/InfrastructureSystems.jl)
documentation in detail:
1. [Style Guide](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/style/)
2. [Contributing Guidelines](https://github.com/Sienna-Platform/PowerSystems.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/enumerated_types.md
================================================
# Specifying the type of...
Some fields in PowerSystems.jl are specified with an option from a pre-defined list
(Specified with [`IS.scoped_enums`](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/InfrastructureSystems/#InfrastructureSystems.@scoped_enum-Tuple%7BAny,%20Vararg%7BAny,%20N%7D%20where%20N%7D)).
Example syntax:
```
set_fuel!(gen, ThermalFuels.COAL)
```
These predefined lists are below:
## [AC Buses](@id acbustypes_list)
`ACBusTypes` categorize buses for modeling activities and denote which quantities are specified
for load flow calculations. `ACBusTypes` has the options:
| Name | Description |
|:---------- |:---------------------------------------------------------- |
| `ISOLATED` | Disconnected from network |
| `PQ` | Active and reactive power defined (load bus) |
| `PV` | Active power and voltage magnitude defined (generator bus) |
| `REF` | Reference bus (θ = 0) |
| `SLACK` | Slack bus |
## [Prime Movers](@id pm_list)
Each generator contains a field for `prime_mover::PrimeMovers`, based on the options in
[EIA form 923](https://www.eia.gov/survey/form/eia_923/instructions.pdf).
`PrimeMovers` has the options:
| Name | Description |
|:----- |:------------------------------------------------------------------------------------------------------ |
| `BA` | Energy Storage, Battery |
| `BT` | Turbines Used in a Binary Cycle (including those used for geothermal applications) |
| `CA` | Combined-Cycle – Steam Part |
| `CC` | Combined-Cycle - Aggregated Plant *augmentation of EIA |
| `CE` | Energy Storage, Compressed Air |
| `CP` | Energy Storage, Concentrated Solar Power |
| `CS` | Combined-Cycle Single-Shaft Combustion turbine and steam turbine share a single generator |
| `CT` | Combined-Cycle Combustion Turbine Part |
| `ES` | Energy Storage, Other |
| `FC` | Fuel Cell |
| `FW` | Energy Storage, Flywheel |
| `GT` | Combustion (Gas) Turbine (including jet engine design) |
| `HA` | Hydrokinetic, Axial Flow Turbine |
| `HB` | Hydrokinetic, Wave Buoy |
| `HK` | Hydrokinetic, Other |
| `HY` | Hydraulic Turbine (including turbines associated with delivery of water by pipeline) |
| `IC` | Internal Combustion (diesel, piston, reciprocating) Engine |
| `PS` | Energy Storage, Reversible Hydraulic Turbine (Pumped Storage) |
| `OT` | Other |
| `ST` | Steam Turbine (including nuclear, geothermal and solar steam; does not include combined-cycle turbine) |
| `PVe` | Photovoltaic \(*Note*: renaming from EIA PV to PVe to avoid conflict with `ACBusType.PV`\) |
| `WT` | Wind Turbine, Onshore |
| `WS` | Wind Turbine, Offshore |
## [Fuels for Thermal Generators](@id tf_list)
Each [`ThermalGen`](@ref) generator has a field for `fuel::ThermalFuels` where `ThermalFuels`
are intended to reflect the options in the
[Aggregated Fuel Codes](https://www.eia.gov/survey/form/eia_923/instructions.pdf) from the
EIA Annual Energy Review. `ThermalFuels` has the options:
| Name | EIA Fuel Code | Description |
|:---------------------------------------------------------------------------------------------------------------------------------- |:------------- |:----------------------------------------------------------------------------------------------------------------------------------- |
| `ANTHRACITE_COAL` | ANT | Anthracite Coal |
| `BITUMINOUS_COAL` | BIT | Bituminous Coal |
| `LIGNITE_COAL` | LIG | Lignite Coal |
| `SUBBITUMINOUS_COAL` | SUB | Subbituminous Coal |
| `WASTE_COAL` | WC | Waste/Other Coal (including anthracite culm, bituminous gob, fine coal, lignite waste, waste coal) |
| `REFINED_COAL` | RC | Refined Coal (A coal product that improves heat content and reduces emissions. Excludes coal processed by coal preparation plants.) |
| `SYNTHESIS_GAS_COAL` | SGC | Coal-Derived Synthesis Gas |
| `DISTILLATE_FUEL_OIL` | DFO | Distillate Fuel Oil (including diesel, No. 1, No. 2, and No. 4 fuel oils) |
| `JET_FUEL` | JF | Jet Fuel |
| `KEROSENE` | KER | Kerosene |
| `PETROLEUM_COKE` | PC | Petroleum Coke |
| `RESIDUAL_FUEL_OIL` | RFO | Residual Fuel Oil (including No. 5 and No. 6 fuel oils, and bunker C fuel oil) |
| `PROPANE` | PG | Propane, gaseous |
| `SYNTHESIS_GAS_PETROLEUM_COKE` | SGP | Petroleum Coke Derived Synthesis Gas |
| `WASTE_OIL` | WO | Waste/Other Oil (including crude oil, liquid butane, liquid propane, naphtha, oil waste, re-refined motor oil, sludge oil, tar oil) |
| `BLASTE_FURNACE_GAS` | BFG | Blast Furnace Gas |
| `NATURAL_GAS` | NG | Natural Gas |
| `OTHER_GAS` | OG | Other Gas |
| `AG_BYPRODUCT` | AB | Agricultural By-products |
| `MUNICIPAL_WASTE` | MSW | Municipal Solid Waste |
| `OTHER_BIOMASS_SOLIDS` | OBS | Other Biomass Solids |
| `WOOD_WASTE_SOLIDS` | WDS | Wood/Wood Waste Solids (including paper, pellets, railroad ties, utility poles, wood chips, bark, and wood waste solids) |
| `OTHER_BIOMASS_LIQUIDS` | OBL | Other Biomass Liquids |
| `SLUDGE_WASTE` | SLW | Sludge Waste |
| `BLACK_LIQUOR` | BLQ | Black Liquor |
| `WOOD_WASTE_LIQUIDS` | WDL | Wood Waste Liquids excluding Black Liquor (includes red liquor, sludge wood, spent sulfite liquor, and other wood-based liquids) |
| `LANDFILL_GAS` | LFG | Landfill Gas |
| `OTHEHR_BIOMASS_GAS` | OBG | Other Biomass Gas (includes digester gas, methane, and other biomass gasses) |
| `NUCLEAR` | NUC | Nuclear Uranium, Plutonium, Thorium |
| `WASTE_HEAT` | WH | Waste heat not directly attributed to a fuel source |
| `TIREDERIVED_FUEL` | TDF | Tire-derived Fuels |
| `COAL`* | N/A | General Coal Fuels |
| `Geothermal`* | GEO | Geothermal Fuels |
| `OTHER` | OTH | Other type of fuel |
| *Asterisk denotes fuel codes not directly from the current EIA 923 form but kept for compatibility with older versions of the form | | |
## [Energy Storage](@id storagetech_list)
`StorageTech` defines the storage technology used in an energy [`Storage`](@ref) system, based
on the options in [EIA form 923](https://www.eia.gov/survey/form/eia_923/instructions.pdf).
`StorageTech` has the options:
| Name | Description |
|:------------- |:----------------------------- |
| `PTES` | Pumped thermal energy storage |
| `LIB` | LiON Battery |
| `LAB` | Lead Acid Battery |
| `FLWB` | Redox Flow Battery |
| `SIB` | Sodium Ion Battery |
| `ZIB` | Zinc Ion Battery |
| `HGS` | Hydrogen Gas Storage |
| `LAES` | Liquid Air Storage |
| `OTHER_CHEM` | Other Chemical Storage |
| `OTHER_MECH` | Other Mechanical Storage |
| `OTHER_THERM` | Other Thermal Storage |
## [Hydro Reservoir Units](@id hydroreservoir_list)
`ReservoirDataType` specifies which units of measurement for a
[`HydroReservoir`](@ref)'s `level`-related parameters (e.g., `level_targets`,
`storage_level_limits`). It defines the units used to perform energy balance
calculations for a [`HydroReservoir`](@ref) and affects how the totals and targets are calculated.
The user is responsible for correctly managing data conversions when switching between
the different alternatives of `ReservoirDataType`, which has the options:
| Name | Units | Description |
|:--------------- |:----- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `USABLE_VOLUME` | m^3 | The volume of water that can be stored for levels between the penstock intake and the top reservoir level |
| `TOTAL_VOLUME` | m^3 | The total volume of the reservoir considering a total depletion of the water levels. This unit system usually requires the specification of a valid minimum volume level |
| `HEAD` | m | The difference in elevations between the top water levels. It requires a valid conversion constant to go from head to potential energy stored. |
| `ENERGY` | MWh | Uses energy units in MWh to approximate the water storage as a generic energy reservoir. |
## [Facts Control Devices](@id factsmodes_list)
`FACTSOperationModes` define the operation modes of a [`FACTSControlDevice`](@ref).
`FACTSOperationModes` has the options:
| Name | Description |
|:----- |:----------------------------------------------------------------------------------------------- |
| `OOS` | Out-Of-Service (i.e., Series and Shunt links open) |
| `NML` | Normal mode of operation, where Series and Shunt links are operating |
| `BYP` | Series link is bypassed (i.e., like a zero impedance line) and Shunt link operates as a STATCOM |
## [Load Conformity](@id loadconform_list)
`LoadConformity` defines whether a load is
[conforming or non-nonforming](@ref conf_loads). `LoadConformity` has the options:
| Name | Description |
|:---------------- |:----------------------------------------------------------------- |
| `NON_CONFORMING` | Non-conforming load |
| `CONFORMING` | Conforming load |
| `UNDEFINED` | Undefined or unknown whether load is conforming or non-conforming |
## [Tranformer Control Objectives](@id xtf_crtl)
`TransformerControlObjective` is used to select the control objective for a transformer's
tap changer, which can be used to determine the tap position during power flow calculations.
| Name | Description |
|:--------------------------------------- |:------------------------------------------------------------------------- |
| `UNDEFINED` | Undefined |
| `VOLTAGE_DISABLED` | Has voltage control capabilities, which are disabled |
| `REACTIVE_POWER_FLOW_DISABLED` | Has reactive power flow control capabilities, which are disabled |
| `ACTIVE_POWER_FLOW_DISABLED` | Has active power flow control capabilities, which are disabled |
| `CONTROL_OF_DC_LINE_DISABLED` | Has capabilities to control a DC line quantity, which are disabled |
| `ASYMMETRIC_ACTIVE_POWER_FLOW_DISABLED` | Has asymmetric active power flow control capabilities, which are disabled |
| `FIXED` | Fixed tap and fixed phase shift |
| `VOLTAGE` | Voltage control |
| `REACTIVE_POWER_FLOW` | Reactive power flow control |
| `ACTIVE_POWER_FLOW` | Active power flow control |
| `CONTROL_OF_DC_LINE` | Control of a DC line quantity |
| `ASYMMETRIC_ACTIVE_POWER_FLOW` | Asymmetric active power flow control |
## [Dynamic States](@id states_list)
`StateTypes` are used to denote the type of dynamic equation a specific [state](@ref S) is subject
to in [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/).
`StateTypes` has the options:
| Name | Description |
|:-------------- |:-------------------------------------------------------------------------------- |
| `Differential` | State evolves over time via a differential equation ``\dot{x} = f(x)`` |
| `Algebraic` | State evolves over time by satisfying an algebraic equation ``0 = g(x)`` |
| `Hybrid` | Depending on specific parameters, the state can be `Differential` or `Algebraic` |
## [Angle Units](@id angleunits_list)
`AngleUnits` can be specified in:
| Name |
|:--------- |
| `DEGREES` |
| `RADIANS` |
## [Motor Load Technologies](@id motor_list)
| Name |
|:-------------- |
| `INDUCTION` |
| `SYNCHRONOUS` |
| `UNDETERMINED` |
================================================
FILE: docs/src/api/glossary.md
================================================
# Glossary and Acronyms
[A](@ref) | [D](@ref) | [E](@ref) | [F](@ref) | [H](@ref) | [I](@ref) | [O](@ref) | [P](@ref) | [R](@ref) |
[S](@ref) | [V](@ref) | [W](@ref) | [Z](@ref)
### A
- *AC*: Alternating current
- *ACE*: Area control error
- *AGC*: Automatic generation control
- *AVR*: Automatic Voltage Regulator
### D
- *DC*: Direct current
- *DERA1*:
- *Dynamic*: Refers to data and simulations for power system transient simulations using differential
equations. Common examples include signal stability analysis to verify the power system will
maintain stability in the few seconds following an unexpected fault or generator trip. For contrast,
see the definition for [Static](@ref S) data.
### E
- *EMF*: Electromotive force
- *ESAC*: IEEE Type AC Excitation System model
- *ESDC*: IEEE Type DC Excitation System model
- *EXAC*: IEEE Type AC Excitation System (modified) model
- *EXPIC*: Proportional/Integral Excitation System from PSS/E
- *EXST*: IEEE Type ST (Static) Excitation System model
- *EX4VSA*: IEEE Excitation System for Voltage Security Assessment with Over-Excitation Limits.
### F
- *Forecast*: Predicted values of a time-varying quantity that commonly features
a look-ahead and can have multiple data values representing each time period.
This data is used in simulation with receding horizons or data generated from
forecasting algorithms. See the article on [`Time Series Data`](@ref ts_data).
- *Forecast window*: Represents the forecasted value starting at a particular initial time.
See the article on [`Time Series Data`](@ref ts_data).
### H
- *Horizon*: Is the duration of all time steps in one forecast. As of PowerSystems.jl
version 4.0, all horizons in `PowerSystems.jl` are represented as a `Dates.Period`.
For instance, many Day-ahead markets will have an hourly-[resolution](@ref R) forecast
for the next day, which would have a horizon of `Dates.Hour(24)` or `Dates.Day(1)`. If the
forecast included the next day plus a 24-hour lookahead window, the horizon would be
`Dates.Hour(48)` or `Dates.Day(2)`. See the article on [`Time Series Data`](@ref ts_data).
- *HVDC*: High-voltage DC
### I
- *IEEET*: IEEE Type I Excitation System.
- *Injector* or *Injection*: Injectors refer to models that represent how a generator or storage
device *injects* power or current into the power system. Loads are negative injectors. In
`PowerSystems.jl`, some components can accept data for both [`StaticInjection`](@ref) and
[`DynamicInjection`](@ref) models for both [static](@ref S) and [dynamic](@ref D) modeling.
- *Interval*: The period of time between forecast initial times. In `PowerSystems.jl` all
intervals are represented using `Dates.Period` types. For instance, in a Day-Ahead market
simulation, the interval is usually `Hour(24)`.
- *Initial time*: The first time-stamp in a forecast window. See the article on
[`Time Series Data`](@ref ts_data).
- *IPC*: Interconnecting power converter
### L
- *LCC*: Line Commutated Converter HVDC line
### O
- *OEL*: Over Excitation Limiter
### P
- *PLL*: Phase-locked loop
- *PSS*: Power System Stabilizer
- *PSSE* or *PSS/E*: Siemens' PSS®E Power System Simulator for Engineering
- *PPA*: Power purchase agreement
- *PSI*: [`PowerSimulations.jl`](https://sienna-platform.github.io/PowerSimulations.jl/latest/)
- *PSID*: [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/)
- *PSLF*: GE Vernova's Positive Sequence Load Flow Software
- *PSY*: `PowerSystems.jl` (this package)
- *pu* or *p.u.*: Per-unit
### R
- *REECB1*: Renewable Energy Electric Controller Type B1
- *REPCA1*: REPCA1: Renewable Energy Power Controller Type A1
- *Resolution*: The period of time between each discrete value in a time series. All resolutions
are represented using `Dates.Period` types. For instance, a Day-ahead market data set usually
has a resolution of `Hour(1)`, a Real-Time market data set usually has a resolution of `Minute(5)`.
### S
- *SCRX*: Bus Fed or Solid Fed Static Exciter
- *SEXS*: Simplified Excitation System model from PSS/E
- *SIL*: Surge impedance loading
- *States*: Correspond to the set of inputs, outputs or variables, that evolve dynamically in
[`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/),
commonly via a differential-algebraic system of equations. In `PowerSystems.jl`, a component
associated to a `DynamicInjector` (for example an AVR) specifies the set of states that specific
component requires to be modeled accurately.
- *Static*: Typically refers to steady state data or models where the power system
and each of its components are assumed to be operating at a steady state equilibrium point. This
includes both power flow data for a single time point simulation as well as quasi-static time
series data and models, where the power system is at an equilibrium point at each time step.
Static data can be used as the input to single time point power flow models and production
cost models with, for example, 5-minute, 15-minute, or 1-hour [Resolution](@ref R).
For contrast, see the definition for [Dynamic](@ref D) data.
- *STAB*: Speed Sensitive Stabilizing PSS Model
### V
- *VSCLine*: Voltage-Source Converter HVDC Line
- *VSM*: Virtual Synchronous Machine
### W
- *Window*: A forecast window is one forecast run that starts at one [initial time](@ref I)
and extends through the forecast [horizon](@ref H). Typically, a forecast data set
contains multiple forecast windows, with sequential initial times. For example, a
year-long data set of day-ahead forecasts contains 365 forecast windows
### Z
- *ZIP load*: A ZIP load model accounts for the voltage-dependency of a load and is primarily used
for dynamics modeling. It includes three kinds of load: constant impedance (Z), constant current (I),
and constant power (P), though many dynamics models just use the constant impedance model.
[`StandardLoad`](@ref) and [`ExponentialLoad`](@ref) are both ZIP load models:
[`StandardLoad`](@ref) breaks up the load into each of its three components, while
[`ExponentialLoad`](@ref) expresses the load as an exponential equation.
================================================
FILE: docs/src/api/internal.md
================================================
```@meta
CollapsedDocStrings = true
```
# Internal API
```@autodocs
Modules = [PowerSystems]
Public = false
```
================================================
FILE: docs/src/api/psse_models.md
================================================
# [Supported PSS/e Models](@id psse_models_ref)
PSS/e's dynamic model library is extensive. `PowerSystems.jl` currently supports parsing the following models for version 5.0:
## Dynamic Generator Models
### Machine Models
| PSS/e Model | PowerSystems Component |
|:----------- |:-------------------------------- |
| GENSAE | [`SalientPoleExponential`](@ref) |
| GENSAL | [`SalientPoleQuadratic`](@ref) |
| GENROE | [`RoundRotorExponential`](@ref) |
| GENCLS | [`BaseMachine`](@ref) |
| GENROU | [`RoundRotorQuadratic`](@ref) |
### Automatic Voltage Regulator (AVR) Models
| PSS/e Model | PowerSystems Component |
|:----------- |:---------------------- |
| IEEET1 | [`IEEET1`](@ref) |
| ESDC1A | [`ESDC1A`](@ref) |
| ESDC2A | [`ESDC2A`](@ref) |
| ESAC1A | [`ESAC1A`](@ref) |
| ESAC6A | [`ESAC6A`](@ref) |
| ESAC8B | [`ESAC8B`](@ref) |
| EXAC1 | [`EXAC1`](@ref) |
| EXAC1A | [`EXAC1A`](@ref) |
| EXAC2 | [`EXAC2`](@ref) |
| EXPIC1 | [`EXPIC1`](@ref) |
| ESST1A | [`ESST1A`](@ref) |
| ESST4B | [`ESST4B`](@ref) |
| SCRX | [`SCRX`](@ref) |
| SEXS | [`SEXS`](@ref) |
| EXST1 | [`EXST1`](@ref) |
| ST6B | [`ST6B`](@ref) |
| ST8C | [`ST8C`](@ref) |
### Turbine Governor Models
| PSS/e Model | PowerSystems Component |
|:----------- |:-------------------------- |
| GAST | [`GasTG`](@ref) |
| GGOV1 | [`GeneralGovModel`](@ref) |
| HYGOV | [`HydroTurbineGov`](@ref) |
| IEEEG1 | [`IEEETurbineGov1`](@ref) |
| TGOV1 | [`SteamTurbineGov1`](@ref) |
| TGOV1DU | [`SteamTurbineGov1`](@ref) |
| DEGOV1 | [`DEGOV1`](@ref) |
| PIDGOV | [`PIDGOV`](@ref) |
| WPIDHY | [`WPIDHY`](@ref) |
### Power System Stabilizer (PSS) Models
| PSS/e Model | PowerSystems Component |
|:----------- |:---------------------- |
| IEEEST | [`IEEEST`](@ref) |
| STAB1 | [`STAB1`](@ref) |
## Dynamic Inverter Models
### Converter Models
| PSS/e Model | PowerSystems Component |
|:----------- |:--------------------------------------- |
| REGCA1 | [`RenewableEnergyConverterTypeA`](@ref) |
### Active and Reactive Power Control Models
| PSS/e Model | PowerSystems Component |
|:----------- |:----------------------------------------------------------------------------------------------------------- |
| REECB1 | [`ActiveRenewableControllerAB`](@ref), [`ReactiveRenewableControllerAB`](@ref), [`RECurrentControlB`](@ref) |
| REPCA1 | [`ActiveRenewableControllerAB`](@ref), [`ReactiveRenewableControllerAB`](@ref) |
## Additional Models
| PSS/e Model | PowerSystems Component |
|:----------- |:----------------------------------------- |
| DERA1 | [`AggregateDistributedGenerationA`](@ref) |
## See also
- Parsing [PSS/e dynamic data](@ref dyr_data)
- Parsing [Matpower or PSS/e RAW Files](@ref pm_data)
================================================
FILE: docs/src/api/public.md
================================================
# Public API Reference
## Modeling
```@autodocs
Modules = [PowerSystems]
Pages = ["PowerSystems.jl",
"branches.jl",
"components.jl",
"injection.jl",
"devices.jl",
"loads.jl",
"supplemental_constructors",
"generation.jl",
"reserves.jl",
"storage.jl",
"services.jl",
"topological_elements.jl",
"dynamic_models.jl",
"static_models.jl",
"subsystems.jl",
"static_injection_subsystem.jl",
"dynamic_models.jl",
"operational_cost.jl",
"cost_function_timeseries.jl",
"definitions.jl"
]
Public = true
Private = false
```
## Supplemental Attributes
```@autodocs
Modules = [PowerSystems]
Pages = ["outages.jl",
"contingencies.jl",
"impedance_correction.jl",
"plant_attribute.jl"
]
Public = true
Private = false
```
```@autodocs
Modules = [IS]
Pages = ["geographic_supplemental_attribute.jl"
]
Order = [:type, :function]
Filter = t -> nameof(t) in names(PowerSystems)
```
## Operating Costs
```@autodocs
Modules = [IS]
Pages = ["production_variable_cost_curve.jl",
"cost_aliases.jl",
"value_curve.jl",
]
Order = [:type, :function]
Filter = t -> nameof(t) in names(PowerSystems)
```
## Time Series
```@autodocs
Modules = [IS]
Pages = ["abstract_time_series.jl",
"deterministic.jl",
"deterministic_single_time_series.jl",
"probabilistic.jl",
"scenarios.jl",
"static_time_series.jl",
"single_time_series.jl",
"forecasts.jl",
]
Order = [:type, :function]
Filter = t -> nameof(t) in names(PowerSystems)
```
```@autodocs
Modules = [IS]
Pages = ["time_series_cache.jl",
"time_series_interface.jl",
"time_series_structs.jl",
"time_series_storage.jl",
"time_series_parser.jl",
"utils/print.jl"]
Order = [:type, :function]
Filter = t -> nameof(t) in names(PowerSystems)
```
## System
```@autodocs
Modules = [PowerSystems]
Pages = ["get_components_interface.jl", "base.jl"]
Public = true
Private = false
Filter = t -> t ∈ [System]
```
```@autodocs
Modules = [PowerSystems]
Pages = ["get_components_interface.jl", "base.jl"]
Public = true
Private = false
Filter = t -> t ∉ [System]
```
```@autodocs
Modules = [PowerSystems]
Pages = ["utils/print.jl",
"utils/generate_struct_files.jl"]
Public = true
Private = false
Filter = t -> t ∉ [System]
```
## Advanced Component Selection
The primary way to retrieve components in PowerSystems.jl is with the [`get_components`](@ref) and similar `get_*` methods above. The following `ComponentSelector` interface offers advanced, repeatable component selection primarily for multi-scenario post-processing analytics. See [`PowerAnalytics.jl`](https://sienna-platform.github.io/PowerAnalytics.jl/stable/).
```@autodocs
Modules = [IS]
Pages = ["component_selector.jl"]
Filter = t -> !(t isa AbstractString) && nameof(t) in names(PowerSystems) && getproperty(PowerSystems, nameof(t)) === t && !(nameof(t) in [:SingularComponentSelector, :PluralComponentSelector, :DynamicallyGroupedComponentSelector, :subtype_to_string, :component_to_qualified_string])
```
```@autodocs
Modules = [PowerSystems]
Pages = ["component_selector_interface.jl"]
Public = true
Private = false
```
```@autodocs
Modules = [IS]
Pages = ["component_selector.jl"]
Filter = t -> !(t isa AbstractString) && nameof(t) in names(PowerSystems) && getproperty(PowerSystems, nameof(t)) === t && (nameof(t) in [:SingularComponentSelector, :PluralComponentSelector, :DynamicallyGroupedComponentSelector, :subtype_to_string, :component_to_qualified_string])
```
## Additional Component Methods
```@autodocs
Modules = [PowerSystems]
Pages = ["supplemental_accessors.jl",
"supplemental_setters.jl"]
Public = true
Private = false
```
## [Deprecated Methods](@id deprecated)
```@autodocs
Modules = [PowerSystems]
Pages = ["deprecated.jl"]
Public = true
Private = false
```
## Parsing
```@autodocs
Modules = [PowerSystems]
Pages = ["parsers/power_system_table_data.jl",
"parsers/power_models_data.jl",
"parsers/TAMU_data.jl",
"parsers/psse_dynamic_data.jl",
"parsers/pm_io/common.jl",
"parsers/im_io/matlab.jl"]
Public = true
Private = false
Filter = t -> t ∉ [System]
```
## [Logging](@id logging)
```@autodocs
Modules = [PowerSystems]
Pages = ["utils/logging.jl"]
Public = true
Private = false
```
================================================
FILE: docs/src/api/static_injection_subtypes.md
================================================
# StaticInjection Subtypes Comparison
This document summarizes the similarities and differences between [`StaticInjection`](@ref) subtypes in PowerSystems.jl, with emphasis on generators, loads, storage, and sources. Some control-related subtypes--like FACTS devices--are omitted from the below charts, simply because they have very little in common with the other subtypes. For all subtypes of [`StaticInjection`](@ref), see [Type Tree](@ref "Type Tree").
* * *
## Power Limits Fields Comparison
### Generators
| Type | `active_power_limits` | `max_active_power` | `reactive_power_limits` | `max_reactive_power` |
|:------------------------------ |:--------------------- |:------------------ |:----------------------- |:-------------------- |
| [`ThermalStandard`](@ref) | ✅ `MinMax` | ❌ | ✅ `MinMax` (optional) | ❌ |
| [`ThermalMultiStart`](@ref) | ✅ `MinMax` | ❌ | ✅ `MinMax` (optional) | ❌ |
| [`RenewableDispatch`](@ref) | ❌ | ❌ ¹ | ✅ `MinMax` (optional) | ❌ |
| [`RenewableNonDispatch`](@ref) | ❌ | ❌ | ❌ | ❌ |
| [`HydroDispatch`](@ref) | ✅ `MinMax` | ❌ | ✅ `MinMax` (optional) | ❌ |
| [`HydroTurbine`](@ref) | ✅ `MinMax` | ❌ | ✅ `MinMax` (optional) | ❌ |
| [`HydroPumpTurbine`](@ref) | ✅ `MinMax` | ❌ | ✅ `MinMax` (optional) | ❌ |
### Loads
| Type | `active_power_limits` | `max_active_power` | `reactive_power_limits` | `max_reactive_power` |
|:----------------------------------- |:--------------------- |:------------------ |:----------------------- |:-------------------- |
| [`PowerLoad`](@ref) | ❌ | ✅ `Float64` | ❌ | ✅ `Float64` |
| [`StandardLoad`](@ref) | ❌ | ⊕ | ❌ | ⊕ |
| [`ExponentialLoad`](@ref) | ❌ | ✅ `Float64` | ❌ | ✅ `Float64` |
| [`MotorLoad`](@ref) | ❌ | ✅ `Float64` | ✅ `MinMax` (optional) | ❌ |
| [`InterruptiblePowerLoad`](@ref) | ❌ | ✅ `Float64` | ❌ | ✅ `Float64` |
| [`InterruptibleStandardLoad`](@ref) | ❌ | ⊕ | ❌ | ⊕ |
| [`ShiftablePowerLoad`](@ref) | ✅ `MinMax` | ✅ `Float64` | ❌ | ✅ `Float64` |
### Storage & Source
| Type | `active_power_limits` | `max_active_power` | `reactive_power_limits` | `max_reactive_power` |
|:-------------------------------- |:--------------------- |:------------------ |:----------------------- |:-------------------- |
| [`EnergyReservoirStorage`](@ref) | ❌ ² | ❌ | ✅ `MinMax` (optional) | ❌ |
| [`Source`](@ref) | ✅ `MinMax` | ❌ | ✅ `MinMax` (optional) | ❌ |
¹ Uses `rating * power_factor` dynamically; no stored field
² EnergyReservoirStorage uses `input_active_power_limits` and `output_active_power_limits` instead
Here, "`MinMax` (optional)" means `Union{MinMax, Nothing}`, with `nothing` repesenting "no limits" and being the default.
⊕ = Split across 3 ZIP fields: `*_constant_*`, `*_impedance_*`, `*_current_*`
* * *
## Generator-Specific Fields
| Field | Thermal* | [`RenewableDispatch`](@ref) | [`RenewableNonDispatch`](@ref) | [`HydroDispatch`](@ref) | [`HydroTurbine`](@ref) | [`HydroPumpTurbine`](@ref) |
|:------------------ |:-------- |:--------------------------- |:------------------------------ |:----------------------- |:---------------------- |:-------------------------- |
| `rating` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `prime_mover_type` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `fuel` | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `status` | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ |
| `must_run` | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
| `ramp_limits` | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ |
| `time_limits` | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ |
| `power_factor` | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| `efficiency` | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
| `operation_cost` | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
\* Thermal = [`ThermalStandard`](@ref), [`ThermalMultiStart`](@ref)
* * *
## Load-Specific Fields
| Field | [`PowerLoad`](@ref) | [`StandardLoad`](@ref) | [`ExponentialLoad`](@ref) | [`MotorLoad`](@ref) | Interruptible* | Shiftable |
|:----------------------- |:------------------- |:---------------------- |:------------------------- |:------------------- |:-------------- |:--------- |
| `active_power` | ✅ | ⊕ | ✅ | ✅ | ✅ | ✅ |
| `reactive_power` | ✅ | ⊕ | ✅ | ✅ | ✅ | ✅ |
| `conformity` | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `operation_cost` | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
| `rating` | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| `α`, `β` (voltage exp.) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
\* Interruptible = [`InterruptiblePowerLoad`](@ref), [`InterruptibleStandardLoad`](@ref); Shiftable = [`ShiftablePowerLoad`](@ref)
* * *
## Universal Fields (All StaticInjection)
| Field | Present in ALL |
|:------------------ |:-------------- |
| `name` | ✅ |
| `available` | ✅ |
| `bus` | ✅ |
| `base_power` | ✅ |
| `services` | ✅ |
| `dynamic_injector` | ✅ |
| `ext` | ✅ |
| `internal` | ✅ |
* * *
## Operation Cost Types by Device
| Device Category | Cost Type |
|:-------------------------- |:------------------------------------------------------------ |
| [`ThermalGen`](@ref) | [`ThermalGenerationCost`](@ref) or [`MarketBidCost`](@ref) |
| [`HydroGen`](@ref) | [`HydroGenerationCost`](@ref) or [`MarketBidCost`](@ref) |
| [`RenewableGen`](@ref) | [`RenewableGenerationCost`](@ref) or [`MarketBidCost`](@ref) |
| [`ControllableLoad`](@ref) | [`LoadCost`](@ref) or [`MarketBidCost`](@ref) |
| [`Storage`](@ref) | [`StorageCost`](@ref) or [`MarketBidCost`](@ref) |
| [`Source`](@ref) | [`ImportExportCost`](@ref) |
* * *
================================================
FILE: docs/src/api/type_tree.md
================================================
# Type Tree
Here is the complete `PowerSystems.jl` type hierarchy:
```@repl types
using PowerSystems #hide
import TypeTree: tt #hide
docs_dir = joinpath(pkgdir(PowerSystems), "docs", "src", "tutorials", "utils"); #hide
include(joinpath(docs_dir, "docs_utils.jl")); #hide
print(join(tt(PowerSystems.IS.InfrastructureSystemsType), "")) #hide
```
================================================
FILE: docs/src/api/valuecurve_options.md
================================================
# [`ValueCurve` Options](@id curve_table)
Operating cost data typically includes both fixed and variable costs. See the how-to on [Adding an Operating Cost](@ref cost_how_to) for a demonstration of defining an operating cost.
In PowerSystems.jl, the *variable* portion of the operating cost can be represented as linear, quadratic, or piecewise input-output curves; potentially piecewise marginal heat rates; average heat rates; and more, as best fits the input data. This is done by constructing various subtypes of [`ValueCurve`](@ref).
This summary table shows each way to construct a `ValueCurve` with the user-friendly subtype aliases. The `ValueCurve`s make no assumption about units; the example interpretation given here assumes that the variable cost `ValueCurve` will be wrapped in a [`CostCurve`](@ref) with natural units. Note that all four `Piecewise` options here fundamentally represent the same curve. More information and explanatory plots are provided for each subtype alias in the subheadings below.
| Description | Example | Example interpretation |
|:------------------------------------------------------------------------------------------------------------------------- |:-------------------------------------------------------------------- |:------------------------------------------------------------------------------------------------------------------------ |
| Linear input-output curve with *zero* no-load cost (constant average rate) | `LinearCurve(5.0)` | \$5/MWh |
| Linear input-output curve with potentially *nonzero* no-load cost (constant marginal rate) | `LinearCurve(5.0, 15.0)` | \$5/MWh + \$15/hr |
| Quadratic input-output curve with potentially nonzero no-load cost | `QuadraticCurve(1.0, 1.0, 18.0)` | $C(P) = 1 P^2 + 1 P + 18$ where $C$ is \$/hr, $P$ is MW |
| Piecewise linear curve specified by cost values at production points | `PiecewisePointCurve([(1.0, 20.0), (2.0, 24.0), (3.0, 30.0)])` | \$20/hr @ 1 MW, \$24/hr @ 2 MW, \$30/hr @ 3 MW, linear \$/hr interpolation between these points |
| Piecewise linear curve specified by initial value and marginal rates (slopes) between production points | `PiecewiseIncrementalCurve(20.0, [1.0, 2.0, 3.0], [4.0, 6.0])` | \$20/hr @ 1 MW plus additional \$4/MWh from 1 MW to 2 MW plus additional \$6/MWh from 2 MW to 3 MW |
| No-load cost plus piecewise linear curve specified by initial value and marginal rates (slopes) between production points | `PiecewiseIncrementalCurve(18.0, 20.0, [1.0, 2.0, 3.0], [4.0, 6.0])` | \$18/hr no-load cost; \$20/hr @ 1 MW plus additional \$4/MWh from 1 MW to 2 MW plus additional \$6/MWh from 2 MW to 3 MW |
| Piecewise linear curve specified by initial value and average rates between production points | `PiecewiseAverageCurve(20.0, [1.0, 2.0, 3.0], [12.0, 10.0])` | \$20/hr @ 1 MW, \$12/MWh @ 2 MW, \$10/MWh @ 3 MW, linear \$/hr interpolation between these points |
## [`LinearCurve`](@ref)
Specify the marginal cost of production $M$ and optionally the no-load cost $C$, which defaults to zero. Here is a graphical representation:
```@raw html
```
## [`QuadraticCurve`](@ref)
Specify the quadratic ($Q$), proportional ($M$), and constant ($C$) terms of a function that defines the input-output curve:
```@raw html
```
## [`PiecewisePointCurve`](@ref)
Specify a vector of $K$ (production, cost) pairs (i.e., $(P_k, C_k)$ for $k = 1, \dots, K$) to define the input-output curve:
```@raw html
```
## [`PiecewiseIncrementalCurve`](@ref)
Specify the cost $C_1$ at the least production point given (NOT the cost at zero production), a vector of $K$ production points $P_1, \dots, P_k$, and a vector of $K-1$ marginal rates $M_1, \dots, M_{k-1}$, that represent the slopes of the curve segments between the points. $C_1$ may be `nothing`, which results in a not-fully-defined curve. The no-load cost $C_0$ can optionally be specified as a first argument; it is not part of the representation of the curve, just another piece of data that may be stored:
```@raw html
```
## [`PiecewiseAverageCurve`](@ref)
Specify the cost $C_1$ at the least production point given (NOT the cost at zero production), a vector of $K$ production points $P_1, \dots, P_k$, and a vector of $K-1$ average rates $R_1, \dots, R_{k-1}$ at the $K-1$ latter production points:
```@raw html
```
================================================
FILE: docs/src/explanation/buses_type_explanation.md
================================================
# [Understanding ACBusTypes](@id bustypes)
`PowerSystems.jl` supports multiple types of AC buses, [listed here](@ref acbustypes_list).
When creating nodal datasets, the definitions for AC Buses can have a significant impact on the
topology logic for the network.
## Voltage Control Types
- `PQ`:
+ **Known:** Real Power Injection ($P$) and Reactive Power Injection ($Q$). These are typically the loads at that bus or fixed power factor generators.
+ **Unknown:** Voltage Magnitude ($|V|$) and Voltage Angle ($\delta$).
+ Represents a bus where the voltage magnitude and angle are free to vary based on the system conditions.
- `PV`:
+ **Known:** Real Power Injection ($P$) and Voltage Magnitude ($|V|$).
+ **Unknown:** Reactive Power Injection ($Q$) and Voltage Angle ($\delta$).
+ Typically represents a bus with an injector connected, where the injector controls the reactive power output and regulates the bus voltage magnitude to a setpoint.
## Reference and Slack Buses
There is a nuanced distinction between a slack bus and a reference bus. In most small test sytems and academic discussions, the system has a single slack bus which is also the reference bus. However, for large interconnected cases or cases with a very radial structure, having a single bus that takes on all the real power mistmatch in the system can lead to erroneous results. In PowerSystems.jl we distinguish the posibility of having slacks and reference buses. Is up to the modeler to decide how to handle the classifications inside of the applications. In other words, wether a reference bus is also a slack or viceversa is left to the application developer.
- `SLACK`:
+ Known: Voltage Magnitude ($|V|$) and Voltage Angle ($\delta$) **when the slack and the reference are the same bus, otherwise is unknown**.
+ Unknown: Real Power ($P$) and Reactive Power ($Q$). These values are calculated as residuals after the power flow solution converges to account for system losses and imbalances and are allocated using participation factors in the model formulation.
+ This kind of bus absorbs or supplies the difference between the total generation and total load plus losses in the system. There can be several slack buses in a system.
- Ref:
+ Known: Voltage Magnitude ($|V|$) and Voltage Angle ($\delta$). Typically, the angle is set to 0 degrees for simplicity, and the voltage is set to a fixed value per unit.0 degrees for simplicity and the voltage is set to a fixed value per unit.
+ Unknown: Real Power ($P$) and Reactive Power ($Q$). These values are calculated as residuals after the power flow solution converges to account for system losses and imbalances when there is a single slack bus that matches the reference bus.
+ Serves as the "reference" for all other bus voltage angles in the AC interconnected system.
For the study of large interconnected areas that include different asynchronous AC networks connected through HVDC, the system can contain multiple reference buses. Since not all modeling efforts require a properly set reference bus, e.g., Zonal Modeling, **PowerSystems.jl does not perform a verification that the system buses are adequately set. This feature is implemented in [`PowerNetworkMatrices.jl`](https://sienna-platform.github.io/PowerNetworkMatrices.jl/stable/).**
## Isolated Buses and the `available` field
In certain modeling applications, particularly power flow modeling tools, the designation of
"isolated" is used to signal that the bus is temporarily disconnected from the network, as are any other components attached to it. However, in `PowerSystems.jl`, a bus and its components can be excluded from an analysis or optimization without changing the underlying network topology by setting the `available` field to false: `set_available!(bus, false)`.
In PowerSystems.jl the `ISOLATED` type means exactly that: The bus is not connected to the network. In
resource analysis where systems contain isolated subsystems that can be ignored for the purposes of the power flow but are relevant when performing optimization, the `ISOLATED` designation provides the capability to describe those situations in precise terms. `ISOLATED` buses can also be made unavailable to make the components attached to them also unavailable.
================================================
FILE: docs/src/explanation/conforming_and_non_conforming_loads.md
================================================
# [Conforming and Non-Conforming Loads](@id conf_loads)
The difference between conforming and non-conforming loads is not particularly significant for how PowerSystems.jl manages data, as loads can be assigned either aggregate or individual time series.
## Definitions and use cases
At its core, the distinction is about forecastability. The De Facto-Criteria and Practical Uses of this distinction comes from CAISO's Energy Imbalance Market (EIM) definitions. This section draws from the [CAISO EIM's "Non-Conforming Load FAQ"](https://www.westerneim.com/Documents/EIM-Non-Conforming-Load-FAQ.pdf) document.
Conforming loads are the typically residential and commercial loads that, in aggregate, follow a predictable daily and seasonal pattern influenced by factors like time of day, day of the week, and weather conditions. This predictability allows modelers to use aggregate forecasts of the total area load with a high degree of accuracy and then desagregate the curve using participation factors.
Non-conforming loads, on the other hand have patterns of consumption that don't follow the aggregate behavior. Their consumption does not follow typical patterns and can fluctuate with different rates as the total system load. These are often large industrial processes with unique operational cycles. For example:
- Electric Arc Furnaces: Used in steel manufacturing, electric arc furnaces cause massive, sudden spikes in power demand when they are in operation. Depending on the time-scale of modeling these loads can require a consumption pattern that mathches the underlying industrial process.
- Large Data Centers: While having a relatively constant base load, the computational demands of large data centers almost never change with the patterns from the rest of the system. These loads tend to be flat and in some advanced models include the behavior of compute load dispatch algorithms that conduct geographic price arbitrage.
- Traction Loads for Railways: The movement of electric trains results in fluctuating power demand along the railway lines based on the transportation demand.
- Pumping Loads: Similarly to tranction loads, pumping loads can change according to water or gas demand and supply needs and not system level behavior. In its data collection manuals, WECC specifies that pumping loads are typically modeled as non-conforming in power flow cases.
## Modeling using PowerSystems.jl
Drawing again from CAISO's EIM procedures, the management of non-conforming loads involves:
1. **Segregated Data Submission**: The historical consumption data for the non-conforming load must be separated from the general, or "conforming," load data. This "cleanses" the historical data used to train weather-based load forecasting models, thereby improving their accuracy for the bulk of the system's load.
2. **Independent Forecasting**: While the system operator forecasts the aggregate conforming load, the entity responsible for the non-conforming load is often required to submit its own forecast or schedule.
3. **Specialized Modeling**: In market and operational models, non-conforming loads are often treated as a type of resource. For instance, in the CAISO market, they are represented as "Dispatchable Demand Response" (DDR) resources, which are essentially modeled as negative generation. This allows their behavior to be explicitly accounted for in market clearing and dispatch instructions.
If a modeler wants to account for the differences in behavior between various loads, they only need to assign a distinct time series to each load. In `PowerSystems.jl`, we keep track of data related to "conformity" for monitoring purposes. This data is defined in the `conformity` field for concrete subtypes of [`StaticLoad`](@ref) and has the [options listed here](@ref loadconform_list). However, the behavioral variations described in the literature are already taken into consideration through the ways modelers can manage these time series assignments.
### See also:
- Parsing [time series](@ref parsing_time_series)
================================================
FILE: docs/src/explanation/dynamic_data.md
================================================
# Dynamic Devices
## Static and Dynamic Data Layers
`PowerSystems.jl` uses two categories to define data for dynamic simulations:
1. [Static](@ref S) components, which includes the data needed to run a power flow problem
2. [Dynamic](@ref D) components are those that define differential equations to run a transient simulation. These dynamic
data are attached to the static components.
Although `PowerSystems.jl` is not constrained to only PSS/e files, commonly the data for a
dynamic simulation comes in a pair of files: One for the static data power flow case (e.g.,
`.raw` file) and a second one with the dynamic components information (e.g., `.dyr` file).
However, `PowerSystems.jl` is able to take any power flow case and specify dynamic
components to it. The two data layers in `PowerSystems.jl` are similar to the data
division between those two files.
### Layer 1: Static Components
The first data layer contains all the information necessary to run a power flow problem:
- Vector of `Bus` elements, that define all the buses in the network.
- Vector of `Branch` elements, that define all the branches elements (that connect two buses) in the network.
- Vector of `StaticInjection` elements, that define all the devices connected to buses that can inject (or withdraw) power. These static devices, typically generators, in `PowerSimulationsDynamics` are used to solve the Power Flow problem that determines the active and reactive power provided for each device.
- Vector of `PowerLoad` elements, that define all the loads connected to buses that can withdraw current. These are also used to solve the Power Flow.
- Vector of `Source` elements, that define source components behind a reactance that can inject or withdraw current.
- The base of power used to define per unit values, in MVA as a `Float64` value.
- The base frequency used in the system, in Hz as a `Float64` value.
### Layer 2: Dynamic Components
The second data layer contains the *additional* information describing the dynamic response
of certain components in the `System`. This data is all attached to components defined in
the static data layer:
- (Optional) Selecting which of the `Lines` (of the `Branch` vector) elements must be modeled of `DynamicLines` elements, that can be used to model lines with differential equations.
- Vector of `DynamicInjection` elements. These components must be attached to a `StaticInjection` that connects the power flow solution to the dynamic formulation of such device.
`DynamicInjection` can be `DynamicGenerator` or `DynamicInverter`, and its specific formulation (i.e. differential equations) will depend on the specific components that define each device (see the sections below). As
a result, it is possible to flexibly define dynamic data models and methods according to
the analysis requirements. [`DynamicInjection`](@ref) components use a parametric
type pattern to materialize the full specification of the dynamic injection model with
parameters. This design enable the use of parametric methods to specify the mathematical
model of the dynamic components separately.
[`DynamicInjection`](@ref) components also implement some additional information useful for
the modeling, like the usual states assumed by the model and the number of states. These values are
derived from the documentation associated with the model, for instance PSS/e models provide
parameters, states and variables. Although `PowerSystems.jl` doesn't assume a specific
mathematical model for the components, the default values for these parameters are derived
directly from the data model source.
## Dynamic Generator Structure
Each generator is a data structure that is defined by the following components:
- [Machine](@ref Machine): That defines the stator electro-magnetic dynamics.
- [Shaft](@ref Shaft): That describes the rotor electro-mechanical dynamics.
- [Automatic Voltage Regulator](@ref AVR): Electromotive dynamics to model an AVR controller.
- [Power System Stabilizer](@ref PSS): Control dynamics to define an stabilization signal for the AVR.
- [Prime Mover and Turbine Governor](@ref TurbineGov): Thermo-mechanical dynamics and associated controllers.
```@raw html
```
## Dynamic Inverter Structure
Each inverter is a data structure that is defined by the following components:
- [DC Source](@ref DCSource): Defines the dynamics of the DC side of the converter.
- [Frequency Estimator](@ref FrequencyEstimator): That describes how the frequency of the grid
can be estimated using the grid voltages. Typically a phase-locked loop (PLL).
- [Outer Loop Control](@ref OuterControl): That describes the active and reactive power
control dynamics.
- [Inner Loop Control](@ref InnerControl): That can describe virtual impedance,
voltage control and current control dynamics.
- [Converter](@ref Converter): That describes the dynamics of the pulse width modulation (PWM)
or space vector modulation (SVM).
- [Filter](@ref Filter): Used to connect the converter output to the grid.
```@raw html
``` ⠀
```
================================================
FILE: docs/src/explanation/per_unit.md
================================================
# [Per-unit Conventions](@id per_unit)
It is often useful to express power systems data in relative terms using per-unit conventions.
`PowerSystems.jl` supports the automatic conversion of data between three different unit systems:
1. `"NATURAL_UNITS"`: The naturally defined units of each parameter (typically MW).
2. `"SYSTEM_BASE"`: Parameter values are divided by the system `base_power`.
3. `"DEVICE_BASE"`: Parameter values are divided by the device `base_power`.
`PowerSystems.jl` supports these unit systems because different power system tools and data
sets use different units systems by convention, such as:
- Dynamics data is often defined in device base
- Network data (e.g., reactance, resistance) is often defined in system base
- Production cost modeling data is often gathered from variety of data sources,
which are typically defined in natural units
These three unit bases allow easy conversion between unit systems.
This allows `PowerSystems.jl` users to input data in the formats they have available,
as well as view data in the unit system that is most intuitive to them.
You can get and set the unit system setting of a `System` with [`get_units_base`](@ref) and
[`set_units_base_system!`](@ref). To support a less stateful style of programming,
`PowerSystems.jl` provides the `Logging.with_logger`-inspired "context manager"-type
function [`with_units_base`](@ref), which sets the unit system to a particular value,
performs some action, then automatically sets the unit system back to its previous value.
Conversion between unit systems does not change
the stored parameter values. Instead, unit system conversions are made when accessing
parameters using the [accessor functions](@ref dot_access), thus making it
imperative to utilize the accessor functions instead of the "dot" accessor methods to
ensure the return of the correct values. The units of the parameter values stored in each
struct are defined in `src/descriptors/power_system_structs.json`.
There are some unit system conventions in `PowerSystems.jl` when defining new components.
Currently, when you define components that aren't attached to a `System`,
you must define all fields in `"DEVICE_BASE"`, except for certain components that don't
have their own `base_power` rating, such as [`Line`](@ref)s, where the `rating` must be
defined in `"SYSTEM_BASE"`.
In the future, `PowerSystems.jl` hopes to support defining components in natural units.
For now, if you want to define data in natural units, you must first
set the system units to `"NATURAL_UNITS"`, define an empty component, and then use the
[accessor functions](@ref dot_access) (e.g., getters and setters), to define each field
within the component. The accessor functions will then do the data conversion from your
input data in natural units (e.g., MW or MVA) to per-unit.
By default, `PowerSystems.jl` uses `"SYSTEM_BASE"` because many optimization problems won't
converge when using natural units. If you change the unit setting, it's suggested that you
switch back to `"SYSTEM_BASE"` before solving an optimization problem (for example in
[`PowerSimulations.jl`](https://sienna-platform.github.io/PowerSimulations.jl/stable/)).
!!! note
Check the [`Transformers per unit explanation`](@ref transformers_pu) for details on how
the per-unit is managed
================================================
FILE: docs/src/explanation/plant_attributes.md
================================================
# [Plant Attributes](@id plant_attributes)
## The Unit vs. Plant Aggregation Problem
In power systems modeling, there is a fundamental tension between different levels of aggregation.
Real-world power plants often consist of multiple generating units that share physical infrastructure,
but data sources and modeling requirements vary in how they represent this relationship:
- **Unit-level data**: Individual generators with their own capacity, cost curves, and operational constraints
- **Plant-level data**: Aggregated capacity and characteristics representing an entire facility
For interoperable analysis across different tools and datasets, it is often necessary to track
**both** the plant and the individual units within it. This is particularly important when:
1. **Data integration**: Combining datasets that use different aggregation levels
2. **Shared infrastructure constraints**: Units on the same shaft, penstock, or point of common coupling
have operational dependencies that must be modeled together
3. **Market operations**: ISOs may require unit-level bidding while planning studies use plant-level data
4. **Regulatory reporting**: Different reports require different aggregation levels
PowerSystems.jl addresses this challenge through **Plant Attributes**, which are
[`SupplementalAttribute`](@ref supplemental_attributes) types that group individual generator
components into logical plant structures while preserving the detailed unit-level information.
## Plant Attribute Types
PowerSystems.jl provides five specialized plant attribute types, each designed for a specific
generation technology:
```mermaid
classDiagram
SupplementalAttribute <|-- PowerPlant
PowerPlant <|-- ThermalPowerPlant
PowerPlant <|-- CombinedCycleBlock
PowerPlant <|-- CombinedCycleFractional
PowerPlant <|-- HydroPowerPlant
PowerPlant <|-- RenewablePowerPlant
```
### ThermalPowerPlant
Represents conventional thermal power plants with synchronous generators. Multiple units can
share a common **shaft**, which is relevant for modeling mechanical coupling constraints.
| Field | Type | Description |
|:------------------- |:------------------------- |:---------------------------------------------- |
| `name` | `String` | Name of the power plant |
| `shaft_map` | `Dict{Int, Vector{UUID}}` | Mapping of shaft numbers to unit UUIDs |
| `reverse_shaft_map` | `Dict{UUID, Int}` | Reverse mapping from unit UUID to shaft number |
### CombinedCycleBlock
Represents combined cycle plants using a block configuration. Models the relationship between
combustion turbines (CTs) and steam turbines through the Heat Recovery Steam Generator (HRSG).
| Field | Type | Description |
|:------------------------------- |:---------------------------- |:-------------------------------------------- |
| `name` | `String` | Name of the combined cycle block |
| `configuration` | `CombinedCycleConfiguration` | Configuration type (see below) |
| `heat_recovery_to_steam_factor` | `Float64` | Factor for heat recovery to steam conversion |
| `hrsg_ct_map` | `Dict{Int, Vector{UUID}}` | HRSG to CT unit mappings (inputs) |
| `hrsg_ca_map` | `Dict{Int, Vector{UUID}}` | HRSG to CA unit mappings (outputs) |
| `ct_hrsg_map` | `Dict{UUID, Vector{Int}}` | Reverse CT to HRSG mapping |
| `ca_hrsg_map` | `Dict{UUID, Vector{Int}}` | Reverse CA to HRSG mapping |
The `CombinedCycleConfiguration` enum describes the plant layout. Combined cycle plants are
typically described using a "CTs x STs" notation (e.g., 2x1 means two combustion turbines
feeding one steam turbine through a Heat Recovery Steam Generator). However, the EIA
[prime mover codes](@ref pm_list) employ CT and CA to distinguish between the combustion
turbine units and the steam portion of the combined cycle respectively.
```@raw html
Combined cycle power plant configurations. Source: U.S. Energy Information Administration
```
| Value | Configuration | Description |
|:------------------------------ |:------------------ |:---------------------------------------- |
| `SingleShaftCombustionSteam` | 1x1 (single shaft) | Single CT + single ST on one shaft |
| `SeparateShaftCombustionSteam` | 1x1 (multi-shaft) | Single CT + single ST on separate shafts |
| `DoubleCombustionOneSteam` | 2x1 | Two CTs feeding one ST via HRSG |
| `TripleCombustionOneSteam` | 3x1 | Three CTs feeding one ST via HRSG |
| `Other` | Various | Other configurations (e.g., 4x1, 2x2) |
For more information on combined cycle configurations, see the
[U.S. Energy Information Administration article on combined-cycle plants](https://www.eia.gov/todayinenergy/detail.php?id=52158).
### CombinedCycleFractional
Represents combined cycle generation when each unit represents a specific configuration with
an aggregate heat rate. Unlike [`CombinedCycleBlock`](@ref), which models the CT/CA relationship
through the HRSG, the fractional representation uses **operation exclusion groups** to define
which units can operate simultaneously. Only generators with the `CC` (combined cycle)
[prime mover type](@ref pm_list) can be added.
| Field | Type | Description |
|:--------------------------------- |:---------------------------- |:-------------------------------------------------------- |
| `name` | `String` | Name of the combined cycle fractional plant |
| `configuration` | `CombinedCycleConfiguration` | Configuration type (see table above) |
| `operation_exclusion_map` | `Dict{Int, Vector{UUID}}` | Mapping of exclusion group numbers to unit UUIDs |
| `inverse_operation_exclusion_map` | `Dict{UUID, Int}` | Reverse mapping from unit UUID to exclusion group number |
### HydroPowerPlant
Represents hydroelectric plants where multiple turbines may share a common **penstock**
(the pipe that delivers water to the turbines). Shared penstocks create operational
dependencies between units.
| Field | Type | Description |
|:---------------------- |:------------------------- |:------------------------------------------------- |
| `name` | `String` | Name of the hydro power plant |
| `penstock_map` | `Dict{Int, Vector{UUID}}` | Mapping of penstock numbers to unit UUIDs |
| `reverse_penstock_map` | `Dict{UUID, Int}` | Reverse mapping from unit UUID to penstock number |
### RenewablePowerPlant
Represents renewable energy plants (wind farms, solar farms) where multiple generators or
storage devices connect through a common **Point of Common Coupling (PCC)** to the grid.
| Field | Type | Description |
|:----------------- |:------------------------- |:-------------------------------------------- |
| `name` | `String` | Name of the renewable power plant |
| `pcc_map` | `Dict{Int, Vector{UUID}}` | Mapping of PCC numbers to unit UUIDs |
| `reverse_pcc_map` | `Dict{UUID, Int}` | Reverse mapping from unit UUID to PCC number |
## Creating Plant Attributes
### Basic Construction
All plant attributes can be created with just a name; the infrastructure mappings are populated
when units are added:
```julia
# Create empty plant attributes
thermal_plant = ThermalPowerPlant(; name = "Coal Plant A")
hydro_plant = HydroPowerPlant(; name = "Dam Complex")
renewable_plant = RenewablePowerPlant(; name = "Wind Farm North")
cc_block = CombinedCycleBlock(;
name = "CC Unit 1",
configuration = CombinedCycleConfiguration.DoubleCombustionOneSteam,
)
cc_fractional = CombinedCycleFractional(;
name = "CC Fractional 1",
configuration = CombinedCycleConfiguration.DoubleCombustionOneSteam,
)
```
### Adding Units to Plants
Units are added to plants using [`add_supplemental_attribute!`](@ref), which requires
specifying the infrastructure number (shaft, penstock, PCC, or HRSG):
```julia
# Add thermal generators to a plant (shaft_number is required)
add_supplemental_attribute!(sys, gen1, thermal_plant; shaft_number = 1)
add_supplemental_attribute!(sys, gen2, thermal_plant; shaft_number = 1) # Same shaft
add_supplemental_attribute!(sys, gen3, thermal_plant; shaft_number = 2) # Different shaft
# Add hydro turbines to a plant (penstock_number is required)
add_supplemental_attribute!(sys, turbine1, hydro_plant, 1) # Penstock 1
add_supplemental_attribute!(sys, turbine2, hydro_plant, 1) # Same penstock
add_supplemental_attribute!(sys, turbine3, hydro_plant, 2) # Penstock 2
# Add renewable generators to a plant (pcc_number is required)
add_supplemental_attribute!(sys, wind_gen1, renewable_plant, 1) # PCC 1
add_supplemental_attribute!(sys, battery, renewable_plant, 1) # Same PCC
# Add CT and CA units to combined cycle block (hrsg_number is required)
# Note: Only CT (combustion turbine) and CA (combined cycle steam part) prime movers are allowed
add_supplemental_attribute!(sys, ct_unit, cc_block; hrsg_number = 1)
add_supplemental_attribute!(sys, steam_unit, cc_block; hrsg_number = 1)
# Add CC units to combined cycle fractional (exclusion_group is required)
# Note: Only CC (combined cycle) prime mover type is allowed
add_supplemental_attribute!(sys, cc_config1, cc_fractional; exclusion_group = 1)
add_supplemental_attribute!(sys, cc_config2, cc_fractional; exclusion_group = 1)
add_supplemental_attribute!(sys, cc_config3, cc_fractional; exclusion_group = 2)
```
## Querying Plant Information
### Getting All Units in a Plant
Use [`get_associated_components`](@ref) to retrieve all units associated with a plant:
```julia
# Get all generators in a thermal plant
for gen in get_associated_components(sys, thermal_plant; component_type = ThermalGen)
@show get_name(gen)
end
```
### Getting Units by Infrastructure
Query units connected to specific infrastructure elements:
```julia
# Get all generators on shaft 1
gens_on_shaft_1 = get_components_in_shaft(sys, thermal_plant, 1)
# Get all turbines on penstock 2
turbines_on_penstock_2 = get_components_in_penstock(sys, hydro_plant, 2)
# Get all generators/storage at PCC 1
components_at_pcc_1 = get_components_in_pcc(sys, renewable_plant, 1)
# Get all generators in exclusion group 1
gens_in_group_1 = get_components_in_exclusion_group(sys, cc_fractional, 1)
```
### Accessing Infrastructure Maps
Direct access to the mapping dictionaries is available through accessor functions:
```julia
# ThermalPowerPlant
shaft_map = get_shaft_map(thermal_plant) # Dict{Int, Vector{UUID}}
reverse_map = get_reverse_shaft_map(thermal_plant) # Dict{UUID, Int}
# HydroPowerPlant
penstock_map = get_penstock_map(hydro_plant)
reverse_map = get_reverse_penstock_map(hydro_plant)
# RenewablePowerPlant
pcc_map = get_pcc_map(renewable_plant)
reverse_map = get_reverse_pcc_map(renewable_plant)
# CombinedCycleBlock
ct_map = get_hrsg_ct_map(cc_block) # HRSG -> CTs
ca_map = get_hrsg_ca_map(cc_block) # HRSG -> CAs
config = get_configuration(cc_block) # CombinedCycleConfiguration
factor = get_heat_recovery_to_steam_factor(cc_block)
# CombinedCycleFractional
exclusion_map = get_operation_exclusion_map(cc_fractional)
inverse_map = get_inverse_operation_exclusion_map(cc_fractional)
config = get_configuration(cc_fractional) # CombinedCycleConfiguration
```
## Removing Units from Plants
Units can be removed from plants while preserving both the unit and the plant:
```julia
remove_supplemental_attribute!(sys, gen1, thermal_plant)
remove_supplemental_attribute!(sys, turbine1, hydro_plant)
remove_supplemental_attribute!(sys, wind_gen1, renewable_plant)
remove_supplemental_attribute!(sys, ct_unit, cc_block)
remove_supplemental_attribute!(sys, cc_config1, cc_fractional)
```
## Complete Example
Here is a complete example demonstrating the workflow for a thermal power plant:
```julia
using PowerSystems
# Create a system with thermal generators
sys = System(100.0) # 100 MVA base
bus = ACBus(;
number = 1,
name = "Bus1",
bustype = ACBusTypes.REF,
angle = 0.0,
magnitude = 1.0,
voltage_limits = (min = 0.9, max = 1.1),
base_voltage = 230.0,
)
add_component!(sys, bus)
# Create three thermal units
gen1 = ThermalStandard(;
name = "Unit1",
available = true,
status = true,
bus = bus,
active_power = 100.0,
reactive_power = 0.0,
rating = 120.0,
active_power_limits = (min = 30.0, max = 100.0),
reactive_power_limits = (min = -50.0, max = 50.0),
ramp_limits = nothing,
operation_cost = ThermalGenerationCost(nothing),
base_power = 100.0,
time_limits = nothing,
prime_mover_type = PrimeMovers.ST,
fuel = ThermalFuels.COAL,
)
gen2 = ThermalStandard(;
name = "Unit2",
available = true,
status = true,
bus = bus,
active_power = 100.0,
reactive_power = 0.0,
rating = 120.0,
active_power_limits = (min = 30.0, max = 100.0),
reactive_power_limits = (min = -50.0, max = 50.0),
ramp_limits = nothing,
operation_cost = ThermalGenerationCost(nothing),
base_power = 100.0,
time_limits = nothing,
prime_mover_type = PrimeMovers.ST,
fuel = ThermalFuels.COAL,
)
gen3 = ThermalStandard(;
name = "Unit3",
available = true,
status = true,
bus = bus,
active_power = 50.0,
reactive_power = 0.0,
rating = 60.0,
active_power_limits = (min = 15.0, max = 50.0),
reactive_power_limits = (min = -25.0, max = 25.0),
ramp_limits = nothing,
operation_cost = ThermalGenerationCost(nothing),
base_power = 50.0,
time_limits = nothing,
prime_mover_type = PrimeMovers.ST,
fuel = ThermalFuels.COAL,
)
add_component!(sys, gen1)
add_component!(sys, gen2)
add_component!(sys, gen3)
# Create a plant attribute
plant = ThermalPowerPlant(; name = "Coal Plant Alpha")
# Add the plant to the system (optional, for serialization)
add_supplemental_attribute!(sys, plant)
# Associate generators with the plant
# Units 1 and 2 share shaft 1, Unit 3 is on shaft 2
add_supplemental_attribute!(sys, gen1, plant; shaft_number = 1)
add_supplemental_attribute!(sys, gen2, plant; shaft_number = 1)
add_supplemental_attribute!(sys, gen3, plant; shaft_number = 2)
# Query generators on shaft 1
shaft_1_gens = get_components_in_shaft(sys, plant, 1)
println("Generators on Shaft 1:")
for gen in shaft_1_gens
println(" - $(get_name(gen)): $(get_active_power_limits(gen).max) MW")
end
# Get total plant capacity
all_gens = collect(get_associated_components(sys, plant; component_type = ThermalGen))
total_capacity = sum(get_active_power_limits(g).max for g in all_gens)
println("Total plant capacity: $total_capacity MW")
```
## Supported Component Types
Each plant attribute type supports specific component types:
| Plant Type | Supported Components |
|:------------------------- |:-------------------------------------------------------- |
| `ThermalPowerPlant` | `ThermalGen` (all subtypes) |
| `CombinedCycleBlock` | `ThermalGen` with `CT` or `CA` prime mover only |
| `CombinedCycleFractional` | `ThermalGen` with `CC` prime mover only |
| `HydroPowerPlant` | `HydroTurbine`, `HydroPumpTurbine` (not `HydroDispatch`) |
| `RenewablePowerPlant` | `RenewableGen`, `EnergyReservoirStorage` |
## Serialization
Plant attributes are fully serializable with the system. The infrastructure mappings (UUIDs)
are preserved during JSON serialization and correctly restored on deserialization, maintaining
the plant-unit relationships across save/load cycles.
## See Also
- [`SupplementalAttribute`](@ref supplemental_attributes) - Base concept for supplemental data
- [`ThermalPowerPlant`](@ref) - API reference
- [`CombinedCycleBlock`](@ref) - API reference
- [`CombinedCycleFractional`](@ref) - API reference
- [`HydroPowerPlant`](@ref) - API reference
- [`RenewablePowerPlant`](@ref) - API reference
================================================
FILE: docs/src/explanation/power_concepts.md
================================================
# [Power Concepts: Base Power, Rating, and Max Active Power](@id power_concepts)
When working with generators in PowerSystems.jl, it's important to understand the distinction between three key power concepts: base power, rating, and maximum active power. These concepts serve different purposes and are stored using different unit conventions.
## Base Power
**Base power** is the reference power value used for per-unitization of a specific device.
- **Purpose**: Serves as the denominator when converting device parameters to per-unit values
- **Units**: Always stored in **natural units** (MVA)
- **Typical value**: The nameplate capacity of the device
- **Access**: Retrieved using `get_base_power(device)`
Base power is a fundamental parameter for the per-unit system and represents the natural scale of the device. For more details on per-unitization, see the [Per-unit Conventions](@ref per_unit) page.
## Rating
**Rating** represents the maximum AC side output power rating of the synchronous machine or generator.
- **Purpose**: Defines the maximum apparent power (MVA) that the generator's electrical components can safely handle
- **Units**: Stored in per-unit using **device base** (i.e., divided by the device's `base_power`)
- **Physical meaning**: The maximum MVA output considering electrical constraints such as:
+ Stator winding thermal limits
+ Rotor field winding limits
+ Cooling system capacity
- **Access**: Retrieved using `get_rating(device)`
The rating is typically determined by the electrical design and thermal limits of the synchronous machine itself. It represents the maximum capability of the electrical generator, independent of the prime mover.
## Maximum Active Power
**Maximum active power** represents the maximum real power output of the prime mover.
- **Purpose**: Defines the maximum real power (MW) that the prime mover can deliver
- **Units**: Stored in per-unit using **device base** (i.e., divided by the device's `base_power`)
- **Physical meaning**: The maximum MW output considering prime mover constraints such as:
+ Turbine capacity (for steam, gas, or hydro turbines)
+ Combustion chamber limits (for gas turbines)
+ Boiler capacity (for steam generators)
+ Fuel flow limitations
- **Access**: Retrieved using `get_max_active_power(device)`
The maximum active power is determined by the mechanical system that drives the generator. This is often less than the rating when considering only real power production.
## Key Distinctions
### Storage Convention Summary
| Concept | Storage Units | Accessor Function |
|:---------------- |:------------------- |:------------------------ |
| Base Power | Natural units (MVA) | `get_base_power()` |
| Rating | Device base (p.u.) | `get_rating()` |
| Max Active Power | Device base (p.u.) | `get_max_active_power()` |
### Physical Interpretation
The relationship between these three quantities can be understood as follows:
- **Base Power**: "What is the natural scale of this device?"
- **Rating**: "What is the maximum apparent power the electrical generator can produce?"
- **Max Active Power**: "What is the maximum real power the prime mover can deliver?"
### Example
Consider a thermal generator with:
- `base_power = 100.0` MVA (stored in natural units)
- `rating = 1.0` p.u. (equals 100 MVA when converted to natural units)
- `max_active_power = 0.95` p.u. (equals 95 MW when converted to natural units)
In this example:
- The generator's electrical components can handle up to 100 MVA
- The prime mover (e.g., steam turbine) can deliver up to 95 MW of real power
- The difference accounts for the fact that the turbine's mechanical power limit is slightly below the generator's electrical rating
### Unit System Conversions
When you access these values through the PowerSystems.jl accessor functions, they are automatically converted based on the current unit system setting:
```julia
# Assuming base_power = 100 MVA, rating = 1.0 p.u., max_active_power = 0.95 p.u.
sys = System(100.0) # System base power = 100 MVA
gen = get_component(ThermalStandard, sys, "gen1")
# In DEVICE_BASE
set_units_base_system!(sys, "DEVICE_BASE")
get_base_power(gen) # Returns: 100.0 MVA (always natural units)
get_rating(gen) # Returns: 1.0 p.u. (on device base)
get_max_active_power(gen) # Returns: 0.95 p.u. (on device base)
# In NATURAL_UNITS
set_units_base_system!(sys, "NATURAL_UNITS")
get_base_power(gen) # Returns: 100.0 MVA (always natural units)
get_rating(gen) # Returns: 100.0 MVA (converted from p.u.)
get_max_active_power(gen) # Returns: 95.0 MW (converted from p.u.)
# In SYSTEM_BASE
set_units_base_system!(sys, "SYSTEM_BASE")
get_base_power(gen) # Returns: 100.0 MVA (always natural units)
get_rating(gen) # Returns: 1.0 p.u. (on system base, assuming system base = device base)
get_max_active_power(gen) # Returns: 0.95 p.u. (on system base)
```
!!! note
Base power is **always** returned in natural units (MVA) regardless of the unit system setting. The rating and maximum active power are stored in device base but are automatically converted when accessed based on the current unit system setting.
## See Also
- [Per-unit Conventions](@ref per_unit) - Detailed explanation of unit systems in PowerSystems.jl
- [`ThermalStandard`](@ref) - Generator type with these power parameters
- [`get_units_base`](@ref) and [`set_units_base_system!`](@ref) - Functions for managing unit systems
================================================
FILE: docs/src/explanation/supplemental_attributes.md
================================================
# [Supplemental Attributes](@id supplemental_attributes)
While the [`ext` field is a mechanism](@ref additional_fields) for adding arbitrary metadata. PowerSystems.jl, has moved towards a more structured and formalized way of handling supplemental data using `SupplementalAttribute` structs. This is designed to store metadata in a more organized fashion than a generic dictionary. These attributes are intended to be attached to a [`Component`](@ref) types.
Supplemmental attributes can be shared between components or have 1-1 relationships. This is particularly
useful to represent components in the same geographic location or outages for multiple components. Conversely, components can contain many attributes.
```mermaid
flowchart LR
A["Attribute A"] --> B["Component 1"]
A --> C["Component2"]
D["Attribute B"] --> C["Component 2"]
E["Attribute C"] --> F["Component 3"]
```
Supplemental attributes can also contain timeseries in the same fashion that a component can allowing the user to model time varying attributes like outage time series or weather dependent probabilities. See the section [`Working with Time Series Data`](@ref tutorial_time_series) for details on time series handling.
## Getting the attributes in a system
You can retrieve the attributes in a system using the function [`get_supplemental_attributes`](@ref).
You must pass a supplemental attribute type, which can be concrete or abstract. If you pass an abstract type, all concrete types
that are subtypes of the abstract type will be returned.
```julia
for outage in get_supplemental_attributes(FixedForcedOutage, system)
@show summary(outage)
end
```
You can optionally pass a filter function to reduce the returned attributes. This example will
return only FixedForcedOutage instances that have a mean time to recovery greater than or equal to 0.5.
```julia
for outage in get_supplemental_attributes(
x -> get_mean_time_to_recovery(x) >= 0.5,
FixedForcedOutage,
system,
)
@show summary(outage)
end
```
## Getting the attributes associated with a component
You can retrieve the attributes associated with a component using the function [`get_supplemental_attributes`](@ref).
This method signatures are identical to the versions above that operate on a system; just swap the system for a component.
You must pass a supplemental attribute type, which can be concrete or abstract. If you pass an abstract type, all concrete types
that are subtypes of the abstract type will be returned.
```julia
gen1 = get_component(ThermalStandard, system, "gen1")
for outage in get_supplemental_attributes(FixedForcedOutage, gen)
@show summary(outage)
end
```
You can optionally pass a filter function to reduce the returned attributes. This example will
return only FixedForcedOutage instances that have a mean time to recovery greater than or equal to 0.5.
```julia
for outage in get_supplemental_attributes(
x -> get_mean_time_to_recovery(x) >= 0.5,
gen,
FixedForcedOutage,
)
@show summary(outage)
end
```
## Getting the attributes associated with a component type
You can retrieve the attributes associated with any component of a given type
using the function [`get_associated_supplemental_attributes`](@ref). If one attribute is attached to
multiple components of the given type, it will still only appear once in the result.
1. Get all the attributes associated with all components of a given type.
```julia
for outage in get_associated_supplemental_attributes(system, ThermalStandard)
@show summary(outage)
end
```
2. Same as #1, but filter the results by attribute type, which can be concrete or abstract.
```julia
for outage in
get_associated_supplemental_attributes(
system,
ThermalStandard;
attribute_type = FixedForcedOutage,
)
@show summary(outage)
end
```
## Getting the components associated with an attribute
You can retrieve the components associated with a single supplemental attribute using the
function [`get_associated_components`](@ref).
1. Get all components associated with a single supplemental attribute.
```julia
outage = first(get_supplemental_attributes(FixedForcedOutage, system))
for component in get_associated_components(system, outage)
@show summary(component)
end
```
2. Same as #1, but filter the results by component type, which can be concrete or abstract.
```julia
outage = first(get_supplemental_attributes(FixedForcedOutage, system))
for component in get_associated_components(system, outage; component_type = ThermalStandard)
@show summary(component)
end
```
## Getting the components associated with an attribute type
You can retrieve the components associated with any supplemental attribute of a given type
using the function [`get_associated_components`](@ref).
1. Get all components associated with any supplemental attribute of a given type.
```julia
for component in get_associated_components(system, FixedForcedOutage)
@show summary(component)
end
```
2. Same as #1, but filter the results by component type, which can be concrete or abstract.
```julia
for component in
get_associated_components(system, FixedForcedOutage; component_type = ThermalStandard)
@show summary(component)
end
```
## Getting component / supplemental attribute pairs
The function [`get_component_supplemental_attribute_pairs`](@ref) returns a vector of component / supplemental
attribute pairs based on types and optional filters. This can be more efficient than double for loops
that iterate over components and their associated attributes independently.
```julia
for (gen, outage) in get_component_supplemental_attribute_pairs(
ThermalStandard,
FixedForcedOutage,
system,
)
@show summary(gen) summary(outage)
end
```
## Adding Time Series to an attribute
## Existing Supplemental Attributes in PowerSystems
- [`GeographicInfo`](@ref)
- [`ImpedanceCorrectionData`](@ref)
### Contingency Attributes
- [`FixedForcedOutage`](@ref)
- [`GeometricDistributionForcedOutage`](@ref)
- [`PlannedOutage`](@ref)
### Plant Attributes
Plant attributes are a specialized category of supplemental attributes for grouping individual
generator units into logical plant structures. See [Plant Attributes](@ref plant_attributes)
for detailed documentation.
- [`ThermalPowerPlant`](@ref) - Thermal plants with shared shafts
- [`CombinedCycleBlock`](@ref) - Combined cycle plants with HRSG configurations
- [`CombinedCycleFractional`](@ref) - Combined cycle plants with aggregate heat rate and exclusion groups
- [`HydroPowerPlant`](@ref) - Hydro plants with shared penstocks
- [`RenewablePowerPlant`](@ref) - Renewable plants with shared PCCs
================================================
FILE: docs/src/explanation/system.md
================================================
# [System](@id system_doc)
The `System` is the main container of components and the time series data references.
`PowerSystems.jl` uses a hybrid approach to data storage, where the component data and time
series references are stored in volatile memory while the actual time series data is stored
in an HDF5 file. This design loads into memory the portions of the data that are relevant
at time of the query, and so avoids overwhelming the memory resources.
```@raw html
```
## Accessing components stored in the `System`
`PowerSystems.jl` implements a wide variety of methods to search for components to
aid in data manipulation. Most of these use the [Type Structure](@ref type_structure) to
retrieve all components of a certain `Type`.
For example, the most common search function is [`get_components`](@ref), which
takes a desired device `Type` (concrete or abstract) and retrieves all components in that
category from the `System`. It also accepts filter functions for a more
refined search.
Given the potential size of the return,
`PowerSystems.jl` returns Julia iterators in order to avoid unnecessary memory allocations.
The container is optimized for iteration over abstract or concrete component
types as described by the [Type Structure](@ref type_structure).
## [Accessing data stored in a component](@id dot_access)
__Using the "dot" access to get a parameter value from a component is actively discouraged, use "getter" functions instead__
Using code autogeneration, `PowerSystems.jl` implements accessor (or "getter") functions to
enable the retrieval of parameters defined in the component struct fields. Julia syntax enables
access to this data using the "dot" access (e.g. `component.field`), however
_this is actively discouraged_ for two reasons:
1. We make no guarantees on the stability of component structure definitions. We will maintain version stability on the accessor methods.
2. Per-unit conversions are made in the return of data from the accessor functions. (see the [per-unit section](@ref per_unit) for more details)
## [Using subsystems](@id subsystems)
For certain applications, such as those that employ dispatch coordination methods or decomposition approaches, it is useful to be able to split components into subsystems based upon user-defined criteria. The `System` provides `subsystem` containers for this purpose. Each subsystem is defined by a name and can hold references to any number of components.
The following commands demonstrate how to create subsystems and add components.
```@repl subsystem
using PowerSystems;
using PowerSystemCaseBuilder;
sys = build_system(PSISystems, "c_sys5_pjm")
add_subsystem!(sys, "1")
add_subsystem!(sys, "2")
```
Devices in the system can be assigned to the subsystems in the following way using the function [`add_component_to_subsystem!`](@ref)
```@repl subsystem
g = get_component(ThermalStandard, sys, "Alta")
add_component_to_subsystem!(sys, "1", g)
g = get_component(ThermalStandard, sys, "Sundance")
add_component_to_subsystem!(sys, "2", g)
```
To retrieve components assigned to a specific subsystem, add the `subsystem_name` keyword argument to `get_components`.
```@repl subsystem
gens_1 = get_components(ThermalStandard, sys; subsystem_name = "1")
get_name.(gens_1)
gens_2 = get_components(ThermalStandard, sys; subsystem_name = "2")
get_name.(gens_2)
```
One useful feature that requires care when used is generating a new [`System`](@ref) from a `subsystem` assignment.
The function [`from_subsystem`](@ref) will allow the user to produce a new [`System`](@ref) that can be used or exported.
This functionality requires careful subsystem assignemnt of the devices and its dependencies. Following from the example in this document, you can export a system as follows:
```@repl subsystem
from_subsystem(sys, "1")
```
!!! warning
The system is invalid because the bus connected to the Alta generator is not part of the subsystem. We can add it, and then run [`from_subsystem`](@ref) again
```@repl subsystem
g = get_component(ThermalStandard, sys, "Alta")
b = get_bus(g)
add_component_to_subsystem!(sys, "1", b)
from_subsystem(sys, "1")
```
Advanced users can use the keyword `runchecks=false` and avoid any topological check in the process.
It is highly recommended that users only do this if they clearly understand how to validate the resulting system before using it for modeling.
================================================
FILE: docs/src/explanation/time_series.md
================================================
# [Time Series Data](@id ts_data)
## Categories of Time Series
The bulk of the data in many power system models is time series data. Given the potential
complexity, `PowerSystems.jl` has a set of definitions to organize this data and
enable consistent modeling.
`PowerSystems.jl` supports two categories of time series data depending on the
process to obtain the data and its interpretation:
- [Static Time Series Data](@ref)
- [Forecasts](@ref)
These categories are are all subtypes of `TimeSeriesData` and fall within this time series
type hierarchy:
```@repl
using PowerSystems #hide
import TypeTree: tt #hide
docs_dir = joinpath(pkgdir(PowerSystems), "docs", "src", "tutorials", "utils"); #hide
include(joinpath(docs_dir, "docs_utils.jl")); #hide
print(join(tt(TimeSeriesData), "")) #hide
```
### Static Time Series Data
A static time series data is a single column of data where each time period has a single
value assigned to a component field, such as its maximum active power. This data commonly
is obtained from historical information or the realization of a time-varying quantity.
Static time series usually comes in the following format, with a set [resolution](@ref R)
between the time-stamps:
| DateTime | Value |
|:------------------- |:-----:|
| 2020-09-01T00:00:00 | 100.0 |
| 2020-09-01T01:00:00 | 101.0 |
| 2020-09-01T02:00:00 | 99.0 |
This example is a 1-hour resolution static time-series.
In PowerSystems, a static time series is represented using [`SingleTimeSeries`](@ref).
### Forecasts
A forecast time series includes predicted values of a time-varying quantity that commonly
includes a look-ahead window and can have multiple data values representing each time
period. This data is used in simulation with receding horizons or data generated from
forecasting algorithms.
Key forecast format parameters are the forecast [resolution](@ref R), the
[interval](@ref I) of time between forecast [initial times](@ref I), and the number of
[forecast windows](@ref F) (or forecasted values) in the forecast [horizon](@ref H).
Forecast data usually comes in the following format, where a column represents the time
stamp associated with the [initial time](@ref I) of the forecast, and the remaining columns
represent the forecasted values at each step in the forecast [horizon](@ref H).
| DateTime | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|:------------------- |:-----:|:-----:|:-----:|:----:|:-----:|:-----:|:-----:|:----- |
| 2020-09-01T00:00:00 | 100.0 | 101.0 | 101.3 | 90.0 | 98.0 | 87.0 | 88.0 | 67.0 |
| 2020-09-01T01:00:00 | 101.0 | 101.3 | 99.0 | 98.0 | 88.9 | 88.3 | 67.1 | 89.4 |
| 2020-09-01T02:00:00 | 99.0 | 67.0 | 89.0 | 99.9 | 100.0 | 101.0 | 112.0 | 101.3 |
This example forecast has a [interval](@ref I) of 1 hour and a [horizon](@ref H) of 8.
PowerSystems defines the following Julia structs to represent forecasts:
- [`Deterministic`](@ref): Point forecast without any uncertainty representation.
- [`Probabilistic`](@ref): Stores a discretized cumulative distribution functions
(CDFs) or probability distribution functions (PDFs) at each time step in the
look-ahead window.
- [`Scenarios`](@ref): Stores a set of probable trajectories for forecasted quantity
with equal probability.
## Multiple Forecast Intervals
PowerSystems supports attaching multiple forecast groups to the same component, where each
group shares the same name and resolution but differs by [interval](@ref I). This is useful
when a component needs forecasts updated at different frequencies — for example, an
hourly-updated forecast and a daily-updated forecast for the same quantity.
Use [`transform_single_time_series!`](@ref) with `delete_existing = false` to create
multiple [`DeterministicSingleTimeSeries`](@ref) transforms from the same
[`SingleTimeSeries`](@ref), each with a different interval:
```julia
# Create a 30-minute interval forecast
transform_single_time_series!(sys, Hour(1), Minute(30); delete_existing = false)
# Create a 1-hour interval forecast from the same underlying data
transform_single_time_series!(sys, Hour(1), Hour(1); delete_existing = false)
```
When multiple forecasts share the same name and resolution, you must specify the `interval`
keyword argument to disambiguate retrieval and removal:
```julia
# Retrieve a specific interval's forecast
ts = get_time_series(DeterministicSingleTimeSeries, component, "max_active_power";
interval = Minute(30))
# Query forecast parameters for a specific interval
get_forecast_horizon(sys; interval = Minute(30))
get_forecast_initial_times(sys; interval = Hour(1))
# Remove only one interval's forecasts
remove_time_series!(sys, DeterministicSingleTimeSeries, component, "max_active_power";
interval = Minute(30))
```
Omitting `interval` when multiple intervals exist for the same name will raise an
`ArgumentError`.
## Data Storage
By default PowerSystems stores time series data in an HDF5 file.
This prevents
large datasets from overwhelming system memory. Refer to this
[page](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/dev_guide/time_series/#Data-Format)
for details on how the time series data is stored in HDF5 files.
Time series data can be stored actual component values (for instance MW) or scaling
factors intended to be multiplied by a scalar to generate the component values.
By default PowerSystems treats the values in the time
series data as physical units. In order to specify them as scaling factors, you
must pass the accessor function that provides the multiplier value (e.g.,
`get_time_series_array`). The scaling factor multiplier
must be passed into the forecast when you create it to use this option.
The time series contains fields for `scaling_factor_multiplier` and `data`
to identify the details of th `Component` field that the time series describes, and the
time series `data`. For example: we commonly want to use a time series to
describe the maximum active power capability of a renewable generator. In this case, we
can create a `SingleTimeSeries` with a `TimeArray` and an accessor function to the
maximum active power field in the struct describing the generator. In this way, we can
store a scaling factor time series that will get multiplied by the maximum active power
rather than the magnitudes of the maximum active power time series.
Examples of how to create and add time series to system can be found in the
[Add Time Series Example](https://sienna-platform.github.io/PowerSystems.jl/stable/tutorials/add_forecasts/)
================================================
FILE: docs/src/explanation/transformer_per_unit_models.md
================================================
# [Transformer per unit transformations](@id transformers_pu)
The per-unit (p.u.) system is a fundamental tool in power system analysis, especially when dealing with transformers. It simplifies calculations by normalizing all quantities (voltage, current, power, impedance) to a common base. This effectively "retains" the ideal transformer from the circuit diagram because the per-unit impedance of a transformer remains the same when referred from one side to the other. This page is not a comprehensive guide on transformer per-unit calculations, a more in depth explanation can be found in [`this link`](https://en.wikipedia.org/wiki/Per-unit_system) or basic power system literature.
## Establishing Base Values
For a multi-voltage system with transformers, you need to establish consistent base values across different voltage zones.
- Transformer Voltage Base ($V_{base, LL}$):
+ The voltage base is determined by the transformer's nominal line-to-line voltage ratio:
$$V_{base, \text{secondary}} = V_{base, \text{primary}} \times \frac{V_{\text{rated, secondary}}}{V_{\text{rated, primary}}}$$
Where $V_{\text{rated, secondary}}$ and $V_{\text{rated, primary}}$ are the transformer's nominal (rated) line-to-line voltages on its secondary and primary sides, respectively.
+ This value can be slightly different that the attached bus voltage value. In certain low voltage systems, transformers with a higher base voltage can be connected to buses with lower voltage set points. As of PowerSystems v5 transformers now have field for the base voltage.
- How is the data stored?: Transformer impedance (usually reactive impedance, $X_{pu}$) is typically given on its own nameplate ratings (rated MVA and rated voltages). **The data in PowerSystems.jl is stored in the device base** and transformer to the system base when using the correct getter functions.
- **Derived Base Impedance ($Z_{base}$):**
+ Once $S_{base, 3\phi}$ and $V_{base, LL}$ are established for each voltage zone, the base impedance can be calculated as follows:
$$Z_{base} = \frac{(V_{base, LL})^2}{S_{base, 3\phi}}$$
Where $V_{base, LL}$ is in kV and $S_{base, 3\phi}$ is in MVA, resulting in $Z_{base}$ in Ohms ($\Omega$).
### Transformer Impedance Transformations
The most significant advantage of the per-unit system for transformers is that **the per-unit impedance of a transformer is the same on both sides**, provided the base voltages are chosen according to the transformer's turns ratio and the base power is consistent.
- Changing Base for Transformer Impedance: If the system-wide base $S_{base, 3\phi}$ and the zone-specific voltage bases ($V_{base, \text{primary zone}}$ and $V_{base, \text{secondary zone}}$) differ from the transformer's ratings, you need to convert the transformer's per-unit impedance to the new system base.
The formula for changing base of an impedance is:
$$Z_{pu, \text{new}} = Z_{pu, \text{old}} \times \left(\frac{S_{base, \text{new}}}{S_{rated, \text{old}}}\right) \times \left(\frac{V_{rated, \text{old}}}{V_{base, \text{new}}}\right)^2$$
+ Here, $S_{base, \text{new}}$ is your chosen system-wide base MVA.
+ $S_{rated, \text{old}}$ is the transformer's rated MVA (from nameplate).
+ $V_{rated, \text{old}}$ is the transformer's rated voltage on the side you are considering (e.g., if you're transforming the impedance to the primary side's base, use the primary rated voltage).
+ $V_{base, \text{new}}$ is the *new* system base voltage for that side of the transformer.
When calculating the transformer's impedance on the system base, you only need to perform this calculation once. Since the per-unit impedance of a transformer is the same when referred from one side to the other (given correct base voltage selection), the $Z_{pu, \text{new}}$ calculated for the transformer will be used regardless of which side you are viewing it from in the per-unit circuit diagram.
!!! note
The return value of the getter functions, e.g., [`get_x`](@ref) for the transformer impedances will perform the transformations following the convention in [`Per-unit Conventions`](@ref per_unit).
================================================
FILE: docs/src/explanation/type_structure.md
================================================
# [Type Structure](@id type_structure)
PowerSystems.jl provides a type hierarchy to contain power system data.
## Types in PowerSystems
In PowerSystems.jl, data that describes infrastructure components is held in `struct`s.
For example, an `ACBus` is a `struct` with the following parameters to describe a bus
on an AC network:
```@repl types
using PowerSystems #hide
import TypeTree: tt #hide
docs_dir = joinpath(pkgdir(PowerSystems), "docs", "src", "tutorials", "utils"); #hide
include(joinpath(docs_dir, "docs_utils.jl")); #hide
print_struct(ACBus) #hide
```
## Type Hierarchy
PowerSystems is intended to organize data by the behavior of the devices that
the data represents. A type hierarchy has been defined with several levels of
abstract types starting with `InfrastructureSystemsType`. There are a bunch of subtypes of
`InfrastructureSystemsType`, but the important ones to know about are:
- `System`: overarching `struct` that collects all of the `Component`s
- `Component`: includes all elements of power system data
+ `Topology`: includes non physical elements describing network connectivity
+ `Service`: includes descriptions of system requirements (other than energy balance)
+ `Device`: includes descriptions of all the physical devices in a power system
- `InfrastructureSystems.DeviceParameter`: includes structs that hold data describing the
dynamic, or economic capabilities of `Device`.
- `TimeSeriesData`: Includes all time series types
+ `Forecast`: includes structs to define time series of forecasted data where multiple
values can represent each time stamp
+ `StaticTimeSeries`: includes structs to define time series with a single value for each
time stamp
The abstract hierarchy enables categorization of the devices by their operational
characteristics and modeling requirements.
For instance, generation is classified by the distinctive
data requirements for modeling in three categories: [`ThermalGen`](@ref), [`RenewableGen`](@ref),
and [`HydroGen`](@ref).
`PowerSystems.jl` has a category [`Topology`](@ref) of topological components
(e.g., [`ACBus`](@ref), [`Arc`](@ref)), separate from the physical components.
The hierarchy also includes components absent in standard data models, such as services.
The services category includes reserves, transfers and [`AGC`](@ref). The power of `PowerSystems.jl`
lies in providing the abstraction without an implicit mathematical representation of the component.
As a result of this design, developers can define model logic entirely based on abstract
types and create generic code to support modeling technologies that are not yet
implemented in the package.
```@raw html
``` ⠀
```
================================================
FILE: docs/src/generate_input_config_table.jl
================================================
@info "Generating Input Configuration Descriptor Table"
function create_md()
descriptor = PowerSystems._read_config_file(
joinpath(
dirname(pathof(PowerSystems)),
"descriptors",
"power_system_inputs.json",
),
)
columns = [
"name",
"description",
"unit",
"unit_system",
"base_reference",
"default_value",
"value_options",
"value_range",
]
header = "| " * join(columns, " | ") * " |\n" * repeat("|----", length(columns)) * "|\n"
s = "## [`PowerSystemTableData` Accepted CSV Columns](@id tabledata_input_config) \n\n"
s = string(
s,
"The following tables describe default CSV column definitions accepted by the ",
)
s = string(
s,
"`PowerSystemeTableData` parser defined by `src/descriptors/power_system_inputs.json`:\n\n",
)
for (cat, items) in descriptor
csv = ""
for name in PowerSystems.INPUT_CATEGORY_NAMES
if name[2] == cat
csv = name[1]
break
end
end
csv == "" && continue
s = string(s, "### $csv.csv:\n\n")
s = string(s, header)
for item in items
extra_cols = setdiff(keys(item), columns)
if !isempty(extra_cols)
# make sure that there arent unexpected entries
throw(@error "config file fields not included in header" extra_cols)
end
row = []
for col in columns
val = string(get(item, col, " "))
if col == "default_value" && val == " "
val = "*REQUIRED*"
end
push!(row, val)
end
s = string(s, "|" * join(row, "|") * "|\n")
end
s = string(s, "\n")
end
s = replace(s, r"[_$]" => s"\\\g<0>")
return s
end
txt = create_md()
open(
"/Users/cbarrows/Documents/repos/PowerSystems.jl/docs/src/modeler_guide/markdown.txt",
"w",
) do f
write(f, txt)
end
================================================
FILE: docs/src/generate_validation_table.jl
================================================
@info "Generating Validation Table"
function generate_validation_table(filepath::AbstractString)
descriptor = InfrastructureSystems.read_validation_descriptor(
joinpath(PSYPATH, "descriptors", "power_system_structs.json"),
)
open(filepath, "w") do io
write(io, "# Data Requirements\n\n")
write(
io,
"| Struct Name | Field Name | DataType | Min | Max | Action |\n",
)
write(
io,
"|---------------|--------------|------------|-------|-------|----------|\n",
)
for item in descriptor
for field in item["fields"]
write(io, "|$(item["struct_name"])|$(field["name"])|$(field["data_type"])|")
if haskey(field, "valid_range")
if field["valid_range"] isa Dict
valid_min = field["valid_range"]["min"]
valid_max = field["valid_range"]["max"]
for value in (valid_min, valid_max)
write(io, isnothing(value) ? "null" : string(value))
write(io, "|")
end
else
write(io, "$(field["valid_range"])|$(field["valid_range"])|")
end
else
write(io, "-|-")
end
if haskey(field, "validation_action")
write(io, "$(field["validation_action"])|\n")
else
write(io, "|-\n")
end
end
end
end
end
generate_validation_table(joinpath(PSYPATH, "../docs/src/man/data_requirements_table.md"))
================================================
FILE: docs/src/how_to/add_component_natural_units.md
================================================
# Add a Component in Natural Units
```@setup add_in_nu
using PowerSystems; #hide
using PowerSystemCaseBuilder #hide
system = build_system(PSISystems, "modified_RTS_GMLC_DA_sys"); #hide
```
`PowerSystems.jl` has [three per-unitization options](@ref per_unit) for getting, setting
and displaying data.
Currently, only one of these options -- `"DEVICE_BASE"` -- is supported when using a
constructor function define a component. You can see
[an example of the default capabilities using `"DEVICE_BASE"` here](@ref "Adding Loads and Generators").
We hope to add capability to define components in
`"NATURAL_UNITS"` with constructors in the future, but for now, below is a workaround
for users who prefer to define data using `"NATURAL_UNITS"` (e.g., MW, MVA, MVAR, or MW/min):
### Step 1: Set Units Base
Set your (previously-defined) `System`'s units base to `"NATURAL_UNITS"`:
```@repl add_in_nu
set_units_base_system!(system, "NATURAL_UNITS")
```
Now, the "setter" functions have been switched to define data using natural units (MW, MVA,
etc.), taking care of the necessary data conversions behind the scenes.
### Step 2: Define Empty Component
Define an empty component with `0.0` or `nothing` for all the power-related fields except
`base_power`, which is always in MVA.
For example:
```@repl add_in_nu
gas1 = ThermalStandard(;
name = "gas1",
available = true,
status = true,
bus = get_component(ACBus, system, "Cobb"), # Attach to a previously-defined bus named Cobb
active_power = 0.0,
reactive_power = 0.0,
rating = 0.0,
active_power_limits = (min = 0.0, max = 0.0),
reactive_power_limits = nothing,
ramp_limits = nothing,
operation_cost = ThermalGenerationCost(nothing),
base_power = 30.0, # MVA
time_limits = (up = 8.0, down = 8.0), # Hours, unaffected by per-unitization
must_run = false,
prime_mover_type = PrimeMovers.CC,
fuel = ThermalFuels.NATURAL_GAS,
);
```
### Step 3: Attach the Component
Attach the component to your `System`:
```@repl add_in_nu
add_component!(system, gas1)
```
### Step 4: Add Data with "setter" Functions
Use individual "setter" functions to set each the value of each numeric field in natural
units:
```@repl add_in_nu
set_rating!(gas1, 30.0) #MVA
set_active_power_limits!(gas1, (min = 6.0, max = 30.0)) # MW
set_reactive_power_limits!(gas1, (min = 6.0, max = 30.0)) # MVAR
set_ramp_limits!(gas1, (up = 6.0, down = 6.0)) #MW/min
```
Notice the return values are divided by the `base_power` of 30 MW, showing the setters have
done the per-unit conversion into `"DEVICE_BASE"` behind the scenes.
!!! tip
Steps 2-4 can be called within a `for` loop to define many components at once (or step 3
can be replaced with [`add_components!`](@ref) to add all components at once).
#### See Also
- [Read more to understand per-unitization in PowerSystems.jl](@ref per_unit)
- Learn how to use the default constructors and explore the per-unitization settings in
[Create and Explore a Power `System`](@ref)
================================================
FILE: docs/src/how_to/add_cost_curve.md
================================================
# [Adding an Operating Cost](@id cost_how_to)
This how-to guide covers the steps to select and add an operating cost to a component,
such as a generator, load, or energy storage system.
```@setup costcurve
using PowerSystems #hide
```
To begin, the user must make 2 or 3 decisions before defining the operating cost:
1. Select an appropriate [`OperationalCost`](@ref) from the [`OperationalCost`](@ref)
options. In general, each operating cost has parameters to define fixed and variable costs.
To be able to define an `OperationalCost`, you must first select a curve to represent the
variable cost(s).
1. If you selected [`ThermalGenerationCost`](@ref) or [`HydroGenerationCost`](@ref),
select either a [`FuelCurve`](@ref) or [`CostCurve`](@ref) to represent the variable
cost, based on the units of the generator's data.
* If you have data in terms of heat rate or water flow, use [`FuelCurve`](@ref).
* If you have data in units of currency, such as \$/MWh, use [`CostCurve`](@ref).
If you selected another `OperationalCost` type, the variable cost is represented
as a `CostCurve`.
2. Select a [`ValueCurve`](@ref) to represent the variable cost data by comparing the format
of your variable cost data to the [Variable Cost Representations table](@ref curve_table)
and the [`ValueCurve`](@ref) options.
Then, the user defines the cost by working backwards:
1. Define the variable cost's `ValueCurve`
2. Use the `ValueCurve` to define the selected `CostCurve` or `FuelCurve`
3. Use the `CostCurve` or `FuelCurve` to define the `OperationalCost`
Let's look at a few examples.
## Example 1: A Renewable Generator
We have a renewable unit that produces at \$22/MWh.
Following the decision steps above:
1. We select [`RenewableGenerationCost`](@ref) to represent this renewable generator.
2. We select a [`LinearCurve`](@ref) to represent the \$22/MWh variable cost.
Following the implementation steps, we define `RenewableGenerationCost` by nesting the
definitions:
```@repl costcurve
RenewableGenerationCost(; variable = CostCurve(; value_curve = LinearCurve(22.0)))
```
## Example 2: A Thermal Generator with Input/Output Data
We have a thermal generating unit that has a heat input of 1400 GJ/h at 100 MW and 2200 GJ/MWh at
200 MW, plus a fixed cost of \$6.0/hr, a start-up cost of \$2000, and a shut-down cost of
\$1000. Its fuel cost is \$20/GJ.
Following the decision steps above:
1. We select [`ThermalGenerationCost`](@ref) to represent this thermal generator.
2. We select [`FuelCurve`](@ref) because we have consumption in units of fuel (GJ/MWh)
instead of currency.
3. We select a [`PiecewisePointCurve`](@ref) to represent the piecewise linear heat rate
curve.
This time, we'll define each step individually, beginning with the heat rate curve:
```@repl costcurve
heat_rate_curve = PiecewisePointCurve([(100.0, 1400.0), (200.0, 2200.0)])
```
Use the heat rate to define the fuel curve, including the cost of fuel:
```@repl costcurve
fuel_curve = FuelCurve(; value_curve = heat_rate_curve, fuel_cost = 20.0)
```
Finally, define the full operating cost:
```@repl costcurve
cost = ThermalGenerationCost(;
variable = fuel_curve,
fixed = 6.0,
start_up = 2000.0,
shut_down = 1000.0,
)
```
This `OperationalCost` can be used when defining a component or added to an existing component using
`set_operation_cost!`.
## Example 3: A Thermal Generator with Marginal Heat Rate Data
Often times, generator efficiency data is provided in the form of marginal heat rates (the additional
heat input energy required per MWh of electrical output energy) as a function of generator output.
For example, the thermal unit above can be described by a heat input of 1400 GJ/h at 100 MW with a marginal
heat rate of 8 GJ/MWh across the operating range (100 MW - 200 MW).
In this case, we can specify the heat rate curve with [`PiecewiseIncrementalCurve`](@ref) via the marginal
heat rate directly:
```@repl costcurve
heat_rate_curve = PiecewiseIncrementalCurve(1400.0, [100.0, 200.0], [8.0])
```
The [`FuelCurve`](@ref) and [`ThermalGenerationCost`](@ref) are specified in the same way despite the
differing representation of the value curve:
```@repl costcurve
fuel_curve = FuelCurve(; value_curve = heat_rate_curve, fuel_cost = 20.0)
cost = ThermalGenerationCost(;
variable = fuel_curve,
fixed = 6.0,
start_up = 2000.0,
shut_down = 1000.0,
)
```
Note that the [`ThermalGenerationCost`](@ref) defined in Example 2 and 3 are functionally equivalent.
================================================
FILE: docs/src/how_to/add_fuel_curve_timeseries.md
================================================
# [Add Time Series Fuel Cost Data](@id fuel_curve_timeseries)
This how-to guide demonstrates how to add time-varying fuel costs to a thermal generator
that uses a [`ThermalGenerationCost`](@ref) with a [`FuelCurve`](@ref). This is useful when
fuel prices vary over time, such as with natural gas prices that change throughout the day
or across seasons.
```@setup fuelcosts
using PowerSystems
using Dates
using TimeSeries
using DataStructures: SortedDict
# Create a bus
bus = ACBus(;
number = 1,
name = "bus1",
available = true,
bustype = ACBusTypes.REF,
angle = 0.0,
magnitude = 1.0,
voltage_limits = (min = 0.9, max = 1.1),
base_voltage = 230.0,
)
# Define the heat rate curve
heat_rate_curve = PiecewisePointCurve([
(100.0, 7.0), # At 100 MW: 7 GJ/MWh
(200.0, 8.0), # At 200 MW: 8 GJ/MWh
(300.0, 9.5), # At 300 MW: 9.5 GJ/MWh
])
# Create a FuelCurve with an initial scalar fuel cost
fuel_curve = FuelCurve(;
value_curve = heat_rate_curve,
fuel_cost = 5.0, # Initial fuel cost: $5.0/GJ
)
# Create the ThermalGenerationCost
thermal_cost = ThermalGenerationCost(;
variable = fuel_curve,
fixed = 10.0,
start_up = 5000.0,
shut_down = 2000.0,
)
# Create the thermal generator
generator = ThermalStandard(;
name = "generator1",
available = true,
status = true,
bus = bus,
active_power = 250.0,
reactive_power = 50.0,
rating = 300.0,
prime_mover_type = PrimeMovers.ST,
fuel = ThermalFuels.NATURAL_GAS,
active_power_limits = (min = 50.0, max = 300.0),
reactive_power_limits = (min = -50.0, max = 100.0),
ramp_limits = (up = 5.0, down = 5.0),
time_limits = (up = 2.0, down = 1.0),
operation_cost = thermal_cost,
base_power = 100.0,
)
# Create the system and add components
sys = System(100.0)
add_component!(sys, bus)
add_component!(sys, generator)
```
## Overview
This guide assumes you have already defined a [`System`](@ref) with a thermal generator (e.g., [`ThermalStandard`](@ref)) that has a
[`ThermalGenerationCost`](@ref) containing a [`FuelCurve`](@ref). The generator's
`FuelCurve` must specify a heat rate curve (fuel consumption at different power outputs)
and an initial scalar fuel cost value, which will be replaced with time series data.
To add time-varying fuel costs, you need to:
1. **Create time series fuel cost data**: Prepare your fuel price data as either
[`SingleTimeSeries`](@ref) (for simple time-varying data like historical prices) or
[`Deterministic`](@ref) (for forecast windows used in day-ahead scheduling with rolling
horizons).
2. **Attach the time series to the generator**: Use the [`set_fuel_cost!`](@ref) function
to attach the time series data to the generator component. The component must already
be added to the system before attaching time series.
3. **Verify and retrieve the data**: Use [`get_fuel_cost`](@ref) to retrieve the time
series data and verify it was attached correctly.
**Key requirements:**
- The generator must use a [`FuelCurve`](@ref) (not a [`CostCurve`](@ref)) in its
[`ThermalGenerationCost`](@ref) to enable time series fuel costs
- Time series resolution should match your simulation resolution (e.g., Hour(1) for
hourly simulations)
- Fuel cost units should be in \$/GJ (or \$/MBtu, etc.) and heat rate in GJ/MWh (or
MBtu/MWh); their product gives the effective cost in \$/MWh
## Step 1: Create Time Series Fuel Cost Data
Create time series data representing fuel costs that vary throughout the day. This example
uses hourly natural gas prices with [`SingleTimeSeries`](@ref):
```@repl fuelcosts
# Define the initial time and resolution
initial_time = DateTime("2024-01-01T00:00:00")
resolution = Hour(1)
# Create hourly fuel cost data for 24 hours
# Prices are higher during peak hours (midday to early evening) and lower at night
fuel_cost_data = [
4.5, 4.3, 4.2, 4.1, 4.2, 4.5, # 00:00 - 05:00 (low overnight prices)
5.0, 5.5, 6.0, 6.5, 7.0, 7.5, # 06:00 - 11:00 (morning ramp)
8.0, 8.0, 7.8, 7.8, 7.5, 7.0, # 12:00 - 17:00 (afternoon peak)
6.5, 6.0, 5.5, 5.0, 4.8, 4.6, # 18:00 - 23:00 (evening decline)
]
# Create timestamps for each data point
timestamps =
collect(initial_time:resolution:(initial_time + Hour(length(fuel_cost_data) - 1)))
# Create a TimeArray with timestamps and data
time_array = TimeArray(timestamps, fuel_cost_data)
# Create a SingleTimeSeries from the TimeArray
fuel_cost_timeseries = SingleTimeSeries(;
name = "fuel_cost",
data = time_array,
)
```
## Step 2: Attach Time Series to the Generator
Use the [`set_fuel_cost!`](@ref) function to attach the time series data to your
previously defined [`System`](@ref) and generator (e.g., [`ThermalStandard`](@ref)):
```@repl fuelcosts
# Add the time series fuel cost to the generator
set_fuel_cost!(sys, generator, fuel_cost_timeseries)
```
## Step 3: Verify and Retrieve Time Series Data
Now the generator has time-varying fuel costs. You can retrieve the time series data:
```@repl fuelcosts
# Get the fuel cost time series starting at the initial time
fuel_forecast = get_fuel_cost(generator; start_time = initial_time)
# Display the first few values
first(TimeSeries.values(fuel_forecast), 6)
```
You can also query for a specific time window:
```@repl fuelcosts
# Get fuel costs for a specific 12-hour period starting at 6 AM
morning_time = DateTime("2024-01-01T06:00:00")
fuel_forecast_morning = get_fuel_cost(generator; start_time = morning_time, len = 12)
# Display these values
TimeSeries.values(fuel_forecast_morning)
```
## See Also
- [Add an Operating Cost](@ref cost_how_to) - General guide for adding operational costs
- [Parse Time Series Data from .csv files](@ref parsing_time_series) - How to load time series from CSV files
- [Working with Time Series Data](@ref tutorial_time_series) - Tutorial on time series data in PowerSystems
- [`ThermalGenerationCost`](@ref) - API reference for thermal generation costs
- [`FuelCurve`](@ref) - API reference for fuel curves
================================================
FILE: docs/src/how_to/add_new_types.md
================================================
# Add a New or Custom Type
This page describes how developers should add types to `PowerSystems.jl`
## Type Hierarchy
All structs that correlate to power system components must be subtypes of the
[`Component`](@ref) abstract type. Browse its type hierachy to choose an appropriate
supertype for your new struct.
## Interfaces
Refer to the
[managing components guide](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/dev_guide/components_and_container/)
for component requirements.
In particular, please note the methods `supports_time_series` (default = false) and
`supports_supplemental_attributes` (default = true) that you may need to implement.
**Note**: `get_internal` and `get_name` are imported into `PowerSystems`, so you should
implement your methods as `PowerSystems` methods.
Some abstract types define required interface functions in docstring. Be sure
to implement each of them for your new type.
Formalized documentation for each abstract type is TBD.
## Specialize an Existing Type
There are scenarios where you may want to make a new type that is identical to
an existing type except for one attribute or behavior, and don't want to
duplicate the entire existing type and methods. In programming languages that
support inheritance you would derive a new class from the existing class and
automatically inherit its fields and methods. Julia doesn't support that.
However, you can achieve a similar result with a forwarding macro.
The basic idea is that you include the existing type within your struct and
then use a macro to automatically forward specific methods to that instance.
A few PowerSystems structs use the macro `InfrastructureSystems.@forward` to
do this. Refer to the struct [`RoundRotorQuadratic`](@ref) for an example of how to
use this.
## Custom Rules
Some types require special checks before they can be added to or removed from a
system. One example is the case where a component includes another component
that is also stored in the system. We must ensure that the parent component
does not contain a reference to another component that is not already attached
to the system.
Similarly, if the child object is removed from the system we must also remove
the parent's reference to that child.
The source file `src/base.jl` provides functions that you can implement for
your new type to manage these scenarios.
- `check_component_addition(sys::System, component::Component; kwargs...)`
- `handle_component_addition!(sys::System, component::Component; kwargs...)`
- `check_component_removal(sys::System, component::Component; kwargs...)`
- `handle_component_removal!(sys::System, component::Component; kwargs...)`
The functions `add_component!()` and `remove_component!()` call the check
function before performing actions and then call the handle function
afterwards. The default behavior of these functions is to do nothing. Implement
versions that take your type in order to add your own checks or perform
additional actions.
Beware of the condition where a custom method is already implemented for a
supertype of your type.
Note that you can call the helper functions `is_attached(component, system)`
and `throw_if_not_attached(component, system)`.
### Custom Validation
You can implement three methods to perform custom validation or correction for your type.
PowerSystems calls all of these functions in `add_component!`.
- `sanitize_component!(component::Component, sys::System)`: intended to make standard data corrections (e.g. voltage angle in degrees -> radians)
- `validate_component(component::Component)`: intended to check component field values for internal consistency
- `validate_component_with_system(component::Component, sys::System)`: intended to check component field values for consistency with system
### Struct Requirements for Serialization of custom components
One key feature of `PowerSystems.jl` is the serialization capabilities. Supporting
serialization and de-serialization of custom components requires the implementation of
several methods. The serialization code converts structs to dictionaries where the struct
fields become dictionary keys.
The code imposes these requirements:
1. The InfrastructureSystems methods `serialize` and `deserialize` must be
implemented for the struct. InfrastructureSystems implements a method that
covers all subtypes of `InfrastructureSystemsType`. All PowerSystems
components should be subtypes of `PowerSystems.Component` which is a subtype
`InfrastructureSystemsType`, so any new structs should be covered as well.
2. All struct fields must be able to be encoded in JSON format or be covered be
covered by `serialize` and `deserialize` methods. Basic types, such as
numbers and strings or arrays and dictionaries of numbers and strings,
should just work. Complex containers with symbols may not.
3. Structs relying on the default `deserialize` method must have a kwarg-only
constructor. The deserialization code constructs objects by splatting the
dictionary key/value pairs into the constructor.
4. Structs that contain other PowerSystem components (like a generator contains
a bus) must serialize those components as UUIDs instead of actual values.
The deserialization code uses the UUIDs as a mechanism to restore a
reference to the actual object rather a new object with identical values. It
also significantly reduces the size of the JSON file.
Refer to `InfrastructureSystems.serialize_struct` for example behavior. New
structs that are not subtypes of `InfrastructureSystemsType` may be able to
call it directly.
#### How to trouble-shoot serialization issues
Here are some examples of potential problems and solutions if you need to implement custom
`InfrastructureSystems.serialize` and `InfrastructureSystems.deserialize` methods
for your type.:
**Problem**: Your struct contains a field defined as an abstract type. The
deserialization process doesn't know what concrete type to construct.
*Solution*: Encode the concrete type into the serialized dictionary as a string.
*Example*: `serialize` and `deserialize` methods for `DynamicBranch` in
`src/models/dynamic_branch.jl`.
**Problem**: Similar to above in that a field is defined as an abstract type
but the struct is parameterized on the actual concrete type.
*Solution*: Use the fact that the concrete type is encoded into the serialized
type of the struct and extract it in a customized `deserialze` method.
*Example*: `deserialize` method for `OuterControl` in
`src/models/OuterControl.jl`.
### Adding `PowerSystems.jl` as a dependency in a modeling package
```julia
module MyModelingModule
import PowerSystems as PSY
import InfrastructureSystems as IS
export MyDevice
export get_name
mutable struct MyDevice <: PSY.Device
name::String
internal::IS.InfrastructureSystemsInternal
end
function MyDevice(name::String)
return MyDevice(name, IS.InfrastructureSystemsInternal())
end
PSY.get_name(val::MyDevice) = val.name
end
```
## [Auto-generating Structs](@id autogen)
Most `PowerSystems.jl` structs are auto-generated from the JSON descriptor file
`src/descriptors/power_system_structs.json`.
You can add your new struct
here or write it manually when contributing code to the repository.
If all you need is the basic struct definition and getter/setter functions then
you will likely find the auto-generation helpful.
If you will need to write specialized functions for the type then you will
probably want to write it manually.
Please refer to the docstrings for the functions `generate_struct`
and `generate_structs`. Full details are in the InfrastructureSystems documentation at
[https://sienna-platform.github.io/InfrastructureSystems.jl/stable/dev_guide/auto_generation/](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/dev_guide/auto_generation/).
### Testing the addition of new struct to the code base
In order to merge new structs to the code base, your struct needs to pass several tests.
1. addition to `System`
2. retrieval from `System`
3. serialization/de-serialization
The following code block is an example of the code that the new struct needs to pass
```julia
using PowerSystems
sys = System(100.0)
device = NewType(data)
# add your component to the system
add_component!(sys, device)
retrived_device = get_component(NewType, sys, "component_name")
# Serialize
to_json(sys, "sys.json")
# Re-create the system and find your component.
sys2 = System("sys.json")
serialized_device = get_component(NewType, sys, "component_name")
@test get_name(retrieved_device) == get_name(serialized_device)
```
================================================
FILE: docs/src/how_to/adding_additional_fields.md
================================================
# [Add additional data to a component](@id additional_fields)
All `PowerSystems.jl` components have an `ext` field that contains an empty `Dictionary`.
This Dictionary is useful to contain additional required data where there is no need to
create new behaviors with that data. A simple example is the addition of geographic
information, if needed.
#### Example
```@setup generated_adding_additional_fields
using PowerSystems #hide
using PowerSystemCaseBuilder #hide
system = build_system(PSISystems, "modified_RTS_GMLC_DA_sys"); #hide
```
__Step 1:__ Use `get_ext` to get the `ext` field of the desired components and assign your data:
```@repl generated_adding_additional_fields
for g in get_components(ThermalStandard, system)
external_field = get_ext(g)
external_field["my_data"] = 1.0
end
```
Here, we added additional data called `my_data` to the [`ThermalStandard`](@ref)
generators in a previously defined [`System`](@ref).
__Step 2:__ Retrieve your data using `get_ext` again
First, retrieve the first ThermalStandard generator:
```@repl generated_adding_additional_fields
gen = collect(get_components(ThermalStandard, system))[1];
```
Then, retrieve `my_data` from the generator and verify it is 1.0, as assigned.
```@repl generated_adding_additional_fields
retrieved_data = get_ext(gen)["my_data"]
```
================================================
FILE: docs/src/how_to/build_system_with_files.md
================================================
# [Building a System from CSV Files](@id system_from_csv)
If you have input data on the component specifications and time series data formatted in
CSV files, rather than a Matpower or PSS/e file that can be
[parsed automatically](@ref pm_data), the basic formula to build a [`System`](@ref)
manually is:
1. Format all .csv data into row-column format, where there is a row for each component and a
column for each input parameter. Load each .csv into a `DataFrame`.
2. Define a [`System`](@ref).
3. Starting with the buses, write a `for` loop for each component `Type` to loop over the
`DataFrame`, using a constructor from `PowerSystems.jl`'s Model Library to define a
component for each row. Hard-code any required parameters that are missing in
your dataset. Use [`add_component!`](@ref) to add each component to the [`System`](@ref).
4. Similarly, add cost and time series data either within each `for` loop, or after the
components have been defined using [`begin_time_series_update`](@ref).
5. [Save your `System` to a JSON](@ref "Write, View, and Load Data with a JSON") once you are
finished
The following example demonstrates this process for selected component
types (e.g., [`ACBus`](@ref), [`ThermalStandard`](@ref), [`RenewableDispatch`](@ref)), but
the same principles apply to build any of the components in `PowerSystems.jl`'s Model
Library.
Feel free to reuse the code below, ensuring that you customize the exact file names,
data columns, column names, and hard-coded parameters in the `for` loops based on the data
you have available.
## Prerequisites
In this example, it is assumed that the CSV files are stored in a directory
called `MyData`. In each section below, ensure your data follows the row-column format
before beginning, and that your data are in the given units.
These are the depedencies needed for this how-to:
```julia
using PowerSystems
using CSV
using DataFrames
using Dates
using TimeSeries
```
## Build the base [`System`](@ref)
```julia
system_base_power = 100.0
sys = System(system_base_power)
```
Begin by building the base [`System`](@ref) using the base power in MVA.
## Add Buses and Network Topology
In this example, we assume that the component data for the buses are contained in a CSV
file, `Buses.csv`. Each row is an individual bus, and there is a column for each input parameter:
| Bus Number | BusType | Magnitude (p.u.) | Voltage-Max (p.u.) | Voltage-Min (p.u.) | Base Voltage (kV) | Region |
|:---------- |:------- |:---------------- |:------------------ |:------------------ |:----------------- |:------ |
| 1 | ref | 1 | 1.06 | 0.94 | 138 | R1 |
| 2 | ref | 1 | 1.06 | 0.94 | 345 | R2 |
| ... | ... | ... | ... | ... | ... | ... |
Read in the contents of the CSV file `Buses.csv` to a data frame and customize
the parameter names based on the column names in your CSV file.
```julia
bus_params = CSV.read("MyData/Buses.csv", DataFrame)
min_volt = "Voltage-Min (p.u.)"
max_volt = "Voltage-Max (p.u.)"
base_volt = "Base Voltage (kV)"
bus_number = "Bus Number"
region = "Region"
```
In this example, we assume that the buses are sorted into `Areas`, where
[`Area`](@ref) is an optional parameter in the [`ACBus`](@ref) constructor.
Because we will be sorting our buses into these areas as we construct the
buses, we must first attach the areas to our [`System`](@ref).
```julia
regions = unique(bus_params[:, region])
for reg in regions
area = Area(reg)
add_component!(sys, area)
end
```
You could similarly add [`LoadZone`](@ref)s at this point, if they are relevant
for your system.
Now, we are ready to build the buses in the `for` loop, using the
[`ACBus`](@ref) constructor, using the input data available in our `Buses.csv`,
and hard coding any missing data.
```julia
for row in eachrow(bus_params)
bus = ACBus(;
number = row[bus_number],
name = "bus$(row[bus_number])",
available = true,
bustype = ACBusTypes.PQ,
angle = 0.0,
magnitude = 1.0,
voltage_limits = (min = row[min_volt], max = row[max_volt]),
base_voltage = row[base_volt],
area = get_component(Area, sys, row[region]),
)
add_component!(sys, bus)
end
```
## Add Branches
The next step is to build the [`Branch`](@ref) components in the system. In this
example, we only have two branch types: a [`Line`](@ref), if the connecting buses
have the same base voltage; and a [`Transformer2W`](@ref) if they
have different base voltages. You may need to implement additional logic if you
have other branch types as well.
We assume the data for each [`Branch`](@ref) is contained in a `Branches.csv`.
The conventions used in `Bus from` and `Bus to` must be consistent with the
conventions used in the `Bus Number` column of `Buses.csv`.
| Branch Number | Bus from | Bus to | Reactance (p.u.) | Resistance (p.u.) | Max Flow (MW) | Min Flow (MW) |
|:------------- |:-------- |:------ |:---------------- |:----------------- |:------------- |:------------- |
| 1 | 1 | 2 | 0.0999 | 0.0303 | 600 | -600 |
| 2 | 4 | 5 | 0.00798 | 0.00176 | 1700 | -1700 |
| ... | ... | ... | ... | ... | ... | ... |
Read in the contents of the CSV file `Branches.csv` to a data frame and customize
the parameter names based on the column names in your CSV file.
```julia
branch_params = CSV.read("MyData/Branches.csv", DataFrame)
branch_num = "Branch Number"
bus_from_col = "Bus from"
bus_to_col = "Bus to"
reactance = "Reactance (p.u.)"
resistance = "Resistance (p.u.)"
max_flow = "Max Flow (MW)"
```
Build the lines and transformers using the [`Line`](@ref) and
[`Transformer2W`](@ref) constructors.
```julia
for row in eachrow(branch_params)
bus_from = get_bus(sys, row[bus_from_col])
bus_to = get_bus(sys, row[bus_to_col])
if get_base_voltage(bus_to) == get_base_voltage(bus_from)
branch = Line(;
name = "line$(row[branch_num])",
available = true,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
arc = Arc(; from = bus_from, to = bus_to),
r = row[resistance],
x = row[reactance],
b = (from = 0.0, to = 0.0),
rating = row[max_flow] / system_base_power,
angle_limits = (min = 0.0, max = 0.0),
)
else
branch = Transformer2W(;
name = "tline$(row[branch_num])",
available = true,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
arc = Arc(; from = bus_from, to = bus_to),
r = row[resistance],
x = row[reactance],
primary_shunt = 0.0,
rating = row[max_flow] / system_base_power,
)
end
add_component!(sys, branch)
end
```
!!! warning
When defining a branch that isn't attached to a `System` yet, you must define the
thermal rating of the transmission line [per-unitized in "SYSTEM_BASE"](@ref per_unit)
using the base power of the `System` you plan to connect it to -- defined above as
`system_base_power`.
## Adding Thermal Generators and their Costs
### Build Thermal Generators
We assume the data needed to build each [`ThermalStandard`](@ref) unit is found
in a CSV file `Thermal_Gens.csv`. The following table is a snapshot of the
first 7 columns of an example `Thermal_Gens.csv`:
| Gen Name | Bus | Rating (MVA) | Min Stable Level (MW) | Max Capacity (MW) | PrimeMoveType | Fuel Type | ... |
|:---------- |:--- |:------------ |:--------------------- |:----------------- |:------------- |:------------ |:--- |
| Biomass 01 | 12 | 3 | 0.9 | 3.0 | OT | AG_BIPRODUCT | ... |
| Biomass 02 | 103 | 1.2 | 0.36 | 1.2 | OT | AG_BIPRODUCT | ... |
| ... | ... | ... | ... | ... | ... | ... | ... |
The naming convention used for the contents of the `Bus` column must be consistent
with the convention used in the `Bus Number` column of `Buses.csv`.
Read in the contents of the CSV file `Thermal_Gens.csv` to a data frame and
customize the parameter names based on the column names in your CSV file. Note
that the [`PrimeMovers`](@ref pm_list) in the `thermal_gens` data frame are
consistent with EIA Form 923, and the `Fuel Type` column data are consistent
with the [`ThermalFuels`](@ref tf_list) naming convention.
```julia
thermal_gens = CSV.read("MyData/Thermal_Gens.csv", DataFrame)
name = "Gen Name"
bus_connection = "Bus"
rate = "Rating (MVA)"
min_active_power = "Min Stable Level (MW)"
max_active_power = "Max Capacity (MW)"
ramp_up = "Max Ramp Up (MW/min)"
ramp_down = "Max Ramp Down (MW/min)"
min_up = "Min Up Time (h)"
min_down = "Min Down Time (h)"
prime_move = "PrimeMoveType"
fuel = "Fuel Type"
```
Build the thermal generator components using the [`ThermalStandard`](@ref)
constructor and data stored in the `thermal_gens` data frame.
!!! warning
When you define components that aren't attached to a `System` yet, the constructors
assume define all fields related to power are
[per-unitized in "DEVICE_BASE"](@ref per_unit). Divide all fields with units such as MW,
MVA, MVAR, or MW/min using the `base_power` of the component (with the exception of
`base_power` itself, which is in MVA).
Since the example data is missing base power, we set base power equal to the rating data, and the
rating parameter to 1.0:
```julia
for row in eachrow(thermal_gens)
base = row[rate]
thermal = ThermalStandard(;
name = row[name],
available = true,
status = true,
bus = get_bus(sys, row[bus_connection]),
active_power = 0.0,
reactive_power = 0.0,
rating = 1.0,
active_power_limits = (
min = row[min_active_power] / base,
max = row[max_active_power] / base,
),
reactive_power_limits = (min = 0.0, max = 0.0),
ramp_limits = (up = row[ramp_up] / base, down = row[ramp_down] / base),
operation_cost = ThermalGenerationCost(nothing),
base_power = base,
time_limits = (up = row[min_up], down = row[min_down]),
prime_mover_type = row[prime_move],
fuel = row[fuel],
)
add_component!(sys, thermal)
end
```
### Add [`ThermalGenerationCost`](@ref)
In this example the [`ThermalGenerationCost`](@ref) constructor is defined by a
[`FuelCurve`](@ref). We are also assuming that the data needed to build each
[`FuelCurve`](@ref) can be found in two separate CSV files. The first,
`Thermal_Gens.csv`, has already been defined in the previous step. The second,
`Thermal_Fuel_Rates.csv`, contains information regarding each [`FuelType`](@ref
tf_list) and its cost:
| Fuel Type | Fuel Price | CO2 rate | NOX rate | SO2 rate |
|:------------ |:---------- |:-------- |:-------- |:-------- |
| COAL | 1.8 | 203.5 | 0.382 | 0.33 |
| NATURAL_GAS | 5.4 | 118 | 0.079 | 0.001 |
| OIL | 21 | 123.1 | 0.176 | 0.006 |
| AG_BIPRODUCT | 2.4 | 130 | 0.177 | 0.006 |
| GEOTHERMAL | 0 | 0 | 0.177 | 0.006 |
Read in `Thermal_Fuel_Rates.csv`, customize parameter names based on
the column names in your CSV file, and create a dictionary pairing fuel types
and fuel prices. Ensure that the strings populating the `Fuel Type` column
match the strings populating the `Fuel Type` column of the `thermal_gens`
data frame.
```julia
fuel_params = CSV.read("MyData/Thermal_Fuels_Rates.csv", DataFrame)
type = "Fuel Type"
price = "Fuel Price"
fuel_cost_dict = Dict{ThermalFuels, Float64}()
for row in eachrow(fuel_params)
fuel_cost_dict[row[type]] = row[price]
end
```
Next, we will create column name variables for heat rate bases, heat rates,
load points, fixed, start up, and shut down costs from the thermal_gens
data frame. Use this data to build the [`PiecewiseIncrementalCurve`](@ref) and
the [`FuelCurve`](@ref) functions, and add them to their associated thermal
generator.
```julia
gen_name = "Generator Name"
heat_rate_base = "Heat Rate Base (MMBTU/hr)"
heat_rate = "Heat Rate (MMBTU/hr)"
load_point = "Load Point Band (MW)"
fixed_cost = "Fixed Cost (dollar)"
start_up_cost = "Start Up Cost (dollar)"
shut_down_cost = "Shut Down Cost (dollar)"
for row in eachrow(thermal_gens)
thermal = get_component(ThermalStandard, sys, row[gen_name])
heat_rate_curve =
PieceWiseIncrementalCurve(row[heat_rate_base], row[load_point], row[heat_rate])
fuel_curve =
FuelCurve(;
value_curve = heat_rate_curve,
fuel_cost = fuel_cost_dict[row[fuel]],
)
cost_thermal = ThermalGenerationCost(;
variable = fuel_curve,
fixed = row[fixed_cost],
start_up = row[start_up_cost],
shut_down = row[shut_down_cost],
)
set_operation_cost!(thermal, cost_thermal)
end
```
For more information regarding thermal cost functions please visit
[`ThermalGenerationCost`](@ref).
## Adding Renewable Generators and Their Time Series
The following section demonstrates how to add solar generators and their time
series to a [`System`](@ref). However, if you desire to add other
[`RenewableDispatch`](@ref) generator types, such as wind, the process is exactly the
same, with changing the [prime mover type](@ref pm_list) from `PrimeMovers.PVe` to
`PrimeMovers.WT`.
We assume the data needed to build each solar powered
[`RenewableDispatch`](@ref) unit is found in the CSV file `Solar_Gens.csv`,
snapshotted below. The convention used for the contents of the `Bus` column
must be consistent with the convention used in the `Bus Number` column of
`Buses.csv`:
| Gen Name | Number | Bus | Rating (MVA) |
|:-------- |:------ |:--- |:------------ |
| Solar 01 | 1 | 32 | 746.76 |
| Solar 02 | 2 | 92 | 369.26 |
| ... | ... | ... | ... |
Read in the contents of the CSV file `Solar_Gens.csv` to a data frame, and
customize the parameter names based on the column names in your CSV file and
the desired prime mover type.
```julia
solar_gens = CSV.read("MyData/Solar_Gens.csv", DataFrame)
name = "Gen Name"
num = "Number"
bus_connection = "Bus"
rate = "Rating (MVA)"
prime_mover = PrimeMovers.PVe
```
Before building the solar generators, we must also set up the solar generators'
time series. In this example, we assume that each solar generator has a unique
time series, and all of these time series are contained in one file:
`MyData/Solar_Time_Series.csv`. Here is a snapshot of this time series CSV
file, where the first column contains time stamps, and the remaining columns
are titled with its respective generator's name, and contain the time series
values in MW for each solar generator:
| Time Stamp | Solar 01 | Solar 02 | Solar 03 | ... |
|:------------ |:-------- |:-------- |:-------- |:--- |
| ... | ... | ... | ... | ... |
| 1/1/23 09:00 | 51.36 | 118.11 | 54.92 | ... |
| 1/1/23 10:00 | 138.61 | 200.32 | 6.85 | ... |
| ... | ... | ... | ... | ... |
Each time series for its respective solar generator has an hourly resolution,
and is for the year 2023, plus one full day into 2024, for a total of 366 days,
and 8784 values per column.
Create a data frame from `Solar_Time_Series.csv` and define variables for the
aforementioned resolution and time stamps:
```julia
solar_time_series = CSV.read("MyData/Solar_Time_Series.csv", DataFrame)
resolution = Dates.Hour(1);
timestamps = range(DateTime("2023-01-01T00:00:00"); step = resolution, length = 8784);
```
In this example, we assume that the [`RenewableGenerationCost`](@ref) is at
zero marginal cost. If the marginal cost is not zero, follow similar steps to
building the [`ThermalGenerationCost`](@ref) constructor from above, but for
the [`RenewableGenerationCost`](@ref) constructor instead.
Moreover, since the example data is missing base power, we use the range of
values in the time series data to determine the value of the base power which
will be used to normalize the time series, and set the generator's rating
parameter to 1.0. (If your data reports a base power, use that for the
generator's base power, and rating data for the generator's rating).
In the same `for` loop, we will build the solar generator components using the
[`RenewableDispatch`](@ref) constructor and data stored in the `solar_gens`
data frame, and build and attach each solar generator's time series:
```julia
for row in eachrow(solar_gens)
norm = maximum(solar_time_series[:, row[name]])
solar_data_MW = solar_time_series[:, row[name]]
base = row[rate]
if any((solar_data_MW ./ base) .> 1.0)
@warn "Generator $(row[name]) has a production larger than its base power. Normalizing by its maximum"
base = norm
end
solar_array = TimeArray(timestamps, (solar_data_MW ./ base)) # normalize data
solar_TS = SingleTimeSeries(;
name = "max_active_power",
data = solar_array,
scaling_factor_multiplier = get_max_active_power,
)
solar = RenewableDispatch(;
name = row[name],
available = true,
bus = get_bus(sys, row[bus_connection]),
active_power = 0.0,
reactive_power = 0.0,
rating = 1.0,
prime_mover_type = prime_mover,
reactive_power_limits = (min = 0.0, max = 0.0),
power_factor = 1.0,
operation_cost = RenewableGenerationCost(zero(CostCurve)),
base_power = base,
)
add_component!(sys, solar)
add_time_series!(sys, solar, solar_TS)
end
```
## Adding Hydro Generators and Their Time Series
We assume the data needed to build each [`HydroDispatch`](@ref) unit is found
in a CSV file `Hydro_Gens.csv`, snapshotted below. The convention used for the
contents of the `Bus` column must be consistent with the convention used in the
`Bus Number` column of `Buses.csv`.
| Gen Name | Number | Bus | Min Stable Level (MW) | Max Capacity (MW) | Max Ramp Up (MW/min) | ... |
|:-------- |:------ |:--- |:--------------------- |:----------------- |:-------------------- |:--- |
| Hydro 01 | 1 | 56 | 0.0 | 75.0 | 0.83 | ... |
| Hydro 02 | 2 | 66 | 0.0 | 77.0 | 0.86 | ... |
| ... | ... | ... | ... | ... | ... | ... |
Read in the contents of the CSV file `Hydro_Gens.csv` to a data frame and
customize the parameter names based on the column names in your CSV file.
```julia
hydro_gens = CSV.read("MyData/Hydro_Gens.csv", DataFrame)
name = "Gen Name"
bus_connection = "Bus"
num = "Number"
rate = "Rating (MVA)"
min_active_power = "Min Stable Level (MW)"
max_active_power = "Max Capacity (MW)"
ramp_up = "Max Ramp Up (MW/min)"
ramp_down = "Max Ramp Down (MW/min)"
min_up = "Min Up Time (h)"
min_down = "Min Down Time (h)"
```
Before building the hydro generators, we must also set up the hydro generators'
time series. In this example, we assume that each hydro generator has a unique
time series, and all of these time series are contained in one file:
`MyData/Hydro_Time_Series.csv`. Here is a snapshot of this time series CSV
file, where the first column contains time stamps, and the remaining columns
are titled with its respective generator's name, and contain the time series
values in MW for each hydro generator:
| Time Stamp | Hydro 01 | Hydro 02 | Hydro 03 | ... |
|:----------- |:-------- |:-------- |:-------- |:--- |
| 1/1/23 0:00 | 0.325386 | 0.325409 | 0.314454 | ... |
| 1/1/23 1:00 | 0.325386 | 0.325409 | 0.314454 | ... |
| ... | ... | ... | ... | ... |
Each time series for its respective hydro generator has an hourly resolution,
and is for the year 2023, plus one full day into 2024, for a total of 366 days,
and 8784 values per column.
Create a data frame from `Hydro_Time_Series.csv` and define variables for the
aforementioned resolution and time stamps:
```julia
hydro_time_series = CSV.read("MyData/Hydro_Time_Series.csv", DataFrame)
resolution = Dates.Hour(1);
timestamps = range(DateTime("2023-01-01T00:00:00"); step = resolution, length = 8784);
```
In this example, we assume that the [`HydroGenerationCost`](@ref) has both zero
fixed and variable costs. Moreover, since the example data is missing base
power, we use the range of values in the time series data to determine the
value of the base power which will be used to normalize the time series and
other parameters, and set the generator's rating parameter to 1.0. (If your
data reports a base power, use that for the generator's base power, and rating
data for the generator's rating).
In the same `for` loop, we will build the hydro generator components using the
[`HydroDispatch`](@ref) constructor and data stored in the `hydro_gens`
data frame, and build and attach each hydro generator's time series:
```julia
for row in eachrow(hydro_gens)
norm = maximum(hydro_time_series[:, row[name]])
hydro_data_MW = hydro_time_series[:, row[name]]
base = row[rate]
if any((hydro_data_MW ./ base) .> 1.0)
@warn "Generator $(row[name]) has a production larger than its base power. Normalizing by its maximum"
base = norm
end
hydro_array = TimeArray(timestamps, (hydro_data_MW ./ base)) # normalize data
hydro_TS = SingleTimeSeries(;
name = "max_active_power",
data = hydro_array,
scaling_factor_multiplier = get_max_active_power,
)
hydro = HydroDispatch(;
name = row[name],
available = true,
bus = get_bus(sys, row[bus_connection]),
active_power = 0.0,
reactive_power = 0.0,
rating = 1.0,
prime_mover_type = PrimeMovers.HA,
active_power_limits = (
min = row[min_active_power] / base,
max = row[max_active_power] / base,
),
reactive_power_limits = (min = 0.0, max = 0.0),
ramp_limits = (up = row[ramp_up] / base, down = row[ramp_down] / base),
time_limits = (up = row[min_up], down = row[min_down]),
base_power = base,
operation_cost = HydroGenerationCost(zero(LinearCurve), 0.0),
)
add_component!(sys, hydro)
add_time_series!(sys, hydro, hydro_TS)
end
```
## Adding Loads and Their Time Series
In this example, we assume that all loads will be represented as
[`PowerLoad`](@ref) components, and that the loads are located in three
regions. Each region has one unique time series, and every load in each region
is assigned its region's normalized time series profile.
The data needed to build each [`PowerLoad`](@ref) unit is found in the CSV file
`Loads.csv`, snapshotted below. The convention used for the contents of the
`Bus` column must be consistent with the convention used in the `Bus Number`
column of `Buses.csv`, and similarly for the `Region` column.
| Load Number | Bus | Region | Participation Factor |
|:----------- |:--- |:------ |:-------------------- |
| 1 | 1 | R1 | 0.047168669 |
| 2 | 2 | R2 | 0.0184963 |
| ... | ... | ... | ... |
Read in the contents of the CSV file `Loads.csv` to a data frame and customize
the parameter names based on the column names in your CSV file.
```julia
load_params = CSV.read("MyData/Loads.csv", DataFrame)
region = "Region"
bus_connection = "Bus"
factor = "Load Participation Factor"
number = "Load Number"
```
Before building the loads, we must also set up the loads' time series. In this
example, we assume that each load region has a unique time series, and all of
these time series are contained in one file: `MyData/Load_Time_Series.csv`.
Here is a snapshot of this time series CSV file, where the first column
contains time stamps, and the remaining columns are titled with its respective
region's name, and contain the time series values in MW for each region:
| Time Stamp | R1 | R2 | R3 |
|:----------- |:---------- |:---------- |:---------- |
| 1/1/23 0:00 | 5465.7296 | 1904.4448 | 2486.38409 |
| 1/1/23 1:00 | 4994.53821 | 1726.22134 | 2273.63274 |
| ... | ... | ... | ... |
Each time series for its respective load region has an hourly resolution, and
is for the year 2023, plus one full day into 2024, for a total of 366 days, and
8784 values per column. Ensure that your time series file is similarly
formatted.
Create a data frame from `Load_Time_Series.csv` and define variables for the
aforementioned resolution and time stamps:
```julia
load_time_series = CSV.read("MyData/Load_Time_Series.csv", DataFrame)
resolution = Dates.Hour(1);
timestamps = range(DateTime("2023-01-01T00:00:00"); step = resolution, length = 8784);
```
Construct and attach the loads to the system using the [`PowerLoad`](@ref)
constructor according to their regions. Because all loads in each region share
a time series profile, the `max_active_power` of each load will depend on the
maximum time series value of its region and its load participation factor.
```julia
for row in eachrow(load_params)
num = row[number]
max = maximum(load_time_series[:, row[region]])
load = PowerLoad(;
name = "load$num",
available = true,
bus = get_bus(sys, row[bus_connection]),
active_power = 0.0,
reactive_power = 0.0,
base_power = system_base_power,
max_active_power = (max) * (row[factor]) / system_base_power,
max_reactive_power = 0.0,
)
add_component!(sys, load)
end
```
In a `for` loop, iterate over the regions in your [`System`](@ref), and use the
[`begin_time_series_update`](@ref) function to create and attach the respective
loads' time series to every load in a region at once. Note: due to how
`max_active_power` is defined, the time series values are normalized to its
maximum.
```julia
regions = unique(load_params[:, region])
for reg in regions
norm = maximum(load_time_series[:, reg])
load_array = TimeArray(
timestamps,
(load_time_series[:, reg] ./ norm),
)
load_TS = SingleTimeSeries(;
name = "max_active_power",
data = load_array,
scaling_factor_multiplier = get_max_active_power,
)
region = get_component(Area, sys, reg)
begin_time_series_update(sys) do
for component in get_components_in_aggregation_topology(PowerLoad, sys, region)
add_time_series!(sys, component, load_TS)
end
end
end
```
## Customizing and Expanding
Additional resources to help you built your own custom [`System`](@ref):
- See how to [Add additional data to a component](@ref additional_fields)
- Learn about [Adding Data for Dynamic Simulations](@ref), which could also be loaded in a
`for` loop from a .csv, if you don't have PSS/e files available for
[automated parsing](@ref dyr_data)
- See more on how to [Parse Time Series Data from .csv's](@ref parsing_time_series)
- See how to [Add a New or Custom Type](@ref)
- See how to [Add a Component in Natural Units](@ref), which is an alternative to the
per-unitized `for` loops above, but requires more code
- See how to [Write, View, and Load Data with a JSON](@ref) to efficiently save your
[`System`](@ref) once you've built it
================================================
FILE: docs/src/how_to/create_hydro_datasets.md
================================================
# [Define Hydro Generators with Reservoirs](@id hydro_resv)
In the current version of `PowerSystems.jl` there is support and testing for hydropower generation plants with the following structures:
## Shared Upstream Reservoir
```mermaid
flowchart TB
subgraph s1["Hydro Plant 2"]
B["Turbine A"]
C["Turbine B"]
end
subgraph s2["HydroPlant 1"]
D["Turbine C"]
end
A --- C
A["Reservoir"] --- B & D
```
For this model, attach an upstream [`HydroReservoir`](@ref) to any number of [`HydroTurbine`](@ref)s. This can model different power house elevations to consider the effect of the elevation and pressure heads on the specific turbines inside of a power plant.
### Example: Single Turbine with Single Reservoir
```julia
using PowerSystems
import PowerSystems as PSY
# Create a system
sys = System(100.0)
set_units_base_system!(sys, "NATURAL_UNITS")
# Create and add a bus
bus = ACBus(;
number = 1,
name = "bus1",
available = true,
bustype = ACBusTypes.PV,
angle = 0.0,
magnitude = 1.0,
voltage_limits = (min = 0.9, max = 1.1),
base_voltage = 230.0,
area = nothing,
load_zone = nothing,
)
add_component!(sys, bus)
# Create a HydroTurbine
turbine = HydroTurbine(;
name = "Turbine1",
available = true,
bus = bus,
active_power = 50.0,
reactive_power = 10.0,
rating = 100.0,
base_power = 100.0,
active_power_limits = (min = 10.0, max = 100.0),
reactive_power_limits = (min = -50.0, max = 50.0),
powerhouse_elevation = 500.0, # meters above sea level
efficiency = 0.9,
conversion_factor = 1.0,
outflow_limits = (min = 0.0, max = 1000.0), # m³/s
travel_time = 0.5, # hours
)
add_component!(sys, turbine)
# Create a HydroReservoir
reservoir = HydroReservoir(;
name = "Reservoir1",
available = true,
storage_level_limits = (min = 1000.0, max = 10000.0), # m³
initial_level = 0.8, # 80% of max
spillage_limits = (min = 0.0, max = 500.0),
inflow = 100.0, # m³/h
outflow = 50.0, # m³/h
level_targets = 0.7,
intake_elevation = 600.0, # meters above sea level
head_to_volume_factor = LinearCurve(1.0),
)
add_component!(sys, reservoir)
# Link the turbine to the reservoir as a downstream turbine
set_downstream_turbine!(reservoir, turbine)
# Verify the connection
@assert has_downstream_turbine(reservoir, turbine)
@assert length(get_connected_head_reservoirs(sys, turbine)) == 1
```
### Example: Multiple Turbines with Single Reservoir
```julia
sys = System(100.0)
set_units_base_system!(sys, "NATURAL_UNITS")
# Create and add a bus
bus = ACBus(;
number = 1,
name = "bus1",
available = true,
bustype = ACBusTypes.PV,
angle = 0.0,
magnitude = 1.0,
voltage_limits = (min = 0.9, max = 1.1),
base_voltage = 230.0,
area = nothing,
load_zone = nothing,
)
add_component!(sys, bus)
# Create multiple turbines and connect them to a single reservoir
turbines = []
for i in 1:5
turbine = HydroTurbine(;
name = "Turbine$i",
available = true,
bus = bus,
active_power = 20.0,
reactive_power = 5.0,
rating = 50.0,
base_power = 100.0,
active_power_limits = (min = 5.0, max = 50.0),
reactive_power_limits = nothing,
powerhouse_elevation = 500.0 + i * 10.0, # Different elevations
efficiency = 0.85 + i * 0.02,
)
add_component!(sys, turbine)
push!(turbines, turbine)
end
# Link all turbines at once
set_downstream_turbines!(reservoir, turbines)
# Verify connections
@assert has_downstream_turbine(reservoir)
@assert length(get_downstream_turbines(reservoir)) == 5
```
## Head and Tail Reservoirs for Pumped Hydropower Plants
For this model, attach two [`HydroReservoir`](@ref)s to any number of [`HydroPumpTurbine`](@ref)s. The turbine and reservoir structs store the elevations to calculate the elevation and pressure heads for the facility.
```mermaid
flowchart TB
subgraph s1["Pumped Hydro Plant"]
B["Turbine A"]
C["Turbine B"]
end
A["Head Reservoir"] --- B
A --- C
C --- D
B --- D["Tail Reservoir"]
```
### Example: Pumped Hydro with Head and Tail Reservoirs
```julia
# Create a HydroPumpTurbine
pump_turbine = HydroPumpTurbine(;
name = "PumpTurbine1",
available = true,
bus = bus,
active_power = 50.0,
reactive_power = 10.0,
rating = 200.0,
active_power_limits = (min = 20.0, max = 200.0), # Generation mode
reactive_power_limits = (min = -100.0, max = 100.0),
active_power_limits_pump = (min = 30.0, max = 180.0), # Pumping mode
outflow_limits = (min = 0.0, max = 500.0),
powerhouse_elevation = 400.0,
base_power = 100.0,
ramp_limits = (up = 20.0, down = 20.0),
time_limits = nothing,
status = PSY.PumpHydroStatusModule.PumpHydroStatus.OFF,
time_at_status = 0.0,
efficiency = (turbine = 0.9, pump = 0.85),
transition_time = (turbine = 0.25, pump = 0.25), # hours
minimum_time = (turbine = 1.0, pump = 1.0), # hours
conversion_factor = 1.0,
)
add_component!(sys, pump_turbine)
# Create head (upper) reservoir
head_reservoir = HydroReservoir(;
name = "HeadReservoir",
available = true,
storage_level_limits = (min = 5000.0, max = 50000.0),
initial_level = 0.6,
spillage_limits = nothing,
inflow = 200.0,
outflow = 100.0,
level_targets = 0.5,
intake_elevation = 800.0,
head_to_volume_factor = LinearCurve(1.0),
)
add_component!(sys, head_reservoir)
# Create tail (lower) reservoir
tail_reservoir = HydroReservoir(;
name = "TailReservoir",
available = true,
storage_level_limits = (min = 3000.0, max = 30000.0),
initial_level = 0.4,
spillage_limits = nothing,
inflow = 50.0,
outflow = 100.0,
level_targets = 0.5,
intake_elevation = 200.0,
head_to_volume_factor = LinearCurve(1.0),
)
add_component!(sys, tail_reservoir)
# Link reservoirs to pump-turbine
# Head reservoir feeds into the turbine (downstream)
set_downstream_turbine!(head_reservoir, pump_turbine)
# Tail reservoir receives flow from the turbine (upstream)
set_upstream_turbine!(tail_reservoir, pump_turbine)
# Verify connections
@assert has_downstream_turbine(head_reservoir, pump_turbine)
@assert has_upstream_turbine(tail_reservoir, pump_turbine)
@assert length(get_connected_head_reservoirs(sys, pump_turbine)) == 1
@assert length(get_connected_tail_reservoirs(sys, pump_turbine)) == 1
```
## Key Component Fields
### HydroTurbine
Key fields for [`HydroTurbine`](@ref):
- `powerhouse_elevation::Float64`: Height in meters above sea level of the powerhouse
- `efficiency::Float64`: Turbine efficiency [0, 1.0]
- `turbine_type::HydroTurbineType`: Type of turbine (e.g., `HydroTurbineType.UNKNOWN`, `HydroTurbineType.FRANCIS`, `HydroTurbineType.PELTON`, `HydroTurbineType.KAPLAN`)
- `conversion_factor::Float64`: Conversion factor from flow/volume to energy (m³ -> p.u-hr)
- `outflow_limits::Union{Nothing, MinMax}`: Turbine outflow limits in m³/s
- `travel_time::Union{Nothing, Float64}`: Downstream travel time in hours from reservoir to turbine
### HydroReservoir
Key fields for [`HydroReservoir`](@ref):
- `storage_level_limits::MinMax`: Storage level limits (in m³, m, or MWh based on `level_data_type`)
- `initial_level::Float64`: Initial level as fraction of `storage_level_limits.max`
- `inflow::Float64`: Water refilling the reservoir (m³/h or MW)
- `outflow::Float64`: Water naturally leaving the reservoir (m³/h or MW)
- `spillage_limits::Union{Nothing, MinMax}`: Water spillage limits
- `level_targets::Union{Nothing, Float64}`: Target level at simulation end as fraction of max
- `intake_elevation::Float64`: Height of intake in meters above sea level
- `head_to_volume_factor::ValueCurve`: Head to volume relationship
- `upstream_turbines::Vector{HydroUnit}`: Turbines feeding into this reservoir (tail reservoir)
- `downstream_turbines::Vector{HydroUnit}`: Turbines fed by this reservoir (head reservoir)
- `upstream_reservoirs::Vector{Device}`: Reservoirs feeding spillage into this reservoir
- `level_data_type::ReservoirDataType`: Data type (e.g., `ReservoirDataType.USABLE_VOLUME`, `ReservoirDataType.HEAD`, `ReservoirDataType.ENERGY`)
### HydroPumpTurbine
Key fields specific to [`HydroPumpTurbine`](@ref):
- `active_power_limits::MinMax`: Power limits for turbine (generation) mode
- `active_power_limits_pump::MinMax`: Power limits for pump mode
- `status::PumpHydroStatus`: Operating status (`PumpHydroStatus.OFF`, `PumpHydroStatus.PUMP`, `PumpHydroStatus.GEN`)
- `efficiency::TurbinePump`: Separate efficiencies for turbine and pump modes `(turbine = 0.9, pump = 0.85)`
- `transition_time::TurbinePump`: Time to switch modes `(turbine = 0.25, pump = 0.25)`
- `minimum_time::TurbinePump`: Minimum operating time in each mode `(turbine = 1.0, pump = 1.0)`
## Helper Functions
### Linking Turbines to Reservoirs
- `set_downstream_turbine!(reservoir, turbine)`: Link a single turbine as downstream of reservoir
- `set_downstream_turbines!(reservoir, turbines)`: Link multiple turbines as downstream
- `set_upstream_turbine!(reservoir, turbine)`: Link a single turbine as upstream of reservoir
- `set_upstream_turbines!(reservoir, turbines)`: Link multiple turbines as upstream
### Checking Connections
- `has_downstream_turbine(reservoir)`: Check if any downstream turbines are attached
- `has_downstream_turbine(reservoir, turbine)`: Check if specific turbine is downstream
- `has_upstream_turbine(reservoir)`: Check if any upstream turbines are attached
- `has_upstream_turbine(reservoir, turbine)`: Check if specific turbine is upstream
### Retrieving Connected Components
- `get_downstream_turbines(reservoir)`: Get vector of downstream turbines
- `get_upstream_turbines(reservoir)`: Get vector of upstream turbines
- `get_connected_head_reservoirs(sys, turbine)`: Get reservoirs where turbine is downstream
- `get_connected_tail_reservoirs(sys, turbine)`: Get reservoirs where turbine is upstream
- `get_turbine_head_reservoirs_mapping(sys)`: Get mapping of all turbines to head reservoirs
- `get_turbine_tail_reservoirs_mapping(sys)`: Get mapping of all turbines to tail reservoirs
### Removing Connections
- `remove_turbine!(reservoir, turbine)`: Remove a specific turbine connection
- `clear_turbines!(reservoir)`: Remove all turbine connections from reservoir
================================================
FILE: docs/src/how_to/create_system_with_source_import_export_cost.md
================================================
# Add costs for imported/exported power
This how-to guide explains how to add an [`ImportExportCost`](@ref) to a [`Source`](@ref)
component to model imports and exports with neighboring areas or external grids.
This guide assumes a [`System`](@ref) is already defined.
```@setup source_ie_cost
using PowerSystems
using PowerSystemCaseBuilder
sys = build_system(PSITestSystems, "c_sys5_uc")
```
## Overview
A [`Source`](@ref) component represents an infinite bus with constant voltage output,
commonly used to represent:
- Very large machines on a single bus in dynamics simulations
- Import/export connections in operational simulations
The [`ImportExportCost`](@ref) operating cost allows you to specify:
- Import offer curves (buy prices for importing power)
- Export offer curves (sell prices for exporting power)
- Weekly energy limits for imports and exports
- Ancillary service offers
## Step 1: Define Import and Export Curves
You can define import and export curves in several ways, depending on your data format.
### Option A: Simple Single-Price Curves
For a simple constant price over a power range:
```@repl source_ie_cost
# Import curve: buy power at $25/MWh up to 200 MW
import_curve = make_import_curve(; power = 200.0, price = 25.0)
# Export curve: sell power at $30/MWh up to 200 MW
export_curve = make_export_curve(; power = 200.0, price = 30.0)
```
### Option B: Piecewise Linear Curves
For more complex pricing with multiple segments:
```@repl source_ie_cost
# Import curve with increasing prices as more power is imported
import_curve = make_import_curve(;
power = [0.0, 100.0, 105.0, 120.0, 200.0],
price = [5.0, 10.0, 20.0, 40.0],
)
# Export curve with decreasing prices as more power is exported
export_curve = make_export_curve(;
power = [0.0, 100.0, 105.0, 120.0, 200.0],
price = [40.0, 20.0, 10.0, 5.0],
)
```
!!! note
- Import curves must have non-decreasing (convex) slopes
- Export curves must have non-increasing (concave) slopes
- Power values must have one more entry than price values
## Step 2: Create the ImportExportCost
Use the curves to create an [`ImportExportCost`](@ref):
```@repl source_ie_cost
ie_cost = ImportExportCost(;
import_offer_curves = import_curve,
export_offer_curves = export_curve,
energy_import_weekly_limit = 10000.0, # MWh per week (optional)
energy_export_weekly_limit = 10000.0, # MWh per week (optional)
)
```
## Step 3: Add the Cost to the Source Component
Define a [`Source`](@ref) component with the import/export cost, or alternatively use
[`set_operation_cost!`](@ref) to add the cost to an existing source:
```@repl source_ie_cost
source = Source(;
name = "external_grid",
available = true,
bus = get_component(ACBus, sys, "nodeC"),
active_power = 0.0,
reactive_power = 0.0,
active_power_limits = (min = -200.0, max = 200.0), # Negative for export
reactive_power_limits = (min = -100.0, max = 100.0),
R_th = 0.01,
X_th = 0.02,
internal_voltage = 1.0,
internal_angle = 0.0,
base_power = 100.0,
operation_cost = ie_cost,
)
```
!!! tip
The `active_power_limits` should span negative (for export) to positive (for import)
values. Negative power indicates exporting power to the external grid.
## Step 4: Add the Source to the System
Add the source component to your system:
```@repl source_ie_cost
add_component!(sys, source)
```
Verify the source was added correctly:
```@repl source_ie_cost
get_component(Source, sys, "external_grid")
get_operation_cost(get_component(Source, sys, "external_grid"))
```
## See Also
- [`Source`](@ref) - Documentation for the Source component
- [`ImportExportCost`](@ref) - Documentation for ImportExportCost
- [Adding an Operating Cost](@ref cost_how_to) - General guide for operating costs
- [`make_import_curve`](@ref) - Function to create import curves
- [`make_export_curve`](@ref) - Function to create export curves
================================================
FILE: docs/src/how_to/handle_3W_transformers.md
================================================
# [Handle 3-winding transformer data](@id 3wtdata)
PowerSystems.jl stores the topological data for the [`Transformer3W`](@ref) as the common equivalent circuit in the star (or wye) configuration. In this representation, the series impedances of each winding are transformed into an equivalent star network with a common star bus.
## The "Starbus" Representation
The resulting $Z_{12}, Z_{23},$ and $Z_{13}$ represent the series impedances in a star network. The common point of this star network is the conceptual "starbus" or internal neutral node. Each winding's terminal in the power system network is then connected to its corresponding impedance in this equivalent star.
```mermaid
graph TD
subgraph Equivalent Star Circuit
N((Neutral/Starbus))
W1 --- Z1 --- N
W2 --- Z2 --- N
W3 --- Z3 --- N
end
```
## Representing 3-winding transformer PSSe Data in `PowerSystems.jl`
PSS®E represents a [`Transformer3W`](@ref) as a single element with a dedicated data record. This record contains several fields that define the transformer's characteristics and connections. The key information stored includes:
### Bus Connections in Delta configuration
- From Bus Number (I): The bus number connected to the primary winding.
- To Bus Number (J): The bus number connected to the secondary winding.
- Third Bus Number (K): The bus number connected to the tertiary winding.
- Circuit Identifier (ID): An alphanumeric identifier to distinguish between multiple transformers connected between the same buses.
- Impedance Data: PSS®E uses the concept of leakage impedances between the windings to model the transformer.
It does not explicitly store the equivalent star (wye) impedances. Instead, it stores the following:
- Positive Sequence Impedance (R1-2, X1-2): Resistance and reactance between winding 1 (primary) and winding 2 (secondary) in per-unit on the transformer's base MVA.
- Positive Sequence Impedance (R1-3, X1-3): Resistance and reactance between winding 1 (primary) and winding 3 (tertiary) in per-unit on the transformer's base MVA.
- Positive Sequence Impedance (R2-3, X2-3): Resistance and reactance between winding 2 (secondary) and winding 3 (tertiary) in per-unit on the transformer's base MVA.
- Star Bus Number: The star bus number is optional and it might be represented or not.
### Magnetizing Admittance
- Magnetizing Conductance (GMAG1): Core loss conductance in per-unit on the transformer's base MVA, usually referred to the primary winding.
- Magnetizing Susceptance (BMAG1): Magnetizing susceptance in per-unit on the transformer's base MVA, usually referred to the primary winding.
### Tap Settings and Phase Shift
- Winding 1 Tap Ratio (RATIO1): Tap ratio for the primary winding.
- Winding 2 Tap Ratio (RATIO2): Tap ratio for the secondary winding.
- Winding 3 Tap Ratio (RATIO3): Tap ratio for the tertiary winding.
- Phase Shift (ANGLE1, ANGLE2, ANGLE3): Phase shift in degrees applied by each winding.
### Winding Ratings
- Winding 1 MVA Base (SBASE1): Base apparent power for winding 1.
- Winding 2 MVA Base (SBASE2): Base apparent power for winding 2.
- Winding 3 MVA Base (SBASE3): Base apparent power for winding 3.
- Nominal Voltages (WINDV1, WINDV2, WINDV3): Nominal voltage levels of each winding in kV.
### Control Information (Optional)
For transformers with on-load tap changers (OLTCs) or phase shifters, additional data related to the control parameters (controlled bus, voltage setpoint, tap limits, etc.) would be included in the relevant control records, not directly within the transformer data record itself.
## Deriving the Equivalent Star Impedances from PSSe
In `PowerSystems.jl`, we explictly represent and store the [`Transformer3W`](@ref) as an equivalent star (wye) circuit with a common neutral point (often referred to conceptually as a "starbus"), we calculate the equivalent series impedance for each winding ($Z_1, Z_2, Z_3$) from the PSS®E Positive Sequence Impedance data (e.g., R1-2, X1-2, etc.) using the following formulas:
$$\begin{aligned}
Z_1 &= \frac{1}{2} (Z_{12} + Z_{13} - Z_{23}) \\
Z_2 &= \frac{1}{2} (Z_{12} + Z_{23} - Z_{13}) \\
Z_3 &= \frac{1}{2} (Z_{13} + Z_{23} - Z_{12})
\end{aligned}$$
Where:
- $Z_1$: Equivalent series impedance of winding 1, connected between its terminal and the neutral point of the equivalent star.
- $Z_2$: Equivalent series impedance of winding 2, connected between its terminal and the neutral point of the equivalent star.
- $Z_3$: Equivalent series impedance of winding 3, connected between its terminal and the neutral point of the equivalent star.
We store the data from both representations (Delta and Wye) for completeness as well as the star bus used in the wye representation.
================================================
FILE: docs/src/how_to/improve_ts_performance.md
================================================
# Improve Performance with Time Series Data
Use the steps here to improve performance with small or large data sets, but
particularly large data sets. These improvements can help handle adding
large numbers of data sets or reduce overhead when accessing time series data
multiple times.
## Choosing the Storage Location
By default, time series data is stored in an HDF5 file in the tmp file system to prevent
large datasets from overwhelming system memory. However, you can change its location.
### Small data sets
If your dataset will fit in your computer's memory, then you can increase
performance by storing it in memory:
```julia
sys = System(100.0; time_series_in_memory = true)
```
### Large data sets
If the system's time series data will be larger than the amount of tmp space available, use
the `time_series_directory` parameter to change its location.
```julia
sys = System(100.0; time_series_directory = "bigger_directory")
```
You can also override the location by setting the environment
variable `SIENNA_TIME_SERIES_DIRECTORY` to another directory.
HDF5 compression is not enabled by default, but you can enable
it with `enable_compression` to get significant storage savings at the cost of CPU time.
[`CompressionSettings`](@ref) can be used to customize the HDF5 compression.
```julia
sys = System(100.0; enable_compression = true)
sys = System(
100.0;
compression = CompressionSettings(;
enabled = true,
type = CompressionTypes.DEFLATE, # BLOSC is also supported
level = 3,
shuffle = true,
),
)
```
## Adding Timeseries To The System
In order to optimize the storage of time series data, time series can be shared
across devices to avoid duplication. If the same forecast applies to multiple
components then can call `add_time_series!`, passing the collection of
components that share the time series data.
Time series data can also be shared on a component level. Suppose a time series array applies to
both the `max_active_power` and `max_reactive_power` attributes of a generator. You can share the
data.
```julia
resolution = Dates.Hour(1)
data = Dict(
DateTime("2020-01-01T00:00:00") => ones(24),
DateTime("2020-01-01T01:00:00") => ones(24),
)
# Define a Deterministic for the first attribute
forecast_max_active_power = Deterministic(
"max_active_power",
data,
resolution;
scaling_factor_multiplier = get_max_active_power,
)
add_time_series!(sys, generator, forecast_max_active_power)
# Reuse time series for second attribute
forecast_max_reactive_power = Deterministic(
forecast_max_active_power,
"max_reactive_power";
scaling_factor_multiplier = get_max_reactive_power,
)
add_time_series!(sys, generator, forecast_max_reactive_power)
```
By default, the call to [`add_time_series!`](@ref) will open the HDF5 file, write the data to the file,
and close the file. It will also add a row to an SQLite database. These operations have overhead.
If you will add thousands of time series arrays, consider using [`begin_time_series_update`](@ref).
All arrays will be written with one file handle. The bulk SQLite operations are much more
efficient.
```julia
begin_time_series_update(sys) do
add_time_series!(sys, component1, time_series1)
add_time_series!(sys, component2, time_series2)
add_time_series!(sys, component3, time_series3)
end
```
## Using Forecast Caches for Simulations
Each retrieval of a forecast window from the HDF5 file will involve a small disk read.
In the case of production cost modeling or other analyses that access
forecast windows repeatedly, this can slow down processes significantly, especially if the
underlying storage uses spinning disks.
PowerSystems provides an alternate interface -- the forecast cache -- that pre-fetches data
into the system memory with large reads in order to mitigate this potential problem.
It is highly recommended that you use this interface for modeling implementations. This is
particularly relevant for models using large datasets.
For example:
```julia
cache = ForecastCache(Deterministic, component, "max_active_power")
window1 = get_next_time_series_array!(cache)
window2 = get_next_time_series_array!(cache)
# or
for window in cache
@show window
end
```
Each iteration of on the cache object will deliver the next forecast window (see
[`get_next_time_series_array!`](@ref)).
================================================
FILE: docs/src/how_to/jump.md
================================================
# [Modeling with JuMP](@id modeling_with_jump)
This guide is for users who are interested in writing custom optimization problems directly in [JuMP](https://jump.dev/JuMP.jl/stable/), using data formatted with `PowerSystems.jl`. Check out [`PowerSimulations.jl`](https://sienna-platform.github.io/PowerSimulations.jl/stable/) for developing reusable templates for optimization problems within the Sienna platform.
This page shows a minimal example to develop a Economic Dispatch model. The code shows the stages to develop modeling code:
1. Make the data set from power flow and time series data,
2. Serialize the system data,
3. Pass the data and algorithm to the model.
One of the main uses of `PowerSystems.jl` is not having re-run the data generation for every model execution. The model code shows an example of populating the constraints and cost functions using accessor functions inside the model function. The example concludes by reading the data created earlier and passing the algorithm with the data.
Start by loading required packages:
```@repl using_jump
using PowerSystems
using JuMP
using Ipopt
using PowerSystemCaseBuilder
using Dates
```
For this example, we'll load an existing data set using
[`PowerSystemCaseBuilder.jl`](https://sienna-platform.github.io/PowerSystemCaseBuilder.jl/stable),
which is a helper library that makes it easier to reproduce examples.
Normally you would pass your local files to create the system data instead of calling the function `build_system`.
We also use [`transform_single_time_series!`](@ref) to format time-series data as forecasts for
this problem:
```@repl using_jump
system_data = build_system(PSISystems, "c_sys5_pjm")
transform_single_time_series!(system_data, Hour(24), Hour(24))
```
Next, we define the custom optimization problem using [`JuMP`](https://jump.dev/JuMP.jl/stable/)'s syntax.
The constraints include each generator's minimum and maximum active power output as well as the system power balance equation, minimizing the operating cost for each step in the 24-hour horizon:
```@repl using_jump
function ed_model(system::System, optimizer, load_scaling_factor::Float64 = 1.0)
ed_m = Model(optimizer)
time_periods = 1:24
thermal_gens_names = get_name.(get_components(ThermalStandard, system))
@variable(ed_m, pg[g in thermal_gens_names, t in time_periods] >= 0)
for g in get_components(ThermalStandard, system), t in time_periods
name = get_name(g)
@constraint(ed_m, pg[name, t] >= get_active_power_limits(g).min)
@constraint(ed_m, pg[name, t] <= get_active_power_limits(g).max)
end
net_load = zeros(length(time_periods))
for g in get_components(RenewableGen, system)
net_load -=
get_time_series_values(SingleTimeSeries, g, "max_active_power")[time_periods]
end
for g in get_components(StaticLoad, system)
net_load +=
get_time_series_values(SingleTimeSeries, g, "max_active_power")[time_periods]
end
for t in time_periods
@constraint(
ed_m,
sum(pg[g, t] for g in thermal_gens_names) == load_scaling_factor * net_load[t]
)
end
@objective(
ed_m,
Min,
sum(
pg[get_name(g), t] *
get_proportional_term(get_function_data(get_variable(get_operation_cost(g))))
for g in get_components(ThermalGen, system), t in time_periods
)
)
optimize!(ed_m)
return ed_m
end
```
Finally, the `PowerSystems.jl` data is combined with this economic dispatch model and solved with the open-source [`Ipopt`](https://github.com/jump-dev/Ipopt.jl) solver:
```@repl using_jump
results = ed_model(system_data, Ipopt.Optimizer)
```
================================================
FILE: docs/src/how_to/market_bid_cost.md
================================================
# Add a Market Bid
A [`MarketBidCost`](@ref) is an `OperationalCost` data structure that allows the user to run a production
cost model that is very similar to most US electricity market auctions with bids for energy
and ancillary services jointly. This page showcases how to create data for this cost function.
## Adding a Single Incremental Energy bids to MarketBidCost
### Construct directly the MarketBidCost using the `make_market_bid_curve` method.
The `make_market_bid_curve` creates an incremental or decremental offer curve from a vector of `n` power values, a vector of `n-1` marginal costs and single initial input. For example, the following code creates an incremental offer curve:
```@repl market_bid_cost
using PowerSystems, Dates
proposed_offer_curve =
make_market_bid_curve([0.0, 100.0, 105.0, 120.0, 130.0], [25.0, 26.0, 28.0, 30.0], 10.0)
```
Then a device with MarketBidCost can be directly instantiated using:
```@repl market_bid_cost
using PowerSystems, Dates
bus = ACBus(1, "nodeE", true, "REF", 0, 1.0, (min = 0.9, max = 1.05), 230, nothing, nothing)
generator = ThermalStandard(;
name = "Brighton",
available = true,
status = true,
bus = bus,
active_power = 6.0,
reactive_power = 1.50,
rating = 0.75,
prime_mover_type = PrimeMovers.ST,
fuel = ThermalFuels.COAL,
active_power_limits = (min = 0.0, max = 6.0),
reactive_power_limits = (min = -4.50, max = 4.50),
time_limits = (up = 0.015, down = 0.015),
ramp_limits = (up = 5.0, down = 3.0),
operation_cost = MarketBidCost(;
no_load_cost = 0.0,
start_up = (hot = 0.0, warm = 0.0, cold = 0.0),
shut_down = 0.0,
incremental_offer_curves = proposed_offer_curve,
),
base_power = 100.0,
)
```
Similarly, a decremental offer curve can also be created directly using the same helper method:
```@repl market_bid_cost
using PowerSystems, Dates
decremental_offer =
make_market_bid_curve([0.0, 100.0, 105.0, 120.0, 130.0], [30.0, 28.0, 26.0, 25.0], 50.0)
```
and can be added to a `MarketBidCost` using the field `decremental_offer_curves`.
## Adding Time Series Energy bids to MarketBidCost
### Step 1: Constructing device with MarketBidCost
When using [`MarketBidCost`](@ref), the user can add the cost struct to the device specifying
only certain elements, at this point the actual energy cost bids don't need to be populated/passed.
The code below shows an example how we can create a thermal device with MarketBidCost.
```@repl market_bid_cost
using PowerSystems, Dates
bus = ACBus(1, "nodeE", true, "REF", 0, 1.0, (min = 0.9, max = 1.05), 230, nothing, nothing)
generator = ThermalStandard(;
name = "Brighton",
available = true,
status = true,
bus = bus,
active_power = 6.0,
reactive_power = 1.50,
rating = 0.75,
prime_mover_type = PrimeMovers.ST,
fuel = ThermalFuels.COAL,
active_power_limits = (min = 0.0, max = 6.0),
reactive_power_limits = (min = -4.50, max = 4.50),
time_limits = (up = 0.015, down = 0.015),
ramp_limits = (up = 5.0, down = 3.0),
operation_cost = MarketBidCost(;
no_load_cost = 0.0,
start_up = (hot = 0.0, warm = 0.0, cold = 0.0),
shut_down = 0.0,
),
base_power = 100.0,
)
```
### Step 2: Creating the `TimeSeriesData` for the Market Bid
The user is expected to pass the `TimeSeriesData` that holds the energy bid data which can be
of any type (i.e. `SingleTimeSeries` or `Deterministic`) and data must be `PiecewiseStepData`.
This data type is created by specifying a vector of `n` powers, and `n-1` marginal costs.
The data must be specified in natural units, that is power in MW and marginal cost in $/MWh
or it will not be accepted when adding to the system.
Code below shows an example of how to build a Deterministic TimeSeries.
```@repl market_bid_cost
initial_time = Dates.DateTime("2020-01-01")
psd1 = PiecewiseStepData([5.0, 7.33, 9.67, 12.0], [2.901, 5.8272, 8.941])
psd2 = PiecewiseStepData([5.0, 7.33, 9.67, 12.0], [3.001, 6.0072, 9.001])
data =
Dict(
initial_time => [
psd1,
psd2,
],
)
time_series_data = Deterministic(;
name = "variable_cost",
data = data,
resolution = Dates.Hour(1),
)
```
### Step 3a: Adding Energy Bid TimeSeriesData to the device
To add energy market bids time-series to the `MarketBidCost`, use `set_variable_cost!`. The
arguments for `set_variable_cost!` are:
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `time_series_data::TimeSeriesData`: TimeSeriesData
- `power_units::UnitSystem`: UnitSystem
Currently, time series data only supports natural units for time series data, i.e. MW for power and $/MWh for marginal costs.
```@repl market_bid_cost
sys = System(100.0, [bus], [generator])
set_variable_cost!(sys, generator, time_series_data, UnitSystem.NATURAL_UNITS)
```
**Note:** `set_variable_cost!` add curves to the `incremental_offer_curves` in the MarketBidCost.
Similarly, `set_incremental_variable_cost!` can be used to add curves to the `incremental_offer_curves`.
On the other hand, `set_decremental_variable_cost!` must be used to decremental curves (usually for storage or demand).
The creation of the TimeSeriesData is similar to Step 2, using `PiecewiseStepData`
### Step 3b: Adding Service Bid TimeSeriesData to the device
Similar to adding energy market bids, for adding bids for ancillary services, use
`set_service_bid!`.
```@repl market_bid_cost
service = VariableReserve{ReserveUp}("example_reserve", true, 0.6, 2.0)
add_service!(sys, service, get_component(ThermalStandard, sys, "Brighton"))
psd3 = PiecewiseStepData([0.0, 10.0], [650.3])
psd4 = PiecewiseStepData([0.0, 10.0], [750.0])
data = Dict(Dates.DateTime("2020-01-01") => [psd3, psd4])
time_series_data = Deterministic(;
name = get_name(service),
data = data,
resolution = Dates.Hour(1),
)
set_service_bid!(sys, generator, service, time_series_data, UnitSystem.NATURAL_UNITS)
```
================================================
FILE: docs/src/how_to/migrating_to_psy5.md
================================================
# [Migrating from version 4.0 to 5.0](@id psy5_migration)
This guide outlines the code updates required to upgrade from PowerSystems.jl version 4.0
to 5.0, which was released in July 2025 and includes breaking changes. Most the changes are related
to modeling in more detail AC transmission technologies.
!!! warning
***PowerSystems v5 is not backwards compatible with PowerSystems v4. The datasets created in PowerSystems v4 need to be converted using a separate script to be loaded
in version 5***
The changes are:
```@contents
Pages = ["migrating_to_psy5.md"]
Depth = 2
```
## AC Branches Type Hierarchy Change
New abstract type [`ACTransmission`](@ref) and was created to better distinguish between AC transmission objects connected between [`ACBus`](@ref) the new added [`TwoTerminalHVDC`](@ref) abstract type to caputre HVDC links connected between [`ACBus`](@ref).
## Renamed Types and Parameters
Some `Types` and fields were renamed, which should require a trivial search and replace:
Renamed `Types`:
- [`TwoTerminalHVDCLine`](@ref) is now named [`TwoTerminalGenericHVDCLine`](@ref) and a method has been included to read old `TwoTerminalHVDCLine` data. See [Deprecated Methods](@ref deprecated)
- `TimeSeriesForcedOutage` is now named [`FixedForcedOutage`](@ref) and the method has been removed but the functionality remains.
New parameters:
- The [`ACTransmission`](@ref) objects now have rating fields for `b` and `c` ratings to enable modeling security constrained problems. These components now also include a `base_power` field, in situations where the base power for the transformer is not available (e.g., when parsing Matpower), the default behavior is to use the [system base for per-unitization](@ref per_unit).
Affected Types are:
- [`Line`](@ref)
- [`MonitoredLine`](@ref)
- [`PhaseShiftingTransformer`](@ref)
- [`TapTransformer`](@ref)
- [`Transformer2W`](@ref)
- [`FuelCurve`](@ref) now has a new field for fuel offtake at the start of a thermal unit. This field defaults to a `LinearCurve(0.0)` value.
## New and Eliminated Types
- [`Transformer3W`](@ref) (see [Handle 3-winding transformer data](@ref 3wtdata))
- [`TwoTerminalLCCLine`](@ref)
- [`TwoTerminalVSCLine`](@ref)
- [`HydroReservoir`](@ref)
- [`HydroTurbine`](@ref)
- [`HydroPumpTurbine`](@ref)
- [`ShiftablePowerLoad`](@ref)
- [`DiscreteControlledACBranch`](@ref)
- [`FACTSControlDevice`](@ref)
- [`ImpedanceCorrectionData`](@ref)
- [`ImportExportCost`](@ref)
- [`SynchronousCondenser`](@ref)
- [`InterruptibleStandardLoad`](@ref)
These types are no longer part of PowerSystems.jl:
- `TwoTerminalVSDCLine`
- `HydroPumpedStorage` (see [Updates to Hydro Storage related devices](@ref Hyd_updates))
- `HydroEnergyReservoir` (see [Updates to Hydro Storage related devices](@ref Hyd_updates))
## [Updates to hydro storage related devices](@id Hyd_updates)
In previous versions of `PowerSystems.jl`, hydropower connected to reservoirs was modeled as a single plant connected to a single reservoir. Further, the model just kept track of the total energy in the reservoir. In this version of `PowerSystems.jl`, new structs [`HydroTurbine`](@ref) and [`HydroReservoir`](@ref) have been included to enable individual unit dispatch modeling as well as a shared reservoir.
The new [`HydroReservoir`](@ref) is also used by the new [`HydroPumpTurbine`](@ref) to model the head and tail reservoirs for Hydro Pump Storage facilities. Check the section [Define Hydro Generators with Reservoirs](@ref hydro_resv)
## Updates to fuel categories
The fuel categories available in form EIA-923 have been expanded, the old categories are still
valid and the expanded list can be explored in the documentation [`ThermalFuels`](@ref tf_list)
## Updates to Transformers
Most of the transformer changes are included to bring PowerSystems.jl closer to the data model employed in PSSe RAW files which tend to be the industry standard. The two notable changes are:
- All transformers now have additional fields for base quantities needed for the calculation of the impedances in adequate bases. See [`Transformer per unit transformations`](@ref transformers_pu) for more details.
- The shunt branch in the transformer now uses a `Complex{Float64}` to model core losses as well as the core inductance.
- Shunt allocation in the transformer between the primary and secondary. We now allocate the shunt to the primary following PSSe's convention. See [`this issue`](https://github.com/Sienna-Platform/PowerSystems.jl/issues/1411) for a description of the discrepancy with Matpower. Note that this mostly affect the results reporting between Matpower and PSSe.
We also added support for [`Transformer3W`](@ref). See [`Handle 3-winding transformer data`](@ref 3wtdata) for more details.
These changes now provide the capability to obtain the impedance values for the transformer's
depending on the [`Per-unit Conventions`](@ref per_unit).
## Updates to ACBuses
[`ACBus`](@ref) has a new field `available` to match the behavior of setting a bus to "isolated" in other simulation applications. A detailed explanation on how to handle this new field has been documented in [`Understanding ACBusTypes`](@ref bustypes)
## Updates to parsing PSSe files
We have implemented new conventions to parsing PSSe files as well as the capability to load PSSe v35 files. See the details in the new documentation section [`Conventions when parsing MATPOWER or PSS/e Files`](@ref parse_conventions)
================================================
FILE: docs/src/how_to/parse_dynamic_data.md
================================================
# [Parsing PSS/e dynamic data](@id dyr_data)
A `PowerSystems.jl` system can be created using a .RAW and a .DYR file. For a complete list of supported models in PowerSystems.jl version 5.0, including machine models, AVR models, turbine governors, PSS models, inverter models, and additional models, see the [Supported PSS/e Models](@ref psse_models_ref) reference page.
In this example we will create a three bus system from these example files:
```@repl raw_dyr_system
using PowerSystems
file_dir = joinpath(pkgdir(PowerSystems), "docs", "src", "tutorials", "tutorials_data")
RAW_dir = joinpath(file_dir, "ThreeBusNetwork.raw")
DYR_dir = joinpath(file_dir, "TestGENCLS.dyr")
```
The data in the RAW file defines a three bus system with three generators, three loads and
three branches:
```raw
0, 100, 33, 0, 0, 60 / 24-Apr-2020 19:28:39 - MATPOWER 7.0.1-dev
101, 'BUS 1 ', 138, 3, 1, 1, 1, 1.02, 0, 1.1, 0.9, 1.1, 0.9
102, 'BUS 2 ', 138, 2, 1, 1, 1, 1.0142, 0, 1.1, 0.9, 1.1, 0.9
103, 'BUS 3 ', 138, 2, 1, 1, 1, 1.0059, 0, 1.1, 0.9, 1.1, 0.9
0 / END OF BUS DATA, BEGIN LOAD DATA
101, 1, 1, 1, 1, 100, 20, 0, 0, 0, 0, 1, 1, 0
102, 1, 1, 1, 1, 70, 10, 0, 0, 0, 0, 1, 1, 0
103, 1, 1, 1, 1, 50, 10, 0, 0, 0, 0, 1, 1, 0
0 / END OF LOAD DATA, BEGIN FIXED SHUNT DATA
0 / END OF FIXED SHUNT DATA, BEGIN GENERATOR DATA
101, 1, 20, 0, 100, -100, 1.02, 0, 100, 0, 0, 0, 0, 1, 1, 100, 318, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1
102, 1, 100, 0, 100, -100, 1.0142, 0, 100, 0, 0.7, 0, 0, 1, 1, 100, 318, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1
103, 1, 100, 0, 100, -100, 1.0059, 0, 100, 0, 0.2, 0, 0, 1, 1, 100, 318, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1
0 / END OF GENERATOR DATA, BEGIN BRANCH DATA
101, 103, 1, 0.01000, 0.12, 0.0, 250, 250, 250, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1
101, 102, 1, 0.01000, 0.12, 0.0, 250, 250, 250, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1
102, 103, 1, 0.01000, 0.12, 0.0, 250, 250, 250, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1
0 / END OF BRANCH DATA, BEGIN TRANSFORMER DATA
0 / END OF TRANSFORMER DATA, BEGIN AREA DATA
0 / END OF AREA DATA, BEGIN TWO-TERMINAL DC DATA
0 / END OF TWO-TERMINAL DC DATA, BEGIN VOLTAGE SOURCE CONVERTER DATA
0 / END OF VOLTAGE SOURCE CONVERTER DATA, BEGIN IMPEDANCE CORRECTION DATA
0 / END OF IMPEDANCE CORRECTION DATA, BEGIN MULTI-TERMINAL DC DATA
0 / END OF MULTI-TERMINAL DC DATA, BEGIN MULTI-SECTION LINE DATA
0 / END OF MULTI-SECTION LINE DATA, BEGIN ZONE DATA
0 / END OF ZONE DATA, BEGIN INTER-AREA TRANSFER DATA
0 / END OF INTER-AREA TRANSFER DATA, BEGIN OWNER DATA
0 / END OF OWNER DATA, BEGIN FACTS CONTROL DEVICE DATA
0 / END OF FACTS CONTROL DEVICE DATA, BEGIN SWITCHED SHUNT DATA
0 / END OF SWITCHED SHUNT DATA, BEGIN GNE DEVICE DATA
0 / END OF GNE DEVICE DATA, BEGIN INDUCTION MACHINE DATA
0 / END OF INDUCTION MACHINE DATA
Q
```
The dynamic data for the generators is provided in the DYR file:
```raw
101 'GENROE' 1 8.000000 0.030000 0.400000 0.050000 6.500000 0.000000 1.800000
1.700000 0.300000 0.550000 0.250000 0.200000 0.039200 0.267200 /
101 'ESST1A' 1 1 1 0.01 99 -99 1 10 1 1 200 0 4 -4 4 -4 0 0 1 0 3 /
102 'GENCLS' 1 0.0 0.0 /
103 'GENCLS' 1 3.1 2.0 /
```
That assigns a GENROU generator and a ESST1A voltage regulator at the generator located at bus 101, while classic machine models for the generators located at bus 102 and 103.
To create the `System` in `PowerSystems.jl`, we pass both files directories:
```@repl raw_dyr_system
dyn_system = System(RAW_dir, DYR_dir; runchecks = false)
```
# Common Issue: Unique Bus Names
Please note that while PSS/e does not enforce unique bus names, `PowerSystems.jl` does. To reparse bus names to comply with this requirement the `bus_name_formatter` *kwarg can be used in `System()` as shown in the example below:
```@repl raw_dyr_system
dyn_system = System(
RAW_dir,
DYR_dir;
bus_name_formatter = x -> strip(string(x["name"])) * "-" * string(x["index"]),
)
```
In this example the anonymous function `x -> strip(string(x["name"])) * "-" * string(x["index"])` takes the bus name and index from PSSe and concatenates them to produce the name.
### See also:
- Parsing [Matpower or PSS/e RAW Files](@ref pm_data)
- [Build a `System` from CSV files](@ref system_from_csv)
- Parsing [time series](@ref parsing_time_series)
================================================
FILE: docs/src/how_to/parse_matpower_psse.md
================================================
# [Parsing MATPOWER or PSS/e Files](@id pm_data)
The following code will create a System from a MATPOWER .m or PSS/e .raw file:
```@repl m_system
using PowerSystems
file_dir = joinpath(pkgdir(PowerSystems), "docs", "src", "tutorials", "tutorials_data")
sys = System(joinpath(file_dir, "case5.m"))
```
Originally, the parsing code was copied with permission from
[`PowerModels.jl`](https://github.com/lanl-ansi/PowerModels.jl) but over the years the code base
has had some divergence due to the need to adapt it to for large industrial cases.
The PSSe parser tries to handle correctly all the gotchas that result from the diverse modeling practices transmission engineers employ. However, it is impossible to anticipate all possible variations.
PowerSystems.jl parsing code has been tested and developed using large cases from North America
like the Western Electricity Coordinating Council (WECC) planning case and the Multiregional Modeling Working Group (MMWG) base case models. This parser has also been adapted to load cases in Latin America and the Caribbean and as many of the open data sets available only.
## [Conventions when parsing MATPOWER or PSS/e Files](@id parse_conventions)
!!! Info
In PowerSystems v5, the parsing conventions changed from those in PowerSystems v4. You might experience different behaviors when loading MATPOWER or PSS/e Files.
PowerSystems.jl utilizes a data model that bridges the gap between operational simulations, such as Production Cost Analysis, and electrical engineering simulations, including power flows. Given the different practices in these domains, there are several discrepancies in how to handle data and we have made changes to make the modeling compatible.
In PowerSystems v5, we have implemented the following conventions for parsing PSSe files:
- **BusType correction**: If a bus has a value set to ISOLATED in PSSe, we will confirm that the bus is not entirely disconnected from the network. If the bus is disconnected, it will be set to ISOLATED and set the field available to false. However, if the bus is connected to a generator, we will infer a bus of type PV and set the field 'available' to false. This correction also applies to Matpower. For any other device connected to the bus, we will set it to PQ and set the 'available' field to false. Check [`Understanding ACBusTypes`](@ref bustypes) for a detailed explanation.
- **Parsing Synchronous Condensers**: If a generator is connected to a PV Bus with activer power set to 0.0, it will be parsed as a [`SynchronousCondenser`](@ref). This prevents for generators to be modeled as dispatchable [`ThermalStandard`](@ref) when it doesn't apply.
- **Reading and Storing Transformer Data**: The transformer data is always stored in the devices
' base. See [`Transformer per unit transformations`](@ref transformers_pu) for additional details.
- **Transformer's Susceptance**: When reading from Matpower we split the transformer's susceptance evenly between the `from` and `to` ends to make it a closer approximation to the model in PSSe.
- **Tap transformer settings automated fix**: When the tap values in the RAW file are not withing the ranges defined in the same entry, PSSe performs a correction to the data. However, this correction isn't stored back in the file. The tap correction is done internally and is not exported from PSSE. Changes are not reflected in the exported file.PowerSystems.jl will correct the tap setting **and change the field in the transformer struct.**
- **Reading and Storing Multi-Section Line Data**: `PowerSystems.jl` does not have a explicit multi-section line object. These devices are parsed as individual lines and the "dummy buses" are added to the system. The additional data is stored in the [`Line`](@ref) `ext` field. Further network reductions are performed using [`PowerNetworkMatrices.jl`](https://sienna-platform.github.io/PowerNetworkMatrices.jl/stable/).
- **Reading [`GeographicInfo`](@ref) data from substations (PSSe v35 only)**: If the file contains a substation section. The coordinates will be automatically loaded as a [`GeographicInfo`](@ref) attribute and assigned to the relevant buses.
- **Use [`InterruptibleStandardLoad`](@ref) (PSSe v35 only)**: In newer versions of PSSe there is a flag for interruptible. Since PowerSystems.jl already has structures to model controllable load like [`InterruptiblePowerLoad`](@ref) and [`ShiftablePowerLoad`](@ref) a new type is used when parsing from PSSe to account of the interruptible behavior in economic modeling.
- **Treatment of conforming and non-conforming flags**: See the section [`Conforming and Non-Conforming Loads`](@ref conf_loads). PowerSystems.jl uses an enum to represent this data but it does not implement specific models for this behavior.
- **Breakers and Switches**: From the perspective of PowerSystems.jl breakers and switches are modeled as [`DiscreteControlledACBranch`](@ref). We use an enum to separate between the two but from the data structure perspective both use the same object definition.
- **Rate data correction**: For rates B and C are set as `nothing` if the value in the file is zero. On the other hand, for rating A, the value gets corrected. If the raw file is zero, then set up the rating to infinite bound first and then reduced according to the voltage values. This proceedure still can produce a large amount of warning for situations where a single line is used to model a double circuit or a whole transmission corridor.
- **Motor Loads**: We included a new device for explictly modeling motor loads. However, PSSe doesn't support explicit representations of these loads. The parser will print a warning in the log when we detect conditions commonly associated to motor load representations but won't be able to capture it directly.
### Pending parsing challenges
- Managing the new format for rate data. In the old PSSe versions, there was Rate A, Rate B and Rate C. However, in newer versions there are 12 possible rates open to intepretation by the modeler. it can still be interpreted as A, B or C rates or a rate per month. PSSe doesn't provide any metada to interpret the rating bands provided.
- Detecting motor loads modeled as generators. Same as with the case for the negative loads, motors are known to be modeled as machines with negative injections (i.e., loads) to match modeling them in transient studies as machines.
- Automated transformer direction swaping. See [`this issue`](https://github.com/Sienna-Platform/PowerSystems.jl/issues/1423)
- Parsing outage data.
### See also:
- Parsing [PSS/e .dyr Files](@ref dyr_data), which also includes an example of parsing a
.raw file
- [Build a `System` from CSV files](@ref system_from_csv)
- Parsing [time series](@ref parsing_time_series)
================================================
FILE: docs/src/how_to/parse_ts_from_csvs.md
================================================
# [Parse Time Series Data from .csv's](@id parsing_time_series)
This example shows how to parse time series data from .csv files to add to a `System`.
For example, a `System` created by [parsing a MATPOWER file](@ref pm_data) doesn't contain
any time series data, so a user may want to add time series to be able to run a production
cost model.
```@setup forecasts
using PowerSystems
using JSON3
file_dir = joinpath(pkgdir(PowerSystems), "docs", "src", "tutorials", "tutorials_data"); #hide
sys = System(joinpath(file_dir, "case5_re.m"));
```
Let's use a predefined 5-bus [`System`](@ref) with some renewable generators and loads that
we want to add time-series data to:
```@repl forecasts
sys
```
## Define pointers to time series files
`PowerSystems` requires a metadata file that maps components to their time series
data in order to be able to automatically construct time_series from .csv data
files.
For example, if we want to add a bunch of time series files, say one for each load and one
for each renewable generator, we need to define *pointers* to each time series .csv file
with the following fields:
- `simulation`: User description of simulation
- `resolution`: Resolution of time series in seconds
- `module`: Module that defines the abstract type of the component
- `category`: Type of component. Must map to abstract types defined by the "module"
entry (Bus, ElectricLoad, Generator, LoadZone, Reserve)
- `component_name`: Name of component
- `name`: User-defined name for the time series data.
- `normalization_factor`: Controls normalization of the data. Use 1.0 for
pre-normalized data. Use 'Max' to divide the time series by the max value in the
column. Use any float for a custom scaling factor.
- `scaling_factor_multiplier_module`: Module that defines the accessor function for the
scaling factor
- `scaling_factor_multiplier`: Accessor function of the scaling factor
- `data_file`: Path to the time series data file
Notes:
- The `module`, `category`, and `component_name` entries must be valid arguments to retrieve
a component using `get_component(${module}.${category}, sys, $name)`.
- The `scaling_factor_multiplier_module` and the `scaling_factor_multiplier` entries must
be sufficient to return the scaling factor data using
`${scaling_factor_multiplier_module}.${scaling_factor_multiplier}(component)`.
`PowerSystems` supports this metadata in either CSV or JSON formats.
In this example, we will use the JSON format. The example file can be found
[here](https://github.com/Sienna-Platform/PowerSystemsTestData/blob/master/5-Bus/5bus_ts/timeseries_pointers_da.json),
and this is what its pointers look like in the required format:
```@repl forecasts
using PowerSystemCaseBuilder #hide
DATA_DIR = PowerSystemCaseBuilder.DATA_DIR #hide
FORECASTS_DIR = joinpath(DATA_DIR, "5-Bus", "5bus_ts"); #hide
fname = joinpath(FORECASTS_DIR, "timeseries_pointers_da.json"); # hide
open(fname, "r") do f # hide
JSON3.@pretty JSON3.read(f) # hide
end #hide
```
## Read and assign time series to `System` using these parameters.
```@repl forecasts
fname = joinpath(FORECASTS_DIR, "timeseries_pointers_da.json")
add_time_series!(sys, fname)
```
You can print the `System` to see a new table summarizing the time series data that has been
added:
```@repl forecasts
sys
```
### See also:
- [Improve Performance with Time Series Data](@ref)
- Parsing [Matpower or PSS/e RAW Files](@ref pm_data)
- Parsing [PSS/e DYR Files](@ref dyr_data)
- [Build a `System` from CSV files](@ref system_from_csv)
================================================
FILE: docs/src/how_to/reduce_repl_printing.md
================================================
# Reduce REPL printing
By default `PowerSystems.jl` outputs to the REPL all Logging statements, which can be
overwhelming in some cases.
Use [`configure_logging`](@ref) to create a logger with your preferences for which logging
statements should be printed to the console or a log file:
**Example**: Set log output to only see error messages in the console
```julia
using PowerSystems
using Logging
configure_logging(; console_level = Logging.Error)
```
**Note:** log messages are not automatically flushed to files. Call
`flush(logger)` to make this happen.
[Refer to this
page](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/dev_guide/logging/#Use-Cases)
for more logging configuration options. Note that it describes how to enable
debug logging for some log messages but not others.
================================================
FILE: docs/src/how_to/serialize_data.md
================================================
# Write, View, and Load Data with a JSON
`PowerSystems.jl` provides functionality to serialize an entire [`System`](@ref) to a JSON
file and then deserialize it back to a `System`. The main benefit is that
deserializing is significantly faster than reconstructing the `System` from raw
data files.
The sections below show how to write data to a JSON, explore the data while it is in
JSON format, and load Data saved in a JSON back into `PowerSystems.jl`.
## Write data to a JSON
You can do this to save your own custom `System`, but we'll use an existing
dataset from
[`PowerSystemCaseBuilder.jl`](https://github.com/Sienna-Platform/PowerSystemCaseBuilder.jl),
simply to illustrate the process.
First, load the dependencies and a `System` from `PowerSystemCaseBuilder`:
```@repl serialize_data
using PowerSystems
using PowerSystemCaseBuilder
sys = build_system(PSISystems, "c_sys5_pjm")
```
Set up your target path, for example in a "mysystems" subfolder:
```@repl serialize_data
folder = mkdir("mysystems");
path = joinpath(folder, "system.json")
```
Now write the system to JSON:
```@repl serialize_data
to_json(sys, path)
```
Notice in the `Info` statements that the serialization process stores 3 files:
1. System data file (`*.json` file)
2. Validation data file (`*.json` file)
3. Time Series data file (`*.h5` file)
## Viewing `PowerSystems` Data in JSON Format
Some users prefer to view and filter the `PowerSystems.jl` data while it is in JSON format.
There are many tools available to browse JSON data.
Here is an example [GUI tool](http://jsonviewer.stack.hu) that is available
online in a browser.
The command line utility [jq](https://stedolan.github.io/jq/) offers even more
features. Below are some example commands, called from the command line within the
"mysystems" subfolder:
View the entire file pretty-printed:
```zsh
jq . system.json
```
View the `PowerSystems` component types:
```zsh
jq '.data.components | .[] | .__metadata__ | .type' system.json | sort | uniq
```
View specific components:
```zsh
jq '.data.components | .[] | select(.__metadata__.type == "ThermalStandard")' system.json
```
Get the count of a component type:
```zsh
# There is almost certainly a better way.
jq '.data.components | .[] | select(.__metadata__.type == "ThermalStandard")' system.json | grep -c ThermalStandard
```
View specific component by name:
```zsh
jq '.data.components | .[] | select(.__metadata__.type == "ThermalStandard" and .name == "107_CC_1")' system.json
```
Filter on a field value:
```zsh
jq '.data.components | .[] | select(.__metadata__.type == "ThermalStandard" and .active_power > 2.3)' system.json
```
## Read the JSON file and create a new `System`
Finally, you can read the file back in, and verify the new system has the same data as above:
```@repl serialize_data
sys2 = System(path)
rm(folder; recursive = true); #hide
```
!!! tip
PowerSystems generates UUIDs for the `System` and all components in order to have
a way to uniquely identify objects. During deserialization it restores the same
UUIDs. If you will modify the `System` or components after deserialization then
it is recommended that you set this flag to generate new UUIDs.
```julia
system2 = System(path; assign_new_uuids = true)
```
================================================
FILE: docs/src/how_to/use_context_managers.md
================================================
# Use Context Managers for Efficient Bulk Operations
`PowerSystems.jl` provides several "context manager" functions that help you perform bulk
operations more efficiently and safely. These functions temporarily change system settings or
optimize batch operations, then automatically restore the original state when complete.
Context managers in PowerSystems follow a pattern similar to `Logging.with_logger` in Julia.
They accept a function (typically as a `do` block) that executes with modified settings,
ensuring cleanup even if errors occur.
## Available Context Managers
PowerSystems provides three main context managers:
1. [`with_units_base`](@ref) - Temporarily change unit system for getting/setting component data
2. [`begin_supplemental_attributes_update`](@ref) - Optimize bulk addition/removal of supplemental attributes
3. [`begin_time_series_update`](@ref) - Optimize bulk addition of time series data
## Using `with_units_base`
The [`with_units_base`](@ref) function temporarily changes the [unit system](@ref per_unit)
for a `System` or `Component`, executes your code, then automatically restores the original
unit system. This is useful when you need to retrieve or set values in a specific unit system
without permanently changing the system's configuration.
!!! note
You can specify the unit system using either the `UnitSystem` enum (e.g.,
`UnitSystem.NATURAL_UNITS`) or a string (e.g., `"NATURAL_UNITS"`). Both forms are
supported and equivalent.
### Example: Getting Component Data in Natural Units
```julia
using PowerSystems
using PowerSystemCaseBuilder
# Load a system
sys = build_system(PSISystems, "c_sys5_pjm")
gen = first(get_components(ThermalStandard, sys))
# Get active power in natural units (MW) regardless of system's unit base
active_power_mw = with_units_base(sys, UnitSystem.NATURAL_UNITS) do
get_active_power(gen)
end
# The system's unit base is automatically restored after the block
```
### Example: Setting Multiple Component Values in Natural Units
```julia
# Temporarily change units to add/modify multiple components in natural units
with_units_base(sys, "NATURAL_UNITS") do
for gen in get_components(ThermalStandard, sys)
# Set values in MW, MVA, etc.
set_active_power!(gen, 150.0) # MW
set_rating!(gen, 200.0) # MVA
end
end
# System automatically returns to original unit base
```
### Component-Level Context Manager
You can also use `with_units_base` on individual components:
```julia
active_power_mw = with_units_base(gen, UnitSystem.NATURAL_UNITS) do
get_active_power(gen)
end
```
!!! tip
The `with_units_base` context manager is particularly useful when you need to work with
data in natural units (MW, MVA, etc.) while keeping your system configured in per-unit
for optimization or simulation purposes.
## Using `begin_supplemental_attributes_update`
The [`begin_supplemental_attributes_update`](@ref) function optimizes performance when adding
or removing many supplemental attributes. It batches operations together, reducing overhead
from repeated index updates.
If an error occurs during the update, all changes are automatically reverted, ensuring data
consistency.
### Example: Adding Multiple Supplemental Attributes
```julia
using PowerSystems
# Define some supplemental attributes (e.g., outage data)
outage1 = FixedForcedOutage(;
mean_time_to_recovery = 8.0,
mean_time_to_failure = 1000.0,
)
outage2 = FixedForcedOutage(;
mean_time_to_recovery = 12.0,
mean_time_to_failure = 800.0,
)
# Get components to attach attributes to
gen1 = get_component(ThermalStandard, sys, "322_CT_6")
gen2 = get_component(ThermalStandard, sys, "323_CC_1")
# Use context manager for efficient bulk addition
begin_supplemental_attributes_update(sys) do
add_supplemental_attribute!(sys, gen1, outage1)
add_supplemental_attribute!(sys, gen2, outage2)
# Add many more attributes...
end
```
### Example: Bulk Operations with Error Handling
```julia
# If an error occurs, all changes are automatically reverted
try
begin_supplemental_attributes_update(sys) do
add_supplemental_attribute!(sys, component1, attribute1)
add_supplemental_attribute!(sys, component2, attribute2)
# ... more operations ...
error("Something went wrong!") # All changes will be reverted
end
catch e
@warn "Operation failed, changes were reverted" exception=e
end
```
!!! note
Without using this context manager, each individual call to
`add_supplemental_attribute!` updates internal indexes separately, which can be slow
when adding many attributes. The context manager batches all updates together for
better performance.
## Using `begin_time_series_update`
The [`begin_time_series_update`](@ref) function optimizes performance when adding many time
series arrays by keeping the HDF5 file open and batching SQLite database operations. This
reduces the overhead of repeatedly opening/closing files and performing individual database
transactions.
If an error occurs during the update, changes are automatically reverted.
!!! note
This context manager is not necessary for in-memory time series stores, only for
HDF5-backed storage.
### Example: Adding Multiple Time Series
```julia
using PowerSystems
using Dates
# Create time series data
resolution = Dates.Hour(1)
data = Dict(
DateTime("2020-01-01T00:00:00") => ones(24),
DateTime("2020-01-02T00:00:00") => ones(24) * 1.1,
)
# Get components
generators = collect(get_components(ThermalStandard, sys))
# Use context manager for efficient bulk addition
begin_time_series_update(sys) do
for (i, gen) in enumerate(generators)
forecast = Deterministic(
"max_active_power",
data,
resolution;
scaling_factor_multiplier = get_max_active_power,
)
add_time_series!(sys, gen, forecast)
end
end
```
### Example: Adding Time Series from Multiple Sources
```julia
# When you have time series data from multiple sources
begin_time_series_update(sys) do
for component in get_components(Generator, sys)
# Create time series data specific to each component
# (In practice, this might come from CSV files, databases, or other sources)
component_data = Dict(
DateTime("2020-01-01T00:00:00") => rand(24),
DateTime("2020-01-02T00:00:00") => rand(24),
)
forecast = Deterministic(
"max_active_power",
component_data,
resolution;
scaling_factor_multiplier = get_max_active_power,
)
add_time_series!(sys, component, forecast)
end
end
```
!!! tip
When adding thousands of time series arrays, using `begin_time_series_update` can
provide significant performance improvements by reducing file I/O and database
transaction overhead.
## Best Practices
1. **Always use context managers for bulk operations**: When adding multiple supplemental
attributes or time series, use the appropriate context manager to improve performance.
2. **Automatic cleanup**: Context managers ensure cleanup happens even if errors occur, so
your system state remains consistent.
3. **Nested context managers**: You can nest context managers if needed:
```julia
with_units_base(sys, "NATURAL_UNITS") do
begin_time_series_update(sys) do
# Add time series with natural unit scaling factors
for gen in get_components(Generator, sys)
# ... add time series ...
end
end
end
```
4. **Error handling**: The context managers automatically handle cleanup, but you can still
use `try-catch` blocks for application-specific error handling:
```julia
try
begin_time_series_update(sys) do
# ... operations ...
end
catch e
@error "Time series update failed" exception=e
# Handle application-specific recovery
end
```
## See Also
- [Per-unit Conventions](@ref per_unit) - Learn more about unit systems
- [Supplemental Attributes](@ref supplemental_attributes) - Details on supplemental attribute usage
- [Working with Time Series Data](@ref tutorial_time_series) - Tutorial on time series handling
- [Improve Performance with Time Series Data](@ref) - Additional time series performance tips
================================================
FILE: docs/src/index.md
================================================
# Welcome to PowerSystems.jl
```@meta
CurrentModule = PowerSystems
```
!!! tip "Announcement"
PowerSystems.jl upgraded to version 5.0 in November 2025, which included breaking changes.
Visit the [v5.0 migration guide](@ref psy5_migration) for information on
how to update your existing code from version 4.0.
## About
`PowerSystems.jl` is part of the National Laboratory of the Rockies'
[Sienna ecosystem](https://www.nlr.gov/analysis/sienna.html), an open source framework for
scheduling problems and dynamic simulations for power systems. The Sienna ecosystem can be
[found on github](https://github.com/Sienna-Platform/Sienna). It contains three applications:
- [Sienna\Data](https://github.com/Sienna-Platform/Sienna?tab=readme-ov-file#siennadata) enables
efficient data input, analysis, and transformation
- [Sienna\Ops](https://github.com/Sienna-Platform/Sienna?tab=readme-ov-file#siennaops) enables
enables system scheduling simulations by formulating and solving optimization problems
- [Sienna\Dyn](https://github.com/Sienna-Platform/Sienna?tab=readme-ov-file#siennadyn) enables
system transient analysis including small signal stability and full system dynamic
simulations
Each application uses multiple packages in the [`Julia`](http://www.julialang.org)
programming language.
`PowerSystems.jl` is the foundation of Sienna\Data, and it is used with all three
applications. It provides a rigorous
data model using Julia structures to enable power systems modeling. `PowerSystems.jl` is
agnostic to a specific mathematical model and can be used for many model categories.
`PowerSystems.jl` provides tools to prepare and process data useful
for electric energy systems modeling. This package serves two purposes:
1. It facilitates the development and open sharing of large data sets for Power Systems modeling
2. It provides a data model that imposes discipline on model specification, addressing the challenge of design and terminology choices when sharing code and data.
The main features include:
- Comprehensive and extensible library of data structures for electric systems modeling.
- Large scale data set development tools based on common text based data formats
(PSS/e `.raw` and `.dyr`, and `MATPOWER`) and configurable tabular data (e.g. CSV)
parsing capabilities.
- Optimized container for component data and time series supporting serialization to
portable file formats and configurable validation routines.
## How To Use This Documentation
There are five main sections containing different information:
- **Tutorials** - Detailed walk-throughs to help you *learn* how to use
`PowerSystems.jl`
- **How to...** - Directions to help *guide* your work for a particular task
- **Explanation** - Additional details and background information to help you *understand*
`PowerSystems.jl`, its structure, and how it works behind the scenes
- **Reference** - Technical references and API for a quick *look-up* during your work
- **Model Library** - Technical references of the data types and their functions that
`PowerSystems.jl` uses to model power system components
`PowerSystems.jl` strives to follow the [Diataxis](https://diataxis.fr/) documentation
framework.
## Installation and Quick Links
- [Sienna installation page](https://sienna-platform.github.io/Sienna/SiennaDocs/docs/build/how-to/install/):
Instructions to install `PowerSystems.jl` and other Sienna packages
!!! note
`PowerSystems.jl` uses [`InfrastructureSystems.jl`](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/) as a utility library. Many methods are re-exported from `InfrastructureSystems.jl`.
For most users there is no need to import `InfrastructureSystems.jl`.
- [Sienna Documentation Hub](https://sienna-platform.github.io/Sienna/SiennaDocs/docs/build/index.html):
Links to other Sienna packages' documentation
================================================
FILE: docs/src/model_library/dynamic_branch.md
================================================
# Dynamic Branch
```@autodocs
Modules = [PowerSystems]
Pages = ["models/dynamic_branch.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/dynamic_generator.md
================================================
# DynamicGenerator
```@autodocs
Modules = [PowerSystems]
Pages = ["dynamic_generator.jl"]
Order = [:type, :function]
Public = true
```
================================================
FILE: docs/src/model_library/dynamic_inverter.md
================================================
# DynamicInverter
```@autodocs
Modules = [PowerSystems]
Pages = ["dynamic_inverter.jl"]
Order = [:type, :function]
Public = true
```
================================================
FILE: docs/src/model_library/hybrid_system.md
================================================
### Hybrid System
```@autodocs
Modules = [PowerSystems]
Pages = ["HybridSystem.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/hydro_generation_cost.md
================================================
# HydroGenerationCost
```@autodocs
Modules = [PowerSystems]
Pages = ["cost_functions/HydroGenerationCost.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/hydro_reservoir.md
================================================
### `HydroReservoir`
```@autodocs
Modules = [PowerSystems]
Pages = ["HydroReservoir.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/hydro_reservoir_cost.md
================================================
### `HydroReservoirCost`
```@autodocs
Modules = [PowerSystems]
Pages = ["cost_functions/HydroReservoirCost.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/import_export_cost.md
================================================
# ImportExportCost
```@autodocs
Modules = [PowerSystems]
Pages = ["cost_functions/ImportExportCost.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/load_cost.md
================================================
# LoadCost
```@autodocs
Modules = [PowerSystems]
Pages = ["cost_functions/LoadCost.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/market_bid_cost.md
================================================
# MarketBidCost
```@autodocs
Modules = [PowerSystems]
Pages = ["cost_functions/MarketBidCost.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/offer_curve_cost.md
================================================
# OfferCurveCost
```@autodocs
Modules = [PowerSystems]
Pages = ["cost_functions/OfferCurveCost.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/outer_control.md
================================================
# OuterControl
The outer control is composed by the ReactivePowerControl and the ActivePowerControl types.
```@autodocs
Modules = [PowerSystems]
Pages = ["/OuterControl.jl"]
Order = [:type, :function]
Public = true
Private = false
```
## Active Power Controllers
### Virtual Inertia
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/VirtualInertia.jl"]
Order = [:type, :function]
Public = true
Private = false
```
### Active Power Droop
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ActivePowerDroop.jl"]
Order = [:type, :function]
Public = true
Private = false
```
### Active Power PI
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ActivePowerPI.jl"]
Order = [:type, :function]
Public = true
Private = false
```
### Active Virtual Oscillator
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ActiveVirtualOscillator.jl"]
Order = [:type, :function]
Public = true
Private = false
```
### Active Renewable Controller Type AB
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ActiveRenewableControllerAB.jl"]
Order = [:type, :function]
Public = true
Private = false
```
## Reactive Power Controllers
### Reactive Power Droop
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ReactivePowerDroop.jl"]
Order = [:type, :function]
Public = true
Private = false
```
### Reactive Power PI
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ReactivePowerPI.jl"]
Order = [:type, :function]
Public = true
Private = false
```
### Reactive Virtual Oscillator
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ReactiveVirtualOscillator.jl"]
Order = [:type, :function]
Public = true
Private = false
```
### Reactive Renewable Controller Type AB
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ReactiveRenewableControllerAB.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/renewable_generation_cost.md
================================================
# RenewableGenerationCost
```@autodocs
Modules = [PowerSystems]
Pages = ["cost_functions/RenewableGenerationCost.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/reserves.md
================================================
# Reserves
## Constant Reserve
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ConstantReserve.jl"]
Public = true
Private = false
```
## Constant Reserve Group
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ConstantReserveGroup.jl"]
Public = true
Private = false
```
## Variable Reserve
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/VariableReserve.jl"]
Public = true
Private = false
```
## Reserve Demand Curve
```@autodocs
Modules = [PowerSystems]
Pages = ["generated/ReserveDemandCurve.jl"]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/storage_cost.md
================================================
# StorageCost
```@autodocs
Modules = [PowerSystems]
Pages = ["cost_functions/StorageCost.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/model_library/thermal_generation_cost.md
================================================
# ThermalGenerationCost
```@autodocs
Modules = [PowerSystems]
Pages = ["cost_functions/ThermalGenerationCost.jl"]
Order = [:type, :function]
Public = true
Private = false
```
================================================
FILE: docs/src/tutorials/add_dynamic_data.jl
================================================
# # Adding Data for Dynamic Simulations
# In this tutorial, we are going to add dynamic data to a power [`System`](@ref), including
# a dynamic generator suitable for phasor-type simulations, as well as a dynamic inverter
# and dynamic lines necessary for more complex EMT (electro-magnetic transient)
# simulations.
# To run a dynamic simulation in Sienna\Dyn using
# [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/),
# two data layers are required:
# 1. A base layer of [static](@ref S) components, which includes the data needed to run a
# power flow problem
# 2. An additional layer of [dynamic](@ref D) components, which define differential equations
# to run a transient simulation
# We'll define these two layers sequentially.
# ## Defining the Static Data Layer
# Instead of defining the static data in the [`System`](@ref) manually, we will load an existing three-bus system using
# [`PowerSystemCaseBuilder.jl`](https://github.com/Sienna-Platform/PowerSystemCaseBuilder.jl)
# to use as a starting point.
# Start by importing these packages:
using PowerSystems
using PowerSystemCaseBuilder
import PowerSystems as PSY;
# To create the system, load pre-existing data for a 3-bus system using
# `PowerSystemCaseBuilder.jl`:
threebus_sys = build_system(PSIDSystems, "3 Bus Inverter Base")
# See that there is a table of "[Static](@ref S) Components", which contains the
# steady state data needed for power flow analysis, but no "[Dynamic](@ref D)" data
# yet to define the differential equations for transient simulations.
# Let's view the generators in the system with [`show_components`](@ref),
# including which bus they are connected at:
show_components(ThermalStandard, threebus_sys, [:bus])
# Notice that there are generators connected at Buses 2 and 3, but not Bus 1.
# Now, we are going to add the data needed to run an EMT simulation.
# We will add an infinite voltage source to Bus 1, which is the last component we
# need to complete the static data layer. Then, we will add a dynamic
# generator or inverter model to the two generators, as well as adding dynamic lines.
# ## Add an Infinite Voltage Source
# Add a infinite voltage source with small impedance to Bus 1 (the reference bus).
# First, retrieve the reference bus using [`get_components`](@ref):
slack_bus = first(get_components(x -> get_bustype(x) == ACBusTypes.REF, Bus, threebus_sys))
# Notice we filtered by the [bus type](@ref acbustypes_list) to get the bus(es) we wanted.
# Next, manually define a [`Source`](@ref):
inf_source = Source(;
name = "InfBus", #name
available = true, #availability
active_power = 0.0,
reactive_power = 0.0,
bus = slack_bus, #bus
R_th = 0.0, #Rth
X_th = 5e-6, #Xth
);
# And add it to the system:
add_component!(threebus_sys, inf_source)
# This completes the first layer of [static](@ref S) data, using components similar to those
# we added manually in the [Create and Explore a Power `System`](@ref) tutorial.
# ## Adding a Dynamic Generator
# Now, we will connect a classic machine model to the generator at bus 102.
# Dynamic generator devices
# are composed by 5 components: a [Machine](@ref Machine),
# [Shaft](@ref Shaft), [Automatic Voltage Regulator](@ref AVR) (AVR),
# [Power System Stabilizer](@ref PSS) (PSS), and
# [Prime Mover and Turbine Governor](@ref TurbineGov).
# For each of those 5 components, we will select a specific model that defines the data and
# differential equations for that component,
# and then use those 5 components to define the complete dynamic generator.
# ```@raw html
#
# ```
# !!! note
# When defining dynamic data, by convention `PowerSystems.jl` assumes that all data is
# in [`DEVICE_BASE`](@ref per_unit).
# First, define a [Machine](@ref Machine) that describes the stator electro-magnetic dynamics:
machine_oneDoneQ = OneDOneQMachine(;
R = 0.0,
Xd = 1.3125,
Xq = 1.2578,
Xd_p = 0.1813,
Xq_p = 0.25,
Td0_p = 5.89,
Tq0_p = 0.6,
)
# Notice that we selected a specific model, [`OneDOneQMachine`](@ref), with the parameters
# tailored to a One-d-one-q dynamic machine model.
# Next, define a specific [Shaft](@ref Shaft) model, [`SingleMass`](@ref) that describes the
# rotor electro-mechanical dynamics:
shaft_no_damping = SingleMass(;
H = 3.01, #(M = 6.02 -> H = M/2)
D = 0.0,
)
# Represent the electromotive dynamics of the AVR controller using a specific
# [Automatic Voltage Regulator](@ref AVR) model, [`AVRTypeI`](@ref):
avr_type1 = AVRTypeI(; # Type I: Resembles a DC1 AVR
Ka = 20.0,
Ke = 0.01,
Kf = 0.063,
Ta = 0.2,
Te = 0.314,
Tf = 0.35,
Tr = 0.001,
Va_lim = (min = -5.0, max = 5.0),
Ae = 0.0039, #1st ceiling coefficient
Be = 1.555, #2nd ceiling coefficient
)
# Define a fixed efficiency [Prime Mover and Turbine Governor](@ref TurbineGov) with
# [`TGFixed`](@ref):
tg_none = TGFixed(; efficiency = 1.0) # No Turbine Governor
# See that we are modeling a machine that does not include a Turbine Governor
# (or PSS below), but you must define components for them to build a
# complete machine model.
# Similarly, define a PSS using [`PSSFixed`](@ref), which is used to describe the stabilization
# signal for the AVR:
pss_none = PSSFixed(; V_pss = 0.0) # No PSS
# Now, we are ready to add a dynamic generator to the static
# generator at bus 102. First, let's get that static generator:
static_gen = get_component(Generator, threebus_sys, "generator-102-1")
# Notice that its `dynamic_injector` field is currently `nothing`.
# Use its name and the 5 components above to define its [`DynamicGenerator`](@ref) model:
dynamic_gen = DynamicGenerator(;
name = get_name(static_gen),
ω_ref = 1.0, # frequency reference set-point
machine = machine_oneDoneQ,
shaft = shaft_no_damping,
avr = avr_type1,
prime_mover = tg_none,
pss = pss_none,
)
# See that the specific component models that we selected and defined above were used to
# specify the states needed to model this generator in a dynamic simulation.
# Finally, use the dynamic version of [`add_component!`](@ref add_component!(
# sys::System,
# dyn_injector::DynamicInjection,
# static_injector::StaticInjection;
# kwargs...,
# )) to add this data to the [`System`](@ref):
add_component!(threebus_sys, dynamic_gen, static_gen)
# Notice that unlike static components, which are just added to the [`System`](@ref),
# this dynamic component is added to a specific static component within the [`System`](@ref).
# !!! tip
# To define identical dynamic devices for multiple generators at once, define the pieces of the
# generator model as *functions*, such as:
# ```
# avr_type1() = AVRTypeI(...
# ```
# When called in the [`DynamicGenerator`](@ref) constructor, this will create a new AVR for each generator, so
# they are different in memory. Later, if you decide to modify the AVR parameters for
# a specific generator, it will not modify the AVR in another generator.
# Recall that you can print the system to see a summary of its data:
threebus_sys
# See that a new table has been added: "Dynamic Components."
# Also, print the static generator to double-check the dynamic layer has been added:
static_gen
# Verify that `dynamic_injector` now contains our dynamic generator model.
# Up to this point, you have added the dynamic data necessary to do a phaser-type simulation,
# which focuses on machine behavior. Now we will also add dynamic inverters and lines to enable
# EMT simulations.
# ## Adding a Dynamic Inverter
# Next we will connect a Virtual Synchronous Generator Inverter at bus 103.
# An inverter is composed of [Converter](@ref), [OuterControl](@ref), [InnerControl](@ref),
# [DCSource](@ref), [FrequencyEstimator](@ref), and [Filter](@ref) components:
# ```@raw html
#
# ```
# As we did for the generator, we will define each of these six components with a specific
# model, which defines its differential equations.
# First, define an [`AverageConverter`](@ref) as the specific model for the [Converter](@ref)
# component:
converter_high_power() = AverageConverter(;
rated_voltage = 138.0,
rated_current = 100.0,
)
# Recall from the tip above that we can define these components as *functions* instead of
# objects for reusability across multiple generators, and notice that that is what we have
# done here.
# Define [OuterControl](@ref) using [Virtual Inertia](@ref) for the active power control and
# [ReactivePowerDroop](@ref) for the reactive power control:
outer_control() = OuterControl(
VirtualInertia(; Ta = 2.0, kd = 400.0, kω = 20.0),
ReactivePowerDroop(; kq = 0.2, ωf = 1000.0),
)
# Define an [InnerControl](@ref) as a Voltage+Current Controller with Virtual Impedance,
# using [`VoltageModeControl`](@ref):
inner_control() = VoltageModeControl(;
kpv = 0.59, #Voltage controller proportional gain
kiv = 736.0, #Voltage controller integral gain
kffv = 0.0, #Binary variable enabling voltage feed-forward in current controllers
rv = 0.0, #Virtual resistance in pu
lv = 0.2, #Virtual inductance in pu
kpc = 1.27, #Current controller proportional gain
kic = 14.3, #Current controller integral gain
kffi = 0.0, #Binary variable enabling the current feed-forward in output of current controllers
ωad = 50.0, #Active damping low pass filter cut-off frequency
kad = 0.2, #Active damping gain
)
# Define a [`FixedDCSource`](@ref) for the [DCSource](@ref):
dc_source_lv() = FixedDCSource(; voltage = 600.0)
# Define a [FrequencyEstimator](@ref) as a phase-locked loop (PLL) using [`KauraPLL`](@ref):
pll() = KauraPLL(;
ω_lp = 500.0, #Cut-off frequency for LowPass filter of PLL filter.
kp_pll = 0.084, #PLL proportional gain
ki_pll = 4.69, #PLL integral gain
)
# Finally, define an [`LCLFilter`](@ref) for the [Filter](@ref):
filt() = LCLFilter(;
lf = 0.08,
rf = 0.003,
cf = 0.074,
lg = 0.2,
rg = 0.01,
)
# Now, use those six functions to define a complete dynamic inverter
# by getting the static component at bus 103:
gen_103 = get_component(Generator, threebus_sys, "generator-103-1");
# using it and our six functions to define a [`DynamicInverter`](@ref):
dynamic_inv = DynamicInverter(;
name = get_name(gen_103),
ω_ref = 1.0, # frequency reference set-point
converter = converter_high_power(),
outer_control = outer_control(),
inner_control = inner_control(),
dc_source = dc_source_lv(),
freq_estimator = pll(),
filter = filt(),
)
# and adding it to the [`System`](@ref):
add_component!(threebus_sys, dynamic_inv, gen_103)
# Both generators have now been updated with dynamic data. Let's complete the [`System`](@ref)
# updates by adding dynamic lines.
# ## Adding Dynamic Lines
# !!! warning
# A [`System`](@ref) must have at least two buses and one branch to run a dynamic simulation in
# [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/).
# Let's review the AC branches currently in the system:
get_components(ACBranch, threebus_sys)
# Notice that we have three static [`Line`](@ref) components.
# Let's also print the first line to review its format:
first(get_components(Line, threebus_sys))
# See that these components do not have the fields for dynamic modeling, such as fields for
# different [states](@ref S).
# Let's update that by cycling through these lines and using [`DynamicBranch`](@ref) to extend
# each static line with the necessary fields:
for l in get_components(Line, threebus_sys)
## create a dynamic branch
dyn_branch = DynamicBranch(l)
## add dynamic branch to the system, replacing the static branch
add_component!(threebus_sys, dyn_branch)
end
# Take a look at the AC branches in the system again:
branches = get_components(ACBranch, threebus_sys)
# Notice that now there are 3 [`DynamicBranch`](@ref) components instead of the `Line` components.
# Let's take a look by printing the first one:
first(branches)
# Observe that this is a wrapper around the static data, with the additional states
# data for dynamic modeling.
# Finally, let's print the [`System`](@ref) again to summarize our additions:
threebus_sys
# Verify that the additions were successful, with an added voltage [`Source`](@ref), [`DynamicBranch`](@ref)es
# replacing the static [`Line`](@ref), and two new dynamic components with the generator and inverter models.
# ## Next Steps
# In this tutorial, you have updated a static system with a second dynamic data layer.
# The data you added can enable a phasor-based simulation using the dynamic generator, or
# a more complex EMT simulation with the additional dynamic inverter and dynamic lines.
# Next, you might like to:
# - Read more about the static and dynamic data layers and the dynamic data format in
# [Dynamic Devices](@ref).
# - Review the specific subsystem models available in `PowerSystems.jl` for [Machine](@ref),
# [Shaft](@ref), [AVR](@ref), [PSS](@ref),
# [Prime Mover and Turbine Governor](@ref TurbineGov), [Converter](@ref),
# [OuterControl](@ref), [InnerControl](@ref), [DCSource](@ref),
# [FrequencyEstimator](@ref), and [Filter](@ref) components
# - Explore [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/)
# for dynamics modeling in Sienna\Dyn
================================================
FILE: docs/src/tutorials/creating_system.jl
================================================
# # Create and Explore a Power `System`
# Welcome to PowerSystems.jl!
# In this tutorial, we will create a power system and add some components to it,
# including some nodes, a transmission line, load, and both renewable
# and fossil fuel generators. Then we will retrieve data from the system and explore the
# system settings.
# ## Setup
# To get started, ensure you have followed the
# [installation instructions](https://sienna-platform.github.io/Sienna/SiennaDocs/docs/build/how-to/install/).
# Start Julia from the command line if you haven't already:
# ```
# $ julia
# ```
# Load the PowerSystems.jl package:
using PowerSystems
# ## Creating a Power [`System`](@ref)
# In PowerSystems.jl, data is held in a [`System`](@ref) that holds all of the individual components
# along with some metadata about the power system itself.
# There are many ways to define a [`System`](@ref), but let's start with an empty system.
# All we need to define is a base power of 100 MVA for [per-unitization](@ref per_unit).
sys = System(100.0)
# Notice that this system is a 60 Hz system with a base power of 100 MVA.
# Now, let's add some components to our system.
# ## Adding Buses
# We'll start by creating some buses. By referring to the documentation for
# [ACBus](@ref), notice that we need define some basic data, including the bus's
# unique identifier and name, base voltage, and whether it's a [load, generator,
# or reference bus](@ref acbustypes_list).
# Let's start with a reference bus:
bus1 = ACBus(;
number = 1,
name = "bus1",
available = true,
bustype = ACBusTypes.REF,
angle = 0.0,
magnitude = 1.0,
voltage_limits = (min = 0.9, max = 1.05),
base_voltage = 230.0,
);
# This bus is on a 230 kV AC transmission network, with an allowable voltage range of
# 0.9 to 1.05 p.u. We are assuming it is currently operating at 1.0 p.u. voltage and
# an angle of 0 radians. Notice that we've defined this bus as [reference bus or slack
# bus](@ref acbustypes_list), where it will be used for balancing power flow in power
# flow studies.
# Let's add this bus to our [`System`](@ref) with [`add_component!`](@ref add_component!(sys::System, component::Component; kwargs...)):
add_component!(sys, bus1)
# We can see the impact this has on the [`System`](@ref) simply by printing it:
sys
# Notice that [`System`](@ref) now shows a summary of components in the system. The table shows
# "[Static](@ref S) Components", which refers to steady state data used for power
# flow analysis or production cost modeling, as opposed to [Dynamic](@ref D) components
# which that can be used to define differential equations for transient simulations.
# Let's create a second bus:
bus2 = ACBus(;
number = 2,
name = "bus2",
available = true,
bustype = ACBusTypes.PV,
angle = 0.0,
magnitude = 1.0,
voltage_limits = (min = 0.9, max = 1.05),
base_voltage = 230.0,
);
# Notice that we've defined this bus with [power and voltage variables](@ref acbustypes_list),
# suitable for power flow studies.
# Let's also add this to our [`System`](@ref):
add_component!(sys, bus2)
# Now, let's use [`show_components`](@ref) to quickly see some basic information about the buses:
show_components(sys, ACBus)
# ## Adding a Transmission Line
# Let's connect our buses. We'll add a transmission [`Line`](@ref) between `bus1` and `bus2`.
# !!! warning
# When defining a line that isn't attached to a [`System`](@ref) yet, you must define the
# thermal rating of the transmission line in per-unit using the base power of the
# [`System`](@ref) you plan to connect it to -- in this case, 100 MVA.
line = Line(;
name = "line1",
available = true,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
arc = Arc(; from = bus1, to = bus2),
r = 0.00281, # Per-unit
x = 0.0281, # Per-unit
b = (from = 0.00356, to = 0.00356), # Per-unit
rating = 2.0, # Line rating of 200 MVA / System base of 100 MVA
angle_limits = (min = -0.7, max = 0.7),
);
# Note that we also had to define an [`Arc`](@ref) in the process to define the connection between
# the two buses.
# Let's also add this to our [`System`](@ref):
add_component!(sys, line)
# Finally, let's check our [`System`](@ref) summary to see all the network topology components we have added
# are attached:
sys
# ## Adding Loads and Generators
# Now that our network topology is complete, we'll start adding components that [inject](@ref I) or
# withdraw power from the network.
# !!! warning
# When you define components that aren't attached to a [`System`](@ref) yet, you must define
# all fields related to power (with units such as MW, MVA, MVAR, or MW/min) in
# per-unit using the `base_power` of the component (with the exception of `base_power`
# itself, which is in MVA).
# We'll start with defining a 10 MW [load](@ref PowerLoad) to `bus2`:
load = PowerLoad(;
name = "load1",
available = true,
bus = bus2,
active_power = 0.5, # Per-unitized by device base_power
reactive_power = 0.0, # Per-unitized by device base_power
base_power = 10.0, # MVA
max_active_power = 1.0, # 10 MW per-unitized by device base_power
max_reactive_power = 0.0,
);
# Notice that we defined the `max_active_power`, which is 10 MW, as 1.0 in per-unit using the
# `base_power` of 10 MVA. We've also used the `bus2` component itself to define where this
# load is located in the network.
# Now add the load to the system:
add_component!(sys, load)
# Finally, we'll add two generators: one renewable and one thermal.
# We'll add a 5 MW solar power plant to `bus2`:
solar = RenewableDispatch(;
name = "solar1",
available = true,
bus = bus2,
active_power = 0.2, # Per-unitized by device base_power
reactive_power = 0.0, # Per-unitized by device base_power
rating = 1.0, # 5 MW per-unitized by device base_power
prime_mover_type = PrimeMovers.PVe,
reactive_power_limits = (min = 0.0, max = 0.05), # 0 MVAR to 0.25 MVAR per-unitized by device base_power
power_factor = 1.0,
operation_cost = RenewableGenerationCost(nothing),
base_power = 5.0, # MVA
);
# Note that we've used a generic [renewable generator](@ref RenewableDispatch) to model
# solar, but we can specify that it is solar through the [prime mover](@ref pm_list).
# Finally, we'll also add a 30 MW gas [thermal generator](@ref ThermalStandard) to `bus1`
# because a slack bus require a controllable generator component:
gas = ThermalStandard(;
name = "gas1",
available = true,
status = true,
bus = bus1,
active_power = 0.0, # Per-unitized by device base_power
reactive_power = 0.0, # Per-unitized by device base_power
rating = 1.0, # 30 MW per-unitized by device base_power
active_power_limits = (min = 0.2, max = 1.0), # 6 MW to 30 MW per-unitized by device base_power
reactive_power_limits = nothing, # Per-unitized by device base_power
ramp_limits = (up = 0.2, down = 0.2), # 6 MW/min up or down, per-unitized by device base_power
operation_cost = ThermalGenerationCost(nothing),
base_power = 30.0, # MVA
time_limits = (up = 8.0, down = 8.0), # Hours
must_run = false,
prime_mover_type = PrimeMovers.CC,
fuel = ThermalFuels.NATURAL_GAS,
);
# This time, let's add these components to our [`System`](@ref) using [`add_components!`](@ref)
# to add them both at the same time:
add_components!(sys, [solar, gas])
# ## Explore the System and its Components
# Congratulations! You have built a power system including buses, a transmission line, a
# load, and different types of generators. Now let's take a look around.
# Remember that we can see a summary of our [`System`](@ref) using the print statement:
sys
# Now, let's double-check some of our data by retrieving it from the [`System`](@ref).
# Let's use [`show_components`](@ref) again to get an overview of our renewable generators:
show_components(sys, RenewableDispatch)
# We just have the one renewable generator named `solar1`. Use `get_component` to
# retrieve it by name:
retrieved_component = get_component(RenewableDispatch, sys, "solar1");
# Let's double-check what type of renewable generator this is using a `get_` function:
get_prime_mover_type(retrieved_component)
# Verify that this a `PVe`, or solar photovoltaic, generator.
# Let's also use a `get_` function to double-check where this generator is connected in the
# transmission network:
get_bus(retrieved_component)
# See that the generator's bus is linked to the actual `bus2` component in our [`System`](@ref).
# These "getter" functions are available for all the data fields in a component.
# !!! tip
# **Always use the `get_*` functions to retrieve the data within a component.**
# While in Julia a user can use `.` to access the fields of a component, we make no
# guarantees on the stability of field names and locations. We do however promise to
# keep the getter functions stable. PowerSystems.jl also does many internal data
# calculations that the getter functions will properly handle for you, as you'll see
# below.
# ## Changing [`System`](@ref) Per-Unit Settings
# Now, let's use a getter function to look up the solar generator's `rating`:
get_rating(retrieved_component)
# !!! tip "Important"
# When we defined the solar generator, we defined the rating
# as 1.0 per-unit with a device `base_power` of 5.0 MVA. Notice that the rating now reads
# 0.05. After we attached this component to our [`System`](@ref), its power data is being
# returned to us in the [`System`](@ref)'s units base.
# Let's double-check the [`System`](@ref)'s units base:
get_units_base(sys)
# `SYSTEM_BASE` means all power-related (MW, MVA, MVAR, MW/min) component data in
# the [`System`](@ref), except for each component's `base_power`, is per-unitized by the
# system base power for consistency.
# Check the [`System`](@ref)'s base_power again:
get_base_power(sys)
# Notice that when we called `get_rating` above, the solar generator's rating, 5.0 MW,
# is being returned as 0.05 = (5 MVA)/(100 MVA) using the system base power.
# Instead of using the [`System`](@ref) base power, let's view everything in MW or MVA -- or what we
# call "NATURAL_UNITS" in PowerSystems.
# Change the [`System`](@ref)'s unit system:
set_units_base_system!(sys, "NATURAL_UNITS")
# Now retrieve the solar generator's rating again:
get_rating(retrieved_component)
# Notice that the value is now its "natural" value, 5.0 MVA.
# Finally, let's change the [`System`](@ref)'s unit system to the final option, "DEVICE_BASE":
set_units_base_system!(sys, "DEVICE_BASE")
# And retrieve the solar generator's rating once more:
get_rating(retrieved_component)
# See that now the data is now 1.0 (5.0 MVA per-unitized by the generator (i.e., the device's)
# `base_power` of 5.0 MVA), which is the format we used to originally define the device.
# As a shortcut to temporarily set the [`System`](@ref)'s unit system to a particular value, perform
# some action, and then automatically set it back to what it was before, we can use
# `with_units_base` and a [`do` block](https://docs.julialang.org/en/v1/manual/functions/#Do-Block-Syntax-for-Function-Arguments):
with_units_base(sys, "NATURAL_UNITS") do
## Everything inside this block will run as if the unit system were NATURAL_UNITS
get_rating(retrieved_component)
end
get_units_base(sys) # Unit system goes back to previous value when the block ends
# Recall that if you ever need to check a [`System`](@ref)'s settings, including the unit system being
# used by all the getter functions, you can always just print the [`System`](@ref):
sys
# See the units base is printed as one of the [`System`](@ref) properties.
# ## Next Steps
# In this tutorial, you manually created a power [`System`](@ref), added and then retrieved its components,
# and modified the [`System`](@ref) per-unit settings.
# Next, you might want to:
# - [Add time series data to components in the `System`](@ref tutorial_time_series)
# - [Add necessary data for dynamic simulations](@ref "Adding Data for Dynamic Simulations")
# - Import a [`System`](@ref) [from an existing Matpower or PSSE file](@ref pm_data) or
# [with PSSE dynamic data](@ref dyr_data) instead of creating it manually
# - [Create your own `System` from .csv files instead of creating it manually](@ref system_from_csv)
# - [Read more to understand per-unitization in PowerSystems.jl](@ref per_unit)
# - See a workaround for how to [Add a Component in Natural Units](@ref)
================================================
FILE: docs/src/tutorials/manipulating_datasets.jl
================================================
# # Manipulating Datasets
# `PowerSystems` provides function interfaces to all data, and in this tutorial we will explore how to do this using the [`show_components`](@ref),
# [`get_component`](@ref get_component(::Type{T}, sys::System, name::AbstractString) where {T <: Component})/
# [`get_components`](@ref), and getter (`get_*`) and setter (`set_*`) functions for component fields.
# ## Viewing Components in the System
# We are going to begin by loading in a test case [`System`](@ref) from [`PowerSystemCaseBuilder.jl`](https://sienna-platform.github.io/PowerSystemCaseBuilder.jl/stable/):
using PowerSystems;
using PowerSystemCaseBuilder;
sys = build_system(PSISystems, "c_sys5_pjm")
# Notice that the print statement for the [`System`](@ref) already includes a basic
# summary of the components, including 5 [`ThermalStandard`](@ref) components.
# We can use the [`show_components`](@ref) function to get more details:
show_components(ThermalStandard, sys)
# We can see the names and availability are the standard fields returned when using [`show_components`](@ref).
# We can also view specific fields within components using the [`show_components`](@ref)
# function. For example, we can view the type of `fuel` the thermal generators are using,
# and their current `active_power` and `reactive_power` for a power flow case:
show_components(ThermalStandard, sys, [:fuel, :active_power, :reactive_power])
# Notice all our thermal generators are currently fueled by coal.
# ## Accessing and Updating a Component in a System
# We can access a component in our system using the
# [`get_component`](@ref get_component(::Type{T}, sys::System, name::AbstractString) where {T <: Component})
# function. For example, if we are interested in accessing a [`ThermalStandard`](@ref) component we can
# do so using the component's name and `Type` from `PowerSystems.jl`'s [Type Tree](@ref).
# From above we know the names of the thermal generators.
solitude = get_component(ThermalStandard, sys, "Solitude")
# Notice that all of Solitude's fields are pretty-printed with the return statement for
# quick reference. However, what is returned is a [`ThermalStandard`](@ref) object we can
# manipulate:
typeof(solitude)
# If we are interested in accessing a particular field, we can use a `get_*` function, also known as a getter,
# on this object. For example, if we are interested in the `fuel` we can use [`get_fuel`](@ref get_fuel(value::ThermalStandard)):
get_fuel(solitude)
# You can see a [`ThermalFuels`](@ref tf_list) option returned.
# To recap, [`get_component`](@ref) will return a component object, but we can use a specific `get_*` function to return the data in a particular field.
# !!! warning
# Using the "dot" access to get a field value from a component is actively discouraged, use `get_*` functions instead.
# Julia syntax enables access to this data using the "dot" access (e.g., `solitude.fuel`), however this is discouraged for two reasons:
# 1. We make no guarantees on the stability of component structure definitions. We will maintain version stability on the accessor methods.
# 2. Per-unit conversions are made in the return of data from the accessor functions. (see the [per-unit](https://sienna-platform.github.io/PowerSystems.jl/stable/explanation/per_unit/#per_unit) section for more details)
# To update a field we can use a specific `set_*`, or setter function, which are defined for each component field.
# We can use [`set_fuel!`](@ref set_fuel!(value::ThermalStandard, val)) to update the `fuel` field of Solitude to natural gas.
set_fuel!(solitude, ThermalFuels.NATURAL_GAS)
# We can use [`show_components`](@ref) again to check that the `Solitude` `fuel` has been
# updated to [`ThermalFuels.NATURAL_GAS`](@ref tf_list):
show_components(ThermalStandard, sys, [:fuel])
# Similarly, you can updated the `active_power` field using its specific `get_*` and `set_*` functions.
# We can access this field by using [`get_active_power`](@ref get_active_power(value::ThermalStandard)):
get_active_power(solitude)
# We can then update it using [`set_active_power!`](@ref set_active_power!(value::ThermalStandard, val)):
set_active_power!(solitude, 4.0)
# We can see that our `active_power` field has been updated to 4.0.
# ## Accessing and Updating Multiple Components in the System at Once
# We can also update more than one component at a time using the [`get_components`](@ref get_components(
# ::Type{T},
# sys::System;
# subsystem_name = nothing,
# ) where {T <: Component}) and `set_*` functions.
# Let's say we were interested in updating the `base_voltage` field for all of the [`ACBus`](@ref).
# We can see that currently the `base_voltages` are:
show_components(ACBus, sys, [:base_voltage])
# But what if we are looking to correct them to 250.0 kV?
# Let's start by getting an iterator for all the buses using [`get_components`](@ref get_components(
# ::Type{T},
# sys::System;
# subsystem_name = nothing,
# ) where {T <: Component}):
buses = get_components(ACBus, sys)
# See that the pretty-print summarizes this set of components, but let's check what was actually returned:
typeof(buses)
# !!! tip
# Notice that [`get_components`](@ref get_components(
# ::Type{T},
# sys::System;
# subsystem_name = nothing,
# ) where {T <: Component}) and similar functions return Julia iterators, which allows you to
# access and manipulate data without a large memory allocation that might occur for very
# large data sets.
# Use [`collect`](https://docs.julialang.org/en/v1/base/collections/#Base.collect-Tuple%7BAny%7D)
# to gather the data to a vector instead, but be aware of your dataset size.
# Now using the [`set_base_voltage!`](@ref) function and a `for` loop we can update the voltage:
for i in buses
set_base_voltage!(i, 250.0)
end
# We could use [`show_components`](@ref) to verify the results, but this time let's use a
# `get_*` function and Julia's dot notation over our bus iterator to get the data for
# a specific field from multiple components:
get_base_voltage.(buses)
# We can see that all of the buses now have a `base_voltage` of 250.0 kV.
# If we are interested in updating the `fuel` in all the thermal generators, we would use a similar approach. We begin by grabbing an iterator for all the components in [`ThermalStandard`](@ref).
thermal_gens = get_components(ThermalStandard, sys)
# Now, using the [`set_fuel!`](@ref set_fuel!(value::ThermalStandard)) and a `for` loop, we will update the `fuel` to `NATURAL_GAS`.
for i in thermal_gens
set_fuel!(i, ThermalFuels.NATURAL_GAS)
end
# We can verify that the `fuel` types for all the thermal generators has been updated,
# using dot notation again to access the `fuel` fields:
get_fuel.(get_components(ThermalStandard, sys))
# See that we linked two functions here with Julia's dot notation -- this is a very convenient way of quickly getting the data you need.
# ## Filtering Specific Data
# We have seen how to update a single component, and all the components of a specific type, but what if we are interested in updating only particular components? We can do this using filter functions.
# For example, let's say we are interested in updating all the `active_power` values of the thermal generators except `Solitude`.
# Let's start by seeing the current `active_power` values.
show_components(ThermalStandard, sys, [:active_power])
# Let's grab an iterator for the all the thermal generators except `Solitude` by adding a filter function
# in another version of the [`get_components`](@ref get_components(
# filter_func::Function,
# ::Type{T},
# sys::System;
# subsystem_name = nothing,
# ) where {T <: Component}) function defined with Julia's multiple dispatch:
thermal_not_solitude = get_components(x -> get_name(x) != "Solitude", ThermalStandard, sys)
# We can see that only four [`ThermalStandard`](@ref) components are returned, as expected.
# Now let's update the `active_power` field of these four thermal generators using the [`set_active_power!`](@ref) function.
for i in thermal_not_solitude
set_active_power!(i, 0.0)
end
# Let's check the update using [`show_components`](@ref):
show_components(ThermalStandard, sys, [:active_power])
# We can see that all the `active_power` values are 0.0, except `Solitude`.
# We can filter on any component field. Similarly, let's filter all of the thermal generators
# that now have an `active_power` of 0.0, and also set their availability to false.
for i in get_components(x -> get_active_power(x) == 0.0, ThermalStandard, sys)
set_available!(i, 0)
end
# ## Getting Available Components
# The [`get_available_components`](@ref) function is a useful short-hand function with a
# built-in filter for grabbing all the components of a particular type that are available.
# For example, if we are interested in grabbing all the available [`ThermalStandard`](@ref):
get_available_components(ThermalStandard, sys)
# We only retrieved one component, because we just set the rest to unavailable above:
show_components(ThermalStandard, sys)
# ## Getting Buses
# We can retrieve the [`ACBus`](@ref) components using
# [`get_buses`](@ref get_buses(sys::System, bus_numbers::Set{Int})),
# by [ID number](@ref get_buses(sys::System, bus_numbers::Set{Int})) or
# [`Area` or `LoadZone`](@ref get_buses(sys::System, aggregator::AggregationTopology)).
# Let's begin by accessing the ID numbers associated with the [`ACBus`](@ref)
# components using the [`get_bus_numbers`](@ref) function.
get_bus_numbers(sys)
# We can see that these bus IDs are numbered 1 through 5.
# Now let's specifically grab buses 2 and 3 using the [`get_buses`](@ref) function:
high_voltage_buses = get_buses(sys, Set(2:3))
# and update their base voltage to 330 kV:
for i in high_voltage_buses
set_base_voltage!(i, 330.0)
end
# As usual, we can review the updated data with [`show_components`](@ref):
show_components(ACBus, sys, [:number, :base_voltage])
# ## Updating Component Names
# We can also access and update the component name field using the
# [`get_name`](@ref get_name(value::ThermalStandard)) and
# [set_name!](@ref set_name!(value::ThermalStandard, name::AbstractString)) functions.
# Recall that we created an iterator called `thermal_gens` for all the thermal generators.
# We can use the [`get_name`](@ref get_name(value::ThermalStandard)) function to access
# the `name` field for these components with dot notation:
get_name.(thermal_gens)
# To update the names we will use the
# [set_name!](@ref set_name!(value::ThermalStandard, name::AbstractString)) function.
# !!! warning
# Specifically when using [set_name!](@ref set_name!(value::ThermalStandard, name::AbstractString))
# to modify multiple components accessed through an iterator, it is important to note that this
# not only changes the field `name`, but also changes the iterator itself
# as you are iterating over it, which will result in unexpected outcomes and errors.
# Therefore, rather than using [set_name!](@ref set_name!(value::ThermalStandard, name::AbstractString))
# on an iterator, only use it after first
# calling [`collect`](https://docs.julialang.org/en/v1/base/collections/#Base.collect-Tuple%7BAny%7D)
# on the iterator to get a vector of the components:
for thermal_gen in collect(get_components(ThermalStandard, sys))
set_name!(sys, thermal_gen, get_name(thermal_gen) * "-renamed")
end
# Now we can check the names using the [`get_name`](@ref) function again.
get_name.(get_components(ThermalStandard, sys))
# Be aware again that accessing components through a vector using
# [`collect`](https://docs.julialang.org/en/v1/base/collections/#Base.collect-Tuple%7BAny%7D)
# might cause large memory allocations, based on your dataset size.
# ## Next Steps & Links
# In this tutorial, we explored a dataset using [`show_components`](@ref) to summarize data
# and accessed particular groups of components with [`get_components`](@ref get_components(
# ::Type{T},
# sys::System;
# subsystem_name = nothing,
# ) where {T <: Component}), [`get_buses`](@ref get_buses(sys::System, bus_numbers::Set{Int})),
# and [`get_available_components`](@ref).
# We used specific `get_*` functions and `set_*` functions to see and update the fields in
# [`ThermalStandard`](@ref) and [`ACBus`](@ref) components, but remember that these getters
# and setters are available for each data field for components of all Types in `PowerSystems.jl`.
# Follow the next tutorials to learn how to [work with time series](@ref tutorial_time_series).
================================================
FILE: docs/src/tutorials/tutorials_data/RTS-GMLC.RAW
================================================
0, 100.00, 33, 0, 0, 60.00 / November 07, 2017 19:41:38; Simulator Version 19; BuildDate 2017_9_5
101,'ABEL ', 138.0000,2, 1, 11, 1,1.04777002, -7.741520, 1.10000, 0.90000, 1.10000, 0.90000
102,'ADAMS ', 138.0000,2, 1, 12, 1,1.04782999, -7.817840, 1.10000, 0.90000, 1.10000, 0.90000
103,'ADLER ', 138.0000,2, 1, 11, 1,1.01084995, -7.210900, 1.10000, 0.90000, 1.10000, 0.90000
104,'AGRICOLA ', 138.0000,2, 1, 11, 1,1.01765001, -10.566140, 1.10000, 0.90000, 1.10000, 0.90000
105,'AIKEN ', 138.0000,1, 1, 11, 1,1.03568006, -10.708870, 1.10000, 0.90000, 1.10000, 0.90000
106,'ALBER ', 138.0000,1, 1, 12, 1,1.03242004, -13.279440, 1.10000, 0.90000, 1.10000, 0.90000
107,'ALDER ', 138.0000,2, 1, 12, 1,1.03744996, -11.276730, 1.10000, 0.90000, 1.10000, 0.90000
108,'ALGER ', 138.0000,1, 1, 12, 1,1.01023996, -13.749670, 1.10000, 0.90000, 1.10000, 0.90000
109,'ALI ', 138.0000,1, 1, 13, 1,1.02610004, -8.815240, 1.10000, 0.90000, 1.10000, 0.90000
110,'ALLEN ', 138.0000,1, 1, 13, 1,1.04999995, -10.620630, 1.10000, 0.90000, 1.10000, 0.90000
111,'ANNA ', 230.0000,1, 1, 13, 1,1.02763999, -3.916740, 1.10000, 0.90000, 1.10000, 0.90000
112,'ARCHER ', 230.0000,1, 1, 13, 1,1.02023995, -2.424240, 1.10000, 0.90000, 1.10000, 0.90000
113,'ARNE ', 230.0000,3, 1, 14, 1,1.03470004, 0.000000, 1.10000, 0.90000, 1.10000, 0.90000
114,'ARNOLD ', 230.0000,2, 1, 16, 1,1.04401004, -1.730560, 1.10000, 0.90000, 1.10000, 0.90000
115,'ARTHUR ', 230.0000,2, 1, 16, 1,1.04334998, 7.959700, 1.10000, 0.90000, 1.10000, 0.90000
116,'ASSER ', 230.0000,2, 1, 16, 1,1.04565001, 7.569290, 1.10000, 0.90000, 1.10000, 0.90000
117,'ASTON ', 230.0000,1, 1, 17, 1,1.04782999, 11.434170, 1.10000, 0.90000, 1.10000, 0.90000
118,'ASTOR ', 230.0000,2, 1, 17, 1,1.04999995, 12.524570, 1.10000, 0.90000, 1.10000, 0.90000
119,'ATTAR ', 230.0000,2, 1, 15, 1,1.03962004, 6.657770, 1.10000, 0.90000, 1.10000, 0.90000
120,'ATTILA ', 230.0000,1, 1, 15, 1,1.04399002, 7.740600, 1.10000, 0.90000, 1.10000, 0.90000
121,'ATTLEE ', 230.0000,2, 1, 17, 1,1.04999995, 13.086530, 1.10000, 0.90000, 1.10000, 0.90000
122,'AUBREY ', 230.0000,2, 1, 17, 1,1.04999995, 18.949779, 1.10000, 0.90000, 1.10000, 0.90000
123,'AUSTEN ', 230.0000,2, 1, 15, 1,1.04999995, 9.056170, 1.10000, 0.90000, 1.10000, 0.90000
124,'AVERY ', 230.0000,1, 1, 16, 1,1.01154995, 2.383390, 1.10000, 0.90000, 1.10000, 0.90000
201,'BACH ', 138.0000,2, 2, 21, 1,1.04841006, -10.689730, 1.10000, 0.90000, 1.10000, 0.90000
202,'BACON ', 138.0000,2, 2, 22, 1,1.04843998, -10.759060, 1.10000, 0.90000, 1.10000, 0.90000
203,'BAFFIN ', 138.0000,1, 2, 21, 1,1.01885998, -10.474530, 1.10000, 0.90000, 1.10000, 0.90000
204,'BAILEY ', 138.0000,1, 2, 21, 1,1.01890004, -13.484790, 1.10000, 0.90000, 1.10000, 0.90000
205,'BAIN ', 138.0000,1, 2, 21, 1,1.03603005, -13.611870, 1.10000, 0.90000, 1.10000, 0.90000
206,'BAJER ', 138.0000,1, 2, 22, 1,1.03259003, -16.156720, 1.10000, 0.90000, 1.10000, 0.90000
207,'BAKER ', 138.0000,2, 2, 22, 1,1.03972995, -13.466060, 1.10000, 0.90000, 1.10000, 0.90000
208,'BALCH ', 138.0000,1, 2, 22, 1,1.01203001, -16.223590, 1.10000, 0.90000, 1.10000, 0.90000
209,'BALZAC ', 138.0000,1, 2, 23, 1,1.02780998, -11.724090, 1.10000, 0.90000, 1.10000, 0.90000
210,'BANKS ', 138.0000,1, 2, 23, 1,1.04999995, -13.479860, 1.10000, 0.90000, 1.10000, 0.90000
211,'BARDEEN ', 230.0000,1, 2, 23, 1,1.02734995, -6.933360, 1.10000, 0.90000, 1.10000, 0.90000
212,'BARKLA ', 230.0000,2, 2, 23, 1,1.01920998, -5.253340, 1.10000, 0.90000, 1.10000, 0.90000
213,'BARLOW ', 230.0000,2, 2, 24, 1,1.03752005, -3.215100, 1.10000, 0.90000, 1.10000, 0.90000
214,'BARRY ', 230.0000,2, 2, 26, 1,1.04334998, -4.685190, 1.10000, 0.90000, 1.10000, 0.90000
215,'BARTON ', 230.0000,2, 2, 26, 1,1.04326999, 4.633510, 1.10000, 0.90000, 1.10000, 0.90000
216,'BASOV ', 230.0000,2, 2, 26, 1,1.04556000, 4.700090, 1.10000, 0.90000, 1.10000, 0.90000
217,'BATES ', 230.0000,1, 2, 27, 1,1.04847002, 8.818390, 1.10000, 0.90000, 1.10000, 0.90000
218,'BAYLE ', 230.0000,2, 2, 27, 1,1.04999995, 9.994730, 1.10000, 0.90000, 1.10000, 0.90000
219,'BEDE ', 230.0000,1, 2, 25, 1,1.03945994, 4.212330, 1.10000, 0.90000, 1.10000, 0.90000
220,'BEETHOVEN ', 230.0000,1, 2, 25, 1,1.04380000, 5.664490, 1.10000, 0.90000, 1.10000, 0.90000
221,'BEHRING ', 230.0000,2, 2, 27, 1,1.04999995, 10.632090, 1.10000, 0.90000, 1.10000, 0.90000
222,'BELL ', 230.0000,2, 2, 27, 1,1.04999995, 16.432030, 1.10000, 0.90000, 1.10000, 0.90000
223,'BLOCH ', 230.0000,2, 2, 25, 1,1.04999995, 7.181510, 1.10000, 0.90000, 1.10000, 0.90000
224,'BORDET ', 230.0000,1, 2, 26, 1,1.01455998, -0.960050, 1.10000, 0.90000, 1.10000, 0.90000
301,'CABELL ', 138.0000,2, 3, 31, 1,1.04859996, -9.348210, 1.10000, 0.90000, 1.10000, 0.90000
302,'CABOT ', 138.0000,2, 3, 32, 1,1.04864001, -9.431000, 1.10000, 0.90000, 1.10000, 0.90000
303,'CAESAR ', 138.0000,2, 3, 31, 1,1.01045001, -8.576890, 1.10000, 0.90000, 1.10000, 0.90000
304,'CAINE ', 138.0000,1, 3, 31, 1,1.01785004, -12.187840, 1.10000, 0.90000, 1.10000, 0.90000
305,'CALVIN ', 138.0000,1, 3, 31, 1,1.03609002, -12.350050, 1.10000, 0.90000, 1.10000, 0.90000
306,'CAMUS ', 138.0000,1, 3, 32, 1,1.03260005, -14.942050, 1.10000, 0.90000, 1.10000, 0.90000
307,'CAREW ', 138.0000,2, 3, 32, 1,1.03804004, -12.547950, 1.10000, 0.90000, 1.10000, 0.90000
308,'CARREL ', 138.0000,2, 3, 32, 1,1.01056004, -15.182870, 1.10000, 0.90000, 1.10000, 0.90000
309,'CARTER ', 138.0000,2, 3, 33, 1,1.02578998, -10.446170, 1.10000, 0.90000, 1.10000, 0.90000
310,'CARUSO ', 138.0000,2, 3, 33, 1,1.04999995, -12.301170, 1.10000, 0.90000, 1.10000, 0.90000
311,'CARY ', 230.0000,1, 3, 33, 1,1.02830005, -5.740690, 1.10000, 0.90000, 1.10000, 0.90000
312,'CAXTON ', 230.0000,2, 3, 33, 1,1.01900005, -4.146040, 1.10000, 0.90000, 1.10000, 0.90000
313,'CECIL ', 230.0000,2, 3, 34, 1,1.03802001, -2.415130, 1.10000, 0.90000, 1.10000, 0.90000
314,'CHAIN ', 230.0000,2, 3, 36, 1,1.04630995, -3.207930, 1.10000, 0.90000, 1.10000, 0.90000
315,'CHASE ', 230.0000,2, 3, 36, 1,1.04299998, 7.050880, 1.10000, 0.90000, 1.10000, 0.90000
316,'CHIFA ', 230.0000,2, 3, 36, 1,1.04558003, 6.598750, 1.10000, 0.90000, 1.10000, 0.90000
317,'CHUHSI ', 230.0000,2, 3, 37, 1,1.04785001, 10.344180, 1.10000, 0.90000, 1.10000, 0.90000
318,'CLARK ', 230.0000,2, 3, 37, 1,1.04999995, 11.342620, 1.10000, 0.90000, 1.10000, 0.90000
319,'CLAY ', 230.0000,2, 3, 35, 1,1.03953004, 5.915390, 1.10000, 0.90000, 1.10000, 0.90000
320,'CLIVE ', 230.0000,2, 3, 35, 1,1.04389000, 7.197090, 1.10000, 0.90000, 1.10000, 0.90000
321,'COBB ', 230.0000,2, 3, 37, 1,1.04999995, 12.341220, 1.10000, 0.90000, 1.10000, 0.90000
322,'COLE ', 230.0000,2, 3, 37, 1,1.04999995, 18.069141, 1.10000, 0.90000, 1.10000, 0.90000
323,'COMTE ', 230.0000,2, 3, 35, 1,1.04999995, 8.621120, 1.10000, 0.90000, 1.10000, 0.90000
324,'CURIE ', 230.0000,2, 3, 36, 1,1.01046002, 1.306060, 1.10000, 0.90000, 1.10000, 0.90000
325,'CURTISS ', 230.0000,1, 3, 35, 1,1.04986000, 8.993320, 1.10000, 0.90000, 1.10000, 0.90000
0 / END OF BUS DATA, BEGIN LOAD DATA
101,'1 ',1, 1, 1, 108.000, 22.000, 0.000, 0.000, 0.000, 0.000, 1,1
102,'1 ',1, 1, 1, 97.000, 20.000, 0.000, 0.000, 0.000, 0.000, 1,1
103,'1 ',1, 1, 1, 180.000, 37.000, 0.000, 0.000, 0.000, 0.000, 1,1
104,'1 ',1, 1, 1, 74.000, 15.000, 0.000, 0.000, 0.000, 0.000, 1,1
105,'1 ',1, 1, 1, 71.000, 14.000, 0.000, 0.000, 0.000, 0.000, 1,1
106,'1 ',1, 1, 1, 136.000, 28.000, 0.000, 0.000, 0.000, 0.000, 1,1
107,'1 ',1, 1, 1, 125.000, 25.000, 0.000, 0.000, 0.000, 0.000, 1,1
108,'1 ',1, 1, 1, 171.000, 35.000, 0.000, 0.000, 0.000, 0.000, 1,1
109,'1 ',1, 1, 1, 175.000, 36.000, 0.000, 0.000, 0.000, 0.000, 1,1
110,'1 ',1, 1, 1, 195.000, 40.000, 0.000, 0.000, 0.000, 0.000, 1,1
113,'1 ',1, 1, 1, 265.000, 54.000, 0.000, 0.000, 0.000, 0.000, 1,1
114,'1 ',1, 1, 1, 194.000, 39.000, 0.000, 0.000, 0.000, 0.000, 1,1
115,'1 ',1, 1, 1, 317.000, 64.000, 0.000, 0.000, 0.000, 0.000, 1,1
116,'1 ',1, 1, 1, 100.000, 20.000, 0.000, 0.000, 0.000, 0.000, 1,1
118,'1 ',1, 1, 1, 333.000, 68.000, 0.000, 0.000, 0.000, 0.000, 1,1
119,'1 ',1, 1, 1, 181.000, 37.000, 0.000, 0.000, 0.000, 0.000, 1,1
120,'1 ',1, 1, 1, 128.000, 26.000, 0.000, 0.000, 0.000, 0.000, 1,1
201,'1 ',1, 2, 1, 108.000, 22.000, 0.000, 0.000, 0.000, 0.000, 1,1
202,'1 ',1, 2, 1, 97.000, 20.000, 0.000, 0.000, 0.000, 0.000, 1,1
203,'1 ',1, 2, 1, 180.000, 37.000, 0.000, 0.000, 0.000, 0.000, 1,1
204,'1 ',1, 2, 1, 74.000, 15.000, 0.000, 0.000, 0.000, 0.000, 1,1
205,'1 ',1, 2, 1, 71.000, 14.000, 0.000, 0.000, 0.000, 0.000, 1,1
206,'1 ',1, 2, 1, 136.000, 28.000, 0.000, 0.000, 0.000, 0.000, 1,1
207,'1 ',1, 2, 1, 125.000, 25.000, 0.000, 0.000, 0.000, 0.000, 1,1
208,'1 ',1, 2, 1, 171.000, 35.000, 0.000, 0.000, 0.000, 0.000, 1,1
209,'1 ',1, 2, 1, 175.000, 36.000, 0.000, 0.000, 0.000, 0.000, 1,1
210,'1 ',1, 2, 1, 195.000, 40.000, 0.000, 0.000, 0.000, 0.000, 1,1
213,'1 ',1, 2, 1, 265.000, 54.000, 0.000, 0.000, 0.000, 0.000, 1,1
214,'1 ',1, 2, 1, 194.000, 39.000, 0.000, 0.000, 0.000, 0.000, 1,1
215,'1 ',1, 2, 1, 317.000, 64.000, 0.000, 0.000, 0.000, 0.000, 1,1
216,'1 ',1, 2, 1, 100.000, 20.000, 0.000, 0.000, 0.000, 0.000, 1,1
218,'1 ',1, 2, 1, 333.000, 68.000, 0.000, 0.000, 0.000, 0.000, 1,1
219,'1 ',1, 2, 1, 181.000, 37.000, 0.000, 0.000, 0.000, 0.000, 1,1
220,'1 ',1, 2, 1, 128.000, 26.000, 0.000, 0.000, 0.000, 0.000, 1,1
301,'1 ',1, 3, 1, 108.000, 22.000, 0.000, 0.000, 0.000, 0.000, 1,1
302,'1 ',1, 3, 1, 97.000, 20.000, 0.000, 0.000, 0.000, 0.000, 1,1
303,'1 ',1, 3, 1, 180.000, 37.000, 0.000, 0.000, 0.000, 0.000, 1,1
304,'1 ',1, 3, 1, 74.000, 15.000, 0.000, 0.000, 0.000, 0.000, 1,1
305,'1 ',1, 3, 1, 71.000, 14.000, 0.000, 0.000, 0.000, 0.000, 1,1
306,'1 ',1, 3, 1, 136.000, 28.000, 0.000, 0.000, 0.000, 0.000, 1,1
307,'1 ',1, 3, 1, 125.000, 25.000, 0.000, 0.000, 0.000, 0.000, 1,1
308,'1 ',1, 3, 1, 171.000, 35.000, 0.000, 0.000, 0.000, 0.000, 1,1
309,'1 ',1, 3, 1, 175.000, 36.000, 0.000, 0.000, 0.000, 0.000, 1,1
310,'1 ',1, 3, 1, 195.000, 40.000, 0.000, 0.000, 0.000, 0.000, 1,1
313,'1 ',1, 3, 1, 265.000, 54.000, 0.000, 0.000, 0.000, 0.000, 1,1
314,'1 ',1, 3, 1, 194.000, 39.000, 0.000, 0.000, 0.000, 0.000, 1,1
315,'1 ',1, 3, 1, 317.000, 64.000, 0.000, 0.000, 0.000, 0.000, 1,1
316,'1 ',1, 3, 1, 100.000, 20.000, 0.000, 0.000, 0.000, 0.000, 1,1
318,'1 ',1, 3, 1, 333.000, 68.000, 0.000, 0.000, 0.000, 0.000, 1,1
319,'1 ',1, 3, 1, 181.000, 37.000, 0.000, 0.000, 0.000, 0.000, 1,1
320,'1 ',1, 3, 1, 128.000, 26.000, 0.000, 0.000, 0.000, 0.000, 1,1
0 / END OF LOAD DATA, BEGIN FIXED SHUNT DATA
0 / END OF FIXED SHUNT DATA, BEGIN GENERATOR DATA
101,'1 ', 8.000, 4.960, 10.000, 0.000,1.04680, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
101,'2 ', 8.000, 4.960, 10.000, 0.000,1.04680, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
101,'3 ', 76.000, 0.140, 30.000, -25.000,1.04680, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 76.000, 30.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
101,'4 ', 76.000, 0.140, 30.000, -25.000,1.04680, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 76.000, 30.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
101,'5 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 25.900, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
101,'6 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 26.700, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
101,'7 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 26.200, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
101,'8 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 25.800, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
102,'1 ', 8.000, 4.880, 10.000, 0.000,1.04670, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
102,'2 ', 8.000, 4.880, 10.000, 0.000,1.04670, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
102,'3 ', 76.000, -2.310, 30.000, -25.000,1.04670, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 76.000, 30.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
102,'4 ', 76.000, -2.310, 30.000, -25.000,1.04670, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 76.000, 30.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
102,'5 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 25.600, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
102,'6 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 25.300, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
103,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 61.500, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
104,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 26.800, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
107,'1 ', 355.000, 49.510, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 355.000, 170.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
113,'1 ', 55.000, 19.000, 19.000, -15.000,1.03470, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
113,'2 ', 55.000, 19.000, 19.000, -15.000,1.03470, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
113,'3 ', 55.000, 19.000, 19.000, -15.000,1.03470, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
113,'4 ', 55.000, 19.000, 19.000, -15.000,1.03470, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
113,'5 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 93.600, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
113,'DC', 0.000, 0.000, 0.000, 0.000,1.03470, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 0.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
114,'1 ', 0.000, 103.320, 200.000, -50.000,1.04410, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 0.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
115,'1 ', 5.000, 6.000, 6.000, 0.000,1.04280, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 12.000, 5.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
115,'2 ', 5.000, 6.000, 6.000, 0.000,1.04280, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 12.000, 5.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
115,'3 ', 155.000, 80.000, 80.000, -50.000,1.04280, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 155.000, 62.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
116,'1 ', 155.000, 80.000, 80.000, -50.000,1.04610, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 155.000, 62.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'1 ', 355.000, 68.430, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 355.000, 170.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'2 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 9.300, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'3 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 9.700, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'4 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 9.400, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'5 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 9.100, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'6 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 9.100, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'7 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 9.700, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'8 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 11.800, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'9 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 11.200, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'A ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 10.300, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
118,'B ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 4.500, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
119,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 66.600, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
121,'1 ', 400.000, -21.870, 200.000, -50.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 400.000, 396.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
122,'1 ', 50.000, -6.790, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
122,'2 ', 50.000, -6.790, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
122,'3 ', 50.000, -6.790, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
122,'4 ', 50.000, -6.790, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
122,'5 ', 50.000, -6.790, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
122,'6 ', 50.000, -6.790, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
122,'7 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 713.500, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
123,'1 ', 155.000, -5.190, 80.000, -50.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 155.000, 62.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
123,'2 ', 350.000, 28.410, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 350.000, 140.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
123,'3 ', 55.000, 0.620, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
123,'4 ', 55.000, 0.620, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
123,'5 ', 55.000, 0.620, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
201,'1 ', 8.000, 5.290, 10.000, 0.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
201,'2 ', 8.000, 5.290, 10.000, 0.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
201,'3 ', 76.000, 6.990, 30.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 76.000, 30.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
201,'4 ', 50.000, 4.150, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
202,'1 ', 8.000, 5.130, 10.000, 0.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
202,'2 ', 8.000, 5.130, 10.000, 0.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
202,'3 ', 76.000, 2.010, 30.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 76.000, 30.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
202,'4 ', 76.000, 2.010, 30.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 76.000, 30.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
207,'1 ', 55.000, 19.000, 19.000, -15.000,0.96990, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
207,'2 ', 55.000, 19.000, 19.000, -15.000,0.96990, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
212,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 200.000, 30.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
213,'1 ', 355.000, 135.800, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 355.000, 170.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
213,'2 ', 55.000, 9.230, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
213,'3 ', 55.000, 9.230, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
213,'4 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 13.200, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
214,'1 ', 0.000, 125.280, 200.000, -50.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 0.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
215,'1 ', 55.000, 19.000, 19.000, -15.000,1.04370, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
215,'2 ', 55.000, 19.000, 19.000, -15.000,1.04370, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
215,'3 ', 50.000, 16.000, 16.000, -10.000,1.04370, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
215,'4 ', 50.000, 16.000, 16.000, -10.000,1.04370, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
215,'5 ', 50.000, 16.000, 16.000, -10.000,1.04370, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
215,'6 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 125.100, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
216,'1 ', 155.000, 80.000, 80.000, -50.000,1.04730, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 155.000, 62.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
218,'1 ', 355.000, 60.300, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 355.000, 170.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
221,'1 ', 296.970, -7.520, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 355.000, 170.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
222,'1 ', 50.000, -6.970, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
222,'2 ', 50.000, -6.970, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
222,'3 ', 50.000, -6.970, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
222,'4 ', 50.000, -6.970, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
222,'5 ', 50.000, -6.970, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
222,'6 ', 50.000, -6.970, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
223,'1 ', 155.000, -10.310, 80.000, -50.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 155.000, 62.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
223,'2 ', 155.000, -10.310, 80.000, -50.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 155.000, 62.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
223,'3 ', 350.000, 20.590, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 350.000, 140.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
223,'4 ', 22.000, 0.240, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
223,'5 ', 22.000, 0.240, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
223,'6 ', 22.000, 0.240, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
301,'1 ', 8.000, 7.950, 10.000, 0.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
301,'2 ', 8.000, 7.950, 10.000, 0.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
301,'3 ', 44.000, 16.530, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
301,'4 ', 44.000, 16.530, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
302,'1 ', 8.000, 6.160, 10.000, 0.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
302,'2 ', 8.000, 6.160, 10.000, 0.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 20.000, 8.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
302,'3 ', 55.000, 10.990, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
302,'4 ', 55.000, 10.990, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
303,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 847.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
307,'1 ', 55.000, 19.000, 19.000, -15.000,0.95680, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
307,'2 ', 55.000, 19.000, 19.000, -15.000,0.95680, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
308,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 100.900, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
309,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 148.300, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
310,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 51.700, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
310,'2 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 51.600, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
312,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 94.100, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'1 ', 355.000, 150.000, 150.000, -25.000,1.03500, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 355.000, 170.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'2 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 95.100, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'3 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 93.300, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'4 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 101.700, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'5 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 63.100, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'6 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 65.400, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'7 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 67.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'8 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 64.800, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'9 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 63.800, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'A ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 64.100, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'B ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 66.600, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'C ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 62.400, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'D ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 66.900, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'E ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 65.200, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'F ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 27.800, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'G ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 27.200, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
313,'H ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
314,'1 ', 0.000, 166.630, 200.000, -50.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 0.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
314,'2 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 51.600, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
314,'3 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 51.600, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
314,'4 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 92.700, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
314,'5 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 51.600, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
315,'1 ', 5.000, 6.000, 6.000, 0.000,1.04220, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 12.000, 5.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
315,'2 ', 5.000, 6.000, 6.000, 0.000,1.04220, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 12.000, 5.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
315,'3 ', 5.000, 6.000, 6.000, 0.000,1.04220, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 12.000, 5.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
315,'4 ', 5.000, 6.000, 6.000, 0.000,1.04220, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 12.000, 5.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
315,'5 ', 5.000, 6.000, 6.000, 0.000,1.04220, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 12.000, 5.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
315,'6 ', 55.000, 19.000, 19.000, -15.000,1.04220, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
315,'7 ', 55.000, 19.000, 19.000, -15.000,1.04220, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
315,'8 ', 55.000, 60.000, 60.000, 0.000,1.04220, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
316,'1 ', 155.000, 80.000, 80.000, -50.000,1.04490, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 155.000, 62.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
316,'DC', 0.000, 0.000, 0.000, 0.000,1.04490, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 0.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
317,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 799.100, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
318,'1 ', 355.000, 63.120, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 355.000, 170.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
319,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 188.200, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
320,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 51.600, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
320,'2 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 27.300, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
320,'3 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 27.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
320,'4 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 28.300, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
320,'5 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 27.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
320,'6 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 28.200, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
320,'7 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 9.400, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
321,'1 ', 355.000, -3.340, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 355.000, 170.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
322,'1 ', 55.000, -9.730, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
322,'2 ', 55.000, -9.730, 19.000, -15.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 55.000, 22.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
322,'3 ', 50.000, -5.130, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
322,'4 ', 50.000, -5.130, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
322,'5 ', 50.000, -5.130, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
322,'6 ', 50.000, -5.130, 16.000, -10.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 50.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
323,'1 ', 355.000, 37.410, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 355.000, 170.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
323,'2 ', 355.000, 37.410, 150.000, -25.000,1.05000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,1, 100.0, 355.000, 170.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
324,'1 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 49.700, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
324,'2 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 51.600, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
324,'3 ', 0.000, 0.000, 0.000, 0.000,1.00000, 0, 100.000, 0.00000, 1.00000, 0.00000, 0.00000,1.00000,0, 100.0, 51.000, 0.000, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,0, 1.0000
0 / END OF GENERATOR DATA, BEGIN BRANCH DATA
101, 102,'1 ',3.00000E-3,1.40000E-2,4.61000E-1, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 3.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
101, 103,'1 ',5.50000E-2,2.11000E-1,5.70000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 55.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
101, 105,'1 ',2.20000E-2,8.50000E-2,2.30000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 22.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
102, 104,'1 ',3.30000E-2,1.27000E-1,3.40000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 33.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
102, 106,'1 ',5.00000E-2,1.92000E-1,5.20000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 50.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
103, 109,'1 ',3.10000E-2,1.19000E-1,3.20000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 31.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
104, 109,'1 ',2.70000E-2,1.04000E-1,2.80000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
105, 110,'1 ',2.30000E-2,8.80000E-2,2.40000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 23.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
106, 110,'1 ',1.40000E-2,6.10000E-2,2.45900E-0, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 16.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
107, 108,'1 ',1.60000E-2,6.10000E-2,1.70000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 16.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
107, 203,'1 ',4.20000E-2,1.61000E-1,4.40000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 42.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
108, 109,'1 ',4.30000E-2,1.65000E-1,4.50000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 43.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
108, 110,'1 ',4.30000E-2,1.65000E-1,4.50000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 43.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
111, 113,'1 ',6.00000E-3,4.80000E-2,1.00000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 33.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
111, 114,'1 ',5.00000E-3,4.20000E-2,8.80000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 29.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
112, 113,'1 ',6.00000E-3,4.80000E-2,1.00000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 33.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
112, 123,'1 ',1.20000E-2,9.70000E-2,2.03000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 67.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
113, 123,'1 ',1.10000E-2,8.70000E-2,1.82000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 60.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
113, 215,'1 ',1.00000E-2,7.50000E-2,1.58000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 52.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
114, 116,'1 ',5.00000E-3,5.90000E-2,8.20000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
115, 116,'1 ',2.00000E-3,1.70000E-2,3.60000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 12.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
115, 121,'1 ',6.00000E-3,4.90000E-2,1.03000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 34.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
115, 121,'2 ',6.00000E-3,4.90000E-2,1.03000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 34.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
115, 124,'1 ',7.00000E-3,5.20000E-2,1.09000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 36.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
116, 117,'1 ',3.00000E-3,2.60000E-2,5.50000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 18.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
116, 119,'1 ',3.00000E-3,2.30000E-2,4.90000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 16.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
117, 118,'1 ',2.00000E-3,1.40000E-2,3.00000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 10.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
117, 122,'1 ',1.40000E-2,1.05000E-1,2.21000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 73.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
118, 121,'1 ',3.00000E-3,2.60000E-2,5.50000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 18.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
118, 121,'2 ',3.00000E-3,2.60000E-2,5.50000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 18.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
119, 120,'1 ',5.00000E-3,4.00000E-2,8.30000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.50, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
119, 120,'2 ',5.00000E-3,4.00000E-2,8.30000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.50, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
120, 123,'1 ',3.00000E-3,2.20000E-2,4.60000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 15.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
120, 123,'2 ',3.00000E-3,2.20000E-2,4.60000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 15.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
121, 122,'1 ',9.00000E-3,6.80000E-2,1.42000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 47.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
123, 217,'1 ',1.00000E-2,7.40000E-2,1.55000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 51.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
201, 202,'1 ',3.00000E-3,1.40000E-2,4.61000E-1, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 3.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
201, 203,'1 ',5.50000E-2,2.11000E-1,5.70000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 55.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
201, 205,'1 ',2.20000E-2,8.50000E-2,2.30000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 22.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
202, 204,'1 ',3.30000E-2,1.27000E-1,3.40000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 33.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
202, 206,'1 ',5.00000E-2,1.92000E-1,5.20000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 50.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
203, 209,'1 ',3.10000E-2,1.19000E-1,3.20000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 31.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
204, 209,'1 ',2.70000E-2,1.04000E-1,2.80000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
205, 210,'1 ',2.30000E-2,8.80000E-2,2.40000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 23.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
206, 210,'1 ',1.40000E-2,6.10000E-2,2.45900E-0, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 16.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
207, 208,'1 ',1.60000E-2,6.10000E-2,1.70000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 16.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
208, 209,'1 ',4.30000E-2,1.65000E-1,4.50000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 43.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
208, 210,'1 ',4.30000E-2,1.65000E-1,4.50000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 43.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
211, 213,'1 ',6.00000E-3,4.80000E-2,1.00000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 33.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
211, 214,'1 ',5.00000E-3,4.20000E-2,8.80000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 29.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
212, 213,'1 ',6.00000E-3,4.80000E-2,1.00000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 33.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
212, 223,'1 ',1.20000E-2,9.70000E-2,2.03000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 67.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
213, 223,'1 ',1.10000E-2,8.70000E-2,1.82000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 60.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
214, 216,'1 ',5.00000E-3,5.90000E-2,8.20000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
215, 216,'1 ',2.00000E-3,1.70000E-2,3.60000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 12.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
215, 221,'1 ',6.00000E-3,4.90000E-2,1.03000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 34.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
215, 221,'2 ',6.00000E-3,4.90000E-2,1.03000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 34.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
215, 224,'1 ',7.00000E-3,5.20000E-2,1.09000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 36.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
216, 217,'1 ',3.00000E-3,2.60000E-2,5.50000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 18.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
216, 219,'1 ',3.00000E-3,2.30000E-2,4.90000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 16.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
217, 218,'1 ',2.00000E-3,1.40000E-2,3.00000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 10.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
217, 222,'1 ',1.40000E-2,1.05000E-1,2.21000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 73.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
218, 221,'1 ',3.00000E-3,2.60000E-2,5.50000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 18.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
218, 221,'2 ',3.00000E-3,2.60000E-2,5.50000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 18.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
219, 220,'1 ',5.00000E-3,4.00000E-2,8.30000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.50, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
219, 220,'2 ',5.00000E-3,4.00000E-2,8.30000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.50, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
220, 223,'1 ',3.00000E-3,2.20000E-2,4.60000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 15.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
220, 223,'2 ',3.00000E-3,2.20000E-2,4.60000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 15.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
221, 222,'1 ',9.00000E-3,6.80000E-2,1.42000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 47.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
301, 302,'1 ',3.00000E-3,1.40000E-2,4.61000E-1, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 3.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
301, 303,'1 ',5.50000E-2,2.11000E-1,5.70000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 55.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
301, 305,'1 ',2.20000E-2,8.50000E-2,2.30000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 22.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
302, 304,'1 ',3.30000E-2,1.27000E-1,3.40000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 33.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
302, 306,'1 ',5.00000E-2,1.92000E-1,5.20000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 50.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
303, 309,'1 ',3.10000E-2,1.19000E-1,3.20000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 31.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
304, 309,'1 ',2.70000E-2,1.04000E-1,2.80000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
305, 310,'1 ',2.30000E-2,8.80000E-2,2.40000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 23.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
306, 310,'1 ',1.40000E-2,6.10000E-2,2.45900E-0, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 16.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
307, 308,'1 ',1.60000E-2,6.10000E-2,1.70000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 16.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
308, 309,'1 ',4.30000E-2,1.65000E-1,4.50000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 43.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
308, 310,'1 ',4.30000E-2,1.65000E-1,4.50000E-2, 175.00, 175.00, 175.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 43.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
311, 313,'1 ',6.00000E-3,4.80000E-2,1.00000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 33.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
311, 314,'1 ',5.00000E-3,4.20000E-2,8.80000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 29.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
312, 313,'1 ',6.00000E-3,4.80000E-2,1.00000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 33.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
312, 323,'1 ',1.20000E-2,9.70000E-2,2.03000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 67.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
313, 323,'1 ',1.10000E-2,8.70000E-2,1.82000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 60.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
314, 316,'1 ',5.00000E-3,5.90000E-2,8.20000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
315, 316,'1 ',2.00000E-3,1.70000E-2,3.60000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 12.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
315, 321,'1 ',6.00000E-3,4.90000E-2,1.03000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 34.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
315, 321,'2 ',6.00000E-3,4.90000E-2,1.03000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 34.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
315, 324,'1 ',7.00000E-3,5.20000E-2,1.09000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 36.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
316, 317,'1 ',3.00000E-3,2.60000E-2,5.50000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 18.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
316, 319,'1 ',3.00000E-3,2.30000E-2,4.90000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 16.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
317, 318,'1 ',2.00000E-3,1.40000E-2,3.00000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 10.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
317, 322,'1 ',1.40000E-2,1.05000E-1,2.21000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 73.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
318, 223,'1 ',1.30000E-2,1.04000E-1,2.18000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 72.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
318, 321,'1 ',3.00000E-3,2.60000E-2,5.50000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 18.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
318, 321,'2 ',3.00000E-3,2.60000E-2,5.50000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 18.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
319, 320,'1 ',5.00000E-3,4.00000E-2,8.30000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.50, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
319, 320,'2 ',5.00000E-3,4.00000E-2,8.30000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 27.50, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
320, 323,'1 ',3.00000E-3,2.20000E-2,4.60000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 15.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
320, 323,'2 ',3.00000E-3,2.20000E-2,4.60000E-2, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 15.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
321, 322,'1 ',9.00000E-3,6.80000E-2,1.42000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 47.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
323, 325,'1 ',1.00000E-7,9.00000E-3,0.00000E-0, 722.00, 722.00, 722.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 0.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
325, 121,'1 ',1.20000E-2,9.70000E-2,2.03000E-1, 500.00, 500.00, 500.00, 0.00000, 0.00000, 0.00000, 0.00000,1,1, 67.00, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000
0 / END OF BRANCH DATA, BEGIN TRANSFORMER DATA
103, 124, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.015000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
109, 111, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.030000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
109, 112, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.030000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
110, 111, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.015000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
110, 112, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.015000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
203, 224, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.015000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
209, 211, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.030000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
209, 212, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.030000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
210, 211, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.015000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
210, 212, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.015000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
303, 324, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.015000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
309, 311, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.030000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
309, 312, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.030000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
310, 311, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.015000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
310, 312, 0,'1 ',1,1,1,0.00000E0,0.00000E0,2,' ',1, 1,1.0000, 0,1.0000, 0,1.0000, 0,1.0000,' '
2.00000E-3,8.40000E-2, 100.00
1.015000,138.000, 0.000, 400.00, 400.00, 400.00,-1, 0,1.500000,0.510000,1.500000,0.510000,159, 0, 0.00000, 0.00000, 0.000
1.000000,230.000
0 / END OF TRANSFORMER DATA, BEGIN AREA DATA
1, 0, 0.000, 1.000,'1 '
2, 0, 0.000, 1.000,'2 '
3, 0, 0.000, 1.000,'3 '
0 / END OF AREA DATA, BEGIN TWO-TERMINAL DC DATA
0 / END OF TWO-TERMINAL DC DATA, BEGIN VOLTAGE SOURCE CONVERTER DATA
0 / END OF VOLTAGE SOURCE CONVERTER DATA, BEGIN IMPEDANCE CORRECTION DATA
0 / END OF IMPEDANCE CORRECTION DATA, BEGIN MULTI-TERMINAL DC DATA
0 / END OF MULTI-TERMINAL DC DATA, BEGIN MULTI-SECTION LINE DATA
0 / END OF MULTI-SECTION LINE DATA, BEGIN ZONE DATA
1,'1 '
11,'11 '
12,'12 '
13,'13 '
14,'14 '
15,'15 '
16,'16 '
17,'17 '
21,'21 '
22,'22 '
23,'23 '
24,'24 '
25,'25 '
26,'26 '
27,'27 '
31,'31 '
32,'32 '
33,'33 '
34,'34 '
35,'35 '
36,'36 '
37,'37 '
0 / END OF ZONE DATA, BEGIN INTER-AREA TRANSFER DATA
0 / END OF INTER-AREA TRANSFER DATA, BEGIN OWNER DATA
1,'1'
0 / END OF OWNER DATA, BEGIN FACTS CONTROL DEVICE DATA
0 / END OF FACTS CONTROL DEVICE DATA, BEGIN SWITCHED SHUNT DATA
106,0,0,1,1.05000,0.95000, 0,100.0,' ', -100.00, 1,-100.00
206,0,0,1,1.05000,0.95000, 0,100.0,' ', -100.00, 1,-100.00
306,0,0,1,1.05000,0.95000, 0,100.0,' ', -100.00, 1,-100.00
0 /END OF SWITCHED SHUNT DATA, BEGIN GNE DEVICE DATA
0 /END OF GNE DEVICE DATA
Q
================================================
FILE: docs/src/tutorials/tutorials_data/RTS_GMLC.m
================================================
function mpc = RTS_GMLC
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% RTS-GMLC Test Case %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%% By: Clayton Barrows, Ali Ehlen, Matt O Connell, %%%%%%%%%%%%%%%%
%%%%%%%%%% Dheepak Krishnamurthy, Brendan McBennett, and Aaron Bloom %%%%%%%%%%%
%%%%%%%%%%%%%%%%%%% National Renewable Energy Lab, Golden CO %%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% MATPOWER Case Format : Version 2
mpc.version = '2';
%%----- Power Flow Data -----%%
%% system MVA base
mpc.baseMVA = 100.0;
%% area data
% area refbus
mpc.areas = [
1 101;
2 201;
3 301;
];
%% bus data
% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin
mpc.bus = [
101 2 108.0 22.0 0.0 0.0 1 1.04777 -7.74152 138.0 11 1.05 0.95
102 2 97.0 20.0 0.0 0.0 1 1.04783 -7.81784 138.0 12 1.05 0.95
103 1 180.0 37.0 0.0 0.0 1 1.01085 -7.21090 138.0 11 1.05 0.95
104 1 74.0 15.0 0.0 0.0 1 1.01765 -10.56614 138.0 11 1.05 0.95
105 1 71.0 14.0 0.0 0.0 1 1.03568 -10.70887 138.0 11 1.05 0.95
106 1 136.0 28.0 0.0 -100.0 1 1.03242 -13.27944 138.0 12 1.05 0.95
107 2 125.0 25.0 0.0 0.0 1 1.03745 -11.27673 138.0 12 1.05 0.95
108 1 171.0 35.0 0.0 0.0 1 1.01024 -13.74967 138.0 12 1.05 0.95
109 1 175.0 36.0 0.0 0.0 1 1.02610 -8.81524 138.0 13 1.05 0.95
110 1 195.0 40.0 0.0 0.0 1 1.05000 -10.62063 138.0 13 1.05 0.95
111 1 0.0 0.0 0.0 0.0 1 1.02764 -3.91674 230.0 13 1.05 0.95
112 1 0.0 0.0 0.0 0.0 1 1.02024 -2.42424 230.0 13 1.05 0.95
113 3 265.0 54.0 0.0 0.0 1 1.03943 0.00000 230.0 14 1.05 0.95
114 2 194.0 39.0 0.0 0.0 1 1.04401 -1.73056 230.0 16 1.05 0.95
115 2 317.0 64.0 0.0 0.0 1 1.04335 7.95970 230.0 16 1.05 0.95
116 2 100.0 20.0 0.0 0.0 1 1.04565 7.56929 230.0 16 1.05 0.95
117 1 0.0 0.0 0.0 0.0 1 1.04783 11.43417 230.0 17 1.05 0.95
118 2 333.0 68.0 0.0 0.0 1 1.05000 12.52457 230.0 17 1.05 0.95
119 1 181.0 37.0 0.0 0.0 1 1.03962 6.65777 230.0 15 1.05 0.95
120 1 128.0 26.0 0.0 0.0 1 1.04399 7.74060 230.0 15 1.05 0.95
121 2 0.0 0.0 0.0 0.0 1 1.05000 13.08653 230.0 17 1.05 0.95
122 2 0.0 0.0 0.0 0.0 1 1.05000 18.94978 230.0 17 1.05 0.95
123 2 0.0 0.0 0.0 0.0 1 1.05000 9.05617 230.0 15 1.05 0.95
124 1 0.0 0.0 0.0 0.0 1 1.01155 2.38339 230.0 16 1.05 0.95
201 2 108.0 22.0 0.0 0.0 2 1.04841 -10.68973 138.0 21 1.05 0.95
202 2 97.0 20.0 0.0 0.0 2 1.04844 -10.75906 138.0 22 1.05 0.95
203 1 180.0 37.0 0.0 0.0 2 1.01886 -10.47453 138.0 21 1.05 0.95
204 1 74.0 15.0 0.0 0.0 2 1.01890 -13.48479 138.0 21 1.05 0.95
205 1 71.0 14.0 0.0 0.0 2 1.03603 -13.61187 138.0 21 1.05 0.95
206 1 136.0 28.0 0.0 -100.0 2 1.03259 -16.15672 138.0 22 1.05 0.95
207 2 125.0 25.0 0.0 0.0 2 1.03973 -13.46606 138.0 22 1.05 0.95
208 1 171.0 35.0 0.0 0.0 2 1.01203 -16.22359 138.0 22 1.05 0.95
209 1 175.0 36.0 0.0 0.0 2 1.02781 -11.72409 138.0 23 1.05 0.95
210 1 195.0 40.0 0.0 0.0 2 1.05000 -13.47986 138.0 23 1.05 0.95
211 1 0.0 0.0 0.0 0.0 2 1.02735 -6.93336 230.0 23 1.05 0.95
212 1 0.0 0.0 0.0 0.0 2 1.01921 -5.25334 230.0 23 1.05 0.95
213 2 265.0 54.0 0.0 0.0 2 1.03752 -3.21510 230.0 24 1.05 0.95
214 2 194.0 39.0 0.0 0.0 2 1.04335 -4.68519 230.0 26 1.05 0.95
215 2 317.0 64.0 0.0 0.0 2 1.04327 4.63351 230.0 26 1.05 0.95
216 2 100.0 20.0 0.0 0.0 2 1.04556 4.70009 230.0 26 1.05 0.95
217 1 0.0 0.0 0.0 0.0 2 1.04847 8.81839 230.0 27 1.05 0.95
218 2 333.0 68.0 0.0 0.0 2 1.05000 9.99473 230.0 27 1.05 0.95
219 1 181.0 37.0 0.0 0.0 2 1.03946 4.21233 230.0 25 1.05 0.95
220 1 128.0 26.0 0.0 0.0 2 1.04380 5.66449 230.0 25 1.05 0.95
221 2 0.0 0.0 0.0 0.0 2 1.05000 10.63209 230.0 27 1.05 0.95
222 2 0.0 0.0 0.0 0.0 2 1.05000 16.43203 230.0 27 1.05 0.95
223 2 0.0 0.0 0.0 0.0 2 1.05000 7.18151 230.0 25 1.05 0.95
224 1 0.0 0.0 0.0 0.0 2 1.01456 -0.96005 230.0 26 1.05 0.95
301 2 108.0 22.0 0.0 0.0 3 1.04860 -9.34821 138.0 31 1.05 0.95
302 2 97.0 20.0 0.0 0.0 3 1.04864 -9.43100 138.0 32 1.05 0.95
303 1 180.0 37.0 0.0 0.0 3 1.01045 -8.57689 138.0 31 1.05 0.95
304 1 74.0 15.0 0.0 0.0 3 1.01785 -12.18784 138.0 31 1.05 0.95
305 1 71.0 14.0 0.0 0.0 3 1.03609 -12.35005 138.0 31 1.05 0.95
306 1 136.0 28.0 0.0 -100.0 3 1.03260 -14.94205 138.0 32 1.05 0.95
307 2 125.0 25.0 0.0 0.0 3 1.03804 -12.54795 138.0 32 1.05 0.95
308 1 171.0 35.0 0.0 0.0 3 1.01056 -15.18287 138.0 32 1.05 0.95
309 1 175.0 36.0 0.0 0.0 3 1.02579 -10.44617 138.0 33 1.05 0.95
310 1 195.0 40.0 0.0 0.0 3 1.05000 -12.30117 138.0 33 1.05 0.95
311 1 0.0 0.0 0.0 0.0 3 1.02830 -5.74069 230.0 33 1.05 0.95
312 1 0.0 0.0 0.0 0.0 3 1.01900 -4.14604 230.0 33 1.05 0.95
313 2 265.0 54.0 0.0 0.0 3 1.03802 -2.41513 230.0 34 1.05 0.95
314 2 194.0 39.0 0.0 0.0 3 1.04631 -3.20793 230.0 36 1.05 0.95
315 2 317.0 64.0 0.0 0.0 3 1.04300 7.05088 230.0 36 1.05 0.95
316 2 100.0 20.0 0.0 0.0 3 1.04558 6.59875 230.0 36 1.05 0.95
317 1 0.0 0.0 0.0 0.0 3 1.04785 10.34418 230.0 37 1.05 0.95
318 2 333.0 68.0 0.0 0.0 3 1.05000 11.34262 230.0 37 1.05 0.95
319 1 181.0 37.0 0.0 0.0 3 1.03953 5.91539 230.0 35 1.05 0.95
320 1 128.0 26.0 0.0 0.0 3 1.04389 7.19709 230.0 35 1.05 0.95
321 2 0.0 0.0 0.0 0.0 3 1.05000 12.34122 230.0 37 1.05 0.95
322 2 0.0 0.0 0.0 0.0 3 1.05000 18.06914 230.0 37 1.05 0.95
323 2 0.0 0.0 0.0 0.0 3 1.05000 8.62112 230.0 35 1.05 0.95
324 1 0.0 0.0 0.0 0.0 3 1.01046 1.30606 230.0 36 1.05 0.95
325 1 0.0 0.0 0.0 0.0 3 1.04986 8.99332 230.0 35 1.05 0.95
];
%% generator data
% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
mpc.gen = [
101 8.0 4.96 10 0 1.04680 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
101 8.0 4.96 10 0 1.04680 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
101 76.0 0.14 30 -25 1.04680 100.0 1 76.0 30 0.0 0.0 0.0 0.0 0.0 0.0 2.0 2.0 2.0 2.0 0.0
101 76.0 0.14 30 -25 1.04680 100.0 1 76.0 30 0.0 0.0 0.0 0.0 0.0 0.0 2.0 2.0 2.0 2.0 0.0
102 8.0 4.88 10 0 1.04670 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
102 8.0 4.88 10 0 1.04670 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
102 76.0 -2.31 30 -25 1.04670 100.0 1 76.0 30 0.0 0.0 0.0 0.0 0.0 0.0 2.0 2.0 2.0 2.0 0.0
102 76.0 -2.31 30 -25 1.04670 100.0 1 76.0 30 0.0 0.0 0.0 0.0 0.0 0.0 2.0 2.0 2.0 2.0 0.0
107 355.0 49.51 150 -25 1.05000 100.0 1 355.0 170 0.0 0.0 0.0 0.0 0.0 0.0 4.14 4.14 4.14 4.14 0.0
113 55.0 19.0 19 -15 1.03470 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
113 55.0 19.0 19 -15 1.03470 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
113 55.0 19.0 19 -15 1.03470 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
113 55.0 19.0 19 -15 1.03470 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
115 5.0 6.0 6 0 1.04280 100.0 1 12.0 5 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 0.0
115 5.0 6.0 6 0 1.04280 100.0 1 12.0 5 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 0.0
115 155.0 80.0 80 -50 1.04280 100.0 1 155.0 62 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
116 155.0 80.0 80 -50 1.04610 100.0 1 155.0 62 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
118 355.0 68.43 150 -25 1.05000 100.0 1 355.0 170 0.0 0.0 0.0 0.0 0.0 0.0 4.14 4.14 4.14 4.14 0.0
123 155.0 -5.19 80 -50 1.05000 100.0 1 155.0 62 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
123 350.0 28.41 150 -25 1.05000 100.0 1 350.0 140 0.0 0.0 0.0 0.0 0.0 0.0 4.0 4.0 4.0 4.0 0.0
123 55.0 0.62 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
123 55.0 0.62 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
123 55.0 0.62 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
201 8.0 5.29 10 0 1.05000 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
201 8.0 5.29 10 0 1.05000 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
201 76.0 6.99 30 -25 1.05000 100.0 1 76.0 30 0.0 0.0 0.0 0.0 0.0 0.0 2.0 2.0 2.0 2.0 0.0
202 8.0 5.13 10 0 1.05000 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
202 8.0 5.13 10 0 1.05000 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
202 76.0 2.01 30 -25 1.05000 100.0 1 76.0 30 0.0 0.0 0.0 0.0 0.0 0.0 2.0 2.0 2.0 2.0 0.0
202 76.0 2.01 30 -25 1.05000 100.0 1 76.0 30 0.0 0.0 0.0 0.0 0.0 0.0 2.0 2.0 2.0 2.0 0.0
207 55.0 19.0 19 -15 0.96990 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
207 55.0 19.0 19 -15 0.96990 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
213 355.0 135.8 150 -25 1.05000 100.0 1 355.0 170 0.0 0.0 0.0 0.0 0.0 0.0 4.14 4.14 4.14 4.14 0.0
213 55.0 9.23 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
213 55.0 9.23 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
215 55.0 19.0 19 -15 1.04370 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
215 55.0 19.0 19 -15 1.04370 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
216 155.0 80.0 80 -50 1.04730 100.0 1 155.0 62 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
218 355.0 60.3 150 -25 1.05000 100.0 1 355.0 170 0.0 0.0 0.0 0.0 0.0 0.0 4.14 4.14 4.14 4.14 0.0
221 296.97 -7.52 150 -25 1.05000 100.0 1 355.0 170 0.0 0.0 0.0 0.0 0.0 0.0 4.14 4.14 4.14 4.14 0.0
223 155.0 -10.31 80 -50 1.05000 100.0 1 155.0 62 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
223 155.0 -10.31 80 -50 1.05000 100.0 1 155.0 62 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
223 350.0 20.59 150 -25 1.05000 100.0 1 350.0 140 0.0 0.0 0.0 0.0 0.0 0.0 4.0 4.0 4.0 4.0 0.0
223 22.0 0.24 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
223 22.0 0.24 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
223 22.0 0.24 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
301 8.0 7.95 10 0 1.05000 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
301 8.0 7.95 10 0 1.05000 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
301 44.0 16.53 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
301 44.0 16.53 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
302 8.0 6.16 10 0 1.05000 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
302 8.0 6.16 10 0 1.05000 100.0 1 20.0 8 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
302 55.0 10.99 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
302 55.0 10.99 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
307 55.0 19.0 19 -15 0.95680 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
307 55.0 19.0 19 -15 0.95680 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
313 355.0 150.0 150 -25 1.00000 100.0 1 355.0 170 0.0 0.0 0.0 0.0 0.0 0.0 4.14 4.14 4.14 4.14 0.0
315 5.0 6.0 6 0 1.04220 100.0 1 12.0 5 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 0.0
315 5.0 6.0 6 0 1.04220 100.0 1 12.0 5 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 0.0
315 5.0 6.0 6 0 1.04220 100.0 1 12.0 5 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 0.0
315 5.0 6.0 6 0 1.04220 100.0 1 12.0 5 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 0.0
315 5.0 6.0 6 0 1.04220 100.0 1 12.0 5 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 0.0
315 55.0 19.0 19 -15 1.04220 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
315 55.0 19.0 19 -15 1.04220 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
315 55.0 60.0 60 0 1.04220 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
316 155.0 80.0 80 -50 1.04490 100.0 1 155.0 62 0.0 0.0 0.0 0.0 0.0 0.0 3.0 3.0 3.0 3.0 0.0
318 355.0 63.12 150 -25 1.05000 100.0 1 355.0 170 0.0 0.0 0.0 0.0 0.0 0.0 4.14 4.14 4.14 4.14 0.0
321 355.0 -3.34 150 -25 1.05000 100.0 1 355.0 170 0.0 0.0 0.0 0.0 0.0 0.0 4.14 4.14 4.14 4.14 0.0
322 55.0 -9.73 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
322 55.0 -9.73 19 -15 1.05000 100.0 1 55.0 22 0.0 0.0 0.0 0.0 0.0 0.0 3.7 3.7 3.7 3.7 0.0
323 355.0 37.41 150 -25 1.05000 100.0 1 355.0 170 0.0 0.0 0.0 0.0 0.0 0.0 4.14 4.14 4.14 4.14 0.0
323 355.0 37.41 150 -25 1.05000 100.0 1 355.0 170 0.0 0.0 0.0 0.0 0.0 0.0 4.14 4.14 4.14 4.14 0.0
114 0.0 103.32 200 -50 1.04410 100.0 1 0.0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
121 400.0 -21.87 200 -50 1.05000 100.0 1 400.0 396 0.0 0.0 0.0 0.0 0.0 0.0 20.0 20.0 20.0 20.0 0.0
122 50.0 -6.79 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
122 50.0 -6.79 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
122 50.0 -6.79 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
122 50.0 -6.79 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
122 50.0 -6.79 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
122 50.0 -6.79 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
201 50.0 4.15 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
214 0.0 125.28 200 -50 1.05000 100.0 1 0.0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
215 50.0 16.0 16 -10 1.04370 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
215 50.0 16.0 16 -10 1.04370 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
215 50.0 16.0 16 -10 1.04370 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
222 50.0 -6.97 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
222 50.0 -6.97 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
222 50.0 -6.97 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
222 50.0 -6.97 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
222 50.0 -6.97 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
222 50.0 -6.97 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
314 0.0 166.63 200 -50 1.00000 100.0 1 0.0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
322 50.0 -5.13 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
322 50.0 -5.13 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
322 50.0 -5.13 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
322 50.0 -5.13 16 -10 1.05000 100.0 1 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
320 0.0 0.0 0 0 1.00000 100.0 0 51.6 0 0.0 0.0 0.0 0.0 0.0 0.0 51.6 51.6 51.6 51.6 0.0
314 0.0 0.0 0 0 1.00000 100.0 0 51.6 0 0.0 0.0 0.0 0.0 0.0 0.0 51.6 51.6 51.6 51.6 0.0
314 0.0 0.0 0 0 1.00000 100.0 0 51.6 0 0.0 0.0 0.0 0.0 0.0 0.0 51.6 51.6 51.6 51.6 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 95.1 0 0.0 0.0 0.0 0.0 0.0 0.0 95.1 95.1 95.1 95.1 0.0
314 0.0 0.0 0 0 1.00000 100.0 0 92.7 0 0.0 0.0 0.0 0.0 0.0 0.0 92.7 92.7 92.7 92.7 0.0
314 0.0 0.0 0 0 1.00000 100.0 0 51.6 0 0.0 0.0 0.0 0.0 0.0 0.0 51.6 51.6 51.6 51.6 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 93.3 0 0.0 0.0 0.0 0.0 0.0 0.0 93.3 93.3 93.3 93.3 0.0
310 0.0 0.0 0 0 1.00000 100.0 0 51.7 0 0.0 0.0 0.0 0.0 0.0 0.0 51.7 51.7 51.7 51.7 0.0
324 0.0 0.0 0 0 1.00000 100.0 0 49.7 0 0.0 0.0 0.0 0.0 0.0 0.0 49.7 49.7 49.7 49.7 0.0
312 0.0 0.0 0 0 1.00000 100.0 0 94.1 0 0.0 0.0 0.0 0.0 0.0 0.0 94.1 94.1 94.1 94.1 0.0
310 0.0 0.0 0 0 1.00000 100.0 0 51.6 0 0.0 0.0 0.0 0.0 0.0 0.0 51.6 51.6 51.6 51.6 0.0
324 0.0 0.0 0 0 1.00000 100.0 0 51.6 0 0.0 0.0 0.0 0.0 0.0 0.0 51.6 51.6 51.6 51.6 0.0
324 0.0 0.0 0 0 1.00000 100.0 0 51.0 0 0.0 0.0 0.0 0.0 0.0 0.0 51.0 51.0 51.0 51.0 0.0
113 0.0 0.0 0 0 1.03470 100.0 0 93.6 0 0.0 0.0 0.0 0.0 0.0 0.0 93.6 93.6 93.6 93.6 0.0
319 0.0 0.0 0 0 1.00000 100.0 0 188.2 0 0.0 0.0 0.0 0.0 0.0 0.0 188.2 188.2 188.2 188.2 0.0
215 0.0 0.0 0 0 1.04370 100.0 0 125.1 0 0.0 0.0 0.0 0.0 0.0 0.0 125.1 125.1 125.1 125.1 0.0
102 0.0 0.0 0 0 1.04670 100.0 0 25.6 0 0.0 0.0 0.0 0.0 0.0 0.0 25.6 25.6 25.6 25.6 0.0
101 0.0 0.0 0 0 1.04680 100.0 0 25.9 0 0.0 0.0 0.0 0.0 0.0 0.0 25.9 25.9 25.9 25.9 0.0
102 0.0 0.0 0 0 1.04670 100.0 0 25.3 0 0.0 0.0 0.0 0.0 0.0 0.0 25.3 25.3 25.3 25.3 0.0
104 0.0 0.0 0 0 1.00000 100.0 0 26.8 0 0.0 0.0 0.0 0.0 0.0 0.0 26.8 26.8 26.8 26.8 0.0
212 0.0 0.0 0 0 1.00000 100.0 0 200.0 30 0.0 0.0 0.0 0.0 0.0 0.0 20.0 20.0 20.0 20.0 0.0
101 0.0 0.0 0 0 1.04680 100.0 0 26.7 0 0.0 0.0 0.0 0.0 0.0 0.0 26.7 26.7 26.7 26.7 0.0
101 0.0 0.0 0 0 1.04680 100.0 0 26.2 0 0.0 0.0 0.0 0.0 0.0 0.0 26.2 26.2 26.2 26.2 0.0
101 0.0 0.0 0 0 1.04680 100.0 0 25.8 0 0.0 0.0 0.0 0.0 0.0 0.0 25.8 25.8 25.8 25.8 0.0
103 0.0 0.0 0 0 1.00000 100.0 0 61.5 0 0.0 0.0 0.0 0.0 0.0 0.0 61.5 61.5 61.5 61.5 0.0
119 0.0 0.0 0 0 1.00000 100.0 0 66.6 0 0.0 0.0 0.0 0.0 0.0 0.0 66.6 66.6 66.6 66.6 0.0
308 0.0 0.0 0 0 1.00000 100.0 0 100.9 0 0.0 0.0 0.0 0.0 0.0 0.0 100.9 100.9 100.9 100.9 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 101.7 0 0.0 0.0 0.0 0.0 0.0 0.0 101.7 101.7 101.7 101.7 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 63.1 0 0.0 0.0 0.0 0.0 0.0 0.0 63.1 63.1 63.1 63.1 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 65.4 0 0.0 0.0 0.0 0.0 0.0 0.0 65.4 65.4 65.4 65.4 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 67.0 0 0.0 0.0 0.0 0.0 0.0 0.0 67.0 67.0 67.0 67.0 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 64.8 0 0.0 0.0 0.0 0.0 0.0 0.0 64.8 64.8 64.8 64.8 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 63.8 0 0.0 0.0 0.0 0.0 0.0 0.0 63.8 63.8 63.8 63.8 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 64.1 0 0.0 0.0 0.0 0.0 0.0 0.0 64.1 64.1 64.1 64.1 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 66.6 0 0.0 0.0 0.0 0.0 0.0 0.0 66.6 66.6 66.6 66.6 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 62.4 0 0.0 0.0 0.0 0.0 0.0 0.0 62.4 62.4 62.4 62.4 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 66.9 0 0.0 0.0 0.0 0.0 0.0 0.0 66.9 66.9 66.9 66.9 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 65.2 0 0.0 0.0 0.0 0.0 0.0 0.0 65.2 65.2 65.2 65.2 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 27.8 0 0.0 0.0 0.0 0.0 0.0 0.0 27.8 27.8 27.8 27.8 0.0
320 0.0 0.0 0 0 1.00000 100.0 0 27.3 0 0.0 0.0 0.0 0.0 0.0 0.0 27.3 27.3 27.3 27.3 0.0
320 0.0 0.0 0 0 1.00000 100.0 0 27.0 0 0.0 0.0 0.0 0.0 0.0 0.0 27.0 27.0 27.0 27.0 0.0
320 0.0 0.0 0 0 1.00000 100.0 0 28.3 0 0.0 0.0 0.0 0.0 0.0 0.0 28.3 28.3 28.3 28.3 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 27.2 0 0.0 0.0 0.0 0.0 0.0 0.0 27.2 27.2 27.2 27.2 0.0
320 0.0 0.0 0 0 1.00000 100.0 0 27.0 0 0.0 0.0 0.0 0.0 0.0 0.0 27.0 27.0 27.0 27.0 0.0
320 0.0 0.0 0 0 1.00000 100.0 0 28.2 0 0.0 0.0 0.0 0.0 0.0 0.0 28.2 28.2 28.2 28.2 0.0
118 0.0 0.0 0 0 1.00000 100.0 0 9.3 0 0.0 0.0 0.0 0.0 0.0 0.0 9.3 9.3 9.3 9.3 0.0
118 0.0 0.0 0 0 1.00000 100.0 0 9.7 0 0.0 0.0 0.0 0.0 0.0 0.0 9.7 9.7 9.7 9.7 0.0
118 0.0 0.0 0 0 1.00000 100.0 0 9.4 0 0.0 0.0 0.0 0.0 0.0 0.0 9.4 9.4 9.4 9.4 0.0
118 0.0 0.0 0 0 1.00000 100.0 0 9.1 0 0.0 0.0 0.0 0.0 0.0 0.0 9.1 9.1 9.1 9.1 0.0
118 0.0 0.0 0 0 1.00000 100.0 0 9.1 0 0.0 0.0 0.0 0.0 0.0 0.0 9.1 9.1 9.1 9.1 0.0
118 0.0 0.0 0 0 1.00000 100.0 0 9.7 0 0.0 0.0 0.0 0.0 0.0 0.0 9.7 9.7 9.7 9.7 0.0
320 0.0 0.0 0 0 1.00000 100.0 0 9.4 0 0.0 0.0 0.0 0.0 0.0 0.0 9.4 9.4 9.4 9.4 0.0
118 0.0 0.0 0 0 1.00000 100.0 0 11.8 0 0.0 0.0 0.0 0.0 0.0 0.0 11.8 11.8 11.8 11.8 0.0
118 0.0 0.0 0 0 1.00000 100.0 0 11.2 0 0.0 0.0 0.0 0.0 0.0 0.0 11.2 11.2 11.2 11.2 0.0
118 0.0 0.0 0 0 1.00000 100.0 0 10.3 0 0.0 0.0 0.0 0.0 0.0 0.0 10.3 10.3 10.3 10.3 0.0
118 0.0 0.0 0 0 1.00000 100.0 0 4.5 0 0.0 0.0 0.0 0.0 0.0 0.0 4.5 4.5 4.5 4.5 0.0
213 0.0 0.0 0 0 1.05000 100.0 0 13.2 0 0.0 0.0 0.0 0.0 0.0 0.0 13.2 13.2 13.2 13.2 0.0
309 0.0 0.0 0 0 1.00000 100.0 0 148.3 0 0.0 0.0 0.0 0.0 0.0 0.0 148.3 148.3 148.3 148.3 0.0
317 0.0 0.0 0 0 1.00000 100.0 0 799.1 0 0.0 0.0 0.0 0.0 0.0 0.0 799.1 799.1 799.1 799.1 0.0
303 0.0 0.0 0 0 1.00000 100.0 0 847.0 0 0.0 0.0 0.0 0.0 0.0 0.0 847.0 847.0 847.0 847.0 0.0
122 0.0 0.0 0 0 1.00000 100.0 0 713.5 0 0.0 0.0 0.0 0.0 0.0 0.0 713.5 713.5 713.5 713.5 0.0
313 0.0 0.0 0 0 1.00000 100.0 0 50.0 0 0.0 0.0 0.0 0.0 0.0 0.0 50.0 50.0 50.0 50.0 0.0
];
%% branch data
% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax
mpc.branch = [
101 102 0.00300 0.01400 0.46100 175 175 175 0.0 0.0 1 -90 90
101 103 0.05500 0.21100 0.05700 175 175 175 0.0 0.0 1 -90 90
101 105 0.02200 0.08500 0.02300 175 175 175 0.0 0.0 1 -90 90
102 104 0.03300 0.12700 0.03400 175 175 175 0.0 0.0 1 -90 90
102 106 0.05000 0.19200 0.05200 175 175 175 0.0 0.0 1 -90 90
103 109 0.03100 0.11900 0.03200 175 175 175 0.0 0.0 1 -90 90
103 124 0.00200 0.08400 0.00000 400 400 400 1.015 0.0 1 -90 90
104 109 0.02700 0.10400 0.02800 175 175 175 0.0 0.0 1 -90 90
105 110 0.02300 0.08800 0.02400 175 175 175 0.0 0.0 1 -90 90
106 110 0.01400 0.06100 2.45900 175 175 175 0.0 0.0 1 -90 90
107 108 0.01600 0.06100 0.01700 175 175 175 0.0 0.0 1 -90 90
107 203 0.04200 0.16100 0.04400 175 175 175 0.0 0.0 1 -90 90
108 109 0.04300 0.16500 0.04500 175 175 175 0.0 0.0 1 -90 90
108 110 0.04300 0.16500 0.04500 175 175 175 0.0 0.0 1 -90 90
109 111 0.00200 0.08400 0.00000 400 400 400 1.03 0.0 1 -90 90
109 112 0.00200 0.08400 0.00000 400 400 400 1.03 0.0 1 -90 90
110 111 0.00200 0.08400 0.00000 400 400 400 1.015 0.0 1 -90 90
110 112 0.00200 0.08400 0.00000 400 400 400 1.015 0.0 1 -90 90
111 113 0.00600 0.04800 0.10000 500 500 500 0.0 0.0 1 -90 90
111 114 0.00500 0.04200 0.08800 500 500 500 0.0 0.0 1 -90 90
112 113 0.00600 0.04800 0.10000 500 500 500 0.0 0.0 1 -90 90
112 123 0.01200 0.09700 0.20300 500 500 500 0.0 0.0 1 -90 90
113 123 0.01100 0.08700 0.18200 500 500 500 0.0 0.0 1 -90 90
113 215 0.01000 0.07500 0.15800 500 500 500 0.0 0.0 1 -90 90
114 116 0.00500 0.05900 0.08200 500 500 500 0.0 0.0 1 -90 90
115 116 0.00200 0.01700 0.03600 500 500 500 0.0 0.0 1 -90 90
115 121 0.00600 0.04900 0.10300 500 500 500 0.0 0.0 1 -90 90
115 121 0.00600 0.04900 0.10300 500 500 500 0.0 0.0 1 -90 90
115 124 0.00700 0.05200 0.10900 500 500 500 0.0 0.0 1 -90 90
116 117 0.00300 0.02600 0.05500 500 500 500 0.0 0.0 1 -90 90
116 119 0.00300 0.02300 0.04900 500 500 500 0.0 0.0 1 -90 90
117 118 0.00200 0.01400 0.03000 500 500 500 0.0 0.0 1 -90 90
117 122 0.01400 0.10500 0.22100 500 500 500 0.0 0.0 1 -90 90
118 121 0.00300 0.02600 0.05500 500 500 500 0.0 0.0 1 -90 90
118 121 0.00300 0.02600 0.05500 500 500 500 0.0 0.0 1 -90 90
119 120 0.00500 0.04000 0.08300 500 500 500 0.0 0.0 1 -90 90
119 120 0.00500 0.04000 0.08300 500 500 500 0.0 0.0 1 -90 90
120 123 0.00300 0.02200 0.04600 500 500 500 0.0 0.0 1 -90 90
120 123 0.00300 0.02200 0.04600 500 500 500 0.0 0.0 1 -90 90
121 122 0.00900 0.06800 0.14200 500 500 500 0.0 0.0 1 -90 90
123 217 0.01000 0.07400 0.15500 500 500 500 0.0 0.0 1 -90 90
201 202 0.00300 0.01400 0.46100 175 175 175 0.0 0.0 1 -90 90
201 203 0.05500 0.21100 0.05700 175 175 175 0.0 0.0 1 -90 90
201 205 0.02200 0.08500 0.02300 175 175 175 0.0 0.0 1 -90 90
202 204 0.03300 0.12700 0.03400 175 175 175 0.0 0.0 1 -90 90
202 206 0.05000 0.19200 0.05200 175 175 175 0.0 0.0 1 -90 90
203 209 0.03100 0.11900 0.03200 175 175 175 0.0 0.0 1 -90 90
203 224 0.00200 0.08400 0.00000 400 400 400 1.015 0.0 1 -90 90
204 209 0.02700 0.10400 0.02800 175 175 175 0.0 0.0 1 -90 90
205 210 0.02300 0.08800 0.02400 175 175 175 0.0 0.0 1 -90 90
206 210 0.01400 0.06100 2.45900 175 175 175 0.0 0.0 1 -90 90
207 208 0.01600 0.06100 0.01700 175 175 175 0.0 0.0 1 -90 90
208 209 0.04300 0.16500 0.04500 175 175 175 0.0 0.0 1 -90 90
208 210 0.04300 0.16500 0.04500 175 175 175 0.0 0.0 1 -90 90
209 211 0.00200 0.08400 0.00000 400 400 400 1.03 0.0 1 -90 90
209 212 0.00200 0.08400 0.00000 400 400 400 1.03 0.0 1 -90 90
210 211 0.00200 0.08400 0.00000 400 400 400 1.015 0.0 1 -90 90
210 212 0.00200 0.08400 0.00000 400 400 400 1.015 0.0 1 -90 90
211 213 0.00600 0.04800 0.10000 500 500 500 0.0 0.0 1 -90 90
211 214 0.00500 0.04200 0.08800 500 500 500 0.0 0.0 1 -90 90
212 213 0.00600 0.04800 0.10000 500 500 500 0.0 0.0 1 -90 90
212 223 0.01200 0.09700 0.20300 500 500 500 0.0 0.0 1 -90 90
213 223 0.01100 0.08700 0.18200 500 500 500 0.0 0.0 1 -90 90
214 216 0.00500 0.05900 0.08200 500 500 500 0.0 0.0 1 -90 90
215 216 0.00200 0.01700 0.03600 500 500 500 0.0 0.0 1 -90 90
215 221 0.00600 0.04900 0.10300 500 500 500 0.0 0.0 1 -90 90
215 221 0.00600 0.04900 0.10300 500 500 500 0.0 0.0 1 -90 90
215 224 0.00700 0.05200 0.10900 500 500 500 0.0 0.0 1 -90 90
216 217 0.00300 0.02600 0.05500 500 500 500 0.0 0.0 1 -90 90
216 219 0.00300 0.02300 0.04900 500 500 500 0.0 0.0 1 -90 90
217 218 0.00200 0.01400 0.03000 500 500 500 0.0 0.0 1 -90 90
217 222 0.01400 0.10500 0.22100 500 500 500 0.0 0.0 1 -90 90
218 221 0.00300 0.02600 0.05500 500 500 500 0.0 0.0 1 -90 90
218 221 0.00300 0.02600 0.05500 500 500 500 0.0 0.0 1 -90 90
219 220 0.00500 0.04000 0.08300 500 500 500 0.0 0.0 1 -90 90
219 220 0.00500 0.04000 0.08300 500 500 500 0.0 0.0 1 -90 90
220 223 0.00300 0.02200 0.04600 500 500 500 0.0 0.0 1 -90 90
220 223 0.00300 0.02200 0.04600 500 500 500 0.0 0.0 1 -90 90
221 222 0.00900 0.06800 0.14200 500 500 500 0.0 0.0 1 -90 90
301 302 0.00300 0.01400 0.46100 175 175 175 0.0 0.0 1 -90 90
301 303 0.05500 0.21100 0.05700 175 175 175 0.0 0.0 1 -90 90
301 305 0.02200 0.08500 0.02300 175 175 175 0.0 0.0 1 -90 90
302 304 0.03300 0.12700 0.03400 175 175 175 0.0 0.0 1 -90 90
302 306 0.05000 0.19200 0.05200 175 175 175 0.0 0.0 1 -90 90
303 309 0.03100 0.11900 0.03200 175 175 175 0.0 0.0 1 -90 90
303 324 0.00200 0.08400 0.00000 400 400 400 1.015 0.0 1 -90 90
304 309 0.02700 0.10400 0.02800 175 175 175 0.0 0.0 1 -90 90
305 310 0.02300 0.08800 0.02400 175 175 175 0.0 0.0 1 -90 90
306 310 0.01400 0.06100 2.45900 175 175 175 0.0 0.0 1 -90 90
307 308 0.01600 0.06100 0.01700 175 175 175 0.0 0.0 1 -90 90
308 309 0.04300 0.16500 0.04500 175 175 175 0.0 0.0 1 -90 90
308 310 0.04300 0.16500 0.04500 175 175 175 0.0 0.0 1 -90 90
309 311 0.00200 0.08400 0.00000 400 400 400 1.03 0.0 1 -90 90
309 312 0.00200 0.08400 0.00000 400 400 400 1.03 0.0 1 -90 90
310 311 0.00200 0.08400 0.00000 400 400 400 1.015 0.0 1 -90 90
310 312 0.00200 0.08400 0.00000 400 400 400 1.015 0.0 1 -90 90
311 313 0.00600 0.04800 0.10000 500 500 500 0.0 0.0 1 -90 90
311 314 0.00500 0.04200 0.08800 500 500 500 0.0 0.0 1 -90 90
312 313 0.00600 0.04800 0.10000 500 500 500 0.0 0.0 1 -90 90
312 323 0.01200 0.09700 0.20300 500 500 500 0.0 0.0 1 -90 90
313 323 0.01100 0.08700 0.18200 500 500 500 0.0 0.0 1 -90 90
314 316 0.00500 0.05900 0.08200 500 500 500 0.0 0.0 1 -90 90
315 316 0.00200 0.01700 0.03600 500 500 500 0.0 0.0 1 -90 90
315 321 0.00600 0.04900 0.10300 500 500 500 0.0 0.0 1 -90 90
315 321 0.00600 0.04900 0.10300 500 500 500 0.0 0.0 1 -90 90
315 324 0.00700 0.05200 0.10900 500 500 500 0.0 0.0 1 -90 90
316 317 0.00300 0.02600 0.05500 500 500 500 0.0 0.0 1 -90 90
316 319 0.00300 0.02300 0.04900 500 500 500 0.0 0.0 1 -90 90
317 318 0.00200 0.01400 0.03000 500 500 500 0.0 0.0 1 -90 90
317 322 0.01400 0.10500 0.22100 500 500 500 0.0 0.0 1 -90 90
318 321 0.00300 0.02600 0.05500 500 500 500 0.0 0.0 1 -90 90
318 321 0.00300 0.02600 0.05500 500 500 500 0.0 0.0 1 -90 90
319 320 0.00500 0.04000 0.08300 500 500 500 0.0 0.0 1 -90 90
319 320 0.00500 0.04000 0.08300 500 500 500 0.0 0.0 1 -90 90
320 323 0.00300 0.02200 0.04600 500 500 500 0.0 0.0 1 -90 90
320 323 0.00300 0.02200 0.04600 500 500 500 0.0 0.0 1 -90 90
321 322 0.00900 0.06800 0.14200 500 500 500 0.0 0.0 1 -90 90
325 121 0.01200 0.09700 0.20300 500 500 500 0.0 0.0 1 -90 90
318 223 0.01300 0.10400 0.21800 500 500 500 0.0 0.0 1 -90 90
323 325 0.00000 0.00900 0.00000 722 722 722 1.0 0.0 1 -90 90
];
%%----- OPF Data -----%%
%% generator cost data
% 1 startup shutdown n x1 y1 ... xn yn
% 2 startup shutdown n c(n-1) ... c0
mpc.gencost = [
1 51.74700 51.74700 4 8.00000 1085.77625 12.00000 1477.23196 16.00000 1869.51562 20.00000 2298.06357
1 51.74700 51.74700 4 8.00000 1085.77625 12.00000 1477.23196 16.00000 1869.51562 20.00000 2298.06357
1 11172.01435 11172.01435 4 30.00000 841.57942 45.33333 1059.17805 60.66667 1319.40176 76.00000 1596.51343
1 11172.01435 11172.01435 4 30.00000 841.57942 45.33333 1059.17805 60.66667 1319.40176 76.00000 1596.51343
1 51.74700 51.74700 4 8.00000 1212.03893 12.00000 1567.93410 16.00000 1946.59795 20.00000 2344.92565
1 51.74700 51.74700 4 8.00000 1212.03893 12.00000 1567.93410 16.00000 1946.59795 20.00000 2344.92565
1 11172.01435 11172.01435 4 30.00000 735.09774 45.33333 1018.20610 60.66667 1337.84562 76.00000 1683.09260
1 11172.01435 11172.01435 4 30.00000 735.09774 45.33333 1018.20610 60.66667 1337.84562 76.00000 1683.09260
1 28046.68102 28046.68102 4 170.00000 4772.49548 231.66667 6203.57553 293.33333 7855.66994 355.00000 9738.36720
1 5665.23443 5665.23443 4 22.00000 1122.43477 33.00000 1417.43201 44.00000 1742.48912 55.00000 2075.88432
1 5665.23443 5665.23443 4 22.00000 1122.43477 33.00000 1417.43201 44.00000 1742.48912 55.00000 2075.88432
1 5665.23443 5665.23443 4 22.00000 1122.43477 33.00000 1417.43201 44.00000 1742.48912 55.00000 2075.88432
1 5665.23443 5665.23443 4 22.00000 1122.43477 33.00000 1417.43201 44.00000 1742.48912 55.00000 2075.88432
1 703.75920 703.75920 4 5.00000 897.29298 7.33333 1187.80064 9.66667 1479.58817 12.00000 1791.41904
1 703.75920 703.75920 4 5.00000 897.29298 7.33333 1187.80064 9.66667 1479.58817 12.00000 1791.41904
1 22784.79562 22784.79562 4 62.00000 1500.19723 93.00000 2132.59734 124.00000 2829.87580 155.00000 3668.44490
1 22784.79562 22784.79562 4 62.00000 1735.06998 93.00000 2345.31970 124.00000 3011.01092 155.00000 3751.14842
1 28046.68102 28046.68102 4 170.00000 4795.62444 231.66667 6187.87116 293.33333 7899.41412 355.00000 9901.24820
1 22784.79562 22784.79562 4 62.00000 1437.41596 93.00000 2039.73610 124.00000 2751.75964 155.00000 3775.85462
1 36749.81356 36749.81356 4 140.00000 3582.87481 210.00000 4981.72313 280.00000 6497.03117 350.00000 8137.67767
1 5665.23443 5665.23443 4 22.00000 1088.22724 33.00000 1377.15264 44.00000 1704.98911 55.00000 2046.97895
1 5665.23443 5665.23443 4 22.00000 1088.22724 33.00000 1377.15264 44.00000 1704.98911 55.00000 2046.97895
1 5665.23443 5665.23443 4 22.00000 1088.22724 33.00000 1377.15264 44.00000 1704.98911 55.00000 2046.97895
1 51.74700 51.74700 4 8.00000 1157.22851 12.00000 1487.12598 16.00000 1822.73633 20.00000 2269.08525
1 51.74700 51.74700 4 8.00000 1157.22851 12.00000 1487.12598 16.00000 1822.73633 20.00000 2269.08525
1 11172.01435 11172.01435 4 30.00000 823.75848 45.33333 1163.94880 60.66667 1523.42575 76.00000 1918.39660
1 51.74700 51.74700 4 8.00000 1131.23082 12.00000 1455.62241 16.00000 1805.10095 20.00000 2196.47386
1 51.74700 51.74700 4 8.00000 1131.23082 12.00000 1455.62241 16.00000 1805.10095 20.00000 2196.47386
1 11172.01435 11172.01435 4 30.00000 751.26977 45.33333 1075.05834 60.66667 1401.47249 76.00000 1819.68454
1 11172.01435 11172.01435 4 30.00000 751.26977 45.33333 1075.05834 60.66667 1401.47249 76.00000 1819.68454
1 5665.23443 5665.23443 4 22.00000 1116.10638 33.00000 1492.56031 44.00000 1897.96238 55.00000 2366.39182
1 5665.23443 5665.23443 4 22.00000 1116.10638 33.00000 1492.56031 44.00000 1897.96238 55.00000 2366.39182
1 28046.68102 28046.68102 4 170.00000 5170.31357 231.66667 6688.64875 293.33333 8361.59810 355.00000 10458.83751
1 5665.23443 5665.23443 4 22.00000 1122.43477 33.00000 1417.43201 44.00000 1742.48912 55.00000 2075.88432
1 5665.23443 5665.23443 4 22.00000 1122.43477 33.00000 1417.43201 44.00000 1742.48912 55.00000 2075.88432
1 5665.23443 5665.23443 4 22.00000 1216.84757 33.00000 1501.96739 44.00000 1800.72745 55.00000 2160.80453
1 5665.23443 5665.23443 4 22.00000 1216.84757 33.00000 1501.96739 44.00000 1800.72745 55.00000 2160.80453
1 22784.79562 22784.79562 4 62.00000 1426.14416 93.00000 2001.92316 124.00000 2679.08278 155.00000 3412.47031
1 28046.68102 28046.68102 4 170.00000 7523.51994 231.66667 8815.08767 293.33333 10151.48151 355.00000 11987.19523
1 28046.68102 28046.68102 4 170.00000 4551.11830 231.66667 5977.40411 293.33333 7600.73310 355.00000 9828.37578
1 22784.79562 22784.79562 4 62.00000 1422.99854 93.00000 2013.06389 124.00000 2623.44468 155.00000 3256.43459
1 22784.79562 22784.79562 4 62.00000 1422.99854 93.00000 2013.06389 124.00000 2623.44468 155.00000 3256.43459
1 36749.81356 36749.81356 4 140.00000 3323.31912 210.00000 4643.59043 280.00000 6258.48853 350.00000 7981.70748
1 5665.23443 5665.23443 4 22.00000 1692.75992 33.00000 2103.03655 44.00000 2540.25162 55.00000 2996.75119
1 5665.23443 5665.23443 4 22.00000 1692.75992 33.00000 2103.03655 44.00000 2540.25162 55.00000 2996.75119
1 5665.23443 5665.23443 4 22.00000 1692.75992 33.00000 2103.03655 44.00000 2540.25162 55.00000 2996.75119
1 51.74700 51.74700 4 8.00000 1208.23035 12.00000 1557.25352 16.00000 1956.03660 20.00000 2377.50557
1 51.74700 51.74700 4 8.00000 1208.23035 12.00000 1557.25352 16.00000 1956.03660 20.00000 2377.50557
1 5665.23443 5665.23443 4 22.00000 1119.44162 33.00000 1432.61161 44.00000 1754.76108 55.00000 2235.93283
1 5665.23443 5665.23443 4 22.00000 1119.44162 33.00000 1432.61161 44.00000 1754.76108 55.00000 2235.93283
1 51.74700 51.74700 4 8.00000 1208.23035 12.00000 1557.25352 16.00000 1956.03660 20.00000 2377.50557
1 51.74700 51.74700 4 8.00000 1208.23035 12.00000 1557.25352 16.00000 1956.03660 20.00000 2377.50557
1 5665.23443 5665.23443 4 22.00000 1316.56254 33.00000 1688.27018 44.00000 2110.47669 55.00000 2535.46257
1 5665.23443 5665.23443 4 22.00000 1316.56254 33.00000 1688.27018 44.00000 2110.47669 55.00000 2535.46257
1 5665.23443 5665.23443 4 22.00000 1141.93307 33.00000 1448.77467 44.00000 1770.19723 55.00000 2160.41970
1 5665.23443 5665.23443 4 22.00000 1141.93307 33.00000 1448.77467 44.00000 1770.19723 55.00000 2160.41970
1 28046.68102 28046.68102 4 170.00000 5243.00459 231.66667 6213.11865 293.33333 7863.05566 355.00000 9944.47408
1 703.75920 703.75920 4 5.00000 745.67427 7.33333 921.69342 9.66667 1155.95898 12.00000 1445.52485
1 703.75920 703.75920 4 5.00000 745.67427 7.33333 921.69342 9.66667 1155.95898 12.00000 1445.52485
1 703.75920 703.75920 4 5.00000 745.67427 7.33333 921.69342 9.66667 1155.95898 12.00000 1445.52485
1 703.75920 703.75920 4 5.00000 745.67427 7.33333 921.69342 9.66667 1155.95898 12.00000 1445.52485
1 703.75920 703.75920 4 5.00000 745.67427 7.33333 921.69342 9.66667 1155.95898 12.00000 1445.52485
1 5665.23443 5665.23443 4 22.00000 884.43584 33.00000 1174.85782 44.00000 1470.71025 55.00000 1821.12370
1 5665.23443 5665.23443 4 22.00000 884.43584 33.00000 1174.85782 44.00000 1470.71025 55.00000 1821.12370
1 5665.23443 5665.23443 4 22.00000 884.43584 33.00000 1174.85782 44.00000 1470.71025 55.00000 1821.12370
1 22784.79562 22784.79562 4 62.00000 1552.62418 93.00000 2207.24021 124.00000 2867.16447 155.00000 3712.68014
1 28046.68102 28046.68102 4 170.00000 5254.89948 231.66667 6910.34987 293.33333 8592.40827 355.00000 10536.71149
1 28046.68102 28046.68102 4 170.00000 4775.79962 231.66667 6177.63481 293.33333 7775.31462 355.00000 9868.71865
1 5665.23443 5665.23443 4 22.00000 1031.69929 33.00000 1288.38408 44.00000 1579.87505 55.00000 1886.71665
1 5665.23443 5665.23443 4 22.00000 1031.69929 33.00000 1288.38408 44.00000 1579.87505 55.00000 1886.71665
1 28046.68102 28046.68102 4 170.00000 4877.56703 231.66667 6507.36825 293.33333 8374.48424 355.00000 10331.01276
1 28046.68102 28046.68102 4 170.00000 4877.56703 231.66667 6507.36825 293.33333 8374.48424 355.00000 10331.01276
1 0.00000 0.00000 4 0.00000 0 0.33333 0 0.66667 0 1.00000 0
1 63999.82230 63999.82230 4 396.00000 3208.98600 397.33333 3219.79067 398.66667 3230.59533 400.00000 3241.40000
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 0.33333 0 0.66667 0 1.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 0.33333 0 0.66667 0 1.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
1 0.00000 0.00000 4 0.00000 0 17.20000 0 34.40000 0 51.60000 0
1 0.00000 0.00000 4 0.00000 0 17.20000 0 34.40000 0 51.60000 0
1 0.00000 0.00000 4 0.00000 0 17.20000 0 34.40000 0 51.60000 0
1 0.00000 0.00000 4 0.00000 0 31.70000 0 63.40000 0 95.10000 0
1 0.00000 0.00000 4 0.00000 0 30.90000 0 61.80000 0 92.70000 0
1 0.00000 0.00000 4 0.00000 0 17.20000 0 34.40000 0 51.60000 0
1 0.00000 0.00000 4 0.00000 0 31.10000 0 62.20000 0 93.30000 0
1 0.00000 0.00000 4 0.00000 0 17.23333 0 34.46667 0 51.70000 0
1 0.00000 0.00000 4 0.00000 0 16.56667 0 33.13333 0 49.70000 0
1 0.00000 0.00000 4 0.00000 0 31.36667 0 62.73333 0 94.10000 0
1 0.00000 0.00000 4 0.00000 0 17.20000 0 34.40000 0 51.60000 0
1 0.00000 0.00000 4 0.00000 0 17.20000 0 34.40000 0 51.60000 0
1 0.00000 0.00000 4 0.00000 0 17.00000 0 34.00000 0 51.00000 0
1 0.00000 0.00000 4 0.00000 0 31.20000 0 62.40000 0 93.60000 0
1 0.00000 0.00000 4 0.00000 0 62.73333 0 125.46667 0 188.20000 0
1 0.00000 0.00000 4 0.00000 0 41.70000 0 83.40000 0 125.10000 0
1 0.00000 0.00000 4 0.00000 0 8.53333 0 17.06667 0 25.60000 0
1 0.00000 0.00000 4 0.00000 0 8.63333 0 17.26667 0 25.90000 0
1 0.00000 0.00000 4 0.00000 0 8.43333 0 16.86667 0 25.30000 0
1 0.00000 0.00000 4 0.00000 0 8.93333 0 17.86667 0 26.80000 0
1 10000.00000 0.00000 4 30.00000 0.00000 66.00000 0.00000 120.00000 0.00000 160.00000 0.00000
1 0.00000 0.00000 4 0.00000 0 8.90000 0 17.80000 0 26.70000 0
1 0.00000 0.00000 4 0.00000 0 8.73333 0 17.46667 0 26.20000 0
1 0.00000 0.00000 4 0.00000 0 8.60000 0 17.20000 0 25.80000 0
1 0.00000 0.00000 4 0.00000 0 20.50000 0 41.00000 0 61.50000 0
1 0.00000 0.00000 4 0.00000 0 22.20000 0 44.40000 0 66.60000 0
1 0.00000 0.00000 4 0.00000 0 33.63333 0 67.26667 0 100.90000 0
1 0.00000 0.00000 4 0.00000 0 33.90000 0 67.80000 0 101.70000 0
1 0.00000 0.00000 4 0.00000 0 21.03333 0 42.06667 0 63.10000 0
1 0.00000 0.00000 4 0.00000 0 21.80000 0 43.60000 0 65.40000 0
1 0.00000 0.00000 4 0.00000 0 22.33333 0 44.66667 0 67.00000 0
1 0.00000 0.00000 4 0.00000 0 21.60000 0 43.20000 0 64.80000 0
1 0.00000 0.00000 4 0.00000 0 21.26667 0 42.53333 0 63.80000 0
1 0.00000 0.00000 4 0.00000 0 21.36667 0 42.73333 0 64.10000 0
1 0.00000 0.00000 4 0.00000 0 22.20000 0 44.40000 0 66.60000 0
1 0.00000 0.00000 4 0.00000 0 20.80000 0 41.60000 0 62.40000 0
1 0.00000 0.00000 4 0.00000 0 22.30000 0 44.60000 0 66.90000 0
1 0.00000 0.00000 4 0.00000 0 21.73333 0 43.46667 0 65.20000 0
1 0.00000 0.00000 4 0.00000 0 9.26667 0 18.53333 0 27.80000 0
1 0.00000 0.00000 4 0.00000 0 9.10000 0 18.20000 0 27.30000 0
1 0.00000 0.00000 4 0.00000 0 9.00000 0 18.00000 0 27.00000 0
1 0.00000 0.00000 4 0.00000 0 9.43333 0 18.86667 0 28.30000 0
1 0.00000 0.00000 4 0.00000 0 9.06667 0 18.13333 0 27.20000 0
1 0.00000 0.00000 4 0.00000 0 9.00000 0 18.00000 0 27.00000 0
1 0.00000 0.00000 4 0.00000 0 9.40000 0 18.80000 0 28.20000 0
1 0.00000 0.00000 4 0.00000 0 3.10000 0 6.20000 0 9.30000 0
1 0.00000 0.00000 4 0.00000 0 3.23333 0 6.46667 0 9.70000 0
1 0.00000 0.00000 4 0.00000 0 3.13333 0 6.26667 0 9.40000 0
1 0.00000 0.00000 4 0.00000 0 3.03333 0 6.06667 0 9.10000 0
1 0.00000 0.00000 4 0.00000 0 3.03333 0 6.06667 0 9.10000 0
1 0.00000 0.00000 4 0.00000 0 3.23333 0 6.46667 0 9.70000 0
1 0.00000 0.00000 4 0.00000 0 3.13333 0 6.26667 0 9.40000 0
1 0.00000 0.00000 4 0.00000 0 3.93333 0 7.86667 0 11.80000 0
1 0.00000 0.00000 4 0.00000 0 3.73333 0 7.46667 0 11.20000 0
1 0.00000 0.00000 4 0.00000 0 3.43333 0 6.86667 0 10.30000 0
1 0.00000 0.00000 4 0.00000 0 1.50000 0 3.00000 0 4.50000 0
1 0.00000 0.00000 4 0.00000 0 4.40000 0 8.80000 0 13.20000 0
1 0.00000 0.00000 4 0.00000 0 49.43333 0 98.86667 0 148.30000 0
1 0.00000 0.00000 4 0.00000 0 266.36667 0 532.73333 0 799.10000 0
1 0.00000 0.00000 4 0.00000 0 282.33333 0 564.66667 0 847.00000 0
1 0.00000 0.00000 4 0.00000 0 237.83333 0 475.66667 0 713.50000 0
1 0.00000 0.00000 4 0.00000 0 16.66667 0 33.33333 0 50.00000 0
];
% bus names
%column_names% name
mpc.bus_name = {
'ABEL';
'ADAMS';
'ADLER';
'AGRICOLA';
'AIKEN';
'ALBER';
'ALDER';
'ALGER';
'ALI';
'ALLEN';
'ANNA';
'ARCHER';
'ARNE';
'ARNOLD';
'ARTHUR';
'ASSER';
'ASTON';
'ASTOR';
'ATTAR';
'ATTILA';
'ATTLEE';
'AUBREY';
'AUSTEN';
'AVERY';
'BACH';
'BACON';
'BAFFIN';
'BAILEY';
'BAIN';
'BAJER';
'BAKER';
'BALCH';
'BALZAC';
'BANKS';
'BARDEEN';
'BARKLA';
'BARLOW';
'BARRY';
'BARTON';
'BASOV';
'BATES';
'BAYLE';
'BEDE';
'BEETHOVEN';
'BEHRING';
'BELL';
'BLOCH';
'BORDET';
'CABELL';
'CABOT';
'CAESAR';
'CAINE';
'CALVIN';
'CAMUS';
'CAREW';
'CARREL';
'CARTER';
'CARUSO';
'CARY';
'CAXTON';
'CECIL';
'CHAIN';
'CHASE';
'CHIFA';
'CHUHSI';
'CLARK';
'CLAY';
'CLIVE';
'COBB';
'COLE';
'COMTE';
'CURIE';
'CURTISS';
};
% generator names types and fuels
%column_names% name type fuel
mpc.gen_name = {
'101_CT_1' 'CT' 'Oil';
'101_CT_2' 'CT' 'Oil';
'101_STEAM_3' 'STEAM' 'Coal';
'101_STEAM_4' 'STEAM' 'Coal';
'102_CT_1' 'CT' 'Oil';
'102_CT_2' 'CT' 'Oil';
'102_STEAM_3' 'STEAM' 'Coal';
'102_STEAM_4' 'STEAM' 'Coal';
'107_CC_1' 'CC' 'NG';
'113_CT_1' 'CT' 'NG';
'113_CT_2' 'CT' 'NG';
'113_CT_3' 'CT' 'NG';
'113_CT_4' 'CT' 'NG';
'115_STEAM_1' 'STEAM' 'Oil';
'115_STEAM_2' 'STEAM' 'Oil';
'115_STEAM_3' 'STEAM' 'Coal';
'116_STEAM_1' 'STEAM' 'Coal';
'118_CC_1' 'CC' 'NG';
'123_STEAM_2' 'STEAM' 'Coal';
'123_STEAM_3' 'STEAM' 'Coal';
'123_CT_1' 'CT' 'NG';
'123_CT_4' 'CT' 'NG';
'123_CT_5' 'CT' 'NG';
'201_CT_1' 'CT' 'Oil';
'201_CT_2' 'CT' 'Oil';
'201_STEAM_3' 'STEAM' 'Coal';
'202_CT_1' 'CT' 'Oil';
'202_CT_2' 'CT' 'Oil';
'202_STEAM_3' 'STEAM' 'Coal';
'202_STEAM_4' 'STEAM' 'Coal';
'207_CT_1' 'CT' 'NG';
'207_CT_2' 'CT' 'NG';
'213_CC_3' 'CC' 'NG';
'213_CT_1' 'CT' 'NG';
'213_CT_2' 'CT' 'NG';
'215_CT_4' 'CT' 'NG';
'215_CT_5' 'CT' 'NG';
'216_STEAM_1' 'STEAM' 'Coal';
'218_CC_1' 'CC' 'NG';
'221_CC_1' 'CC' 'NG';
'223_STEAM_1' 'STEAM' 'Coal';
'223_STEAM_2' 'STEAM' 'Coal';
'223_STEAM_3' 'STEAM' 'Coal';
'223_CT_4' 'CT' 'NG';
'223_CT_5' 'CT' 'NG';
'223_CT_6' 'CT' 'NG';
'301_CT_1' 'CT' 'Oil';
'301_CT_2' 'CT' 'Oil';
'301_CT_3' 'CT' 'NG';
'301_CT_4' 'CT' 'NG';
'302_CT_1' 'CT' 'Oil';
'302_CT_2' 'CT' 'Oil';
'302_CT_3' 'CT' 'NG';
'302_CT_4' 'CT' 'NG';
'307_CT_1' 'CT' 'NG';
'307_CT_2' 'CT' 'NG';
'313_CC_1' 'CC' 'NG';
'315_STEAM_1' 'STEAM' 'Oil';
'315_STEAM_2' 'STEAM' 'Oil';
'315_STEAM_3' 'STEAM' 'Oil';
'315_STEAM_4' 'STEAM' 'Oil';
'315_STEAM_5' 'STEAM' 'Oil';
'315_CT_6' 'CT' 'NG';
'315_CT_7' 'CT' 'NG';
'315_CT_8' 'CT' 'NG';
'316_STEAM_1' 'STEAM' 'Coal';
'318_CC_1' 'CC' 'NG';
'321_CC_1' 'CC' 'NG';
'322_CT_5' 'CT' 'NG';
'322_CT_6' 'CT' 'NG';
'323_CC_1' 'CC' 'NG';
'323_CC_2' 'CC' 'NG';
'114_SYNC_COND_1' 'SYNC_COND' 'Sync_Cond';
'121_NUCLEAR_1' 'NUCLEAR' 'Nuclear';
'122_HYDRO_1' 'HYDRO' 'Hydro';
'122_HYDRO_2' 'HYDRO' 'Hydro';
'122_HYDRO_3' 'HYDRO' 'Hydro';
'122_HYDRO_4' 'HYDRO' 'Hydro';
'122_HYDRO_5' 'HYDRO' 'Hydro';
'122_HYDRO_6' 'HYDRO' 'Hydro';
'201_HYDRO_4' 'HYDRO' 'Hydro';
'214_SYNC_COND_1' 'SYNC_COND' 'Sync_Cond';
'215_HYDRO_1' 'HYDRO' 'Hydro';
'215_HYDRO_2' 'HYDRO' 'Hydro';
'215_HYDRO_3' 'HYDRO' 'Hydro';
'222_HYDRO_1' 'HYDRO' 'Hydro';
'222_HYDRO_2' 'HYDRO' 'Hydro';
'222_HYDRO_3' 'HYDRO' 'Hydro';
'222_HYDRO_4' 'HYDRO' 'Hydro';
'222_HYDRO_5' 'HYDRO' 'Hydro';
'222_HYDRO_6' 'HYDRO' 'Hydro';
'314_SYNC_COND_1' 'SYNC_COND' 'Sync_Cond';
'322_HYDRO_1' 'HYDRO' 'Hydro';
'322_HYDRO_2' 'HYDRO' 'Hydro';
'322_HYDRO_3' 'HYDRO' 'Hydro';
'322_HYDRO_4' 'HYDRO' 'Hydro';
'320_PV_1' 'PV' 'Solar';
'314_PV_1' 'PV' 'Solar';
'314_PV_2' 'PV' 'Solar';
'313_PV_1' 'PV' 'Solar';
'314_PV_3' 'PV' 'Solar';
'314_PV_4' 'PV' 'Solar';
'313_PV_2' 'PV' 'Solar';
'310_PV_1' 'PV' 'Solar';
'324_PV_1' 'PV' 'Solar';
'312_PV_1' 'PV' 'Solar';
'310_PV_2' 'PV' 'Solar';
'324_PV_2' 'PV' 'Solar';
'324_PV_3' 'PV' 'Solar';
'113_PV_1' 'PV' 'Solar';
'319_PV_1' 'PV' 'Solar';
'215_PV_1' 'PV' 'Solar';
'102_PV_1' 'PV' 'Solar';
'101_PV_1' 'PV' 'Solar';
'102_PV_2' 'PV' 'Solar';
'104_PV_1' 'PV' 'Solar';
'212_CSP_1' 'CSP' 'Solar';
'101_PV_2' 'PV' 'Solar';
'101_PV_3' 'PV' 'Solar';
'101_PV_4' 'PV' 'Solar';
'103_PV_1' 'PV' 'Solar';
'119_PV_1' 'PV' 'Solar';
'308_RTPV_1' 'RTPV' 'Solar';
'313_RTPV_1' 'RTPV' 'Solar';
'313_RTPV_2' 'RTPV' 'Solar';
'313_RTPV_3' 'RTPV' 'Solar';
'313_RTPV_4' 'RTPV' 'Solar';
'313_RTPV_5' 'RTPV' 'Solar';
'313_RTPV_6' 'RTPV' 'Solar';
'313_RTPV_7' 'RTPV' 'Solar';
'313_RTPV_8' 'RTPV' 'Solar';
'313_RTPV_9' 'RTPV' 'Solar';
'313_RTPV_10' 'RTPV' 'Solar';
'313_RTPV_11' 'RTPV' 'Solar';
'313_RTPV_12' 'RTPV' 'Solar';
'320_RTPV_1' 'RTPV' 'Solar';
'320_RTPV_2' 'RTPV' 'Solar';
'320_RTPV_3' 'RTPV' 'Solar';
'313_RTPV_13' 'RTPV' 'Solar';
'320_RTPV_4' 'RTPV' 'Solar';
'320_RTPV_5' 'RTPV' 'Solar';
'118_RTPV_1' 'RTPV' 'Solar';
'118_RTPV_2' 'RTPV' 'Solar';
'118_RTPV_3' 'RTPV' 'Solar';
'118_RTPV_4' 'RTPV' 'Solar';
'118_RTPV_5' 'RTPV' 'Solar';
'118_RTPV_6' 'RTPV' 'Solar';
'320_RTPV_6' 'RTPV' 'Solar';
'118_RTPV_7' 'RTPV' 'Solar';
'118_RTPV_8' 'RTPV' 'Solar';
'118_RTPV_9' 'RTPV' 'Solar';
'118_RTPV_10' 'RTPV' 'Solar';
'213_RTPV_1' 'RTPV' 'Solar';
'309_WIND_1' 'WIND' 'Wind';
'317_WIND_1' 'WIND' 'Wind';
'303_WIND_1' 'WIND' 'Wind';
'122_WIND_1' 'WIND' 'Wind';
'313_STORAGE_1' 'STORAGE' 'Storage';
};
%%----- DC Line Data -----%%
% F_BUS T_BUS BR_STATUS PF PT QF QT VF VT PMIN PMAX QMINF QMAXF QMINT QMAXT LOSS0 LOSS1 MU_PMIN MU_PMAX MU_QMINF MU_QMAXF MU_QMINT MU_QMAXT
mpc.dcline = [
113 316 1 0 0 0 0 1 1 -100 100 -9999 9999 -9999 9999 0 0 0 0 0 0 0 0
];
================================================
FILE: docs/src/tutorials/tutorials_data/TestGENCLS.dyr
================================================
101 'GENROE' 1 8.000000 0.030000 0.400000 0.050000 6.500000 0.000000 1.800000
1.700000 0.300000 0.550000 0.250000 0.200000 0.039200 0.267200 /
101 'ESST1A' 1 1 1 0.01 99 -99 1 10 1 1 200 0 4 -4 4 -4 0 0 1 0 3 /
102 'GENCLS' 1 0.0 0.0 /
103 'GENCLS' 1 3.1 2.0 /
================================================
FILE: docs/src/tutorials/tutorials_data/case5.m
================================================
% NESTA v0.6.0
% used in tests of,
% - non-contiguous bus ids
% - tranformer orentation swapping
% - dual values
%
function mpc = nesta_case5_pjm
mpc.version = '2';
mpc.baseMVA = 100.0;
%% area data
% area refbus
mpc.areas = [
1 4;
];
%% bus data
% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin
mpc.bus = [
1 2 0.0 0.0 0.0 0.0 1 1.00000 2.80377 230.0 1 1.10000 0.90000;
2 1 300.0 98.61 0.0 0.0 1 1.08407 -0.73465 230.0 1 1.10000 0.90000;
3 2 300.0 98.61 0.0 0.0 1 1.00000 -0.55972 230.0 1 1.10000 0.90000;
4 3 400.0 131.47 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000;
10 2 0.0 0.0 0.0 0.0 1 1.00000 3.59033 230.0 1 1.10000 0.90000;
];
%% generator data
% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
mpc.gen = [
1 40.0 30.0 30.0 -30.0 1.07762 100.0 1 40.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
1 170.0 127.5 127.5 -127.5 1.07762 100.0 1 170.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
3 324.498 390.0 390.0 -390.0 1.1 100.0 1 520.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
4 0.0 -10.802 150.0 -150.0 1.06414 100.0 1 200.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
10 470.694 -165.039 450.0 -450.0 1.06907 100.0 1 600.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
];
%% generator cost data
% 2 startup shutdown n c(n-1) ... c0
mpc.gencost = [
2 0.0 0.0 3 0.000000 14.000000 0.000000;
2 0.0 0.0 3 0.000000 15.000000 0.000000;
2 0.0 0.0 3 0.000000 30.000000 0.000000;
2 0.0 0.0 3 0.000000 40.000000 0.000000;
2 0.0 0.0 3 0.000000 10.000000 0.000000;
];
%% branch data
% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax
mpc.branch = [
1 2 0.00281 0.0281 0.00712 400.0 400.0 400.0 0.0 0.0 1 -30.0 30.0;
1 4 0.00304 0.0304 0.00658 426 426 426 0.0 0.0 1 -30.0 30.0;
1 10 0.00064 0.0064 0.03126 426 426 426 0.0 0.0 1 -30.0 30.0;
2 3 0.00108 0.0108 0.01852 426 426 426 0.0 0.0 1 -30.0 30.0;
3 4 0.00297 0.0297 0.00674 426 426 426 1.05 1.0 1 -30.0 30.0;
4 3 0.00297 0.0297 0.00674 426 426 426 1.05 -1.0 1 -30.0 30.0;
4 10 0.00297 0.0297 0.00674 240.0 240.0 240.0 0.0 0.0 1 -30.0 30.0;
];
================================================
FILE: docs/src/tutorials/tutorials_data/case5_re.m
================================================
% NESTA v0.6.0
% extended to include renewable generators
% used in tests of,
% - non-contiguous bus ids
% - tranformer orentation swapping
% - dual values
%
function mpc = nesta_case5_pjm
mpc.version = '2';
mpc.baseMVA = 100.0;
%% area data
% area refbus
mpc.areas = [
1 4;
];
%% bus data
% bus_i type Pd Qd Gs Bs area Vm Va baseKV zone Vmax Vmin
mpc.bus = [
1 2 0.0 0.0 0.0 0.0 1 1.00000 2.80377 230.0 1 1.10000 0.90000;
2 1 300.0 98.61 0.0 0.0 1 1.08407 -0.73465 230.0 1 1.10000 0.90000;
3 2 300.0 98.61 0.0 0.0 1 1.00000 -0.55972 230.0 1 1.10000 0.90000;
4 3 400.0 131.47 0.0 0.0 1 1.00000 0.00000 230.0 1 1.10000 0.90000;
10 2 0.0 0.0 0.0 0.0 1 1.00000 3.59033 230.0 1 1.10000 0.90000;
];
%% generator data
% bus Pg Qg Qmax Qmin Vg mBase status Pmax Pmin Pc1 Pc2 Qc1min Qc1max Qc2min Qc2max ramp_agc ramp_10 ramp_30 ramp_q apf
mpc.gen = [
1 40.0 30.0 30.0 -30.0 1.07762 100.0 1 40.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
1 170.0 127.5 127.5 -127.5 1.07762 100.0 1 170.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
3 324.498 390.0 390.0 -390.0 1.1 100.0 1 520.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
4 0.0 -10.802 150.0 -150.0 1.06414 100.0 1 200.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
10 470.694 -165.039 450.0 -450.0 1.06907 100.0 1 600.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
3 0 0 0 0 1.1 100.0 1 60 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
10 0 0 0 0 1.06907 100.0 1 60 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0;
];
%% generator cost data
% 2 startup shutdown n c(n-1) ... c0
mpc.gencost = [
2 0.0 0.0 3 0.000000 14.000000 0.000000;
2 0.0 0.0 3 0.000000 15.000000 0.000000;
2 0.0 0.0 3 0.000000 30.000000 0.000000;
2 0.0 0.0 3 0.000000 40.000000 0.000000;
2 0.0 0.0 3 0.000000 10.000000 0.000000;
2 0.0 0.0 3 0.000000 0.000000 0.000000;
2 0.0 0.0 3 0.000000 0.000000 0.000000;
];
%% branch data
% fbus tbus r x b rateA rateB rateC ratio angle status angmin angmax
mpc.branch = [
1 2 0.00281 0.0281 0.00712 200.0 200.0 200.0 0.0 0.0 1 -30.0 30.0;
1 4 0.00304 0.0304 0.00658 200 200 200 0.0 0.0 1 -30.0 30.0;
1 10 0.00064 0.0064 0.03126 1000 1000 1000 0.0 0.0 1 -30.0 30.0;
2 3 0.00108 0.0108 0.01852 1200 1200 1200 0.0 0.0 1 -30.0 30.0;
3 4 0.00297 0.0297 0.00674 1000 1000 1000 1.05 1.0 1 -30.0 30.0;
4 3 0.00297 0.0297 0.00674 426 426 426 1.05 -1.0 1 -30.0 30.0;
4 10 0.00297 0.0297 0.00674 200.0 200.0 200.0 0.0 0.0 1 -30.0 30.0;
];
% generator names types and fuels
%column_names% name type fuel
mpc.gen_name = {
'Alta' 'CT' 'Gas';
'Park City' 'CC' 'Gas';
'Solitude' 'ST' 'Nuc';
'Sundance' 'CC' 'Gas';
'Brighton' 'ST' 'Coal';
'SolarBusC' 'PV' 'Solar';
'WindBusA' 'WIND' 'Wind';
};
% bus names
%column_names% name
mpc.bus_name = {
'bus1';
'bus2';
'bus3';
'bus4';
'bus5';
};
================================================
FILE: docs/src/tutorials/utils/docs_utils.jl
================================================
"""
`print_struct()`
Prints the definition of a struct.
"""
function print_struct(type)
mutable = ismutable(type) ? "mutable" : ""
println("$mutable struct $type")
for (fn, ft) in zip(fieldnames(type), fieldtypes(type))
println(" $fn::$ft")
end
println("end")
end
================================================
FILE: docs/src/tutorials/working_with_time_series.jl
================================================
# # [Working with Time Series Data](@id tutorial_time_series)
# In this tutorial, we will manually add, retrieve, and inspect time-series data in
# different formats, including identifying which components in a power [`System`](@ref) have time
# series data. Along the way, we will also use workarounds for missing forecast data and
# reuse identical time series profiles to avoid unnecessary memory usage.
# ## Example Data and Setup
# We will make an example [`System`](@ref) with a wind generator and two loads, and
# add the time series needed to model, for example, the impacts of wind forecast uncertainty.
# Here is the available data:
# ```@raw html
#
# ```
# For the wind generator, we have the historical point (deterministic) forecasts of power
# output. The forecasts were generated every 30 minutes with a 5-minute [resolution](@ref R)
# and 1-hour [horizon](@ref H). We also have
# measurements of what actually happened at 5-minute resolution over the 2 hours.
# For the loads, note that the forecast data is missing. We only have the historical
# measurements of total load for the system, which is normalized to the system's peak load.
# Load the `PowerSystems`, `Dates`, and `TimeSeries` packages to get started:
using PowerSystems
using Dates
using TimeSeries
# As usual, we need to define a power [`System`](@ref) that holds all our data. Let's define
# a simple system with a bus, a wind generator, and two loads:
system = System(100.0); # 100 MVA base power
bus1 = ACBus(;
number = 1,
name = "bus1",
available = true,
bustype = ACBusTypes.REF,
angle = 0.0,
magnitude = 1.0,
voltage_limits = (min = 0.9, max = 1.05),
base_voltage = 230.0,
);
wind1 = RenewableDispatch(;
name = "wind1",
available = true,
bus = bus1,
active_power = 0.0, # Per-unitized by device base_power
reactive_power = 0.0, # Per-unitized by device base_power
rating = 1.0, # 10 MW per-unitized by device base_power
prime_mover_type = PrimeMovers.WT,
reactive_power_limits = (min = 0.0, max = 0.0), # per-unitized by device base_power
power_factor = 1.0,
operation_cost = RenewableGenerationCost(nothing),
base_power = 10.0, # MVA
);
load1 = PowerLoad(;
name = "load1",
available = true,
bus = bus1,
active_power = 0.0, # Per-unitized by device base_power
reactive_power = 0.0, # Per-unitized by device base_power
base_power = 10.0, # MVA
max_active_power = 1.0, # 10 MW per-unitized by device base_power
max_reactive_power = 0.0,
);
load2 = PowerLoad(;
name = "load2",
available = true,
bus = bus1,
active_power = 0.0, # Per-unitized by device base_power
reactive_power = 0.0, # Per-unitized by device base_power
base_power = 30.0, # MVA
max_active_power = 1.0, # 30 MW per-unitized by device base_power
max_reactive_power = 0.0,
);
add_components!(system, [bus1, wind1, load1, load2])
# Recall that we can also set the [`System`](@ref)'s unit base to natural units (MW)
# to make it easier to inspect results:
set_units_base_system!(system, "NATURAL_UNITS")
# Before we get started, print `wind1` to see its data:
wind1
# See the `has_time_series` field at the bottom is `false`.
# Recall that we also can see a summary of the system by printing it:
system
# Observe that there is no mention of time series data in the system yet.
# # Add and Retrieve a Single Time Series
# Let's start by defining and attaching the wind measurements shown in the data above.
# This is a single time series profile, so we will use a [`SingleTimeSeries`](@ref).
# First, define a `TimeSeries.TimeArray` of input data, using the 5-minute
# [resolution](@ref R) to define the time-stamps in the example data:
wind_values = [6.0, 7, 7, 6, 7, 9, 9, 9, 8, 8, 7, 6, 5, 5, 5, 5, 5, 6, 6, 6, 7, 6, 7, 7];
resolution = Dates.Minute(5);
timestamps = range(DateTime("2020-01-01T08:00:00"); step = resolution, length = 24);
wind_timearray = TimeArray(timestamps, wind_values);
# Now, use the input data to define a Single Time Series in PowerSystems:
wind_time_series = SingleTimeSeries(;
name = "max_active_power",
data = wind_timearray,
);
# Note that we've chosen the name `max_active_power`, which is the default time series profile
# name when using
# [PowerSimulations.jl](https://sienna-platform.github.io/PowerSimulations.jl/stable/formulation_library/RenewableGen/)
# for simulations.
# So far, this time series has been defined, but not attached to our [`System`](@ref) in any way. Now,
# attach it to `wind1` using [`add_time_series!`](@ref add_time_series!(sys::System, component::Component, time_series::TimeSeriesData; features...)):
add_time_series!(system, wind1, wind_time_series);
# Let's double-check this worked by calling [`show_time_series`](@ref):
show_time_series(wind1)
# Now `wind1` has the first time-series data set. Recall that you can also print `wind1` and
# check the `has_time_series` field like we did above.
# Finally, let's retrieve and inspect the new timeseries, using `get_time_series_array`:
get_time_series_array(SingleTimeSeries, wind1, "max_active_power")
# Verify this matches your expectation based on the input data.
# # Add and Retrieve a Forecast
# Next, let's add the wind power forecasts. We will use a [`Deterministic`](@ref) format for
# the point forecasts.
# Because we have forecasts with at different [initial times](@ref I), the input data must be
# a dictionary where the keys are the initial times and the values are vectors or
# `TimeSeries.TimeArray`s of the forecast data.
# Set up the example input data:
wind_forecast_data = Dict(
DateTime("2020-01-01T08:00:00") => [5.0, 6, 7, 7, 7, 8, 9, 10, 10, 9, 7, 5],
DateTime("2020-01-01T08:30:00") => [9.0, 9, 9, 9, 8, 7, 6, 5, 4, 5, 4, 4],
DateTime("2020-01-01T09:00:00") => [6.0, 6, 5, 5, 4, 5, 6, 7, 7, 7, 6, 6],
);
# Define the [`Deterministic`](@ref) forecast and attach it to `wind1`:
wind_forecast = Deterministic("max_active_power", wind_forecast_data, resolution);
add_time_series!(system, wind1, wind_forecast);
# Let's call `show_time_series` once again:
show_time_series(wind1)
# Notice that we now have two types of time series listed -- the single time series and
# the forecasts.
# Finally, let's retrieve the forecast data to double check it was added properly, specifying
# the initial time to get the 2nd forecast window starting at 8:30:
get_time_series_array(
Deterministic,
wind1,
"max_active_power";
start_time = DateTime("2020-01-01T08:30:00"),
)
# # Add A Time Series Using Scaling Factors
# Let's add the load time series. Recall that this data is normalized to the peak system
# power, so we'll use it to scale both of our loads. We call normalized time series data
# *scaling factors*.
# First, let's create our input data `TimeSeries.TimeArray` with the example data and the same
# time stamps we used in the wind time series:
load_values = [0.3, 0.3, 0.3, 0.3, 0.4, 0.4, 0.4, 0.4, 0.5, 0.5, 0.6, 0.6,
0.7, 0.8, 0.8, 0.8, 0.8, 0.8, 0.9, 0.8, 0.8, 0.8, 0.8, 0.8];
load_timearray = TimeArray(timestamps, load_values);
# Again, define a [`SingleTimeSeries`](@ref), but this time use the
# `scaling_factor_multiplier` parameter to scale this time series from
# normalized values to power values:
load_time_series = SingleTimeSeries(;
name = "max_active_power",
data = load_timearray,
scaling_factor_multiplier = get_max_active_power,
);
# Notice that we assigned the
# [`get_max_active_power`](@ref get_max_active_power(value::PowerLoad)) *function*
# to scale the time series, rather than a value, making the time series reusable for multiple
# components or multiple fields in a component. Note that the values are normalized using
# each device's `max_active_power` parameter, not the system-wide `base_power`.
# Now, add the scaling factor time series to both loads to save memory and avoid data
# duplication:
add_time_series!(system, [load1, load2], load_time_series);
# Let's take a look at `load1`, including printing its parameters...
load1
# ...as well as its time series:
show_time_series(load1)
# !!! tip "Important"
# Notice that each load now has two references to `max_active_power`. This is intentional.
# There is the parameter, `max_active_power`, which is the
# maximum demand of each load at any time (10 MW or 30 MW). There is also
# `max_active_power` the time series, which is the time varying demand over the 2-hour
# window, calculated using the scaling factors and the `max_active_power` parameter.
# This means that if we change the `max_active_power` parameter, the time series will
# also change when we retrieve it! This is also true when we apply the same scaling factors
# to multiple components or parameters.
# Let's check the impact that these two `max_active_power` data sources have on the times
# series data when we retrieve it. Get the `max_active_power` time series for `load1`:
get_time_series_array(SingleTimeSeries, load1, "max_active_power") # in MW
# See that the normalized values have been scaled up by 10 MW.
# Now let's look at `load2`. First check its `max_active_power` parameter:
get_max_active_power(load2)
# This has a higher peak maximum demand of 30 MW.
# Next, retrieve its `max_active_power` time series:
get_time_series_array(SingleTimeSeries, load2, "max_active_power") # in MW
# Observe the difference compared to `load1`'s time series.
# Finally, retrieve the underlying time series data with no scaling factor multiplier
# applied:
get_time_series_array(SingleTimeSeries,
load2,
"max_active_power";
ignore_scaling_factors = true,
)
# Notice that this is the normalized input data, which is still being stored underneath. Each
# load is using a reference to that data when we call `get_time_series_array` to avoid
# unnecessary data duplication.
# # Transform a [`SingleTimeSeries`](@ref) into a Forecast
# Finally, let's use a workaround to handle the missing load forecast data. We will assume a
# perfect forecast where the forecast is based on the [`SingleTimeSeries`](@ref) we just added.
# Rather than unnecessarily duplicating and reformatting data, use PowerSystems.jl's dedicated
# [`transform_single_time_series!`](@ref) function to generate a [`DeterministicSingleTimeSeries`](@ref),
# which saves memory while behaving just like a [`Deterministic`](@ref) forecast.
# Before we call `transform_single_time_series!`, we need to remove the [`SingleTimeSeries`](@ref) from
# the wind component. This is because the wind component already has a [`Deterministic`](@ref) forecast
# with the name `"max_active_power"`, and having both a [`Deterministic`](@ref) and a
# [`DeterministicSingleTimeSeries`](@ref) with the same name is not allowed. If we tried to keep both,
# functions like `get_time_series` wouldn't know which forecast to retrieve when you request
# `"max_active_power"`. Let's remove the [`SingleTimeSeries`](@ref) to avoid this conflict:
remove_time_series!(system, SingleTimeSeries, wind1, "max_active_power");
# Now we can transform the remaining [`SingleTimeSeries`](@ref) (the ones attached to the loads):
transform_single_time_series!(
system,
Dates.Hour(1), # horizon
Dates.Minute(30), # interval
);
# Let's see the results for `load1`'s time series summary:
show_time_series(load1)
# Notice we now have a load forecast data set with the resolution, horizon, and, interval
# matching our wind forecasts.
# Retrieve the first forecast window:
get_time_series_array(
DeterministicSingleTimeSeries,
load1,
"max_active_power";
start_time = DateTime("2020-01-01T08:00:00"),
)
# See that `load1`'s scaling factor multiplier is still being applied as expected.
# # Transform with Multiple Intervals
# PowerSystems supports creating multiple forecast transforms from the same
# [`SingleTimeSeries`](@ref), each with a different [interval](@ref I). This is useful when
# a component needs forecasts updated at different frequencies.
# Use `delete_existing = false` to preserve the existing transform and add a second one
# with a different interval:
transform_single_time_series!(
system,
Dates.Hour(1), # horizon
Dates.Hour(1); # a longer interval
delete_existing = false,
);
# Now `load1` has two [`DeterministicSingleTimeSeries`](@ref) forecasts with different
# intervals. Let's verify:
show_time_series(load1)
# When multiple intervals exist for the same name, you must specify `interval` to
# disambiguate retrieval:
get_time_series_array(
DeterministicSingleTimeSeries,
load1,
"max_active_power";
start_time = DateTime("2020-01-01T08:00:00"),
interval = Dates.Minute(30),
)
# You can also query forecast parameters for a specific interval:
get_forecast_horizon(system; interval = Dates.Hour(1))
#
get_forecast_interval(system; interval = Dates.Minute(30))
# To selectively remove one interval's forecasts while keeping the other:
remove_time_series!(
system,
DeterministicSingleTimeSeries,
load1,
"max_active_power";
interval = Dates.Hour(1),
);
show_time_series(load1)
# The 30-minute interval forecast is still present while the 1-hour one has been removed.
# # Finding, Retrieving, and Inspecting Time Series
# Now, let's complete this tutorial by doing a few sanity checks on the data that we've added,
# where are we will also examine components with time series and retrieve
# the time series data in a few more ways.
# First, recall that we can print a component to check its `has_time_series` field:
load1
# Also, recall we can print the [`System`](@ref) to summarize the data in our system:
system
# Notice that a new table has been added -- the Time Series Summary, showing the count of
# each Type of component that has a given time series type.
# Notice that the [`RenewableDispatch`](@ref) generator (`wind1`) only has its [`Deterministic`](@ref) forecast
# and no [`DeterministicSingleTimeSeries`](@ref). This is because we removed the wind's [`SingleTimeSeries`](@ref)
# before calling `transform_single_time_series!`, preventing a conflict with its existing
# [`Deterministic`](@ref) forecast.
# Let's verify `wind1`'s time series to confirm:
show_time_series(wind1)
# See that it only has the [`Deterministic`](@ref) forecast, as expected.
# Finally, let's do a last data sanity check on the forecasts. Since we defined the wind
# time series in MW instead of scaling factors, let's make sure none of our forecasts exceeds
# the `max_active_power` parameter.
# Instead of using `get_time_series_array` where we need to remember some details of
# the time series we're looking up, let's use [`get_time_series_keys`](@ref) to refresh our
# memories:
keys = get_time_series_keys(wind1)
# See the forecast key is first, so let's retrieve it using [`get_time_series`](@ref):
forecast = get_time_series(wind1, keys[1])
# See that unlike when we used `get_time_series_array`, this returns an object we can
# manipulate.
# Use [`iterate_windows`](@ref) to cycle through the 3 forecast windows and inspect the peak
# value:
for window in iterate_windows(forecast)
@show values(maximum(window))
end
# Finally, use [`get_max_active_power`](@ref get_max_active_power(d::RenewableGen)) to
# check the expected maximum:
get_max_active_power(wind1)
# See that the forecasts are not exceeding this maximum -- sanity check complete.
# !!! tip
# Unlike [`PowerLoad`](@ref) components, [`RenewableDispatch`](@ref) components do not have a
# `max_active_power` field, so check
# [`get_max_active_power`](@ref get_max_active_power(d::RenewableGen))
# to see how its calculated.
# # Next Steps
# In this tutorial, you defined, added, and retrieved four time series data
# sets, including static time series and deterministic forecasts. Along the way, we
# reduced data duplication using normalized scaling factors for reuse by multiple components
# or component fields, as well as by referencing a [`StaticTimeSeries`](@ref) to address missing
# forecast data.
# Next you might like to:
# - [Parse many timeseries data sets from CSV's](@ref parsing_time_series)
# - [See how to improve performance efficiency with your own time series data](@ref "Improve Performance with Time Series Data")
# - [Review the available time series data formats](@ref ts_data)
# - [Learn more about how times series data is stored](@ref "Data Storage")
================================================
FILE: scripts/formatter/Project.toml
================================================
uuid = "c6367ca8-164d-4469-afe3-c91cf8860505"
authors = ["Jose Daniel Lara "]
[deps]
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
[compat]
JuliaFormatter = "2"
julia = "^1.7"
================================================
FILE: scripts/formatter/formatter_code.jl
================================================
using Pkg
Pkg.activate(@__DIR__)
Pkg.instantiate()
Pkg.update()
using JuliaFormatter
main_paths = ["./src", "./test", "./docs/src"]
for main_path in main_paths
for (root, dir, files) in walkdir(main_path)
for f in files
@show file_path = abspath(root, f)
!((occursin(".jl", f) || occursin(".md", f))) && continue
format(file_path;
whitespace_ops_in_indices = true,
remove_extra_newlines = true,
verbose = true,
always_for_in = true,
whitespace_typedefs = true,
conditional_to_if = true,
join_lines_based_on_source = true,
separate_kwargs_with_semicolon = true,
format_markdown = true,
ignore = ["*LICENSE.md", "how_to/install.md"] # install has complicated formatting
# always_use_return = true. # Disabled since it throws a lot of false positives
)
end
end
end
================================================
FILE: scripts/generate_config_file.py
================================================
#!/usr/bin/env python
"""Generates a user descriptor file for parsing power system raw data."""
# Note: This is written in Python instead of Julia because the Julia YAML
# package does not support writing (only reading).
import json
import os
import sys
import yaml
POWER_SYSTEM_DESCRIPTOR_FILE = os.path.join(
"src",
"descriptors",
"power_system_inputs.json"
)
def read_json_data(filename):
"""Return the JSON data from a file."""
with open(filename) as fp_in:
return json.load(fp_in)
def generate_config(input_file):
"""Generate user descriptors from the PowerSystems descriptor file."""
config = {}
data = read_json_data(input_file)
for key, value in data.items():
items = []
for item in value:
config_item = {
"name": item["name"],
"custom_name": item["name"],
}
items.append(config_item)
config[key] = items
return config
def generate_file(output_file, input_file=POWER_SYSTEM_DESCRIPTOR_FILE):
"""Generate user file from the PowerSystems descriptor file."""
config = generate_config(input_file)
with open(output_file, "w") as fp_out:
yaml.dump(config, fp_out)
print("Generated {} from {}".format(output_file, input_file))
def main():
"""Controls execution."""
if len(sys.argv) != 2:
print("Usage: {} output_file".format(os.path.basename(__file__)))
sys.exit(1)
generate_file(sys.argv[1])
if __name__ == "__main__":
main()
================================================
FILE: scripts/generate_validation_config_file.py
================================================
#!/usr/bin/env python
"""Generates a validation configuration file from JSON struct data"""
# Note: This is written in Python instead of Julia because the Julia YAML
# package does not support writing (only reading).
import json
import os
import sys
from collections import OrderedDict
#import yaml
def read_json_data(filename):
"""Return the JSON data from a file."""
with open(filename) as fp_in:
return json.load(fp_in)
def generate_config(input_file):
"""Generate validation descriptors from the PowerSystems struct data file."""
config = {}
data = read_json_data(input_file)
items = []
for ps_struct in data["auto_generated_structs"]:
new_struct = OrderedDict()
new_struct["struct_name"] = ps_struct["struct_name"]
new_struct["fields"] = []
for field in ps_struct["fields"]:
new_field = OrderedDict()
new_field["name"] = field["name"]
if "data_type" in field:
new_field["data_type"] = field["data_type"]
if "valid_range" in field:
new_field["valid_range"] = field["valid_range"]
if "validation_action" in field:
new_field["validation_action"] = field["validation_action"]
new_struct["fields"].append(new_field)
items.append(new_struct)
return {"auto_generated_structs": items}
def generate_file(input_file, output_file):
"""Generate validation descriptors from the PowerSystems struct data file."""
config = generate_config(input_file)
with open(output_file, "w") as fp_out:
#yaml.dump(config, fp_out, vspacing=True)
json.dump(config, fp_out, indent=4)
print("Generated {} from {}".format(output_file, input_file))
def main():
"""Controls execution."""
if len(sys.argv) != 3:
example = "python bin/{} src/descriptors/power_system_structs.json validation.json".format(
os.path.basename(__file__)
)
print("Usage: {} input_file output_file\nExample: {}".format(
os.path.basename(__file__), example)
)
sys.exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
generate_file(input_file, output_file)
if __name__ == "__main__":
main()
================================================
FILE: src/PowerSystems.jl
================================================
isdefined(Base, :__precompile__) && __precompile__()
"""
Module for constructing self-contained power system objects.
"""
module PowerSystems
#################################################################################
# Exports
export System
export Topology
export Bus
export ACBus
export DCBus
export Arc
export AggregationTopology
export Area
export LoadZone
export AreaInterchange
export get_aggregation_topology_accessor
export SupplementalAttribute
export GeographicInfo
export get_geo_json
export PowerPlant
export ThermalPowerPlant
export CombinedCycleBlock
export CombinedCycleFractional
export CombinedCycleConfiguration
export HydroPowerPlant
export RenewablePowerPlant
export get_shaft_map
export get_reverse_shaft_map
export get_components_in_shaft
export get_configuration
export get_heat_recovery_to_steam_factor
export get_penstock_map
export get_reverse_penstock_map
export get_components_in_penstock
export get_hrsg_ct_map
export get_hrsg_ca_map
export get_ct_hrsg_map
export get_ca_hrsg_map
export get_pcc_map
export get_reverse_pcc_map
export get_components_in_pcc
export get_operation_exclusion_map
export get_inverse_operation_exclusion_map
export get_components_in_exclusion_group
export Component
export Device
export get_max_active_power
export get_max_reactive_power
export get_high_voltage
export get_low_voltage
export Branch
export StaticInjection
export StaticInjectionSubsystem
export DiscreteControlledACBranch
export ACBranch
export ACTransmission
export TwoWindingTransformer
export ThreeWindingTransformer
export TwoTerminalHVDC
export Line
export MonitoredLine
export GenericArcImpedance
export DCBranch
export TwoTerminalGenericHVDCLine
export TwoTerminalVSCLine
export TwoTerminalLCCLine
export TModelHVDCLine
export Transformer2W
export TapTransformer
export PhaseShiftingTransformer
export FACTSControlDevice
export Transformer3W
export PhaseShiftingTransformer3W
export SynchronousCondenser
# from IS function_data.jl
export FunctionData
export LinearFunctionData
export QuadraticFunctionData
export PiecewiseLinearData
export PiecewiseStepData
export get_proportional_term
export get_quadratic_term
export get_constant_term
export get_slopes
export get_average_rates
export get_x_lengths
export is_convex
export is_concave
export get_points
export get_x_coords
export get_y_coords
# from IS value_curve.jl, cost_aliases.jl, and production_variable_cost_curve.jl
export ValueCurve
export InputOutputCurve, IncrementalCurve, AverageRateCurve
export LinearCurve, QuadraticCurve
export PiecewisePointCurve, PiecewiseIncrementalCurve, PiecewiseAverageCurve
export ProductionVariableCostCurve, CostCurve, FuelCurve
export get_function_data, get_initial_input, get_input_at_zero
export get_value_curve, get_power_units
export OperationalCost,
OfferCurveCost, MarketBidCost, LoadCost, StorageCost, ImportExportCost
export HydroGenerationCost, RenewableGenerationCost, ThermalGenerationCost
export HydroReservoirCost
export get_fuel_cost, set_fuel_cost!, get_vom_cost
export is_market_bid_curve, make_market_bid_curve
export make_import_curve, make_export_curve
export get_no_load_cost, set_no_load_cost!, get_start_up, set_start_up!
export set_shut_down!
export get_curtailment_cost
export set_curtailment_cost!
export get_fixed
export set_fixed!
export get_charge_variable_cost, set_charge_variable_cost!
export get_discharge_variable_cost, set_discharge_variable_cost!
export get_energy_shortage_cost, set_energy_shortage_cost!
export get_energy_surplus_cost, set_energy_surplus_cost!
export get_level_shortage_cost, set_level_shortage_cost!
export get_level_surplus_cost, set_level_surplus_cost!
export get_spillage_cost, set_spillage_cost!
export Generator
export HydroGen
export HydroDispatch
export HydroTurbine
export HydroReservoir
export HydroPumpTurbine
export InterconnectingConverter
export RenewableGen
export RenewableNonDispatch
export RenewableDispatch
export ThermalGen
export ThermalStandard
export ThermalMultiStart
export ElectricLoad
export StaticLoad
export PowerLoad
export StandardLoad
export FixedAdmittance
export SwitchedAdmittance
export ControllableLoad
export InterruptiblePowerLoad
export InterruptibleStandardLoad
export ShiftablePowerLoad
export ExponentialLoad
export MotorLoad
export LoadConformity
export Storage
export EnergyReservoirStorage
export DynamicComponent
export DynamicInjection
export DynamicGenerator
export DynamicInverter
export DynamicBranch
export HybridSystem
export GenericDER
export AggregateDistributedGenerationA
export SingleCageInductionMachine
export SimplifiedSingleCageInductionMachine
export ActiveConstantPowerLoad
export DynamicExponentialLoad
#AVR Exports
export AVR
export AVRFixed
export AVRSimple
export AVRTypeI
export AVRTypeII
export IEEET1
export ESDC1A
export ESDC2A
export ESAC1A
export ESAC6A
export ESAC8B
export EXAC1
export EXAC1A
export EXAC2
export EXPIC1
export ESST1A
export ESST4B
export ST6B
export SCRX
export SEXS
export ST8C
#Machine Exports
export Machine
export BaseMachine
export RoundRotorMachine
export SalientPoleMachine
export RoundRotorQuadratic
export SalientPoleQuadratic
export RoundRotorExponential
export SalientPoleExponential
export OneDOneQMachine
export SauerPaiMachine
export MarconatoMachine
export SimpleMarconatoMachine
export AndersonFouadMachine
export SimpleAFMachine
export FullMachine
export SimpleFullMachine
#PSS Exports
export PSS
export PSSFixed
export PSSSimple
export IEEEST
export STAB1
export PSS2A
export PSS2B
export PSS2C
export CSVGN1
#Shaft Exports
export Shaft
export SingleMass
export FiveMassShaft
#TG Exports
export TurbineGov
export TGFixed
export TGTypeI
export TGTypeII
export GasTG
export GeneralGovModel
export HydroTurbineGov
export IEEETurbineGov1
export SteamTurbineGov1
export DEGOV
export DEGOV1
export PIDGOV
export WPIDHY
export TGSimple
# Converter Exports
export Converter
export AverageConverter
export RenewableEnergyConverterTypeA
export RenewableEnergyVoltageConverterTypeA
# DC Source Exports
export DCSource
export FixedDCSource
export ZeroOrderBESS
# Filter Exports
export Filter
export LCLFilter
export LCFilter
export RLFilter
# FrequencyEstimator Exports
export FrequencyEstimator
export KauraPLL
export ReducedOrderPLL
export FixedFrequency
# Outer Control Exports
export OuterControl
export VirtualInertia
export ReactivePowerDroop
export ActivePowerDroop
export ActivePowerPI
export ReactivePowerPI
export ActiveVirtualOscillator
export ReactiveVirtualOscillator
export ActiveRenewableControllerAB
export ReactiveRenewableControllerAB
# InnerControl Export
export InnerControl
export VoltageModeControl
export CurrentModeControl
export RECurrentControlB
# OutputCurrentLimiters Export
export OutputCurrentLimiter
export MagnitudeOutputCurrentLimiter
export InstantaneousOutputCurrentLimiter
export PriorityOutputCurrentLimiter
export SaturationOutputCurrentLimiter
export HybridOutputCurrentLimiter
export Source
export PeriodicVariableSource
export Contingency
# Outages
export Outage
export GeometricDistributionForcedOutage
export PlannedOutage
export FixedForcedOutage
export get_mean_time_to_recovery
export get_outage_transition_probability
export get_outage_schedule
# Impedance Correction Data
export ImpedanceCorrectionData
export WindingCategory
export WindingGroupNumber
export ImpedanceCorrectionTransformerControlMode
export get_table_number
export get_impedance_correction_curve
export get_transformer_winding
export get_transformer_control_mode
export Service
export AbstractReserve
export Reserve
export ReserveNonSpinning
export ReserveDirection
export ReserveUp
export ReserveDown
export ReserveSymmetric
export ConstantReserve
export VariableReserve
export AGC
export ReserveDemandCurve
export ConstantReserveGroup
export ConstantReserveNonSpinning
export VariableReserveNonSpinning
export TransmissionInterface
export AngleUnits
export ACBusTypes
export FACTSOperationModes
export DiscreteControlledBranchStatus
export DiscreteControlledBranchType
export PrimeMovers
export ThermalFuels
export StorageTech
export StateTypes
export ReservoirDataType
export MotorLoadTechnology
export HydroTurbineType
export ReservoirLocation
# from IS time_series_structs.jl, time_series_cache.jl
export TimeSeriesAssociation
export TimeSeriesKey
export StaticTimeSeriesKey
export ForecastKey
export TimeSeriesCounts
export ForecastCache
export StaticTimeSeriesCache
# from IS time_series_metadata_store.jl and defined for System in base.jl
export get_static_time_series_summary_table
export get_forecast_summary_table
# from IS time_series_parser.jl
export NormalizationFactor
export NormalizationTypes
# from IS forecasts.jl
export Forecast
export AbstractDeterministic
export TimeSeriesData # abstract_time_series.jl
export StaticTimeSeries # static_time_series.jl
export Deterministic # deterministic.jl
export Probabilistic # Probabilistic.jl
export SingleTimeSeries # Single_Time_Series.jl
export DeterministicSingleTimeSeries # deterministic_single_time_series.jl
export Scenarios # scenarios.jl
export get_dynamic_components
export parse_file
export open_time_series_store!
export add_time_series!
export bulk_add_time_series!
export begin_time_series_update
export remove_time_series!
export check_time_series_consistency
export clear_time_series!
export copy_time_series!
export copy_subcomponent_time_series!
export add_component!
export add_components!
export replace_dynamic_injector!
export remove_component!
export remove_components!
export clear_components!
export add_service!
export remove_service!
export clear_services!
export get_services
export has_service
export remove_turbine!
export clear_turbines!
export has_upstream_turbine
export has_downstream_turbine
export has_time_series
export get_buses
export is_component_in_aggregation_topology
export get_components_in_aggregation_topology
export get_aggregation_topology_mapping
export get_contributing_devices
export set_upstream_turbine!
export set_downstream_turbine!
export get_connected_head_reservoirs
export get_connected_tail_reservoirs
export get_contributing_device_mapping
export get_contributing_reserve_mapping
export get_turbine_head_reservoirs_mapping
export get_turbine_tail_reservoirs_mapping
export ServiceContributingDevices
export ServiceContributingDevicesKey
export ServiceContributingDevicesMapping
export TurbineConnectedDevices
export TurbineConnectedDevicesKey
export TurbineConnectedDevicesMapping
export get_component
export get_components
export get_num_components
export get_associated_components
export show_components
export get_subcomponents
export get_components_by_name
export get_available
export set_available!
export get_available_component
export get_available_components
export get_existing_device_types
export get_existing_component_types
export get_forecast_horizon
export get_forecast_initial_timestamp
export get_forecast_interval
export get_forecast_window_count
export add_supplemental_attribute!
export remove_supplemental_attribute!
export remove_supplemental_attributes!
export get_component_supplemental_attribute_pairs
export get_supplemental_attribute
export get_supplemental_attributes
export get_associated_supplemental_attributes
export has_supplemental_attributes
export iterate_supplemental_attributes
export begin_supplemental_attributes_update
export get_time_series
export get_time_series_type
export get_time_series_array
export get_time_series_resolutions
export supports_time_series
export supports_supplemental_attributes
export get_time_series_timestamps
export get_time_series_values
export get_time_series_counts
export get_scenario_count
export get_percentiles
export get_next_time_series_array!
export get_next_time
export reset!
export get_horizon
export get_forecast_initial_times
export get_time_series_keys
export show_time_series
export get_resolution
export get_data
export iterate_components
export get_time_series_multiple
export get_variable_cost
export get_incremental_variable_cost, get_decremental_variable_cost
export get_no_load_cost
export get_start_up
export get_shut_down
export get_incremental_offer_curves, set_incremental_offer_curves!
export get_decremental_offer_curves, set_decremental_offer_curves!
export get_incremental_initial_input, set_incremental_initial_input!
export get_decremental_initial_input, set_decremental_initial_input!
export get_ancillary_service_offers, set_ancillary_service_offers!
export get_import_offer_curves, set_import_offer_curves!
export get_export_offer_curves, set_export_offer_curves!
export get_import_variable_cost, get_export_variable_cost
export get_energy_import_weekly_limit, set_energy_import_weekly_limit!
export get_energy_export_weekly_limit, set_energy_export_weekly_limit!
export get_services_bid
export set_variable_cost!
export set_incremental_variable_cost!, set_decremental_variable_cost!
export set_import_variable_cost!, set_export_variable_cost!
export set_service_bid!
export iterate_windows
export get_window
export transform_single_time_series!
export sanitize_component!
export validate_component
export validate_component_with_system
export get_compression_settings
export CompressionSettings
export CompressionTypes
# Parsing functions
export create_poly_cost
#export make_time_series
export get_bus_numbers
export set_bus_number!
export set_number! # Remove this in v5.0.
export get_name
export set_name!
export get_component_uuids
export get_description
export set_description!
export get_base_power
export get_frequency
export get_frequency_droop
export set_units_base_system!
export with_units_base
export to_json
export from_json
export serialize
export deserialize
export clear_ext!
export convert_component!
export set_area!
export set_load_zone!
export PowerModelsData
export PowerSystemTableData
export add_dyn_injectors!
export get_machine
export get_shaft
export get_avr
export get_prime_mover
export get_pss
export get_converter
export get_outer_control
export get_inner_control
export get_dc_source
export get_freq_estimator
export get_filter
export get_V_ref
export get_P_ref
export get_saturation_coeffs
export get_units_base
export get_runchecks
export get_thermal_unit
export get_electric_load
export get_storage
export get_renewable_unit
export get_interconnection_rating
export get_interconnection_impedance
export get_from_to_flow_limit
export get_to_from_flow_limit
export get_min_active_power_flow_limit
export get_max_active_power_flow_limit
# Subsystems
export add_subsystem!
export get_subsystems
export get_num_subsystems
export remove_subsystem!
export add_component_to_subsystem!
export get_subsystem_components
export remove_component_from_subsystem!
export remove_component_from_subsystems!
export has_component
export has_components
export get_assigned_subsystems
export has_subsystems
export is_assigned_to_subsystem
export from_subsystem
export filter_components_by_subsystem!
export set_runchecks!
export check
export check_component
export check_components
export check_ac_transmission_rate_values
# From IS logging.jl, generate_struct_files.jl
export configure_logging
export open_file_logger
export make_logging_config_file
export MultiLogger
export LogEventTracker
export StructField
export StructDefinition
export generate_struct_file
export generate_struct_files
export UnitSystem # internal.jl
# ComponentSelector
export ComponentSelector
export SingularComponentSelector
export PluralComponentSelector
export DynamicallyGroupedComponentSelector
export subtype_to_string
export component_to_qualified_string
export make_selector
export rebuild_selector
export get_groups
export get_available_groups
#################################################################################
# Imports
import Base: @kwdef
import LinearAlgebra
import Unicode: normalize
import Logging
import Dates
import TimeSeries
import DataFrames
import DataStructures: OrderedDict, SortedDict
import JSON3
import CSV
import YAML
import UUIDs
import Base.to_index
import InteractiveUtils
import PrettyTables
import PowerFlowData
# Import InfrastructureSystems both as full module name (needed for internal macros like @forward)
# and with alias for convenient usage throughout the codebase
import InfrastructureSystems
import InfrastructureSystems as IS
import InfrastructureSystems:
Components,
TimeSeriesData,
StaticTimeSeries,
Forecast,
AbstractDeterministic,
Deterministic,
Probabilistic,
SingleTimeSeries,
StaticTimeSeriesKey,
DeterministicSingleTimeSeries,
ForecastKey,
Scenarios,
ForecastCache,
StaticTimeSeriesCache,
TimeSeriesKey,
TimeSeriesCounts,
TimeSeriesAssociation,
InfrastructureSystemsComponent,
InfrastructureSystemsType,
InfrastructureSystemsInternal,
SupplementalAttribute,
DeviceParameter,
FlattenIteratorWrapper,
LazyDictFromIterator,
DataFormatError,
InvalidRange,
InvalidValue,
GeographicInfo,
get_geo_json,
copy_time_series!,
get_available,
set_available!,
get_count,
get_data,
get_horizon,
get_resolution,
get_window,
get_name,
get_num_components,
get_component_uuids,
get_supplemental_attribute,
get_supplemental_attributes,
set_name!,
get_internal,
set_internal!,
iterate_windows,
get_time_series,
has_time_series,
get_time_series_type,
get_time_series_array,
get_time_series_timestamps,
get_time_series_values,
get_time_series_keys,
show_time_series,
get_scenario_count, # Scenario Forecast Exports
get_percentiles, # Probabilistic Forecast Exports
get_next_time_series_array!,
get_next_time,
reset!,
has_supplemental_attributes,
get_units_info,
set_units_info!,
to_json,
from_json,
serialize,
deserialize,
get_time_series_multiple,
compare_values,
CompressionSettings,
CompressionTypes,
NormalizationFactor,
NormalizationTypes,
UnitSystem,
SystemUnitsSettings,
open_file_logger,
make_logging_config_file,
validate_struct,
MultiLogger,
LogEventTracker,
StructField,
StructDefinition,
FunctionData,
LinearFunctionData,
QuadraticFunctionData,
PiecewiseLinearData,
PiecewiseStepData,
get_proportional_term,
get_quadratic_term,
get_constant_term,
get_slopes,
running_sum,
get_x_lengths,
is_convex,
is_concave,
get_points, # TODO possible rename to disambiguate from geographical information
get_x_coords,
get_y_coords,
get_raw_data_type,
supports_time_series,
supports_supplemental_attributes,
fast_deepcopy_system,
ComponentSelector,
SingularComponentSelector,
PluralComponentSelector,
DynamicallyGroupedComponentSelector,
NameComponentSelector,
ListComponentSelector,
TypeComponentSelector,
FilterComponentSelector,
RegroupedComponentSelector,
component_to_qualified_string,
subtype_to_string,
COMPONENT_NAME_DELIMITER,
make_selector,
rebuild_selector
import InfrastructureSystems:
ValueCurve,
InputOutputCurve,
IncrementalCurve,
AverageRateCurve,
LinearCurve,
QuadraticCurve,
PiecewisePointCurve,
PiecewiseIncrementalCurve,
PiecewiseAverageCurve,
get_function_data,
get_initial_input,
get_input_at_zero,
get_average_rates,
ProductionVariableCostCurve,
CostCurve,
FuelCurve,
get_value_curve,
get_vom_cost,
get_startup_fuel_offtake,
get_power_units,
get_fuel_cost
#################################################################################
using DocStringExtensions
@template (FUNCTIONS, METHODS) = """
$(TYPEDSIGNATURES)
$(DOCSTRING)
"""
#################################################################################
# Includes
"""
Supertype for all PowerSystems components.
All subtypes must include a InfrastructureSystemsInternal member.
Subtypes should call InfrastructureSystemsInternal() by default, but also must
provide a constructor that allows existing values to be deserialized.
"""
abstract type Component <: IS.InfrastructureSystemsComponent end
""" Supertype for "devices" (bus, line, etc.) """
abstract type Device <: Component end
"""
All PowerSystems [Device](@ref) types support time series. This can be overridden for
custom component types that do not support time series.
"""
supports_time_series(::Device) = true
"""
All PowerSystems [Device](@ref) types support supplemental attributes. This can be overridden for
custom component types that do not support supplemental attributes.
"""
supports_supplemental_attributes(::Device) = true
# Include utilities
include("utils/logging.jl")
include("utils/IO/base_checks.jl")
include("utils/generate_struct_files.jl")
include("definitions.jl")
include("models/static_models.jl")
include("models/dynamic_models.jl")
include("models/injection.jl")
include("models/static_injection_subsystem.jl")
# PowerSystems models
include("models/topological_elements.jl")
include("models/branches.jl")
#include("models/network.jl")
# Static types
include("models/services.jl")
include("models/reserves.jl")
include("models/generation.jl")
include("models/storage.jl")
include("models/loads.jl")
include("models/dynamic_generator_components.jl")
include("models/dynamic_inverter_components.jl")
include("models/OuterControl.jl")
# Costs
include("models/cost_functions/operational_cost.jl")
include("models/cost_functions/OfferCurveCost.jl")
include("models/cost_functions/MarketBidCost.jl")
include("models/cost_functions/ImportExportCost.jl")
include("models/cost_functions/HydroGenerationCost.jl")
include("models/cost_functions/LoadCost.jl")
include("models/cost_functions/RenewableGenerationCost.jl")
include("models/cost_functions/StorageCost.jl")
include("models/cost_functions/ThermalGenerationCost.jl")
include("models/cost_functions/HydroReservoirCost.jl")
# Include all auto-generated structs.
include("models/generated/includes.jl")
include("models/HybridSystem.jl")
#Methods for devices
include("models/components.jl")
include("models/devices.jl")
# Dynamic Composed types
include("models/dynamic_generator.jl")
include("models/dynamic_inverter.jl")
include("models/dynamic_loads.jl")
include("models/dynamic_machines.jl")
include("models/RoundRotorExponential.jl")
include("models/RoundRotorQuadratic.jl")
include("models/SalientPoleExponential.jl")
include("models/SalientPoleQuadratic.jl")
include("models/dynamic_branch.jl")
include("impedance_correction.jl")
include("models/supplemental_constructors.jl")
include("models/supplemental_accessors.jl")
include("models/supplemental_setters.jl")
# Supplemental attributes
include("contingencies.jl")
include("outages.jl")
# Definitions of PowerSystem
include("base.jl")
include("plant_attribute.jl")
include("subsystems.jl")
include("component_selector.jl")
include("data_format_conversions.jl")
include("get_components_interface.jl")
include("component_selector_interface.jl")
#Data Checks
include("utils/IO/system_checks.jl")
include("utils/IO/branchdata_checks.jl")
# cost function TimeSeries convertion
include("models/cost_function_timeseries.jl")
#Conversions
include("utils/conversion.jl")
# Include Parsing files
include("parsers/common.jl")
include("parsers/enums.jl")
include("parsers/pm_io.jl")
include("parsers/im_io.jl")
include("parsers/power_system_table_data.jl")
include("parsers/power_models_data.jl")
include("parsers/powerflowdata_data.jl")
include("parsers/psse_dynamic_data.jl")
include("parsers/psse_metadata_reimport.jl")
# Better printing
include("utils/print.jl")
@static if pkgversion(PrettyTables).major == 2
# When PrettyTables v2 is more widely adopted in the ecosystem, we can remove this file.
# In this case, we should also update the compat bounds in Project.toml to list only
# PrettyTables v3.
include("utils/print_pt_v2.jl")
else
include("utils/print_pt_v3.jl")
end
include("models/serialization.jl")
#Deprecated
include("deprecated.jl")
end # module
================================================
FILE: src/base.jl
================================================
const SKIP_PM_VALIDATION = false
const SYSTEM_KWARGS = Set((
:area_name_formatter,
:branch_name_formatter,
:xfrm_3w_name_formatter,
:switched_shunt_name_formatter,
:transformer_control_objective_formatter,
:dcline_name_formatter,
:vscline_name_formatter,
:bus_name_formatter,
:config_path,
:frequency,
:gen_name_formatter,
:generator_mapping,
:internal,
:load_name_formatter,
:loadzone_name_formatter,
:runchecks,
:shunt_name_formatter,
:time_series_directory,
:time_series_in_memory,
:time_series_read_only,
:timeseries_metadata_file,
:unit_system,
:pm_data_corrections,
:import_all,
:enable_compression,
:compression,
:name,
:description,
))
# This will be used in the future to handle serialization changes.
const DATA_FORMAT_VERSION = "5.0.0"
mutable struct SystemMetadata <: IS.InfrastructureSystemsType
name::Union{Nothing, String}
description::Union{Nothing, String}
end
"""
A power system
`System` is the main data container in `PowerSystems.jl`, including basic metadata (base
power, frequency), components (network topology, loads, generators, and services), and
time series data.
```julia
System(base_power)
System(base_power, buses, components...)
System(base_power, buses, generators, loads, branches, storage, services; kwargs...)
System(base_power, buses, generators, loads; kwargs...)
System(file; kwargs...)
System(; buses, generators, loads, branches, storage, base_power, services, kwargs...)
System(; kwargs...)
```
# Arguments
- `base_power::Float64`: the base power value for the system
- `buses::Vector{ACBus}`: an array of buses
- `components...`: Each element (e.g., `buses`, `generators`, ...) must be an iterable
containing subtypes of `Component`.
- `file::AbstractString`: Path to a Matpower, PSSE, or JSON file ending with .m, .raw, or .json
# Keyword arguments
- `name::String`: System name.
- `description::String`: System description.
- `frequency::Float64`: (default = 60.0) Operating frequency (Hz).
- `runchecks::Bool`: Run available checks on input fields and when add_component! is called.
Throws InvalidValue if an error is found.
- `generator_mapping`: A dictionary mapping generator names to their corresponding topologies. This is used to associate generators with their respective buses when parsing from CSV.
- `time_series_in_memory::Bool=false`: Store time series data in memory instead of HDF5.
- `time_series_directory::Union{Nothing, String}`: Directory for the time series HDF5 file.
Defaults to the tmp file system.
- `timeseries_metadata_file`: Path to a file containing time series metadata descriptors. This is used to add time series data to the system from files.
- `time_series_read_only::Bool=false`: Open the time series store in read-only mode.
This is useful for reading time series data without modifying it.
- `enable_compression::Bool=false`: Enable compression of time series data in HDF5.
- `compression::CompressionSettings`: Allows customization of HDF5 compression settings.
- `config_path::String`: specify path to validation config file
- `unit_system::String`: (Default = `"SYSTEM_BASE"`) Set the unit system for
[per-unitization](@ref per_unit) while getting and setting data (`"SYSTEM_BASE"`,
`"DEVICE_BASE"`, or `"NATURAL_UNITS"`)
- `bus_name_formatter`: A function that takes a `Dict` of bus data (with keys like `"name"` and `"index"`) and returns a `String` to use as the bus name when [parsing PSSe or Matpower files](@ref pm_data).
- `load_name_formatter`: A function that takes a `Dict` of load data (with key `"source_id"`) and returns a `String` to use as the load name when [parsing PSSe or Matpower files](@ref pm_data).
- `loadzone_name_formatter`: A function that takes a load zone identifier (typically an `Int`) and returns a `String` to use as the load zone name when [parsing PSSe or Matpower files](@ref pm_data).
- `gen_name_formatter`: A function that takes a `Dict` of generator data and returns a `String` to use as the generator name when [parsing PSSe or Matpower files](@ref pm_data).
- `shunt_name_formatter`: A function that takes a `Dict` of shunt data and returns a `String` to use as the [`FixedAdmittance`](@ref) name when [parsing PSSe or Matpower files](@ref pm_data).
- `branch_name_formatter`: A function that takes a `Dict` of branch data, a from-bus (`ACBus`), and a to-bus (`ACBus`), and returns a `String` to use as the branch name when [parsing PSSe or Matpower files](@ref pm_data).
- `pm_data_corrections::Bool`: A function that applies the correction to the data from [`PowerModels.jl`](https://lanl-ansi.github.io/PowerModels.jl/stable/).
- `import_all::Bool`: A boolean flag to indicate whether to import all available data when [parsing PSSe or Matpower files](@ref pm_data). The additional data will be stored in the `ext` dictionary and can be retrieved using [`get_ext`](@ref)
- `internal::IS.InfrastructureSystemsInternal`: Internal structure for [`InfrastructureSystems.jl`](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/). This is used only during JSON de-seralization, do not pass it when building a `System` manually.
By default, time series data is stored in an HDF5 file in the tmp file system to prevent
large datasets from overwhelming system memory (see [Data Storage](@ref)).
**If the system's time series data will be larger than the amount of tmp space available**, use the
`time_series_directory` parameter to change its location.
You can also override the location by setting the environment
variable `SIENNA_TIME_SERIES_DIRECTORY` to another directory.
HDF5 compression is not enabled by default, but you can enable
it with `enable_compression` to get significant storage savings at the cost of CPU time.
[`CompressionSettings`](@ref) can be used to customize the HDF5 compression.
If you know that your dataset will fit in your computer's memory, then you can increase
performance by storing it in memory with `time_series_in_memory`.
# Examples
```julia
sys = System(100.0; name = "My Power System")
sys = System(100.0; name = "My Power System", description = "System corresponds to scenario A")
sys= System(path_to_my_psse_raw_file; # PSSE file bus names are not unique
bus_name_formatter = x -> strip(string(x["name"])) * "-" * string(x["index"]),
)
sys = System(100.0; enable_compression = true)
sys = System(100.0; compression = CompressionSettings(
enabled = true,
type = CompressionTypes.DEFLATE, # BLOSC is also supported
level = 3,
shuffle = true)
)
sys = System(100.0; time_series_in_memory = true)
```
"""
struct System <: IS.ComponentContainer
data::IS.SystemData
frequency::Float64 # [Hz]
bus_numbers::Set{Int}
runchecks::Base.RefValue{Bool}
units_settings::SystemUnitsSettings
time_series_directory::Union{Nothing, String}
metadata::SystemMetadata
internal::IS.InfrastructureSystemsInternal
function System(
data,
units_settings::SystemUnitsSettings,
internal::IS.InfrastructureSystemsInternal;
runchecks = true,
frequency = DEFAULT_SYSTEM_FREQUENCY,
time_series_directory = nothing,
name = nothing,
description = nothing,
kwargs...,
)
# Note to devs: if you add parameters to kwargs then consider whether they need
# special handling in the deserialization function in this file.
# See deserialize for System.
# Implement a strict check here to make sure that SYSTEM_KWARGS can be used
# elsewhere.
unsupported = setdiff(keys(kwargs), SYSTEM_KWARGS)
!isempty(unsupported) && error("Unsupported kwargs = $unsupported")
if !isnothing(get(kwargs, :unit_system, nothing))
@warn(
"unit_system kwarg ignored. The value in SystemUnitsSetting takes precedence"
)
end
bus_numbers = Set(get_number.(IS.get_components(ACBus, data)))
return new(
data,
frequency,
bus_numbers,
Base.RefValue{Bool}(runchecks),
units_settings,
time_series_directory,
SystemMetadata(name, description),
internal,
)
end
end
function System(data, base_power::Number, internal; kwargs...)
unit_system_ = get(kwargs, :unit_system, "SYSTEM_BASE")
unit_system = UNIT_SYSTEM_MAPPING[unit_system_]
units_settings = SystemUnitsSettings(base_power, unit_system)
return System(data, units_settings, internal; kwargs...)
end
"""Construct an empty `System`. Useful for building a System while parsing raw data."""
function System(base_power::Number; kwargs...)
return System(_create_system_data_from_kwargs(; kwargs...), base_power; kwargs...)
end
"""Construct a `System` from `InfrastructureSystems.SystemData`"""
function System(
data,
base_power::Number;
internal = IS.InfrastructureSystemsInternal(),
kwargs...,
)
return System(data, base_power, internal; kwargs...)
end
"""
System constructor when components are constructed externally.
"""
function System(base_power::Float64, buses::Vector{ACBus}, components...; kwargs...)
data = _create_system_data_from_kwargs(; kwargs...)
sys = System(data, base_power; kwargs...)
for bus in buses
add_component!(sys, bus)
end
for component in Iterators.flatten(components)
add_component!(sys, component)
end
if get(kwargs, :runchecks, true)
check(sys)
end
return sys
end
"""Constructs a non-functional System for demo purposes."""
function System(
::Nothing;
buses = [
ACBus(;
number = 0,
name = "init",
bustype = ACBusTypes.REF,
available = true,
angle = 0.0,
magnitude = 0.0,
voltage_limits = (min = 0.0, max = 0.0),
base_voltage = nothing,
area = nothing,
load_zone = nothing,
ext = Dict{String, Any}(),
),
],
generators = [ThermalStandard(nothing), RenewableNonDispatch(nothing)],
loads = [PowerLoad(nothing)],
branches = nothing,
storage = nothing,
base_power::Float64 = 100.0,
services = nothing,
kwargs...,
)
for component in Iterators.flatten((generators, loads))
if get_name(component) == "init"
set_bus!(component, first(buses))
end
end
_services = isnothing(services) ? [] : services
_branches = isnothing(branches) ? [] : branches
_storage = isnothing(storage) ? [] : storage
return System(
base_power,
buses,
generators,
loads,
_branches,
_storage,
_services;
kwargs...,
)
end
function system_via_power_models(file_path::AbstractString; kwargs...)
pm_kwargs = Dict(k => v for (k, v) in kwargs if !in(k, SYSTEM_KWARGS))
sys_kwargs = Dict(k => v for (k, v) in kwargs if in(k, SYSTEM_KWARGS))
return System(PowerModelsData(file_path; pm_kwargs...); sys_kwargs...)
end
"""Constructs a System from a file path ending with .m, .raw, or .json
If the file is JSON, then `assign_new_uuids = true` will generate new UUIDs for the system
and all components. If the file is .raw, then `try_reimport = false` will skip searching for
a `_export_metadata.json` file in the same directory.
"""
function System(
file_path::AbstractString;
assign_new_uuids = false,
try_reimport = true,
kwargs...,
)
ext = lowercase(splitext(file_path)[2])
if ext == ".m"
return system_via_power_models(file_path; kwargs...)
elseif ext == ".raw"
try_reimport && return system_from_psse_reimport(file_path; kwargs...)
return system_via_power_models(file_path; kwargs...)
elseif ext == ".json"
unsupported = setdiff(keys(kwargs), SYSTEM_KWARGS)
!isempty(unsupported) && error("Unsupported kwargs = $unsupported")
runchecks = get(kwargs, :runchecks, true)
time_series_read_only = get(kwargs, :time_series_read_only, false)
time_series_directory = get(kwargs, :time_series_directory, nothing)
config_path = get(kwargs, :config_path, POWER_SYSTEM_STRUCT_DESCRIPTOR_FILE)
sys = deserialize(
System,
file_path;
time_series_read_only = time_series_read_only,
runchecks = runchecks,
time_series_directory = time_series_directory,
config_path = config_path,
)
_post_deserialize_handling(
sys;
runchecks = runchecks,
assign_new_uuids = assign_new_uuids,
)
return sys
else
throw(DataFormatError("$file_path is not a supported file type"))
end
end
"""
If assign_new_uuids = true, generate new UUIDs for the system and all components.
Warning: time series data is not restored by this method. If that is needed, use the normal
process to construct the system from a serialized JSON file instead, such as with
`System("sys.json")`.
"""
function IS.from_json(
io::Union{IO, String},
::Type{System};
runchecks = true,
assign_new_uuids = false,
kwargs...,
)
data = JSON3.read(io, Dict)
sys = from_dict(System, data; kwargs...)
_post_deserialize_handling(
sys;
runchecks = runchecks,
assign_new_uuids = assign_new_uuids,
)
return sys
end
function _post_deserialize_handling(sys::System; runchecks = true, assign_new_uuids = false)
runchecks && check(sys)
if assign_new_uuids
IS.assign_new_uuid!(sys)
for component in get_components(Component, sys)
IS.assign_new_uuid!(sys, component)
end
for component in
IS.get_masked_components(InfrastructureSystemsComponent, sys.data)
IS.assign_new_uuid!(sys, component)
end
# Note: this does not change UUIDs for time series data because they are
# shared with components.
end
end
"""
Parse static and dynamic data directly from PSS/e text files. Automatically generates
all the relationships between the available dynamic injection models and the static counterpart
Each dictionary indexed by id contains a vector with 5 of its components:
* Machine
* Shaft
* AVR
* TurbineGov
* PSS
Files must be parsed from a .raw file (PTI data format) and a .dyr file.
## Examples:
```julia
raw_file = "Example.raw"
dyr_file = "Example.dyr"
sys = System(raw_file, dyr_file)
```
"""
function System(sys_file::AbstractString, dyr_file::AbstractString; kwargs...)
ext = splitext(sys_file)[2]
if lowercase(ext) in [".raw"]
pm_kwargs = Dict(k => v for (k, v) in kwargs if !in(k, SYSTEM_KWARGS))
sys = System(PowerModelsData(sys_file; pm_kwargs...); kwargs...)
else
throw(DataFormatError("$sys_file is not a .raw file type"))
end
add_dyn_injectors!(sys, dyr_file)
return sys
end
"""
Construct a System from a subsystem of an existing system.
# Arguments
- `sys::System`: the base system from which the subsystems are derived
- `subsystem::String`: the name of the subsystem to extract from the original system
# Keyword arguments
- `runchecks::Bool`: (default = true) whether to run system validation checks.
"""
function from_subsystem(sys::System, subsystem::AbstractString; runchecks = true)
if !in(subsystem, get_subsystems(sys))
error("subsystem = $subsystem is not stored")
end
# It would be faster to create an empty system and then populate it with
# deep copies of each component in the subsystem. It would also result in a "clean" HDF5
# file (the result here will have deleted entries that need to repacked through
# serialization/de-serialization). That is not implemented because
# 1. The performance loss should not be too large.
# 2. We haven't yet implemented deepcopy(Component).
# 3. There is extra code complexity in adding copied components in the correct order
# as well as copying time series data.
new_sys = deepcopy(sys)
filter_components_by_subsystem!(new_sys, subsystem; runchecks = runchecks)
IS.assign_new_uuid!(new_sys)
for component in get_components(Component, new_sys)
IS.assign_new_uuid!(new_sys, component)
end
return new_sys
end
"""
Filter out all components that are not part of the subsystem.
"""
function filter_components_by_subsystem!(
sys::System,
subsystem::AbstractString;
runchecks = true,
)
component_uuids = get_component_uuids(sys, subsystem)
for component in get_components(Component, sys)
if !in(IS.get_uuid(component), component_uuids)
remove_component!(sys, component)
end
end
for component in IS.get_masked_components(Component, sys.data)
if !in(IS.get_uuid(component), component_uuids)
IS.remove_masked_component!(sys.data, component)
end
end
if runchecks
check(sys)
check_components(sys)
end
end
"""
Serializes a system to a JSON file and saves time series to an HDF5 file.
# Arguments
- `sys::System`: system
- `filename::AbstractString`: filename to write
# Keyword arguments
- `user_data::Union{Nothing, Dict} = nothing`: optional metadata to record
- `pretty::Bool = false`: whether to pretty-print the JSON
- `force::Bool = false`: whether to overwrite existing files
- `check::Bool = false`: whether to run system validation checks
Refer to [`check_component`](@ref) for exceptions thrown if `check = true`.
"""
function IS.to_json(
sys::System,
filename::AbstractString;
user_data = nothing,
pretty = false,
force = false,
runchecks = false,
)
if runchecks
check(sys)
check_components(sys)
end
IS.prepare_for_serialization_to_file!(sys.data, filename; force = force)
data = to_json(sys; pretty = pretty)
open(filename, "w") do io
write(io, data)
end
mfile = joinpath(dirname(filename), splitext(basename(filename))[1] * "_metadata.json")
@info "Serialized System to $filename"
_serialize_system_metadata_to_file(sys, mfile, user_data)
return
end
function _serialize_system_metadata_to_file(sys::System, filename, user_data)
name = get_name(sys)
description = get_description(sys)
resolutions = [x.value for x in get_time_series_resolutions(sys)]
metadata = OrderedDict(
"name" => isnothing(name) ? "" : name,
"description" => isnothing(description) ? "" : description,
"frequency" => sys.frequency,
"time_series_resolutions_milliseconds" => resolutions,
"component_counts" => IS.get_component_counts_by_type(sys.data),
"time_series_counts" => IS.get_time_series_counts_by_type(sys.data),
)
if !isnothing(user_data)
metadata["user_data"] = user_data
end
open(filename, "w") do io
JSON3.pretty(io, metadata)
end
@info "Serialized System metadata to $filename"
end
IS.assign_new_uuid!(sys::System) = IS.assign_new_uuid_internal!(sys)
"""
Return the internal of the system
"""
IS.get_internal(sys::System) = sys.internal
"""
Return a user-modifiable dictionary to store extra information.
"""
get_ext(sys::System) = IS.get_ext(sys.internal)
"""
Return the system's base power.
"""
get_base_power(sys::System) = sys.units_settings.base_value
"""
Return the system's frequency.
"""
get_frequency(sys::System) = sys.frequency
"""
Clear any value stored in ext.
"""
clear_ext!(sys::System) = IS.clear_ext!(sys.internal)
"""
Return true if checks are enabled on the system.
"""
get_runchecks(sys::System) = sys.runchecks[]
"""
Enable or disable system checks.
Applies to component addition as well as overall system consistency.
"""
function set_runchecks!(sys::System, value::Bool)
sys.runchecks[] = value
@info "Set runchecks to $value"
end
function set_units_setting!(
component::Component,
settings::Union{SystemUnitsSettings, Nothing},
)
set_units_info!(get_internal(component), settings)
return
end
function _set_units_base!(system::System, settings::UnitSystem)
to_change = (system.units_settings.unit_system != settings)
to_change && (system.units_settings.unit_system = settings)
return (to_change, settings)
end
_set_units_base!(system::System, settings::String) =
_set_units_base!(system::System, UNIT_SYSTEM_MAPPING[uppercase(settings)])
"""
Sets the units base for the getter functions on the devices. It modifies the behavior of all getter functions
# Examples
```julia
set_units_base_system!(sys, "NATURAL_UNITS")
```
```julia
set_units_base_system!(sys, UnitSystem.SYSTEM_BASE)
```
"""
function set_units_base_system!(system::System, units::Union{UnitSystem, String})
changed, new_units = _set_units_base!(system::System, units)
changed && @info "Unit System changed to $new_units"
return
end
_get_units_base(system::System) = system.units_settings.unit_system
"""
Get the system's [unit base](@ref per_unit))
"""
function get_units_base(system::System)
return string(_get_units_base(system))
end
"""
A "context manager" that sets the [`System`](@ref)'s [units base](@ref per_unit) to the
given value, executes the function, then sets the units base back.
# Examples
```julia
active_power_mw = with_units_base(sys, UnitSystem.NATURAL_UNITS) do
get_active_power(gen)
end
# now active_power_mw is in natural units no matter what units base the system is in
```
"""
function with_units_base(f::Function, sys::System, units::Union{UnitSystem, String})
old_units = _get_units_base(sys)
_set_units_base!(sys, units)
try
f()
finally
_set_units_base!(sys, old_units)
end
end
_set_units_base!(c::Component, settings::String) =
_set_units_base!(c::Component, UNIT_SYSTEM_MAPPING[uppercase(settings)])
function _set_units_base!(c::Component, settings::UnitSystem)
units_info = get_internal(c).units_info
old_base_value = units_info.base_value
set_units_setting!(
c,
SystemUnitsSettings(old_base_value, settings),
)
return
end
"""
A "context manager" that sets the [`Component`](@ref)'s [units base](@ref per_unit) to the
given value, executes the function, then sets the units base back.
# Examples
```julia
active_power_mw = with_units_base(component, UnitSystem.NATURAL_UNITS) do
get_active_power(component)
end
# now active_power_mw is in natural units no matter what units base the system is in
```
"""
function with_units_base(f::Function, c::Component, units::Union{UnitSystem, String})
internal = get_internal(c)
old_units_info = internal.units_info # Save reference to restore later
_set_units_base!(c, units)
temp_units_info = internal.units_info # The temporary object we just created
try
f()
finally
# Only restore if units_info is still temp_units_info.
# The user may have changed it in the function body, by e.g. removing the component
# and then attaching it to a different system.
internal.units_info === temp_units_info || error(
"Units info was modified during with_units_base.")
IS.set_units_info!(internal, old_units_info)
end
end
function get_units_setting(component::T) where {T <: Component}
return get_units_info(get_internal(component))
end
function has_units_setting(component::T) where {T <: Component}
return !isnothing(get_units_setting(component))
end
"""
Set the name of the system.
"""
set_name!(sys::System, name::AbstractString) = sys.metadata.name = name
"""
Get the name of the system.
"""
get_name(sys::System) = sys.metadata.name
"""
Set the description of the system.
"""
set_description!(sys::System, description::AbstractString) =
sys.metadata.description = description
"""
Get the description of the system.
"""
get_description(sys::System) = sys.metadata.description
"""
Add a component to the system.
A component cannot be added to more than one `System`.
Throws ArgumentError if the component's name is already stored for its concrete type.
Throws ArgumentError if any Component-specific rule is violated.
Throws InvalidValue if any of the component's field values are outside of defined valid
range.
# Examples
```julia
sys = System(100.0)
# Add a single component.
add_component!(sys, bus)
# Add many at once.
buses = [bus1, bus2, bus3]
generators = [gen1, gen2, gen3]
foreach(x -> add_component!(sys, x), Iterators.flatten((buses, generators)))
```
See also [`add_components!`](@ref).
"""
function add_component!(
sys::System,
component::T;
skip_validation = false,
kwargs...,
) where {T <: Component}
set_units_setting!(component, sys.units_settings)
@assert has_units_setting(component)
check_topology(sys, component)
check_component_addition(sys, component; kwargs...)
deserialization_in_progress = _is_deserialization_in_progress(sys)
if !deserialization_in_progress
# Services are attached to devices at deserialization time.
check_for_services_on_addition(sys, component)
end
skip_validation = _validate_or_skip!(sys, component, skip_validation)
_kwargs = Dict(k => v for (k, v) in kwargs if k !== :static_injector)
IS.add_component!(
sys.data,
component;
allow_existing_time_series = deserialization_in_progress,
skip_validation = skip_validation,
_kwargs...,
)
if !deserialization_in_progress
# Whatever this may change should have been validated above in
# check_component_addition, so this should not fail.
# Doesn't run at deserialization time because the changes made by this function
# occurred when the original addition ran and do not apply to that scenario.
handle_component_addition!(sys, component; kwargs...)
# Special condition required to populate the bus numbers in the system after
elseif component isa Bus
handle_component_addition!(sys, component; kwargs...)
end
return
end
"""
Add many components to the system at once.
A component cannot be added to more than one `System`.
Throws ArgumentError if the component's name is already stored for its concrete type.
Throws ArgumentError if any Component-specific rule is violated.
Throws InvalidValue if any of the component's field values are outside of defined valid
range.
# Examples
```julia
sys = System(100.0)
buses = [bus1, bus2, bus3]
generators = [gen1, gen2, gen3]
add_components!(sys, Iterators.flatten((buses, generators))
```
"""
function add_components!(sys::System, components)
foreach(x -> add_component!(sys, x), components)
return
end
"""
Add a dynamic injector to the system.
A component cannot be added to more than one `System`.
Throws ArgumentError if the name does not match the `static_injector` name.
Throws ArgumentError if the `static_injector` is not attached to the system.
All rules for the generic `add_component!` method also apply.
"""
function add_component!(
sys::System,
dyn_injector::DynamicInjection,
static_injector::StaticInjection;
kwargs...,
)
add_component!(sys, dyn_injector; static_injector = static_injector, kwargs...)
return
end
"""
Replace the dynamic injector in a static component.
Safely removes the old dynamic injector from the system if no other component references it.
If another component references the old dynamic injector, it is kept in the system and an
info message is logged.
Throws ArgumentError if the static injector is not attached to the system.
Throws ArgumentError if the static injector does not have a dynamic injector.
Throws ArgumentError if the new dynamic injector name does not match the static injector name.
"""
function replace_dynamic_injector!(
sys::System,
static_injector::StaticInjection,
new_dynamic_injector::DynamicInjection,
)
throw_if_not_attached(static_injector, sys)
old_dynamic_injector = get_dynamic_injector(static_injector)
if isnothing(old_dynamic_injector)
throw(
ArgumentError(
"$(get_name(static_injector)) does not have a dynamic injector to replace",
),
)
end
if get_name(new_dynamic_injector) != get_name(static_injector)
throw(
ArgumentError(
"new_dynamic_injector must have the same name as the static_injector",
),
)
end
# Unlink old dynamic injector from this static component
set_dynamic_injector!(static_injector, nothing)
# Check if any other static injector in the system references the old dynamic injector
is_referenced_elsewhere = false
for si in get_components(StaticInjection, sys)
si === static_injector && continue
dyn = get_dynamic_injector(si)
if dyn === old_dynamic_injector
is_referenced_elsewhere = true
break
end
end
if is_referenced_elsewhere
@info "The dynamic injector $(get_name(old_dynamic_injector)) is referenced by " *
"another component and will not be removed from the system."
else
# Safely remove old dynamic injector from the system
_handle_component_removal_common!(old_dynamic_injector)
IS.remove_component!(sys.data, old_dynamic_injector)
end
# Add the new dynamic injector, linked to the static component
add_component!(sys, new_dynamic_injector, static_injector)
return
end
function _add_service!(
sys::System,
service::Service,
contributing_devices;
skip_validation = false,
kwargs...,
)
skip_validation = _validate_or_skip!(sys, service, skip_validation)
for device in contributing_devices
device_type = typeof(device)
if !(device_type <: Device)
throw(ArgumentError("contributing_devices must be of type Device"))
end
throw_if_not_attached(device, sys)
end
set_units_setting!(service, sys.units_settings)
# Since this isn't atomic, order is important. Add to system before adding to devices.
IS.add_component!(sys.data, service; skip_validation = skip_validation, kwargs...)
for device in contributing_devices
add_service_internal!(device, service)
end
end
function _validate_types_for_interface(sys::System, contributing_devices)
device_types = Set{DataType}()
for device in contributing_devices
device_type = typeof(device)
if !(device_type <: Branch)
throw(ArgumentError("contributing_devices must be of type Branch"))
end
push!(device_types, device_type)
throw_if_not_attached(device, sys)
end
if length(device_types) > 1 && AreaInterchange in device_types
throw(
ArgumentError(
"contributing_devices can't mix AreaInterchange with other Branch types",
),
)
end
return
end
function _validate_types_for_agc(contributing_devices)
for device in contributing_devices
device_type = typeof(device)
if !(device_type <: Reserve)
throw(ArgumentError("contributing_devices of AGC must be of type Reserve"))
end
end
return
end
function _add_service!(
sys::System,
service::TransmissionInterface,
contributing_devices;
skip_validation = false,
kwargs...,
)
skip_validation = _validate_or_skip!(sys, service, skip_validation)
_validate_types_for_interface(sys, contributing_devices)
set_units_setting!(service, sys.units_settings)
# Since this isn't atomic, order is important. Add to system before adding to devices.
IS.add_component!(sys.data, service; skip_validation = skip_validation, kwargs...)
for device in contributing_devices
add_service_internal!(device, service)
end
end
function _add_service!(
sys::System,
service::AGC,
contributing_devices;
skip_validation = false,
kwargs...,
)
skip_validation = _validate_or_skip!(sys, service, skip_validation)
_validate_types_for_agc(contributing_devices)
set_units_setting!(service, sys.units_settings)
# Since this isn't atomic, order is important. Add to system before adding to devices.
IS.add_component!(sys.data, service; skip_validation = skip_validation, kwargs...)
for device in contributing_devices
add_service_internal!(service, device)
end
end
"""
Similar to [`add_component!`](@ref) but for services.
# Arguments
- `sys::System`: system
- `service::Service`: service to add
- `contributing_devices`: Must be an iterable of type Device
"""
function add_service!(sys::System, service::Service, contributing_devices; kwargs...)
_add_service!(sys, service, contributing_devices; kwargs...)
return
end
"""
Similar to [`add_component!`](@ref) but for services.
# Arguments
- `sys::System`: system
- `service::Service`: service to add
- `contributing_device::Device`: Valid Device
"""
function add_service!(sys::System, service::Service, contributing_device::Device; kwargs...)
_add_service!(sys, service, [contributing_device]; kwargs...)
return
end
"""
Similar to [`add_service!`](@ref) but for Service and Device already stored in the system.
Performs validation checks on the device and the system
# Arguments
- `device::Device`: Device
- `service::Service`: Service
- `sys::System`: system
"""
function add_service!(device::Device, service::Service, sys::System)
throw_if_not_attached(service, sys)
throw_if_not_attached(device, sys)
add_service_internal!(device, service)
return
end
"""
Similar to [`add_component!`](@ref) but for ConstantReserveGroup.
# Arguments
- `sys::System`: system
- `service::ConstantReserveGroup`: service to add
"""
function add_service!(
sys::System,
service::ConstantReserveGroup;
skip_validation = false,
kwargs...,
)
skip_validation = _validate_or_skip!(sys, service, skip_validation)
for _service in get_contributing_services(service)
throw_if_not_attached(_service, sys)
end
set_units_setting!(service, sys.units_settings)
IS.add_component!(sys.data, service; skip_validation = skip_validation, kwargs...)
return
end
"""Set ConstantReserveGroup contributing_services with check"""
function set_contributing_services!(
sys::System,
service::ConstantReserveGroup,
val::Vector{<:Service},
)
for _service in val
throw_if_not_attached(_service, sys)
end
service.contributing_services = val
return
end
"""
Similar to [`add_component!`](@ref) but for ConstantReserveGroup.
# Arguments
- `sys::System`: system
- `service::ConstantReserveGroup`: service to add
- `contributing_services`: contributing services to the group
"""
function add_service!(
sys::System,
service::ConstantReserveGroup,
contributing_services::Vector{<:Service};
skip_validation = false,
kwargs...,
)
skip_validation = _validate_or_skip!(sys, service, skip_validation)
set_contributing_services!(sys, service, contributing_services)
set_units_setting!(service, sys.units_settings)
IS.add_component!(sys.data, service; skip_validation = skip_validation, kwargs...)
return
end
"""
Open the time series store for bulk additions or reads
This is recommended before calling `add_time_series!` many times because of the overhead
associated with opening and closing an HDF5 file.
This is not necessary for an in-memory time series store.
# Examples
```julia
# Assume there is a system with an array of Components and SingleTimeSeries
# stored in the variables components and single_time_series, respectively
open_time_series_store!(sys, "r+") do
for (component, ts) in zip(components, single_time_series)
add_time_series!(sys, component, ts)
end
end
```
You can also use this function to make reads faster.
Change the mode from `"r+"` to `"r"` to open the file read-only.
See also: [`begin_time_series_update`](@ref)
"""
function open_time_series_store!(
func::Function,
sys::System,
mode = "r",
args...;
kwargs...,
)
IS.open_time_series_store!(func, sys.data, mode, args...; kwargs...)
end
"""
Begin an update of time series. Use this function when adding many time series arrays
in order to improve performance.
If an error occurs during the update, changes will be reverted.
Using this function to remove time series is currently not supported.
# Examples
```julia
begin_time_series_update(sys) do
add_time_series!(sys, component1, time_series1)
add_time_series!(sys, component2, time_series2)
end
```
"""
begin_time_series_update(func::Function, sys::System) =
IS.begin_time_series_update(func, sys.data.time_series_manager)
"""
Add time series data from a metadata file or metadata descriptors.
# Arguments
- `sys::System`: system
- `metadata_file::AbstractString`: metadata file for timeseries
that includes an array of IS.TimeSeriesFileMetadata instances or a vector.
- `resolution::DateTime.Period=nothing`: skip time series that don't match this resolution.
"""
function add_time_series!(sys::System, metadata_file::AbstractString; resolution = nothing)
return IS.add_time_series_from_file_metadata!(
sys.data,
Component,
metadata_file;
resolution = resolution,
)
end
"""
Add time series data from a metadata file or metadata descriptors.
# Arguments
- `sys::System`: system
- `timeseries_metadata::Vector{IS.TimeSeriesFileMetadata}`: metadata for timeseries
- `resolution::DateTime.Period=nothing`: skip time series that don't match this resolution.
"""
function add_time_series!(
sys::System,
file_metadata::Vector{IS.TimeSeriesFileMetadata};
resolution = nothing,
)
return IS.add_time_series_from_file_metadata!(
sys.data,
Component,
file_metadata;
resolution = resolution,
)
end
function IS.add_time_series_from_file_metadata_internal!(
data::IS.SystemData,
::Type{<:Component},
cache::IS.TimeSeriesParsingCache,
file_metadata::IS.TimeSeriesFileMetadata,
)
associations = TimeSeriesAssociation[]
IS.set_component!(file_metadata, data, PowerSystems)
component = file_metadata.component
if isnothing(component)
return associations
end
ts = IS.make_time_series!(cache, file_metadata)
if component isa AggregationTopology && file_metadata.scaling_factor_multiplier in
["get_max_active_power", "get_max_reactive_power"]
uuids = Set{Base.UUID}()
for bus in _get_buses(data, component)
push!(uuids, IS.get_uuid(bus))
end
for _component in (
load for load in IS.get_components(ElectricLoad, data) if
IS.get_uuid(get_bus(load)) in uuids
)
file_metadata.component = _component
if !IS.has_assignment(cache, file_metadata)
IS.add_assignment!(cache, file_metadata)
push!(associations, TimeSeriesAssociation(_component, ts))
end
end
file_metadata.component = component
orig_sf = file_metadata.scaling_factor_multiplier
try
file_metadata.scaling_factor_multiplier = replace(orig_sf, "max" => "peak")
area_ts = IS.make_time_series!(cache, file_metadata)
IS.add_assignment!(cache, file_metadata)
push!(associations, TimeSeriesAssociation(component, area_ts))
finally
file_metadata.scaling_factor_multiplier = orig_sf
end
else
push!(associations, TimeSeriesAssociation(component, ts))
IS.add_assignment!(cache, file_metadata)
end
return associations
end
"""
Iterates over all components.
# Examples
```julia
for component in iterate_components(sys)
@show component
end
```
See also: [`get_components`](@ref)
"""
function iterate_components(sys::System)
return IS.iterate_components(sys.data)
end
"""
Remove all components from the system.
"""
function clear_components!(sys::System)
return IS.clear_components!(sys.data)
end
"""
Remove all components of type T from the system.
Throws ArgumentError if the type is not stored.
"""
# the argument order in this function is un-julian and should be deprecated in 2.0
function remove_components!(::Type{T}, sys::System) where {T <: Component}
return remove_components!(sys, T)
end
"""
Remove all components of type `T` from the system.
Throws `ArgumentError` if the type is not stored.
"""
function remove_components!(sys::System, ::Type{T}) where {T <: Component}
components = IS.remove_components!(T, sys.data)
for component in components
handle_component_removal!(sys, component)
end
return components
end
"""
Remove all components of type `T` that match `filter_func` from the system.
"""
function remove_components!(
filter_func::Function,
sys::System,
::Type{T},
) where {T <: Component}
components = collect(get_components(filter_func, T, sys))
for component in components
remove_component!(sys, component)
end
return components
end
"""
Set the name for a component that is attached to the system.
"""
set_name!(sys::System, component::Component, name::AbstractString) =
set_name!(sys.data, component, name)
"""
Set the name of a component.
Throws an exception if the component is attached to a system.
"""
function set_name!(component::Component, name::AbstractString)
# The units setting is nothing until the component is attached to the system.
if get_units_setting(component) !== nothing
# This is not allowed because components are stored in the system in a Dict
# keyed by name.
error(
"The component is attached to a system. " *
"Call set_name!(system, component, name) instead.",
)
end
component.name = name
end
function clear_units!(component::Component)
get_internal(component).units_info = nothing
return
end
"""
Remove a component from the system by its value.
Throws ArgumentError if the component is not stored.
"""
function remove_component!(sys::System, component::T) where {T <: Component}
check_component_removal(sys, component)
IS.remove_component!(sys.data, component)
handle_component_removal!(sys, component)
return
end
"""
Throws ArgumentError if a PowerSystems rule blocks removal from the system.
"""
function check_component_removal(sys::System, service::T) where {T <: Service}
if T == ConstantReserveGroup
return
end
groupservices = get_components(ConstantReserveGroup, sys)
for groupservice in groupservices
if service ∈ get_contributing_services(groupservice)
throw(
ArgumentError(
"service $(get_name(service)) cannot be removed with an attached ConstantReserveGroup",
),
)
return
end
end
end
"""
Remove a component from the system by its name.
Throws ArgumentError if the component is not stored.
"""
function remove_component!(
::Type{T},
sys::System,
name::AbstractString,
) where {T <: Component}
component = IS.remove_component!(T, sys.data, name)
handle_component_removal!(sys, component)
return
end
"""
Check to see if the component of type T exists.
"""
function has_components(sys::System, T::Type{<:Component})
return IS.has_components(sys.data.components, T)
end
"""
Check to see if the component of type T with name exists.
"""
function has_component(sys::System, T::Type{<:Component}, name::AbstractString)
return IS.has_component(sys.data, T, name)
end
has_component(T::Type{<:Component}, sys::System, name::AbstractString) =
has_component(sys, T, name)
"""
Get the component of type T with name. Returns nothing if no component matches. If T is an abstract
type then the names of components across all subtypes of T must be unique.
See [`get_components_by_name`](@ref) for abstract types with non-unique names across subtypes.
Throws ArgumentError if T is not a concrete type and there is more than one component with
requested name
"""
function IS.get_component(
::Type{T},
sys::System,
name::AbstractString,
) where {T <: Component}
return IS.get_component(T, sys.data, name)
end
"""
Return an iterator of components of a given `Type` from a [`System`](@ref).
`T` can be a concrete or abstract [`Component`](@ref) type from the [Type Tree](@ref).
Call collect on the result if an array is desired.
# Examples
```julia
iter = get_components(ThermalStandard, sys)
iter = get_components(Generator, sys)
generators = collect(get_components(Generator, sys))
```
See also: [`iterate_components`](@ref), [`get_components` with a filter](@ref get_components(
filter_func::Function,
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component}),
[`get_available_components`](@ref), [`get_buses`](@ref)
"""
function IS.get_components(
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component}
return IS.get_components(T, sys.data; subsystem_name = subsystem_name)
end
function IS.get_components(
filter_func::Function,
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component}
return IS.get_components(filter_func, T, sys.data; subsystem_name = subsystem_name)
end
"""
Return a vector of components that are attached to the supplemental attribute.
"""
function IS.get_components(sys::System, attribute::SupplementalAttribute)
return IS.get_components(sys.data, attribute)
end
"""
Get the component by UUID.
"""
IS.get_component(sys::System, uuid::Base.UUID) = IS.get_component(sys.data, uuid)
IS.get_component(sys::System, uuid::String) = IS.get_component(sys.data, Base.UUID(uuid))
"""
Change the UUID of a component.
"""
IS.assign_new_uuid!(sys::System, x::Component) = IS.assign_new_uuid!(sys.data, x)
function _get_components_by_name(abstract_types, data::IS.SystemData, name::AbstractString)
_components = []
for subtype in abstract_types
component = IS.get_component(subtype, data, name)
if !isnothing(component)
push!(_components, component)
end
end
return _components
end
"""
Get the components of abstract type T with name. Note that PowerSystems enforces unique
names on each concrete type but not across concrete types.
See [`get_component`](@ref) if the concrete type is known.
Throws ArgumentError if T is not an abstract type.
"""
function get_components_by_name(
::Type{T},
sys::System,
name::AbstractString,
) where {T <: Component}
return IS.get_components_by_name(T, sys.data, name)
end
"""
Return true if the component is attached to the system.
"""
function is_attached(component::T, sys::System) where {T <: Component}
existing_component = get_component(T, sys, get_name(component))
isnothing(existing_component) && return false
return component === existing_component
end
"""
Throws ArgumentError if the component is not attached to the system.
"""
function throw_if_not_attached(component::Component, sys::System)
if !is_attached(component, sys)
throw(ArgumentError("$(summary(component)) is not attached to the system"))
end
end
"""
Return a vector of devices contributing to the service.
"""
function get_contributing_devices(sys::System, service::T) where {T <: Service}
throw_if_not_attached(service, sys)
return [
x for x in get_components(supports_services, Device, sys) if has_service(x, service)
]
end
"""
Return a vector of devices contributing to the service.
"""
function get_contributing_devices(sys::System, service::TransmissionInterface)
throw_if_not_attached(service, sys)
return [x for x in get_components(Branch, sys) if has_service(x, service)]
end
"""
Container associating a [`Service`](@ref) with the [`Device`](@ref) components that
contribute to it.
"""
struct ServiceContributingDevices
service::Service
contributing_devices::Vector{Device}
end
const ServiceContributingDevicesKey = NamedTuple{(:type, :name), Tuple{DataType, String}}
const ServiceContributingDevicesMapping =
Dict{ServiceContributingDevicesKey, ServiceContributingDevices}
struct AGCContributingReserves
agc::AGC
contributing_reserves::Vector{Reserve}
end
const AGCContributingReservesKey = NamedTuple{(:type, :name), Tuple{DataType, String}}
const AGCContributingReservesMapping =
Dict{AGCContributingReservesKey, AGCContributingReserves}
"""
Returns a ServiceContributingDevices object.
"""
function _get_contributing_devices(sys::System, service::T) where {T <: Service}
uuid = IS.get_uuid(service)
devices = ServiceContributingDevices(service, Vector{Device}())
for device in get_components(Device, sys)
if supports_services(device)
for _service in get_services(device)
if IS.get_uuid(_service) == uuid
push!(devices.contributing_devices, device)
break
end
end
end
end
return devices
end
"""
Returns a ServiceContributingDevices object.
"""
function _get_contributing_devices(sys::System, service::TransmissionInterface)
uuid = IS.get_uuid(service)
devices = ServiceContributingDevices(service, Vector{Device}())
for device in get_components(Branch, sys)
if supports_services(device)
for _service in get_services(device)
if IS.get_uuid(_service) == uuid
push!(devices.contributing_devices, device)
break
end
end
end
end
return devices
end
"""
Return an instance of AGCContributingReservesMapping.
"""
function get_contributing_reserve_mapping(sys::System)
agcs = AGCContributingReservesMapping()
for agc in get_components(AGC, sys)
key = AGCContributingReservesKey((typeof(agc), get_name(agc)))
agcs[key] = AGCContributingReserves(agc, get_reserves(agc))
end
return agcs
end
"""
Return an instance of ServiceContributingDevicesMapping.
"""
function get_contributing_device_mapping(sys::System)
services = ServiceContributingDevicesMapping()
for service in get_components(Service, sys)
key = ServiceContributingDevicesKey((typeof(service), get_name(service)))
services[key] = _get_contributing_devices(sys, service)
end
return services
end
"""
Return a vector of connected head reservoirs to the turbine. Reservoirs that have the turbine in their downstream_turbines field are head reservoirs of such turbine.
"""
function get_connected_head_reservoirs(sys::System, turbine::T) where {T <: HydroUnit}
throw_if_not_attached(turbine, sys)
return [
x for x in get_components(HydroReservoir, sys) if has_downstream_turbine(x, turbine)
]
end
"""
Return a vector of connected tail reservoirs to the turbine. Reservoirs that have the turbine in their upstream_turbines field are tail reservoirs of such turbine.
"""
function get_connected_tail_reservoirs(sys::System, turbine::T) where {T <: HydroUnit}
throw_if_not_attached(turbine, sys)
return [
x for x in get_components(HydroReservoir, sys) if has_upstream_turbine(x, turbine)
]
end
"""
Container associating a hydro turbine with its connected [`Device`](@ref) components
(e.g., [`HydroReservoir`](@ref) units).
"""
struct TurbineConnectedDevices
turbine::HydroUnit
connected_devices::Vector{Device}
end
const TurbineConnectedDevicesKey = NamedTuple{(:type, :name), Tuple{DataType, String}}
const TurbineConnectedDevicesMapping =
Dict{TurbineConnectedDevicesKey, TurbineConnectedDevices}
"""
Returns a TurbineConnectedDevices object.
"""
function _get_connected_head_devices(sys::System, turbine::T) where {T <: HydroUnit}
uuid = IS.get_uuid(turbine)
devices = TurbineConnectedDevices(turbine, Vector{Device}())
for device in get_components(HydroReservoir, sys)
# Only add reservoirs that have the turbine in their downstream_turbines field
# That is, those reservoirs are a head reservoir to that turbine
for _turbine in get_downstream_turbines(device)
if IS.get_uuid(_turbine) == uuid
push!(devices.connected_devices, device)
break
end
end
end
return devices
end
"""
Returns a TurbineConnectedDevices object.
"""
function _get_connected_tail_devices(sys::System, turbine::T) where {T <: HydroUnit}
uuid = IS.get_uuid(turbine)
devices = TurbineConnectedDevices(turbine, Vector{Device}())
for device in get_components(HydroReservoir, sys)
# Only add reservoirs that have the turbine in their upstream_turbines field
# That is, those reservoirs are a tail reservoir to that turbine
for _turbine in get_upstream_turbines(device)
if IS.get_uuid(_turbine) == uuid
push!(devices.connected_devices, device)
break
end
end
end
return devices
end
"""
Return an instance of TurbineConnectedDevicesMapping.
"""
function get_turbine_head_reservoirs_mapping(sys::System)
turbine_mapping = TurbineConnectedDevicesMapping()
for turbine in get_components(HydroUnit, sys)
key = TurbineConnectedDevicesKey((typeof(HydroUnit), get_name(turbine)))
turbine_mapping[key] = _get_connected_head_devices(sys, turbine)
end
return turbine_mapping
end
"""
Return an instance of TurbineConnectedDevicesMapping.
"""
function get_turbine_tail_reservoirs_mapping(sys::System)
turbine_mapping = TurbineConnectedDevicesMapping()
for turbine in get_components(HydroUnit, sys)
key = TurbineConnectedDevicesKey((typeof(HydroUnit), get_name(turbine)))
turbine_mapping[key] = _get_connected_tail_devices(sys, turbine)
end
return turbine_mapping
end
"""
Return a vector of components with buses in the [`AggregationTopology`](@ref).
"""
function get_components_in_aggregation_topology(
::Type{T},
sys::System,
aggregator::AggregationTopology,
) where {T <: StaticInjection}
buses = Set{String}((get_name(x) for x in get_buses(sys, aggregator)))
components = Vector{T}()
for component in get_components(T, sys)
bus = get_bus(component)
bus_name = get_name(bus)
if bus_name in buses
push!(components, component)
end
end
return components
end
"Return whether the given component's bus is in the [`AggregationTopology`](@ref)"
function is_component_in_aggregation_topology(
comp::Component,
aggregator::T,
) where {T <: AggregationTopology}
accessor = get_aggregation_topology_accessor(T)
return IS.get_uuid(accessor(get_bus(comp))) == IS.get_uuid(aggregator)
end
"""
Return a mapping of [`AggregationTopology`](@ref) name to vector of [`ACBus`](@ref)es within it.
"""
function get_aggregation_topology_mapping(
::Type{T},
sys::System,
) where {T <: AggregationTopology}
mapping = Dict{String, Vector{ACBus}}()
accessor_func = get_aggregation_topology_accessor(T)
for bus in get_components(ACBus, sys)
aggregator = accessor_func(bus)
name = get_name(aggregator)
buses = get(mapping, name, nothing)
if isnothing(buses)
mapping[name] = Vector{ACBus}([bus])
else
push!(buses, bus)
end
end
return mapping
end
"""
Return a vector of buses contained within an [`AggregationTopology`](@ref).
# Examples
```julia
area = get_component(Area, system, "my_area"); # Get an Area named my_area
area_buses = get_buses(system, area)
```
"""
function get_buses(sys::System, aggregator::AggregationTopology)
return _get_buses(sys.data, aggregator)
end
function _get_buses(data::IS.SystemData, aggregator::T) where {T <: AggregationTopology}
accessor_func = get_aggregation_topology_accessor(T)
buses = Vector{ACBus}()
for bus in IS.get_components(ACBus, data)
_aggregator = accessor_func(bus)
if !isnothing(_aggregator) && IS.get_uuid(_aggregator) == IS.get_uuid(aggregator)
push!(buses, bus)
end
end
return buses
end
"""
Add time series data to a component. Assign optional features to differentiate time series
of the same type with the same name but with different data.
Returns a key that can later be used to retrieve the time series data.
Throws ArgumentError if the component is not stored in the system.
# Examples
```julia
ts1 = Deterministic(
name = "max_active_power",
data = deterministic_data,
resolution = Dates.Hour(1),
)
ts2 = SingleTimeSeries(
name = "max_active_power",
data = time_array_1,
)
ts3 = SingleTimeSeries(
name = "max_active_power",
data = time_array_2,
)
key1 = add_time_series!(system, component, ts1)
key2 = add_time_series!(system, component, ts2, scenario = "high")
key3 = add_time_series!(system, component, ts3, scenario = "low")
ts1_b = get_time_series(component, key1)
ts2_b = get_time_series(component, key2)
ts3_b = get_time_series(component, key3)
```
"""
function add_time_series!(
sys::System,
component::Component,
time_series::TimeSeriesData;
features...,
)
return IS.add_time_series!(sys.data, component, time_series; features...)
end
"""
Add time series in bulk.
Prefer use of [`begin_time_series_update`](@ref).
# Examples
```julia
# Assumes `read_time_series` will return data appropriate for Deterministic forecasts
# based on the generator name and the filenames match the component and time series names.
resolution = Dates.Hour(1)
associations = (
IS.TimeSeriesAssociation(
gen,
Deterministic(
data = read_time_series(get_name(gen) * ".csv"),
name = "get_max_active_power",
resolution=resolution),
)
for gen in get_components(ThermalStandard, sys)
)
bulk_add_time_series!(sys, associations)
```
"""
function bulk_add_time_series!(
sys::System,
associations;
batch_size::Int = IS.ADD_TIME_SERIES_BATCH_SIZE,
)
return IS.bulk_add_time_series!(sys.data, associations; batch_size = batch_size)
end
"""
Add the same time series data to multiple components.
This function stores a single copy of the data. Each component will store a reference to
that data. This is significantly more efficent than calling `add_time_series!` for each
component individually with the same data because in this case, only one time series
array is stored.
Throws ArgumentError if a component is not stored in the system.
"""
function add_time_series!(sys::System, components, time_series::TimeSeriesData; features...)
return IS.add_time_series!(sys.data, components, time_series; features...)
end
#=
# TODO 1.0: do we need this functionality? not currently present in IS
"""
Return a vector of time series data from a metadata file.
# Arguments
- `data::SystemData`: system
- `metadata_file::AbstractString`: path to metadata file
- `resolution::{Nothing, Dates.Period}`: skip data that doesn't match this resolution
See InfrastructureSystems.TimeSeriesFileMetadata for description of what the file
should contain.
"""
function make_time_series(sys::System, metadata_file::AbstractString; resolution = nothing)
return IS.make_time_series(
sys.data,
metadata_file,
PowerSystems;
resolution = resolution,
)
end
"""
Return a vector of time series data from a vector of TimeSeriesFileMetadata values.
# Arguments
- `data::SystemData`: system
- `timeseries_metadata::Vector{TimeSeriesFileMetadata}`: metadata values
- `resolution::{Nothing, Dates.Period}`: skip data that doesn't match this resolution
"""
function make_time_series(
sys::System,
metadata::Vector{IS.TimeSeriesFileMetadata};
resolution = nothing,
)
return IS.make_time_series!(sys.data, metadata; resolution = resolution)
end
=#
"""
Return the compression settings used for system data such as time series arrays.
"""
get_compression_settings(sys::System) = IS.get_compression_settings(sys.data)
"""
Return the initial times for all forecasts. Use `resolution` and/or `interval` keyword
arguments to filter when multiple forecast groups exist.
"""
get_forecast_initial_times(sys::System; kwargs...) =
IS.get_forecast_initial_times(sys.data; kwargs...)
"""
Return the window count for all forecasts. Use `resolution` and/or `interval` keyword
arguments to filter when multiple forecast groups exist.
"""
get_forecast_window_count(sys::System; kwargs...) =
IS.get_forecast_window_count(sys.data; kwargs...)
"""
Return the horizon for all forecasts. Use `resolution` and/or `interval` keyword
arguments to filter when multiple forecast groups exist.
"""
get_forecast_horizon(sys::System; kwargs...) =
IS.get_forecast_horizon(sys.data; kwargs...)
"""
Return the initial timestamp for all forecasts. Use `resolution` and/or `interval` keyword
arguments to filter when multiple forecast groups exist.
"""
get_forecast_initial_timestamp(sys::System; kwargs...) =
IS.get_forecast_initial_timestamp(sys.data; kwargs...)
"""
Return the forecast interval. Use `resolution` and/or `interval` keyword arguments to
select which forecast group to query when multiple exist.
"""
get_forecast_interval(sys::System; kwargs...) =
IS.get_forecast_interval(sys.data; kwargs...)
"""
Return a sorted Vector of distinct resolutions for all time series of the given type
(or all types).
"""
get_time_series_resolutions(
sys::System;
time_series_type::Union{Type{<:TimeSeriesData}, Nothing} = nothing,
) = IS.get_time_series_resolutions(sys.data; time_series_type = time_series_type)
"""
Return an iterator of time series attached to components in the system.
Note that passing a filter function can be much slower than the other filtering parameters
because it reads time series data from media.
Call `collect` on the result to get an array.
# Arguments
- `sys::System`: system
- `filter_func = nothing`: Only return time series for which this returns true.
- `type = nothing`: Only return time series with this type.
- `name = nothing`: Only return time series matching this value.
- `resolution = nothing`: Only return time series matching this resolution.
- `interval = nothing`: Only return time series matching this interval.
# Examples
```julia
for time_series in get_time_series_multiple(sys)
@show time_series
end
ts = collect(get_time_series_multiple(sys; type = SingleTimeSeries))
```
"""
function IS.get_time_series_multiple(
sys::System,
filter_func = nothing;
type = nothing,
name = nothing,
resolution = nothing,
interval = nothing,
)
Channel{TimeSeriesData}() do channel
for component in
IS.iterate_components_with_time_series(sys.data; time_series_type = type)
for time_series in get_time_series_multiple(
component,
filter_func;
type = type,
name = name,
resolution = resolution,
interval = interval,
)
put!(channel, time_series)
end
end
end
end
"""
Clear all time series data from the system.
If you are storing time series data in an HDF5 file, this will
will delete the HDF5 file and create a new one.
See also: [`remove_time_series!`](@ref remove_time_series!(sys::System, ::Type{T}) where {T <: TimeSeriesData})
"""
function clear_time_series!(sys::System)
return IS.clear_time_series!(sys.data)
end
"""
Remove the time series data for a component or supplemental attribute and time series type.
Use `resolution`, `interval`, and `features` keyword arguments to disambiguate when multiple
time series of the same type and name exist with different resolutions, intervals, or
user-defined feature tags.
"""
function remove_time_series!(
sys::System,
::Type{T},
owner::Union{Component, SupplementalAttribute},
name::String;
resolution::Union{Nothing, Dates.Period} = nothing,
interval::Union{Nothing, Dates.Period} = nothing,
features...,
) where {T <: TimeSeriesData}
return IS.remove_time_series!(
sys.data,
T,
owner,
name;
resolution = resolution,
interval = interval,
features...,
)
end
"""
Remove all the time series data for a time series type.
See also: [`clear_time_series!`](@ref)
If you are storing time series data in an HDF5 file, `remove_time_series!` does
not actually free up file space (HDF5 behavior). If you want to remove all or
most time series instances then consider using `clear_time_series!`. It
will delete the HDF5 file and create a new one. PowerSystems has plans to
automate this type of workflow.
"""
function remove_time_series!(
sys::System,
::Type{T};
resolution::Union{Nothing, Dates.Period} = nothing,
interval::Union{Nothing, Dates.Period} = nothing,
) where {T <: TimeSeriesData}
return IS.remove_time_series!(sys.data, T; resolution = resolution, interval = interval)
end
"""
Transform all instances of [`SingleTimeSeries`](@ref) in a `System` to
[`DeterministicSingleTimeSeries`](@ref)
This can be used to generate a perfect forecast from historical measurements or realizations
when actual forecasts are unavailable, without unnecessarily duplicating data.
If all `SingleTimeSeries` instances cannot be transformed then none will be.
By default, any existing `DeterministicSingleTimeSeries` forecasts will be deleted before the
transform (`delete_existing = true`). Set `delete_existing = false` to preserve existing
`DeterministicSingleTimeSeries`; entries with matching name, resolution, features, horizon,
and interval are skipped, allowing multiple calls with different resolutions to coexist.
# Arguments
- `sys::System`: System containing the components.
- `horizon::Dates.Period`: desired [horizon](@ref H) of each forecast [window](@ref W)
- `interval::Dates.Period`: desired [interval](@ref I) between forecast [windows](@ref W)
- `resolution::Union{Nothing, Dates.Period} = nothing`: If set, only transform time series
with this resolution.
- `delete_existing::Bool = true`: If `true`, delete all existing
`DeterministicSingleTimeSeries` before transforming.
"""
function transform_single_time_series!(
sys::System,
horizon::Dates.Period,
interval::Dates.Period;
resolution::Union{Nothing, Dates.Period} = nothing,
delete_existing::Bool = true,
)
IS.transform_single_time_series!(
sys.data,
IS.DeterministicSingleTimeSeries,
horizon,
interval;
resolution = resolution,
delete_existing = delete_existing,
)
return
end
"""
Add a supplemental attribute to the component. The attribute may already be attached to a
different component.
"""
function add_supplemental_attribute!(
sys::System,
component::Component,
attribute::IS.SupplementalAttribute,
)
return IS.add_supplemental_attribute!(sys.data, component, attribute)
end
"""
Begin an update of supplemental attributes. Use this function when adding
or removing many supplemental attributes in order to improve performance.
If an error occurs during the update, changes will be reverted.
# Examples
```julia
begin_supplemental_attributes_update(sys) do
add_supplemental_attribute!(sys, component1, attribute1)
add_supplemental_attribute!(sys, component2, attribute2)
end
```
"""
begin_supplemental_attributes_update(func::Function, sys::System) =
IS.begin_supplemental_attributes_update(func, sys.data.supplemental_attribute_manager)
"""
Remove the supplemental attribute from the component. The attribute will be removed from the
system if it is not attached to any other component.
"""
function remove_supplemental_attribute!(
sys::System,
component::Component,
attribute::IS.SupplementalAttribute,
)
return IS.remove_supplemental_attribute!(sys.data, component, attribute)
end
"""
Remove all supplemental attributes with the given type from the system.
"""
function remove_supplemental_attributes!(
::Type{T},
sys::System,
) where {T <: IS.SupplementalAttribute}
return IS.remove_supplemental_attributes!(sys.data, T)
end
"""
Returns an iterator of supplemental attributes. T can be concrete or abstract.
Call collect on the result if an array is desired.
# Examples
```julia
iter = get_supplemental_attributes(GeometricDistributionForcedOutage, sys)
iter = get_supplemental_attributes(Outage, sys)
iter = get_supplemental_attributes(x -> get_mean_time_to_recovery(x) == >= 0.5, GeometricDistributionForcedOutage, sys)
outages = get_supplemental_attributes(GeometricDistributionForcedOutage, sys) do outage
get_mean_time_to_recovery(x) == >= 0.5
end
outages = collect(get_supplemental_attributes(GeometricDistributionForcedOutage, sys))
```
See also: [`iterate_supplemental_attributes`](@ref)
"""
function get_supplemental_attributes(
filter_func::Function,
::Type{T},
sys::System,
) where {T <: IS.SupplementalAttribute}
return IS.get_supplemental_attributes(filter_func, T, sys.data)
end
function get_supplemental_attributes(
::Type{T},
sys::System,
) where {T <: IS.SupplementalAttribute}
return IS.get_supplemental_attributes(T, sys.data)
end
"""
get_associated_supplemental_attributes(obj)
Retrieves supplemental attributes associated with the given object.
This function extracts and returns additional metadata or auxiliary information
that is linked to the specified object, typically used for extended functionality
or configuration purposes.
# Arguments
- `obj`: The object for which to retrieve associated supplemental attributes
# Returns
- Collection of supplemental attributes associated with the input object
# Examples
```julia
gen_attr_pairs = get_component_supplemental_attribute_pairs(
GeometricDistributionForcedOutage,
ThermalStandard,
sys,
)
for (gen, attr) in gen_attr_pairs
@show summary(gen) summary(attr)
end
my_generators = [gen1, gen2, gen3]
gen_attr_pairs_limited = get_component_supplemental_attribute_pairs(
GeometricDistributionForcedOutage,
ThermalStandard,
sys,
components = my_generators,
)
for (gen, attr) in gen_attr_pairs_limited
@show summary(gen) summary(attr)
end
```
"""
function get_associated_supplemental_attributes(
sys::System,
::Type{T};
attribute_type::Union{Nothing, Type{<:IS.SupplementalAttribute}} = nothing,
) where {T <: IS.InfrastructureSystemsComponent}
return IS.get_associated_supplemental_attributes(
sys.data,
T;
attribute_type = attribute_type,
)
end
"""
Return the supplemental attribute with the given uuid.
Throws ArgumentError if the attribute is not stored.
"""
function get_supplemental_attribute(sys::System, uuid::Base.UUID)
return IS.get_supplemental_attribute(sys.data, uuid)
end
"""
Iterates over all supplemental_attributes.
# Examples
```julia
for supplemental_attribute in iterate_supplemental_attributes(sys)
@show supplemental_attribute
end
```
See also: [`get_supplemental_attributes`](@ref)
"""
function iterate_supplemental_attributes(sys::System)
return IS.iterate_supplemental_attributes(sys.data)
end
"""
Return a vector of NamedTuples with pairs of components and supplemental attributes that
are associated with each other. Limit by `components` and `attributes` if provided.
The return type is `NamedTuple{(:component, :supplemental_attribute), Tuple{T, U}}[]`
where `T` is the component type and `U` is the supplemental attribute type.
# Arguments
- `sys::System`: System containing the components and attributes.
- `::Type{T}`: Type of the components to filter by. Can be concrete or abstract.
- `::Type{U}`: Type of the supplemental attributes to filter by. Can be concrete or abstract.
- `components`: Optional iterable. If set, filter pairs where the component is in this
iterable.
- `attributes`: Optional iterable. If set, filter pairs where the supplemental attribute is
in this iterable.
# Examples
```julia
gen_attr_pairs = get_component_supplemental_attribute_pairs(
GeometricDistributionForcedOutage,
ThermalStandard,
sys,
)
for (gen, attr) in gen_attr_pairs
@show summary(gen) summary(attr)
end
my_generators = [gen1, gen2, gen3]
gen_attr_pairs_limited = get_component_supplemental_attribute_pairs(
GeometricDistributionForcedOutage,
ThermalStandard,
sys,
components = my_generators,
)
for (gen, attr) in gen_attr_pairs_limited
@show summary(gen) summary(attr)
end
```
"""
function get_component_supplemental_attribute_pairs(
::Type{T},
::Type{U},
sys::System;
components = nothing,
attributes = nothing,
) where {T <: Component, U <: SupplementalAttribute}
return IS.get_component_supplemental_attribute_pairs(
T,
U,
sys.data;
components = components,
attributes = attributes,
)
end
"""
Sanitize component values.
"""
sanitize_component!(component::Component, sys::System) = true
"""
Validate the component fields using only those fields. Refer to
[`validate_component_with_system`](@ref) to use other System data for the
validation.
Return true if the instance is valid.
"""
validate_component(component::Component) = true
"""
Validate a component against System data. Return true if the instance is valid.
Refer to [`validate_component`](@ref) if the validation logic only requires data contained
within the instance.
"""
validate_component_with_system(component::Component, sys::System) = true
Base.@deprecate validate_struct(sys::System, component::Component) validate_component_with_system(
component,
sys,
) false
# Keeps the code working with IS.
IS.validate_struct(component::Component) = validate_component(component)
"""
Check system consistency and validity.
"""
function check(sys::System)
buses = get_components(ACBus, sys)
slack_bus_check(buses)
buscheck(sys)
critical_components_check(sys)
adequacy_check(sys)
check_subsystems(sys)
return
end
"""
Check the the consistency of subsystems.
"""
function check_subsystems(sys::System)
must_be_assigned_to_subsystem = false
for (i, component) in enumerate(iterate_components(sys))
is_assigned = is_assigned_to_subsystem(sys, component)
if i == 1
must_be_assigned_to_subsystem = is_assigned
elseif is_assigned != must_be_assigned_to_subsystem
throw(
IS.InvalidValue(
"If any component is assigned to a subsystem then all " *
"components must be assigned to a subsystem.",
),
)
end
check_subsystems(sys, component)
end
end
"""
Check the values of all components. See [`check_component`](@ref) for exceptions thrown.
"""
function check_components(sys::System; check_masked_components = true)
must_be_assigned_to_subsystem = false
for (i, component) in enumerate(iterate_components(sys))
is_assigned = is_assigned_to_subsystem(sys, component)
if i == 1
must_be_assigned_to_subsystem = is_assigned
elseif is_assigned != must_be_assigned_to_subsystem
throw(
IS.InvalidValue(
"If any component is assigned to a subsystem then all " *
"components must be assigned to a subsystem.",
),
)
end
check_component(sys, component)
end
if check_masked_components
for component in IS.get_masked_components(Component, sys.data)
check_component(sys, component)
end
end
end
"""
Check the values of components of a given abstract or concrete type.
See [`check_component`](@ref) for exceptions thrown.
"""
function check_components(
sys::System,
::Type{T};
check_masked_components = true,
) where {T <: Component}
for component in get_components(T, sys)
check_component(sys, component)
end
if check_masked_components
for component in IS.get_masked_components(T, sys.data)
check_component(sys, component)
end
end
end
"""
Check the values of each component in an iterable of components.
See [`check_component`](@ref) for exceptions thrown.
"""
function check_components(sys::System, components)
for component in components
check_component(sys, component)
end
end
"""
Check the values of a component.
Throws InvalidValue if any of the component's field values are outside of defined valid
range or if the custom validate method for the type fails its check.
"""
function check_component(sys::System, component::Component)
if !validate_component_with_system(component, sys)
throw(IS.InvalidValue("Invalid value for $(summary(component))"))
end
IS.check_component(sys.data, component)
return
end
"""
Check that all AC transmission [`Line`](@ref) and [`MonitoredLine`](@ref) components
have valid rate values relative to the system base power.
Returns `true` if all values are valid, `false` otherwise.
"""
function check_ac_transmission_rate_values(sys::System)
is_valid = true
base_power = get_base_power(sys)
for line in
Iterators.flatten((get_components(Line, sys), get_components(MonitoredLine, sys)))
if !check_rating_values(line, base_power)
is_valid = false
end
end
return is_valid
end
"""
Serialize a [System](@ref) instance. Returns a `Dict{String, Any}`
of the form `Dict("data_format_version" => "1.0", "field1" => serialize(sys.field1), ...)`,
which can then be written to a JSON3 file.
"""
function IS.serialize(sys::T) where {T <: System}
data = Dict{String, Any}()
data["data_format_version"] = DATA_FORMAT_VERSION
for field in fieldnames(T)
# Exclude bus_numbers because they will get rebuilt during deserialization.
# Exclude time_series_directory because the system may get deserialized on a
# different system.
if field != :bus_numbers && field != :time_series_directory
data[string(field)] = serialize(getfield(sys, field))
end
end
return data
end
"""
Deserialize a [System](@ref) instance from a JSON3 file; the reverse of [`IS.serialize`](@ref).
"""
function IS.deserialize(
::Type{System},
filename::AbstractString;
kwargs...,
)
raw = open(filename) do io
JSON3.read(io, Dict)
end
if raw["data_format_version"] != DATA_FORMAT_VERSION
pre_read_conversion!(raw)
end
# These file paths are relative to the system file.
directory = dirname(filename)
for file_key in ("time_series_storage_file",)
if haskey(raw["data"], file_key) && !isabspath(raw["data"][file_key])
raw["data"][file_key] = joinpath(directory, raw["data"][file_key])
end
end
return from_dict(System, raw; kwargs...)
end
function from_dict(
::Type{System},
raw::Dict{String, Any};
time_series_read_only = false,
time_series_directory = nothing,
config_path = POWER_SYSTEM_STRUCT_DESCRIPTOR_FILE,
kwargs...,
)
# Read any field that is defined in System but optional for the constructors and not
# already handled here.
handled = (
"data",
"units_settings",
"bus_numbers",
"internal",
"data_format_version",
"metadata",
"name",
"description",
)
parsed_kwargs = Dict{Symbol, Any}()
for field in setdiff(keys(raw), handled)
parsed_kwargs[Symbol(field)] = raw[field]
end
# The user can override the serialized runchecks value by passing a kwarg here.
if haskey(kwargs, :runchecks)
parsed_kwargs[:runchecks] = kwargs[:runchecks]
end
units = IS.deserialize(SystemUnitsSettings, raw["units_settings"])
data = IS.deserialize(
IS.SystemData,
raw["data"];
time_series_read_only = time_series_read_only,
time_series_directory = time_series_directory,
validation_descriptor_file = config_path,
)
metadata = get(raw, "metadata", Dict())
name = get(metadata, "name", nothing)
description = get(metadata, "description", nothing)
internal = IS.deserialize(InfrastructureSystemsInternal, raw["internal"])
sys = System(
data,
units,
internal;
name = name,
description = description,
parsed_kwargs...,
)
if raw["data_format_version"] != DATA_FORMAT_VERSION
pre_deserialize_conversion!(raw, sys)
end
ext = get_ext(sys)
ext["deserialization_in_progress"] = true
try
deserialize_components!(sys, raw["data"])
finally
pop!(ext, "deserialization_in_progress")
isempty(ext) && clear_ext!(sys)
end
if !get_runchecks(sys)
@warn "The System was deserialized with checks disabled, and so was not validated."
end
if raw["data_format_version"] != DATA_FORMAT_VERSION
post_deserialize_conversion!(sys, raw)
end
return sys
end
function deserialize_components!(sys::System, raw)
# Convert the array of components into type-specific arrays to allow addition by type.
data = Dict{Any, Vector{Dict}}()
# This field was not present in older versions.
masked_components = get(raw, "masked_components", [])
for component in Iterators.Flatten((raw["components"], masked_components))
type = IS.get_type_from_serialization_data(component)
components = get(data, type, nothing)
if components === nothing
components = Vector{Dict}()
data[type] = components
end
push!(components, component)
end
# Maintain a lookup of UUID to component because some component types encode
# composed types as UUIDs instead of actual types.
component_cache = Dict{Base.UUID, Component}()
# Add each type to this as we parse.
parsed_types = Set()
function is_matching_type(type, types)
return any(x -> type <: x, types)
end
function deserialize_and_add!(;
skip_types = nothing,
include_types = nothing,
post_add_func = nothing,
)
for (type, components) in data
type in parsed_types && continue
if !isnothing(skip_types) && is_matching_type(type, skip_types)
continue
end
if !isnothing(include_types) && !is_matching_type(type, include_types)
continue
end
components =
_handle_hydro_reservoirs_deserialization_special_cases(components, type)
for component in components
handle_deserialization_special_cases!(component, type)
comp = deserialize(type, component, component_cache)
add_component!(sys, comp)
component_cache[IS.get_uuid(comp)] = comp
if !isnothing(post_add_func)
post_add_func(comp)
end
end
push!(parsed_types, type)
end
end
# Run in order based on type composition.
# Bus instances can have areas and LoadZones.
# AGC instances can have areas and contributing reserves
# Most components have buses.
# Static injection devices can contain dynamic injection devices.
# StaticInjectionSubsystem instances have StaticInjection subcomponents.
deserialize_and_add!(; include_types = [Area, LoadZone])
deserialize_and_add!(; include_types = [AbstractReserve])
deserialize_and_add!(; include_types = [AGC])
deserialize_and_add!(; include_types = [Bus])
deserialize_and_add!(;
include_types = [Arc, Service],
skip_types = [ConstantReserveGroup],
)
deserialize_and_add!(;
include_types = [HydroTurbine, HydroPumpTurbine],
skip_types = [ConstantReserveGroup, HydroReservoir],
)
deserialize_and_add!(; include_types = [HydroReservoir])
deserialize_and_add!(; include_types = [Branch])
deserialize_and_add!(; include_types = [DynamicBranch])
deserialize_and_add!(; include_types = [ConstantReserveGroup, DynamicInjection])
deserialize_and_add!(; skip_types = [StaticInjectionSubsystem])
deserialize_and_add!()
for subsystem in get_components(StaticInjectionSubsystem, sys)
# This normally happens when the subsytem is added to the system.
# Workaround for deserialization.
for subcomponent in get_subcomponents(subsystem)
IS.mask_component!(sys.data, subcomponent)
end
end
end
"""
Allow types to implement handling of special cases during deserialization.
# Arguments
- `component::Dict`: The component serialized as a dictionary.
- `::Type`: The type of the component.
"""
handle_deserialization_special_cases!(component::Dict, ::Type{<:Component}) = nothing
# TODO DT: Do I need to handle this in the new format upgrade?
#function handle_deserialization_special_cases!(component::Dict, ::Type{DynamicBranch})
# # IS handles deserialization of supplemental attribues in each component.
# # In this case the DynamicBranch's composed branch is not part of the system and so
# # IS will not handle it. It can never attributes.
# if !isempty(component["branch"]["supplemental_attributes_container"])
# error(
# "Bug: serialized DynamicBranch.branch has supplemental attributes: $component",
# )
# end
# return
#end
# This function does an iterative union find to handle the ordering of the reservoir chains
function _handle_hydro_reservoirs_deserialization_special_cases(
components::Vector{Dict},
::Type{HydroReservoir},
)
# Build a mapping from UUID to component for quick lookup
uuid_to_component = Dict{String, Dict}()
for component in components
uuid_str = string(component["internal"]["uuid"])
uuid_to_component[uuid_str] = component
end
# Build parent mapping for union-find (each reservoir points to its upstream reservoir)
parent = Dict{String, String}()
for component in components
uuid_str = string(component["internal"]["uuid"])
upstream_uuids = component["upstream_reservoirs"]
if isempty(upstream_uuids)
parent[uuid_str] = uuid_str # Root of its own chain
else
# Assume single upstream reservoir for simplicity
parent[uuid_str] = string(upstream_uuids[1])
end
end
# Find root of each chain iteratively
function find_root(uuid_str)
current = uuid_str
while parent[current] != current
current = parent[current]
end
return current
end
# Group components by their chain root
chains = Dict{String, Vector{Dict}}()
for component in components
uuid_str = string(component["internal"]["uuid"])
root = find_root(uuid_str)
if !haskey(chains, root)
chains[root] = Vector{Dict}()
end
push!(chains[root], component)
end
# Order each chain from upstream (root) to downstream
ordered_components = Vector{Dict}()
for (root_uuid, chain) in chains
# Sort chain by dependency order - upstream reservoirs first
chain_ordered = Vector{Dict}()
remaining = Set(chain)
while !isempty(remaining)
# Find next component whose upstream is already processed or is a root
for component in remaining
upstream_uuids = component["upstream_reservoirs"]
can_add =
isempty(upstream_uuids) ||
all(
string(uuid) in
[string(c["internal"]["uuid"]) for c in chain_ordered] for
uuid in upstream_uuids
)
if can_add
push!(chain_ordered, component)
delete!(remaining, component)
break
end
end
end
append!(ordered_components, chain_ordered)
end
return ordered_components
end
_handle_hydro_reservoirs_deserialization_special_cases(
components::Vector{Dict},
::Type{<:Component}) = components
"""
Return [`ACBus`](@ref) with `name`.
"""
function get_bus(sys::System, name::AbstractString)
return get_component(ACBus, sys, name)
end
"""
Return [`ACBus`](@ref) with `bus_number`.
"""
function get_bus(sys::System, bus_number::Int)
for bus in get_components(ACBus, sys)
if bus.number == bus_number
return bus
end
end
return nothing
end
"""
Return [`ACBus`](@ref)es from a set of identification `number`s
# Examples
```julia
# View all the bus ID numbers in the System
get_number.(get_components(ACBus, system))
# Select a subset
buses_by_ID = get_buses(system, Set(101:110))
```
"""
function get_buses(sys::System, bus_numbers::Set{Int})
buses = Vector{ACBus}()
for bus in get_components(ACBus, sys)
if bus.number in bus_numbers
push!(buses, bus)
end
end
return buses
end
"""
Return all the device types in the system. It does not return component types or masked components.
"""
function get_existing_device_types(sys::System)
device_types = Vector{DataType}()
for component_type in keys(sys.data.components.data)
if component_type <: Device
push!(device_types, component_type)
end
end
return device_types
end
"""
Return all the component types in the system. It does not return masked components.
"""
function get_existing_component_types(sys::System)
return collect(keys(sys.data.components.data))
end
function _is_deserialization_in_progress(sys::System)
ext = get_ext(sys)
return get(ext, "deserialization_in_progress", false)
end
check_for_services_on_addition(sys::System, component::Component) = nothing
function check_for_services_on_addition(sys::System, component::T) where {T <: Device}
if supports_services(component) && length(get_services(component)) > 0
throw(
ArgumentError(
"type $(IS.strip_module_name(string(T))) cannot be added with services",
),
)
end
return
end
function check_topology(sys::System, component::AreaInterchange)
throw_if_not_attached(get_from_area(component), sys)
throw_if_not_attached(get_to_area(component), sys)
return
end
function check_topology(sys::System, component::Component)
check_attached_buses(sys, component)
return
end
"""
Throws ArgumentError if any bus attached to the component is invalid.
"""
check_attached_buses(sys::System, component::Component) = nothing
function check_attached_buses(sys::System, component::StaticInjection)
throw_if_not_attached(get_bus(component), sys)
return
end
function check_attached_buses(sys::System, component::Branch)
throw_if_not_attached(get_from_bus(component), sys)
throw_if_not_attached(get_to_bus(component), sys)
return
end
function check_attached_buses(
sys::System,
component::ThreeWindingTransformer,
)
bus_primary = get_from(get_primary_star_arc(component))
bus_secondary = get_from(get_secondary_star_arc(component))
bus_tertiary = get_from(get_tertiary_star_arc(component))
star_bus = get_star_bus(component)
throw_if_not_attached(bus_primary, sys)
throw_if_not_attached(bus_secondary, sys)
throw_if_not_attached(bus_tertiary, sys)
throw_if_not_attached(star_bus, sys)
return
end
function check_attached_buses(sys::System, component::DynamicBranch)
check_attached_buses(sys, get_branch(component))
return
end
function check_attached_buses(sys::System, component::Arc)
throw_if_not_attached(get_from(component), sys)
throw_if_not_attached(get_to(component), sys)
return
end
"""
Throws ArgumentError if a PowerSystems rule blocks addition to the system.
This method is tied with handle_component_addition!. If the methods are re-implemented for
a subtype then whatever is added in handle_component_addition! must be checked here.
"""
check_component_addition(sys::System, component::Component; kwargs...) = nothing
"""
Throws ArgumentError if a PowerSystems rule blocks removal from the system.
"""
check_component_removal(sys::System, component::Component) = nothing
function check_component_removal(sys::System, static_injector::StaticInjection)
if get_dynamic_injector(static_injector) !== nothing
name = get_name(static_injector)
throw(ArgumentError("$name cannot be removed with an attached dynamic injector"))
end
end
function check_component_removal(sys::System, area::Area)
for interchange in get_components(AreaInterchange, sys)
if area in [get_from_area(interchange), get_to_area(interchange)]
throw(
ArgumentError(
"Area $(summary(area)) cannot be removed with attached AreaInterchange: $(summary(interchange))",
),
)
end
end
return
end
"""
Refer to docstring for check_component_addition!
"""
handle_component_addition!(sys::System, component::Component; kwargs...) = nothing
handle_component_removal!(sys::System, component::Component) = nothing
function check_component_addition(sys::System, branch::AreaInterchange; kwargs...)
throw_if_not_attached(get_from_area(branch), sys)
throw_if_not_attached(get_to_area(branch), sys)
return
end
function check_component_addition(sys::System, branch::Branch; kwargs...)
arc = get_arc(branch)
throw_if_not_attached(get_from(arc), sys)
throw_if_not_attached(get_to(arc), sys)
return
end
function check_component_addition(
sys::System,
component::ThreeWindingTransformer;
kwargs...,
)
bus_primary = get_from(get_primary_star_arc(component))
bus_secondary = get_from(get_secondary_star_arc(component))
bus_tertiary = get_from(get_tertiary_star_arc(component))
star_bus = get_star_bus(component)
throw_if_not_attached(bus_primary, sys)
throw_if_not_attached(bus_secondary, sys)
throw_if_not_attached(bus_tertiary, sys)
throw_if_not_attached(star_bus, sys)
return
end
function check_component_addition(sys::System, dyn_branch::DynamicBranch; kwargs...)
if !_is_deserialization_in_progress(sys)
throw_if_not_attached(dyn_branch.branch, sys)
end
arc = get_arc(dyn_branch)
throw_if_not_attached(get_from(arc), sys)
throw_if_not_attached(get_to(arc), sys)
return
end
function check_component_addition(sys::System, dyn_injector::DynamicInjection; kwargs...)
if _is_deserialization_in_progress(sys)
# Ordering of component addition makes these checks impossible.
return
end
static_injector = get(kwargs, :static_injector, nothing)
if static_injector === nothing
throw(
ArgumentError("static_injector must be passed when adding a DynamicInjection"),
)
end
if get_name(dyn_injector) != get_name(static_injector)
throw(
ArgumentError(
"static_injector must have the same name as the DynamicInjection",
),
)
end
throw_if_not_attached(static_injector, sys)
return
end
function check_component_addition(sys::System, bus::Bus; kwargs...)
number = get_number(bus)
if number in sys.bus_numbers
throw(ArgumentError("bus number $number is already stored in the system"))
end
area = get_area(bus)
if !isnothing(area)
throw_if_not_attached(area, sys)
end
load_zone = get_load_zone(bus)
if !isnothing(load_zone)
throw_if_not_attached(load_zone, sys)
end
end
function handle_component_addition!(sys::System, bus::Bus; kwargs...)
number = get_number(bus)
if number in sys.bus_numbers
throw(ArgumentError("bus number $number is already stored"))
end
push!(sys.bus_numbers, number)
return
end
function handle_component_addition!(sys::System, component::Branch; kwargs...)
_handle_branch_addition_common!(sys, component)
return
end
function handle_component_addition!(sys::System, component::DynamicBranch; kwargs...)
_handle_branch_addition_common!(sys, component)
remove_component!(sys, component.branch)
return
end
function handle_component_addition!(sys::System, dyn_injector::DynamicInjection; kwargs...)
static_injector = kwargs[:static_injector]
static_base_power = get_base_power(static_injector)
set_base_power!(dyn_injector, static_base_power)
set_dynamic_injector!(static_injector, dyn_injector)
return
end
function handle_component_addition!(
sys::System,
subsystem::StaticInjectionSubsystem;
kwargs...,
)
for subcomponent in get_subcomponents(subsystem)
if is_attached(subcomponent, sys)
IS.mask_component!(sys.data, subcomponent)
copy_subcomponent_time_series!(subsystem, subcomponent)
else
IS.add_masked_component!(sys.data, subcomponent)
end
end
end
function _handle_branch_addition_common!(sys::System, component::Branch)
# If this arc is already attached to the system, assign it to the branch.
# Else, add it to the system.
arc = get_arc(component)
_arc = get_component(Arc, sys, get_name(arc))
if isnothing(_arc)
add_component!(sys, arc)
else
set_arc!(component, _arc)
end
return
end
function _handle_branch_addition_common!(
sys::System,
component::ThreeWindingTransformer,
)
# If this arc is already attached to the system, assign it to the 3W XFRM.
# Else, add it to the system.
arcs = [
get_primary_star_arc(component),
get_secondary_star_arc(component),
get_tertiary_star_arc(component),
]
set_arc_methods = [
set_primary_star_arc!,
set_secondary_star_arc!,
set_tertiary_star_arc!,
]
for (ix, arc) in enumerate(arcs)
_arc = get_component(Arc, sys, get_name(arc))
if isnothing(_arc)
add_component!(sys, arc)
else
set_arc_methods[ix](component, _arc)
end
end
return
end
_handle_branch_addition_common!(sys::System, component::AreaInterchange) = nothing
"""
Throws ArgumentError if the bus number is not stored in the system.
"""
function handle_component_removal!(sys::System, bus::Bus)
_handle_component_removal_common!(bus)
number = get_number(bus)
if !(number in sys.bus_numbers)
throw(ArgumentError("bus number $number is not stored"))
end
pop!(sys.bus_numbers, number)
return
end
function handle_component_removal!(sys::System, device::Device)
_handle_component_removal_common!(device)
# This may have to be refactored if handle_component_removal! needs to be implemented
# for a subtype.
clear_services!(device)
return
end
function handle_component_removal!(sys::System, service::Service)
_handle_component_removal_common!(service)
for device in get_components(Device, sys)
if !supports_services(device)
continue
end
_remove_service!(device, service)
end
end
function handle_component_removal!(sys::System, component::StaticInjectionSubsystem)
_handle_component_removal_common!(component)
subcomponents = collect(get_subcomponents(component))
for subcomponent in subcomponents
IS.remove_masked_component!(sys.data, subcomponent)
end
end
function handle_component_removal!(sys::System, value::T) where {T <: AggregationTopology}
_handle_component_removal_common!(value)
for device in get_components(ACBus, sys)
if get_aggregation_topology_accessor(T)(device) == value
_remove_aggregration_topology!(device, value)
end
end
end
function handle_component_removal!(sys::System, dyn_injector::DynamicInjection)
_handle_component_removal_common!(dyn_injector)
injectors = get_components_by_name(StaticInjection, sys, get_name(dyn_injector))
found = false
for static_injector in injectors
_dyn_injector = get_dynamic_injector(static_injector)
_dyn_injector === nothing && continue
if _dyn_injector === dyn_injector
@assert !found
set_dynamic_injector!(static_injector, nothing)
found = true
end
end
@assert found
end
function _handle_component_removal_common!(component)
clear_units!(component)
end
"""
Return a sorted vector of bus numbers in the system.
"""
function get_bus_numbers(sys::System)
return sort(collect(sys.bus_numbers))
end
_fetch_match_fn(match_fn::Function) = match_fn
_fetch_match_fn(::Nothing) = IS.isequivalent
function IS.compare_values(
match_fn::Union{Function, Nothing},
x::T,
y::T;
compare_uuids = false,
exclude = Set{Symbol}(),
) where {T <: Union{StaticInjection, DynamicInjection}}
# Must implement this method because a device of one of these subtypes might have a
# reference to its counterpart, and vice versa, and so infinite recursion will occur
# in the default function.
match = true
for name in fieldnames(T)
name in exclude && continue
val1 = getfield(x, name)
val2 = getfield(y, name)
if val1 isa StaticInjection || val2 isa DynamicInjection
if !compare_uuids
name1 = get_name(val1)
name2 = get_name(val2)
if !_fetch_match_fn(match_fn)(name1, name2)
@error "values do not match" T name name1 name2
match = false
end
else
uuid1 = IS.get_uuid(val1)
uuid2 = IS.get_uuid(val2)
if uuid1 != uuid2
@error "values do not match" T name uuid1 uuid2
match = false
end
end
elseif !isempty(fieldnames(typeof(val1)))
if !IS.compare_values(
match_fn,
val1,
val2;
compare_uuids = compare_uuids,
exclude = exclude,
)
@error "values do not match" T name val1 val2
match = false
end
elseif val1 isa AbstractArray
if !IS.compare_values(
match_fn,
val1,
val2;
compare_uuids = compare_uuids,
exclude = exclude,
)
match = false
end
else
if !_fetch_match_fn(match_fn)(val1, val2)
@error "values do not match" T name val1 val2
match = false
end
end
end
return match
end
function _create_system_data_from_kwargs(;
time_series_in_memory = false,
time_series_directory = nothing,
compression = nothing,
enable_compression = false,
config_path = POWER_SYSTEM_STRUCT_DESCRIPTOR_FILE,
kwargs...,
)
if isnothing(compression)
compression = IS.CompressionSettings(; enabled = enable_compression)
end
return IS.SystemData(;
validation_descriptor_file = config_path,
time_series_in_memory = time_series_in_memory,
time_series_directory = time_series_directory,
compression = compression,
)
end
"""
Converts a Line component to a MonitoredLine component and replaces the original in the
system
"""
function convert_component!(
sys::System,
line::Line,
linetype::Type{MonitoredLine};
kwargs...,
)
new_line = linetype(
line.name,
line.available,
line.active_power_flow,
line.reactive_power_flow,
line.arc,
line.r,
line.x,
line.b,
(from_to = line.rating, to_from = line.rating),
line.rating,
line.angle_limits,
line.rating_b,
line.rating_c,
line.g,
line.services,
line.ext,
_copy_internal_for_conversion(line),
)
IS.assign_new_uuid!(sys, line)
add_component!(sys, new_line)
copy_time_series!(new_line, line)
# TODO: PSY4
# copy_supplemental_attibutes!(new_line, line)
remove_component!(sys, line)
return
end
"""
Converts a MonitoredLine component to a Line component and replaces the original in the
system.
"""
function convert_component!(
sys::System,
line::MonitoredLine,
linetype::Type{Line};
kwargs...,
)
force = get(kwargs, :force, false)
if force
@warn("Possible data loss converting from $(typeof(line)) to $linetype")
else
error(
"Possible data loss converting from $(typeof(line)) to $linetype, add `force = true` to convert anyway.",
)
end
new_line = linetype(
line.name,
line.available,
line.active_power_flow,
line.reactive_power_flow,
line.arc,
line.r,
line.x,
line.b,
line.rating,
line.angle_limits,
line.rating_b,
line.rating_c,
line.g,
line.services,
line.ext,
_copy_internal_for_conversion(line),
)
IS.assign_new_uuid!(sys, line)
add_component!(sys, new_line)
copy_time_series!(new_line, line)
# TODO: PSY4
# copy_supplemental_attibutes!(new_line, line)
remove_component!(sys, line)
return
end
"""
Converts a PowerLoad component to a StandardLoad component and replaces the original in the
system. Does not set any fields in StandardLoad that lack a PowerLoad equivalent.
"""
function convert_component!(
sys::System,
old_load::PowerLoad,
new_type::Type{StandardLoad};
kwargs...,
)
new_load = new_type(;
name = get_name(old_load),
available = get_available(old_load),
bus = get_bus(old_load),
base_power = get_base_power(old_load),
constant_active_power = get_active_power(old_load),
constant_reactive_power = get_reactive_power(old_load),
max_constant_active_power = get_max_active_power(old_load),
max_constant_reactive_power = get_max_active_power(old_load),
conformity = get_conformity(old_load),
dynamic_injector = get_dynamic_injector(old_load),
internal = _copy_internal_for_conversion(old_load),
services = Device[],
)
IS.assign_new_uuid!(sys, old_load)
add_component!(sys, new_load)
copy_time_series!(new_load, old_load)
# TODO: PSY4
# copy_supplemental_attibutes!(new_line, line)
for service in get_services(old_load)
add_service!(new_load, service, sys)
end
remove_component!(sys, old_load)
end
"""
Set the number of a bus.
"""
function set_bus_number!(sys::System, bus::Bus, number::Int)
throw_if_not_attached(bus, sys)
orig = get_number(bus)
if number == orig
return
end
if number in sys.bus_numbers
throw(ArgumentError("bus number $number is already stored in the system"))
end
set_number!(bus, number)
replace!(sys.bus_numbers, orig => number)
return
end
function set_number!(bus::ACBus, number::Int)
Base.depwarn(
"This method will be removed in v5.0 because its use breaks system consistency" *
"checks. Please call `set_bus_number!(::System, bus, number)` instead.",
:set_number!,
)
bus.number = number
return
end
# Use this function to avoid deepcopy of shared_system_references.
function _copy_internal_for_conversion(component::Component)
internal = get_internal(component)
return InfrastructureSystemsInternal(;
uuid = deepcopy(internal.uuid),
units_info = deepcopy(internal.units_info),
shared_system_references = nothing,
ext = deepcopy(internal.ext),
)
end
function _validate_or_skip!(sys, component, skip_validation)
if skip_validation && get_runchecks(sys)
@warn(
"skip_validation is deprecated; construct System with runchecks = true or call set_runchecks!. Disabling System.runchecks"
)
set_runchecks!(sys, false)
end
# Always skip if system checks are disabled.
if !skip_validation && !get_runchecks(sys)
skip_validation = true
end
if !skip_validation
sanitize_component!(component, sys)
if !validate_component_with_system(component, sys)
throw(IS.InvalidValue("Invalid value for $(summary(component))"))
end
end
return skip_validation
end
"""
Returns counts of time series including attachments to components and supplemental
attributes.
"""
get_time_series_counts(sys::System) = IS.get_time_series_counts(sys.data)
"""
Checks time series in the system for inconsistencies.
For SingleTimeSeries, returns a Tuple of initial_timestamp and length.
This is a no-op for subtypes of Forecast because those are already guaranteed to be
consistent.
Throws InfrastructureSystems.InvalidValue if any time series is inconsistent.
"""
function check_time_series_consistency(sys::System, ::Type{T}) where {T <: TimeSeriesData}
return IS.check_time_series_consistency(sys.data, T)
end
stores_time_series_in_memory(sys::System) = IS.stores_time_series_in_memory(sys.data)
"""
Make a `deepcopy` of a [`System`](@ref) more quickly by skipping the copying of time
series and/or supplemental attributes.
# Arguments
- `data::System`: the `System` to copy
- `skip_time_series::Bool = true`: whether to skip copying time series
- `skip_supplemental_attributes::Bool = true`: whether to skip copying supplemental
attributes
Note that setting both `skip_time_series` and `skip_supplemental_attributes` to `false`
results in the same behavior as `deepcopy` with no performance improvement.
"""
function fast_deepcopy_system(
sys::System;
skip_time_series::Bool = true,
skip_supplemental_attributes::Bool = true,
)
new_data = IS.fast_deepcopy_system(
sys.data;
skip_time_series = skip_time_series,
skip_supplemental_attributes = skip_supplemental_attributes,
)
new_sys = System(
new_data,
deepcopy(sys.units_settings),
deepcopy(sys.internal);
runchecks = deepcopy(sys.runchecks[]),
frequency = deepcopy(sys.frequency),
time_series_directory = deepcopy(sys.time_series_directory),
name = deepcopy(sys.metadata.name),
description = deepcopy(sys.metadata.description))
# deepcopying sys.data separately from sys.units_settings broke the shared units references, so we have to fix them here
for comp in iterate_components(new_sys)
comp.internal.units_info = new_sys.units_settings
end
return new_sys
end
"""
Return a DataFrame with the number of static time series for components and supplemental
attributes.
"""
function get_static_time_series_summary_table(sys::System)
return IS.get_static_time_series_summary_table(sys.data)
end
"""
Return a DataFrame with the number of forecasts for components and supplemental
attributes.
"""
function get_forecast_summary_table(sys::System)
return IS.get_forecast_summary_table(sys.data)
end
IS.get_base_component_type(sys::System) = Component
================================================
FILE: src/component_selector.jl
================================================
# Most of the `ComponentSelector` functionality in PowerSystems.jl is implemented by
# wrapping the InfrastructureSystems.jl versions (that wrapping occurs in
# `component_selector_interface.jl`). An exception is `TopologyComponentSelector`, which is
# wholly implemented in PSY rather than in IS because it depends on
# `PSY.AggregationTopology`.
"""
`PluralComponentSelector` represented by an `AggregationTopology` and a type of `Component`.
"""
@kwdef struct TopologyComponentSelector <: DynamicallyGroupedComponentSelector
component_type::Type{<:Component}
topology_type::Type{<:AggregationTopology}
topology_name::AbstractString
groupby::Union{Symbol, Function}
name::String
TopologyComponentSelector(
component_type::Type{<:InfrastructureSystemsComponent},
topology_type::Type{<:AggregationTopology},
topology_name::AbstractString,
groupby::Union{Symbol, Function},
name::String,
) =
new(
component_type,
topology_type,
topology_name,
IS.validate_groupby(groupby),
name,
)
end
# Construction
TopologyComponentSelector(
component_type::Type{<:InfrastructureSystemsComponent},
topology_type::Type{<:AggregationTopology},
topology_name::AbstractString,
groupby::Union{Symbol, Function},
name::Nothing = nothing,
) =
TopologyComponentSelector(
component_type,
topology_type,
topology_name,
groupby,
component_to_qualified_string(topology_type, topology_name) *
COMPONENT_NAME_DELIMITER * subtype_to_string(component_type),
)
"""
Make a `ComponentSelector` from an `AggregationTopology` and a type of component. Optionally
provide a name and/or grouping behavior for the `ComponentSelector`.
"""
make_selector(
component_type::Type{<:Component},
topology_type::Type{<:AggregationTopology},
topology_name::AbstractString;
groupby::Union{Symbol, Function} = IS.DEFAULT_GROUPBY,
name::Union{String, Nothing} = nothing,
) = TopologyComponentSelector(
component_type,
topology_type,
topology_name,
groupby,
name,
)
# Contents
function IS.get_components(
scope_limiter::Union{Function, Nothing},
selector::TopologyComponentSelector,
sys::System,
)
agg_topology = get_component(selector.topology_type, sys, selector.topology_name)
isnothing(agg_topology) && return IS._make_empty_iterator(selector.component_type)
combo_filter = IS.optional_and_fns(
scope_limiter,
Base.Fix2(is_component_in_aggregation_topology, agg_topology),
)
return IS.get_components(combo_filter, selector.component_type, sys)
end
================================================
FILE: src/component_selector_interface.jl
================================================
# A continuation of `get_components_interface.jl` to facilitate neater documentation of
# `ComponentSelector`. See the long comment at the top of that file.
# get_components
"""
Get the components of the [`System`](@ref) that make up the [`ComponentSelector`](@ref).
Optionally specify a filter function `scope_limiter` as the first argument to limit the
components that should be considered.
# Arguments
- `scope_limiter::Union{Function, Nothing}`: see [`ComponentSelector`](@ref)
- `selector::ComponentSelector`: the `ComponentSelector` whose components to retrieve
- `sys::System`: the system from which to draw components
"""
get_components(
scope_limiter::Union{Function, Nothing},
selector::ComponentSelector,
sys::System,
) =
IS.get_components(scope_limiter, selector, sys)
"""
Get the components of the [`System`](@ref) that make up the [`ComponentSelector`](@ref).
# Arguments
- `selector::ComponentSelector`: the `ComponentSelector` whose components to retrieve
- `sys::System`: the system from which to draw components
"""
get_components(selector::ComponentSelector, sys::System) =
IS.get_components(selector, sys)
# get_component
"""
Get the component of the [`System`](@ref) that makes up the
[`SingularComponentSelector`](@ref); `nothing` if there is none. Optionally specify a filter
function `scope_limiter` as the first argument to limit the components that should be
considered.
# Arguments
- `scope_limiter::Union{Function, Nothing}`: see [`ComponentSelector`](@ref)
- `selector::SingularComponentSelector`: the `SingularComponentSelector` whose component
to retrieve
- `sys::System`: the system from which to draw components
"""
get_component(
scope_limiter::Union{Function, Nothing},
selector::SingularComponentSelector,
sys::System,
) =
IS.get_component(scope_limiter, selector, sys)
"""
Get the component of the [`System`](@ref) that makes up the
[`SingularComponentSelector`](@ref); `nothing` if there is none.
# Arguments
- `selector::SingularComponentSelector`: the `SingularComponentSelector` whose component to retrieve
- `sys::System`: the system from which to draw components
"""
get_component(selector::SingularComponentSelector, sys::System) =
IS.get_component(selector, sys)
# get_available_components
"""
Like [`get_components`](@ref get_components(
scope_limiter::Union{Function, Nothing},
selector::ComponentSelector,
sys::System,
)) but only operates on components for which [`get_available`](@ref) is `true`.
"""
get_available_components(
scope_limiter::Union{Function, Nothing},
selector::ComponentSelector,
sys::System,
) =
IS.get_available_components(scope_limiter, selector::ComponentSelector, sys::System)
"""
Like [`get_components`](@ref get_components(selector::ComponentSelector, sys::System)) but
only operates on components for which [`get_available`](@ref) is `true`.
"""
get_available_components(selector::ComponentSelector, sys::System) =
IS.get_available_components(selector::ComponentSelector, sys::System)
# get_available_component
"""
Like [`get_component`](@ref get_component(
scope_limiter::Union{Function, Nothing},
selector::IS.SingularComponentSelector,
sys::System,
)) but only operates on components for which [`get_available`](@ref) is `true`.
"""
get_available_component(
scope_limiter::Union{Function, Nothing},
selector::IS.SingularComponentSelector,
sys::System,
) =
IS.get_available_component(scope_limiter, selector, sys)
"""
Like [`get_component`](@ref get_component(
selector::IS.SingularComponentSelector,
sys::System,
)) but only operates on components for which [`get_available`](@ref) is `true`.
"""
get_available_component(
selector::IS.SingularComponentSelector,
sys::System,
) =
IS.get_available_component(selector, sys)
# get_groups
"""
Get the groups that make up the [`ComponentSelector`](@ref). Optionally specify a filter
function `scope_limiter` as the first argument to limit the components that should be
considered.
# Arguments
- `scope_limiter::Union{Function, Nothing}`: see [`ComponentSelector`](@ref)
- `selector::ComponentSelector`: the `ComponentSelector` whose groups to retrieve
- `sys::System`: the system from which to draw components
"""
get_groups(
scope_limiter::Union{Function, Nothing},
selector::ComponentSelector,
sys::System,
) =
IS.get_groups(scope_limiter, selector, sys)
"""
Get the groups that make up the [`ComponentSelector`](@ref).
# Arguments
- `selector::ComponentSelector`: the `ComponentSelector` whose groups to retrieve
- `sys::System`: the system from which to draw components
"""
get_groups(selector::ComponentSelector, sys::System) =
IS.get_groups(selector, sys)
# get_available_groups
"""
Like [`get_groups`](@ref get_groups(
scope_limiter::Union{Function, Nothing},
selector::ComponentSelector,
sys::System,
)) but only operates on components for which [`get_available`](@ref) is `true`.
"""
get_available_groups(
scope_limiter::Union{Function, Nothing},
selector::ComponentSelector,
sys::System,
) =
IS.get_available_groups(scope_limiter, selector, sys)
"""
Like [`get_groups`](@ref get_groups(selector::ComponentSelector, sys::System)) but
only operates on components for which [`get_available`](@ref) is `true`.
"""
get_available_groups(selector::ComponentSelector, sys::System) =
IS.get_available_groups(selector, sys)
================================================
FILE: src/contingencies.jl
================================================
"""
Supertype for contingency events that can be attached to components as supplemental
attributes.
Concrete subtypes include [`Outage`](@ref) and its descendants.
"""
abstract type Contingency <: SupplementalAttribute end
================================================
FILE: src/data_format_conversions.jl
================================================
# This file contains code to convert serialized data from old formats to work with newer
# code.
#
# In version 1.0.1 the DeterministicMetadata struct added field time_series type.
# Deserialization needs to add this field and value.
#
# List of structs that have a "variable" field that requires 3.0.0 VariableCost -> 4.0.0 FunctionData conversion
const COST_CONTAINERS =
["MultiStartCost", "StorageManagementCost", "ThreePartCost", "TwoPartCost"]
function _convert_data!(
raw::Dict{String, Any},
::Val{Symbol("2.0.0")},
::Val{Symbol("3.0.0")},
)
for component in raw["data"]["components"]
if component["__metadata__"]["type"] == "Bus"
component["__metadata__"]["type"] = "ACBus"
continue
end
if component["__metadata__"]["type"] == "HVDCLine"
component["__metadata__"]["type"] = "TwoTerminalGenericHVDCLine"
continue
end
if component["__metadata__"]["type"] == "VSCDCLine"
component["__metadata__"]["type"] = "TwoTerminalLCCLine"
continue
end
if haskey(component, "prime_mover") && haskey(component, "dynamic_injector")
component["prime_mover_type"] = pop!(component, "prime_mover")
end
end
return
end
function _convert_data!(
raw::Dict{String, Any},
::Val{Symbol("1.0.0")},
::Val{Symbol("3.0.0")},
)
_convert_data!(raw, Val{Symbol("1.0.0")}(), Val{Symbol("2.0.0")}())
_convert_data!(raw, Val{Symbol("2.0.0")}(), Val{Symbol("3.0.0")}())
return
end
function _convert_data!(
raw::Dict{String, Any},
::Val{Symbol("1.0.1")},
::Val{Symbol("3.0.0")},
)
_convert_data!(raw, Val{Symbol("2.0.0")}(), Val{Symbol("3.0.0")}())
return
end
_convert_cost(old_cost::Real) = LinearFunctionData(old_cost)
_convert_cost((squared_term, proportional_term)::Tuple{<:Real, <:Real}) =
QuadraticFunctionData(squared_term, proportional_term, 0)
function _convert_cost(points::Vector)
# We can't rely on the typing to be nice after deserialization, so "dispatch" on the structure
((length(points) == 2) && all(typeof.(points) .<: Real)) &&
return _convert_cost(Tuple(points))
@assert all(length.(points) .== 2)
@assert all([all(typeof.(point) .<: Real) for point in points])
# NOTE: old representation stored points as (y, x); new representation is (x, y)
return PiecewiseLinearData([(x, y) for (y, x) in points])
end
# _convert_op_cost: take a component type, an old operational cost type, and old operational
# cost data; and create the proper new operational cost struct. Some of these cost structs
# no longer exist, so we dispatch instead on symbols.
_convert_op_cost(::Val{:ThermalStandard}, ::Val{:ThreePartCost}, op_cost::Dict) =
ThermalGenerationCost(
CostCurve(InputOutputCurve(op_cost["variable"])),
op_cost["fixed"],
op_cost["start_up"],
op_cost["shut_down"],
)
function _convert_op_cost(::Val{:RenewableDispatch}, ::Val{:TwoPartCost}, op_cost::Dict)
(op_cost["fixed"] != 0) && throw(
ArgumentError("Not implemented for nonzero fixed cost, got $(op_cost["fixed"])"),
)
return RenewableGenerationCost(CostCurve(InputOutputCurve(op_cost["variable"])))
end
_convert_op_cost(::Val{:GenericBattery}, ::Val{:StorageManagementCost}, op_cost::Dict) =
StorageCost(;
charge_variable_cost = CostCurve(InputOutputCurve(op_cost["variable"])),
discharge_variable_cost = CostCurve(InputOutputCurve(op_cost["variable"])),
fixed = op_cost["fixed"],
start_up = float(op_cost["start_up"]),
shut_down = float(op_cost["shut_down"]),
energy_shortage_cost = op_cost["energy_shortage_cost"],
energy_surplus_cost = op_cost["energy_surplus_cost"],
)
_convert_op_cost(::Val{:HydroDispatch}, ::Val{:TwoPartCost}, op_cost::Dict) =
HydroGenerationCost(CostCurve(InputOutputCurve(op_cost["variable"])), op_cost["fixed"])
# TODO implement remaining _convert_op_cost methods
function _convert_data!(
raw::Dict{String, Any},
::Val{Symbol("3.0.0")},
::Val{Symbol("4.0.0")},
)
for component in vcat(raw["data"]["components"], raw["data"]["masked_components"])
# Convert costs: all old cost structs are in fields named `operation_cost`
if haskey(component, "operation_cost")
op_cost = component["operation_cost"]
# Step 1: insert a FunctionData
if op_cost["__metadata__"]["type"] in COST_CONTAINERS &&
haskey(op_cost["variable"], "cost")
old_cost = op_cost["variable"]["cost"]
new_cost = _convert_cost(old_cost)
op_cost["variable"] = new_cost
end
# Step 2: convert TwoPartCost/ThreePartCost to new domain-specific cost structs
comp_type = Val{Symbol(component["__metadata__"]["type"])}()
op_cost_type = Val{Symbol(op_cost["__metadata__"]["type"])}()
new_op_cost = IS.serialize(_convert_op_cost(comp_type, op_cost_type, op_cost))
component["operation_cost"] = new_op_cost
end
(component["__metadata__"]["type"] == "RenewableFix") &&
(component["__metadata__"]["type"] = "RenewableNonDispatch")
if component["__metadata__"]["type"] ∈ ["BatteryEMS", "GenericBattery"]
old_type = component["__metadata__"]["type"]
component["__metadata__"]["type"] = "EnergyReservoirStorage"
component["storage_technology_type"] = IS.serialize(StorageTech.OTHER_CHEM)
soc_min = component["state_of_charge_limits"]["min"]
soc_max = component["state_of_charge_limits"]["max"]
if soc_max == 0.0
component["storage_capacity"] = 0.0
component["storage_level_limits"] = Dict("min" => 0.0, "max" => 1.0)
(component["initial_energy"] != 0.0) && throw(
ArgumentError(
"Maximum state of charge is zero but initial energy is not; cannot parse",
),
)
component["initial_storage_capacity_level"] = 0.0
else
# Derive storage_capacity from old state of charge limits and normalize new
# state of charge limits, initial capacity accordingly
@warn "Parsing $PowerSystems 3.0.0 $old_type as $PowerSystems 4.0.0 $(component["__metadata__"]["type"]), accuracy of conversion not guaranteed"
component["storage_capacity"] = soc_max
component["storage_level_limits"] =
Dict("min" => soc_min / soc_max, "max" => 1.0)
component["initial_storage_capacity_level"] =
component["initial_energy"] / soc_max
end
end
if haskey(component, "rate") # Line, TapTransformer, etc.
component["rating"] = component["rate"]
end
end
return
end
function _convert_data!(
raw::Dict{String, Any},
from::Val,
::Val{Symbol("4.0.0")},
)
_convert_data!(raw, from, Val{Symbol("3.0.0")}())
_convert_data!(raw, Val{Symbol("3.0.0")}(), Val{Symbol("4.0.0")}())
return
end
function _convert_data!(
raw::Dict{String, Any},
::Val{Symbol("4.0.0")},
::Val{Symbol("5.0.0")},
)
error("Conversion from 4.0.0 to 5.0.0 JSON format is not supported yet.")
#=
for component in raw["data"]["components"]
if component["__metadata__"]["type"] == "TwoTerminalHVDCLine"
component["__metadata__"]["type"] = "TwoTerminalGenericHVDCLine"
continue
end
if component["__metadata__"]["type"] ∈ ("Transformer2W", "TapTransformer") &&
"winding_group_number" ∉ keys(component)
component["winding_group_number"] = WindingGroupNumber.GROUP_0
continue
end
end
=#
return
end
function _convert_data!(
raw::Dict{String, Any},
from::Val,
::Val{Symbol("5.0.0")},
)
_convert_data!(raw, from, Val{Symbol("4.0.0")}())
_convert_data!(raw, Val{Symbol("4.0.0")}(), Val{Symbol("5.0.0")}())
return
end
# Conversions to occur immediately after the data is loaded from disk
function pre_read_conversion!(raw)
if VersionNumber(raw["data_format_version"]) < v"4.0.0"
haskey(raw["data"], "subsystems") ||
(raw["data"]["subsystems"] = Dict{String, Any}())
haskey(raw["data"], "attributes") || (raw["data"]["attributes"] = Any[])
end
end
# Conversions to occur before deserialize_components!
function pre_deserialize_conversion!(raw, sys::System)
old = raw["data_format_version"]
if old == DATA_FORMAT_VERSION
return
else
_convert_data!(raw, Val{Symbol(old)}(), Val{Symbol(DATA_FORMAT_VERSION)}())
@warn(
"System loaded in the data format version $old will be automatically upgraded to $DATA_FORMAT_VERSION upon saving"
)
end
end
# Conversions to occur at the end of deserialization
function post_deserialize_conversion!(sys::System, raw)
old = raw["data_format_version"]
if old == "1.0.1" || old == "2.0.0" || old == "3.0.0"
# Version 1.0.1 can be converted
raw["data_format_version"] = DATA_FORMAT_VERSION
@warn(
"System loaded in the data format version $old will be automatically upgraded to $DATA_FORMAT_VERSION upon saving"
)
return
else
error("Conversion of data from $old to $DATA_FORMAT_VERSION is not supported")
end
end
================================================
FILE: src/definitions.jl
================================================
const MinMax = NamedTuple{(:min, :max), Tuple{Float64, Float64}}
const UpDown = NamedTuple{(:up, :down), Tuple{Float64, Float64}}
const StartUpShutDown = NamedTuple{(:startup, :shutdown), Tuple{Float64, Float64}}
const FromTo = NamedTuple{(:from, :to), Tuple{Float64, Float64}}
const TurbinePump = NamedTuple{(:turbine, :pump), Tuple{Float64, Float64}}
# Exception to CamelCase convention for aliases due to confusssing reading of FromToToFrom
const FromTo_ToFrom = NamedTuple{(:from_to, :to_from), Tuple{Float64, Float64}}
const StartUpStages = NamedTuple{(:hot, :warm, :cold), NTuple{3, Float64}}
# Intended for use with generators that are not multi-start (e.g. ThermalStandard).
# Operators use `hot` when they don’t have multiple stages.
"Convert a single start-up cost value to a `StartUpStages`"
single_start_up_to_stages(start_up::Real) =
(hot = Float64(start_up), warm = 0.0, cold = 0.0)
IS.@scoped_enum(GeneratorCostModels, PIECEWISE_LINEAR = 1, POLYNOMIAL = 2,)
@doc"
GeneratorCostModel
Enumeration representing different cost models for generators in power system analysis.
" GeneratorCostModels
IS.@scoped_enum(AngleUnits, DEGREES = 1, RADIANS = 2,)
@doc"
AngleUnits
An enumeration of angular measurement units used throughout the PowerSystems package.
Values
- `DEGREES`: Angles expressed in degrees.
- `RADIANS`: Angles expressed in radians.
Usage
Use `AngleUnits` to make unit semantics explicit for functions, fields, and APIs that accept or return angular values. When performing trigonometric calculations with Base functions (`sin`, `cos`, etc.), convert degrees to radians (e.g., `θ * π/180`) if the unit is `DEGREES`.
Examples
julia> unit = AngleUnits.DEGREES
AngleUnits.DEGREES
julia> θ = 30.0
julia> θ_rad = unit == AngleUnits.DEGREES ? θ * (π/180) : θ
" AngleUnits
IS.@scoped_enum(ACBusTypes, PQ = 1, PV = 2, REF = 3, ISOLATED = 4, SLACK = 5,)
@doc"
ACBusTypes
Enumeration of AC power system bus types (MATPOWER Table B‑1).
Each variant corresponds to a standard bus classification used in power flow
and steady‑state network models:
- PQ (1): Load bus — active (P) and reactive (Q) power injections are specified;
the bus voltage magnitude and angle are solved by the power‑flow algorithm.
- PV (2): Generator (PV) bus — active power (P) and voltage magnitude (V) are
specified; reactive power (Q) and voltage angle are solved.
- REF (3): Reference bus — a named reference for the system voltage angle; often
equivalent to a slack bus in semantics but provided separately for clarity.
- ISOLATED (4): Isolated bus — not connected to the main network (islanded or
disconnected); typically excluded from the global power‑flow solution.
- SLACK (5): Slack bus — balances the system active and reactive power mismatch
and sets the reference voltage angle (commonly one per connected network).
Notes
- Numeric values follow the MATPOWER convention for bus type codes.
- Use the enum members (e.g., `ACBusTypes.PQ`, `ACBusTypes.SLACK`) when
constructing or interpreting network data structures to ensure clarity and
compatibility with MATPOWER-based data conventions.
Reference: MATPOWER manual, Table B‑1 (http://www.pserc.cornell.edu/matpower/MATPOWER-manual.pdf).
" ACBusTypes
IS.@scoped_enum(
LoadConformity,
NON_CONFORMING = 0,
CONFORMING = 1,
UNDEFINED = 2,
)
@doc"""
LoadConformity
WECC-defined enumeration for load conformity classification used in dynamic modeling.
Load conformity indicates whether a load follows system voltage and frequency variations
according to WECC modeling standards:
- `NON_CONFORMING = 0`: Load that does not respond predictably to voltage and frequency changes,
typically representing constant power loads or loads with complex control systems
- `CONFORMING = 1`: Load that responds predictably to voltage and frequency variations,
following standard load modeling practices for dynamic studies
- `UNDEFINED = 2`: Load conformity status is not specified or unknown
This classification is essential for WECC dynamic studies as it determines how loads are
modeled during system disturbances and stability analysis.
""" LoadConformity
# "From PSSE POM v33 Manual"
IS.@scoped_enum(
FACTSOperationModes,
OOS = 0, # out-of-service (i.e., Series and Shunt links open)
NML = 1, # Normal mode of operation, where Series and Shunt links are operating.
BYP = 2, # Series link is bypassed (i.e., like a zero impedance line) and Shunt link operates as a STATCOM.
)
@doc"
FACTSOperationModes
Enumeration defining the operational modes for FACTS (Flexible AC Transmission System) devices.
Based on PSSE POM v33 Manual specifications.
# Values
- `OOS = 0`: Out-of-service mode where both Series and Shunt links are open
- `NML = 1`: Normal mode of operation where both Series and Shunt links are operating
- `BYP = 2`: Bypass mode where Series link is bypassed (acts like zero impedance line)
and Shunt link operates as a STATCOM
" FACTSOperationModes
IS.@scoped_enum(
DiscreteControlledBranchType,
SWITCH = 0,
BREAKER = 1,
OTHER = 2,
)
@doc"
DiscreteControlledBranchType
An enumeration representing different types of discrete controlled branches in power systems.
# Values
- `SWITCH = 0`: Represents a switch device that can be opened or closed
- `BREAKER = 1`: Represents a circuit breaker that can interrupt current flow
- `OTHER = 2`: Represents other types of discrete controlled branch devices
" DiscreteControlledBranchType
IS.@scoped_enum(
DiscreteControlledBranchStatus,
OPEN = 0,
CLOSED = 1,
)
@doc"
DiscreteControlledBranchStatus
Enumeration describing the controlled (commanded) status of a branch device
(such as a breaker or a switch) in a power system model.
Values
- OPEN = 0: The device is open (interrupting state) — the branch is non-conducting.
- CLOSED = 1: The device is closed (conducting state) — the branch provides a normal conduction path.
Notes
- This enum represents the intended or commanded state used by control and protection
logic; it may differ from actual measured/telemetry state during faults or failures.
- The integer encoding (0/1) is chosen for compact storage and interop with serialization
or external data formats.
" DiscreteControlledBranchStatus
IS.@scoped_enum(
WindingCategory,
TR2W_WINDING = 0, # Transformer2W only winding associated with a TICT
PRIMARY_WINDING = 1, # Primary winding of Trasnformer3W associated with a TICT
SECONDARY_WINDING = 2, # Secondary winding of Trasnformer3W associated with a TICT
TERTIARY_WINDING = 3, # Tertiary winding of Trasnformer3W associated with a TICT
)
@doc"
WindingCategory
An enumeration representing different types of transformer windings used in power system analysis.
Reflects how to interpret the Transformer Impedance Correction Table (TICT) winding association as described in [`ImpedanceCorrectionData`](@ref).
# Values
- `TR2W_WINDING = 0`: Winding associated with a two-winding transformer (Transformer2W) connected to a tap-changing transformer's [`ImpedanceCorrectionData`](@ref)
- `PRIMARY_WINDING = 1`: Primary winding of a three-winding transformer (Transformer3W) associated with a [`ImpedanceCorrectionData`](@ref)
- `SECONDARY_WINDING = 2`: Secondary winding of a three-winding transformer (Transformer3W) associated with a [`ImpedanceCorrectionData`](@ref)
- `TERTIARY_WINDING = 3`: Tertiary winding of a three-winding transformer (Transformer3W) associated with a [`ImpedanceCorrectionData`](@ref)
This enumeration is used to categorize transformer windings based on their role and configuration
in the power system model, particularly in relation to tap-changing transformers.
" WindingCategory
IS.@scoped_enum(
WindingGroupNumber,
UNDEFINED = -99,
GROUP_0 = 0, # 0 Degrees
GROUP_1 = 1, # -30 Degrees
GROUP_5 = 5, # -150 Degrees
GROUP_6 = 6, # 180 Degrees
GROUP_7 = 7, # 150 Degrees
GROUP_11 = 11, # 30 Degrees
)
@doc"
WindingGroupNumber
Enumeration defining transformer winding group numbers based on IEC 60076-1 standard.
These numbers represent the phase displacement between primary and secondary windings
of three-phase transformers.
# Valid Values
- `UNDEFINED = -99`: Undefined or unspecified winding group
- `GROUP_0 = 0`: 0° phase displacement (Yy0, Dd0, Dz0)
- `GROUP_1 = 1`: -30° phase displacement (Yy1, Dd1, Dz1)
- `GROUP_5 = 5`: -150° phase displacement (Yy5, Dd5, Dz5)
- `GROUP_6 = 6`: 180° phase displacement (Yy6, Dd6, Dz6)
- `GROUP_7 = 7`: 150° phase displacement (Yy7, Dd7, Dz7)
- `GROUP_11 = 11`: 30° phase displacement (Yy11, Dd11, Dz11)
# Notes
The phase displacement is measured from the primary to secondary winding, with
positive angles representing a lead and negative angles representing a lag.
Clock notation follows the convention where each hour represents 30°.
" WindingGroupNumber
IS.@scoped_enum(
ImpedanceCorrectionTransformerControlMode,
PHASE_SHIFT_ANGLE = 1,
TAP_RATIO = 2,
)
@doc"""
ImpedanceCorrectionTransformerControlMode
Enumeration defining the control modes for impedance correction in transformers,
based on PSS/E transformer control definitions.
# Values
- `PHASE_SHIFT_ANGLE = 1`: Control mode for phase-shifting transformers where the
impedance correction is applied based on the phase shift angle. Used when the
transformer primarily controls power flow through phase angle adjustment.
- `TAP_RATIO = 2`: Control mode for tap-changing transformers where the impedance
correction is applied based on the tap ratio. Used when the transformer primarily
controls voltage magnitude through tap position changes.
# Notes
This enumeration corresponds to PSS/E transformer control field definitions for
determining how impedance corrections are calculated and applied in power flow
and dynamic simulation studies.
""" ImpedanceCorrectionTransformerControlMode
IS.@scoped_enum(
TransformerControlObjective, # COD1 or COD2 in PSS\e
UNDEFINED = -99,
VOLTAGE_DISABLED = -1,
REACTIVE_POWER_FLOW_DISABLED = -2,
ACTIVE_POWER_FLOW_DISABLED = -3,
CONTROL_OF_DC_LINE_DISABLED = -4,
ASYMMETRIC_ACTIVE_POWER_FLOW_DISABLED = -5,
FIXED = 0,
VOLTAGE = 1,
REACTIVE_POWER_FLOW = 2,
ACTIVE_POWER_FLOW = 3,
CONTROL_OF_DC_LINE = 4,
ASYMMETRIC_ACTIVE_POWER_FLOW = 5,
)
@doc"
TransformerControlObjective
Enumeration of transformer control objectives based on PSS/E COD1 and COD2 fields.
This enumeration defines the control modes for transformer tap changers and phase shifters
as specified in the PSS/E-35 manual.
# Values
- `UNDEFINED = -99`: Undefined control objective
- `VOLTAGE_DISABLED = -1`: Voltage control disabled
- `REACTIVE_POWER_FLOW_DISABLED = -2`: Reactive power flow control disabled
- `ACTIVE_POWER_FLOW_DISABLED = -3`: Active power flow control disabled
- `CONTROL_OF_DC_LINE_DISABLED = -4`: DC line control disabled
- `ASYMMETRIC_ACTIVE_POWER_FLOW_DISABLED = -5`: Asymmetric active power flow control disabled
- `FIXED = 0`: Fixed tap position (no automatic control)
- `VOLTAGE = 1`: Voltage magnitude control at controlled bus
- `REACTIVE_POWER_FLOW = 2`: Reactive power flow control through the transformer
- `ACTIVE_POWER_FLOW = 3`: Active power flow control through the transformer
- `CONTROL_OF_DC_LINE = 4`: Control of DC transmission line
- `ASYMMETRIC_ACTIVE_POWER_FLOW = 5`: Asymmetric active power flow control
# Notes
Negative values indicate disabled control modes, while positive values represent active
control objectives. The `FIXED` mode (0) indicates manual tap position control without
automatic adjustment.
" TransformerControlObjective
IS.@scoped_enum(
MotorLoadTechnology,
INDUCTION = 1,
SYNCHRONOUS = 2,
UNDETERMINED = 3,
)
@doc"
MotorLoadTechnology
An enumeration representing different motor load technologies used in industrial applications.
# Values
- `INDUCTION`: Induction motor technology, commonly used for general-purpose applications
- `SYNCHRONOUS`: Synchronous motor technology, used for applications requiring constant speed
- `UNDETERMINED`: Motor technology type is not specified or unknown
" MotorLoadTechnology
IS.@scoped_enum(
PrimeMovers,
BA = 1, # Energy Storage, Battery
BT = 2, # Turbines Used in a Binary Cycle (including those used for geothermal applications)
CA = 3, # Combined-Cycle – Steam Part
CC = 4, # Combined-Cycle - Aggregated Plant *augmentation of EIA
CE = 5, # Energy Storage, Compressed Air
CP = 6, # Energy Storage, Concentrated Solar Power
CS = 7, # Combined-Cycle Single-Shaft Combustion turbine and steam turbine share a single generator
CT = 8, # Combined-Cycle Combustion Turbine Part
ES = 9, # Energy Storage, Other (Specify on Schedule 9, Comments)
FC = 10, # Fuel Cell
FW = 11, # Energy Storage, Flywheel
GT = 12, # Combustion (Gas) Turbine (including jet engine design)
HA = 13, # Hydrokinetic, Axial Flow Turbine
HB = 14, # Hydrokinetic, Wave Buoy
HK = 15, # Hydrokinetic, Other
HY = 16, # Hydraulic Turbine (including turbines associated with delivery of water by pipeline)
IC = 17, # Internal Combustion (diesel, piston, reciprocating) Engine
PS = 18, # Energy Storage, Reversible Hydraulic Turbine (Pumped Storage)
OT = 19, # Other – Specify on SCHEDULE 9.
ST = 20, # Steam Turbine (including nuclear, geothermal and solar steam; does not include combined-cycle turbine)
PVe = 21, # Photovoltaic *renaming from EIA PV to PVe to avoid conflict with BusType.PV
WT = 22, # Wind Turbine, Onshore
WS = 23, # Wind Turbine, Offshore
)
@doc"
PrimeMovers
Enumeration of prime mover types used in electric power generation, as defined by the
U.S. Energy Information Administration (EIA) Form 923 instructions.
Prime movers are the engines, turbines, water wheels, or similar machines that drive
electric generators or provide mechanical energy for other purposes. This enumeration
provides standardized codes for different types of prime movers used in power plants.
PVe is used for photovoltaic systems renaming from EIA PV to avoid conflict with BusType.PV
# References
- [EIA Form 923 Instructions](https://www.eia.gov/survey/form/eia_923/instructions.pdf)
# See Also
- [`ThermalStandard`](@ref): Uses prime mover information for generator specifications
- [`ThermalMultiStart`](@ref): Uses prime mover information for generator specifications
" PrimeMovers
IS.@scoped_enum(
ThermalFuels,
COAL = 1, # General Coal Category.
ANTHRACITE_COAL = 2,# ANT
BITUMINOUS_COAL = 3, # BIT
LIGNITE_COAL = 4, # LIG
SUBBITUMINOUS_COAL = 5, # SUB
WASTE_COAL = 6, # WC # includes anthracite culm, bituminous gob, fine coal, lignite waste, waste coal
REFINED_COAL = 7, # RC # ncludes any coal which meets the IRS definition of refined coal [Notice 2010-54 or any superseding IRS notices]. Does not include coal processed by coal preparation plants.)
SYNTHESIS_GAS_COAL = 8, # SGC
DISTILLATE_FUEL_OIL = 9, # DFO # includes Diesel, No. 1, No. 2, and No. 4
JET_FUEL = 10, # JF
KEROSENE = 11, # KER
PETROLEUM_COKE = 12, # PC
RESIDUAL_FUEL_OIL = 13, # RFO # includes No. 5, No. 6 Fuel Oils, and Bunker Oil
PROPANE = 14, # PG # Propane, gaseous
SYNTHESIS_GAS_PETROLEUM_COKE = 15, # SGP
WASTE_OIL = 16, # WO # including crude oil, liquid butane, liquid propane, naphtha, oil waste, re-refined motor oil, sludge oil, tar oil, or other petroleum-based liquid wastes
BLASTE_FURNACE_GAS = 17, # BFG
NATURAL_GAS = 18, # NG # Natural Gas
OTHER_GAS = 19, # OOG # Other Gas and blast furnace gas
NUCLEAR = 20, # NUC # Nuclear Fission (Uranium, Plutonium, Thorium)
AG_BYPRODUCT = 21, # AB # Agricultural Crop Byproducts/Straw/Energy Crops
MUNICIPAL_WASTE = 22, # MSW # Municipal Solid Waste – Biogenic component
OTHER_BIOMASS_SOLIDS = 23, # OBS
WOOD_WASTE_SOLIDS = 24, # WDS # including paper 18 pellets, railroad ties, utility poles, wood chips, bark, and wood waste solid
OTHER_BIOMASS_LIQUIDS = 26, # OBL
SLUDGE_WASTE = 27, # SLW
BLACK_LIQUOR = 28, # BLQ
WOOD_WASTE_LIQUIDS = 29, # WDL # includes red liquor, sludge wood, spent sulfite liquor, and other wood-based liquid. Excluding black liquour
LANDFILL_GAS = 30, # LFG
OTHEHR_BIOMASS_GAS = 31, # OBG # includes digester gas, methane, and other biomass gasses
GEOTHERMAL = 32, # GEO
WASTE_HEAT = 33, # WH # WH should only be reported where the fuel source for the waste heat is undetermined, and for combined-cycle steam turbines that do not have supplemental firing.
TIREDERIVED_FUEL = 34, # TDF
OTHER = 35, # OTH
)
@doc"
ThermalFuels
Enumeration of thermal fuel types based on AER (Aggregated Energy Reporting) fuel codes
as defined by the U.S. Energy Information Administration (EIA) Form 923.
The fuel codes represent standardized categories for reporting fuel consumption in
electric power generation, covering major thermal fuel types including:
- Coal and coal-derived fuels
- Natural gas and petroleum products
- Nuclear fuel
- Biomass and waste fuels
- Other thermal energy sources
Reference: EIA Form 923 Instructions (https://www.eia.gov/survey/form/eia_923/instructions.pdf)
General Coal and Geothermal codes not directly from the current EIA 923 form but kept for compatibility with older versions of the form.
See also: [`ThermalStandard`](@ref)
" ThermalFuels
IS.@scoped_enum(
StorageTech,
PTES = 1, # Pumped thermal energy storage
LIB = 2, # LiON Battery
LAB = 3, # Lead Acid Battery
FLWB = 4, # Redox Flow Battery
SIB = 5, # Sodium Ion Battery
ZIB = 6, # Zinc Ion Battery,
HGS = 7, # Hydrogen Gas Storage,
LAES = 8, # Liquid Air Storage
OTHER_CHEM = 9, # Chemmical Storage
OTHER_MECH = 10, # Mechanical Storage
OTHER_THERM = 11, # Thermal Storage
)
@doc"
StorageTech
Enumeration of energy storage technologies used in power systems.
# Values
- `PTES`: Pumped thermal energy storage
- `LIB`: Lithium-ion Battery
- `LAB`: Lead Acid Battery
- `FLWB`: Redox Flow Battery
- `SIB`: Sodium Ion Battery
- `ZIB`: Zinc Ion Battery
- `HGS`: Hydrogen Gas Storage
- `LAES`: Liquid Air Energy Storage
- `OTHER_CHEM`: Chemical Storage (other than specified)
- `OTHER_MECH`: Mechanical Storage (other than specified)
- `OTHER_THERM`: Thermal Storage (other than specified)
This enumeration is used to classify different types of energy storage systems
based on their underlying technology and storage mechanism.
" StorageTech
IS.@scoped_enum(
PumpHydroStatus,
OFF = 0,
GEN = 1,
PUMP = -1,
)
@doc"
PumpHydroStatus
Operating status of a pumped‑storage hydro unit.
Values
- OFF = 0: Unit is idle — neither generating nor pumping.
- GEN = 1: Generating mode (turbine operation), producing active power.
- PUMP = -1: Pumping mode, consuming active power to store energy.
Notes
- The sign of the value reflects the net direction of active power (positive = generation, negative = pumping).
- Intended for use in scheduling, dispatch, and state-tracking of pumped‑storage units.
" PumpHydroStatus
IS.@scoped_enum(StateTypes, Differential = 1, Algebraic = 2, Hybrid = 3,)
@doc """
Categorization of dynamic state variables.
# Values
- `Differential`: State governed by a differential equation
- `Algebraic`: State governed by an algebraic constraint
- `Hybrid`: State with both differential and algebraic aspects
""" StateTypes
IS.@scoped_enum(
ReservoirDataType,
USABLE_VOLUME = 1,
TOTAL_VOLUME = 2,
HEAD = 3,
ENERGY = 4,
)
@doc"
ReservoirDataType
Enumeration of reservoir accounting unit classes.
This enum identifies the type of data recorded or tracked for a reservoir. Use these values when specifying
the kind of measurement or accounting quantity associated with a reservoir (for example in time series,
storage models, reporting, or data exchange).
Values
- USABLE_VOLUME: Volume available for operations and dispatch (active storage). Typically reported in cubic meters (m³) or other volumetric units.
- TOTAL_VOLUME: Total reservoir volume including dead and active storage. Reported in the same volumetric units as USABLE_VOLUME.
- HEAD: Hydraulic head or water surface elevation relative to a datum, typically reported in meters (m).
- ENERGY: Stored or deliverable energy associated with the reservoir (e.g., potential energy or expected generation), often expressed in MWh, GWh, or joules.
" ReservoirDataType
IS.@scoped_enum(
HydroTurbineType,
UNKNOWN = 0, # Default / unspecified
PELTON = 1, # Impulse turbine for high head
FRANCIS = 2, # Reaction turbine for medium head
KAPLAN = 3, # Propeller-type turbine for low head
TURGO = 4, # Impulse turbine similar to Pelton
CROSSFLOW = 5, # Banki-Michell (crossflow) turbine
BULB = 6, # Kaplan variation for very low head
DERIAZ = 7, # Diagonal flow turbine
PROPELLER = 8, # Simple propeller turbine
OTHER = 9 # Catch-all for less common designs
)
@doc"
HydroTurbineType
Enumeration of hydro turbine types supported in `PowerSystems.jl`.
This type is used to categorize hydroelectric generators by their
turbine design and operating head. It provides a standardized set
of turbine types to ensure consistent modeling and data handling
across different systems.
# Values
- `UNKNOWN` : Default value when the turbine type is not specified.
- `PELTON` : Impulse turbine, typically used for high-head, low-flow sites.
- `FRANCIS` : Reaction turbine, widely used for medium-head applications.
- `KAPLAN` : Adjustable-blade propeller turbine for low-head, high-flow sites.
- `TURGO` : Impulse turbine similar to Pelton but suitable for higher flow rates.
- `CROSSFLOW` : Banki-Michell (crossflow) impulse turbine, robust for small hydro.
- `BULB` : Compact Kaplan variant, typically installed in low-head run-of-river plants.
- `DERIAZ` : Diagonal flow reaction turbine with variable pitch blades.
- `PROPELLER` : Fixed-blade propeller turbine, simpler than Kaplan but less efficient at part load.
- `OTHER` : Placeholder for less common or custom turbine designs.
" HydroTurbineType
IS.@scoped_enum(
ReservoirLocation,
HEAD = 1,
TAIL = 2,
)
@doc"
ReservoirLocation
Enumeration representing the location of a hydro reservoir relative to its associated turbine.
# Values
- `HEAD`: The reservoir is located upstream of the turbine, typically at a higher elevation.
- `TAIL`: The reservoir is located downstream of the turbine at a lower or same elevation.
" ReservoirLocation
IS.@scoped_enum(
CombinedCycleConfiguration,
SingleShaftCombustionSteam = 1,
SeparateShaftCombustionSteam = 2,
DoubleCombustionOneSteam = 3,
TripleCombustionOneSteam = 4,
Other = 5,
)
@doc """
Configuration types for combined cycle power plants.
# Values
- `SingleShaftCombustionSteam`: Single-shaft arrangement with one combustion and one steam turbine
- `SeparateShaftCombustionSteam`: Separate shafts for combustion and steam turbines
- `DoubleCombustionOneSteam`: Two combustion turbines feeding one steam turbine
- `TripleCombustionOneSteam`: Three combustion turbines feeding one steam turbine
- `Other`: Other combined cycle configuration
""" CombinedCycleConfiguration
const PS_MAX_LOG = parse(Int, get(ENV, "PS_MAX_LOG", "50"))
const DEFAULT_BASE_MVA = 100.0
const POWER_SYSTEM_STRUCT_DESCRIPTOR_FILE =
joinpath(dirname(pathof(PowerSystems)), "descriptors", "power_system_structs.json")
const DEFAULT_SYSTEM_FREQUENCY = 60.0
const INFINITE_TIME = 1e4
const START_COST = 1e8
const INFINITE_COST = 1e8
const INFINITE_BOUND = 1e6
const BRANCH_BUS_VOLTAGE_DIFFERENCE_TOL = 0.01
const PSSE_PARSER_TAP_RATIO_UBOUND = 1.5
const PSSE_PARSER_TAP_RATIO_LBOUND = 0.5
const PARSER_TAP_RATIO_CORRECTION_TOL = 1e-5
const ZERO_IMPEDANCE_REACTANCE_THRESHOLD = 1e-4
const WINDING_NAMES = Dict(
WindingCategory.PRIMARY_WINDING => "primary",
WindingCategory.SECONDARY_WINDING => "secondary",
WindingCategory.TERTIARY_WINDING => "tertiary",
)
const TRANSFORMER3W_PARAMETER_NAMES = [
"COD", "CONT", "NOMV", "WINDV", "RMA", "RMI",
"NTP", "VMA", "VMI", "RATA", "RATB", "RATC",
]
================================================
FILE: src/deprecated.jl
================================================
# BEGIN 4.0.0 deprecations
export TwoTerminalHVDCLine
"""
Deprecated method for the old TwoTerminalHVDCLine that returns the new TwoTerminalGenericHVDCLine.
This constructor is used for some backward compatibility and will be removed in a future version.
"""
function TwoTerminalHVDCLine(
name,
available,
active_power_flow,
arc,
active_power_limits_from,
active_power_limits_to,
reactive_power_limits_from,
reactive_power_limits_to,
loss::NamedTuple{(:l0, :l1), Tuple{Float64, Float64}},
services,
ext,
internal,
)
new_loss = LinearCurve(loss.l0, loss.l1)
@warn(
"The TwoTerminalHVDCLine constructor is deprecated. Use TwoTerminalGenericHVDCLine instead. \
This constructor will be removed in a future version.",)
TwoTerminalGenericHVDCLine(
name,
available,
active_power_flow,
arc,
active_power_limits_from,
active_power_limits_to,
reactive_power_limits_from,
reactive_power_limits_to,
new_loss,
services,
ext,
internal,
)
end
"""
Deprecated method for the old TwoTerminalHVDCLine that returns the new [`TwoTerminalGenericHVDCLine`](@ref).
This constructor is used for some backward compatibility and will be removed in a future version.
"""
function TwoTerminalHVDCLine(
name,
available,
active_power_flow,
arc,
active_power_limits_from,
active_power_limits_to,
reactive_power_limits_from,
reactive_power_limits_to,
loss::NamedTuple{(:l0, :l1), Tuple{Float64, Float64}},
services = Device[],
ext = Dict{String, Any}(),
)
@warn(
"The TwoTerminalHVDCLine constructor is deprecated. Use TwoTerminalGenericHVDCLine instead. \
This constructor will be removed in a future version.",)
new_loss = LinearCurve(loss.l0, loss.l1)
TwoTerminalGenericHVDCLine(
name,
available,
active_power_flow,
arc,
active_power_limits_from,
active_power_limits_to,
reactive_power_limits_from,
reactive_power_limits_to,
new_loss,
services,
ext,
InfrastructureSystemsInternal(),
)
end
"""
Deprecated method for the old TwoTerminalHVDCLine that returns the new [`TwoTerminalGenericHVDCLine`](@ref).
This constructor is used for some backward compatibility and will be removed in a future version.
"""
function TwoTerminalHVDCLine(
name,
available,
active_power_flow,
arc,
active_power_limits_from,
active_power_limits_to,
reactive_power_limits_from,
reactive_power_limits_to,
loss::Union{LinearCurve, PiecewiseIncrementalCurve},
services = Device[],
ext = Dict{String, Any}(),
)
@warn(
"The TwoTerminalHVDCLine constructor is deprecated. Use TwoTerminalGenericHVDCLine instead. \
This constructor will be removed in a future version.",)
return TwoTerminalGenericHVDCLine(
name,
available,
active_power_flow,
arc,
active_power_limits_from,
active_power_limits_to,
reactive_power_limits_from,
reactive_power_limits_to,
loss,
services,
ext,
InfrastructureSystemsInternal(),
)
end
"""
Deprecated method for the old TwoTerminalHVDCLine that returns the new [`TwoTerminalGenericHVDCLine`](@ref).
This constructor is used for some backward compatibility and will be removed in a future version.
"""
function TwoTerminalHVDCLine(
name,
available,
active_power_flow,
arc,
active_power_limits_from,
active_power_limits_to,
reactive_power_limits_from,
reactive_power_limits_to,
loss = LinearCurve(0.0),
services = Device[],
ext = Dict{String, Any}(),
)
@warn(
"The TwoTerminalHVDCLine constructor is deprecated. Use TwoTerminalGenericHVDCLine instead. \
This constructor will be removed in a future version.",)
TwoTerminalGenericHVDCLine(
name,
available,
active_power_flow,
arc,
active_power_limits_from,
active_power_limits_to,
reactive_power_limits_from,
reactive_power_limits_to,
loss,
services,
ext,
InfrastructureSystemsInternal(),
)
end
"""
Deprecated method for the old TwoTerminalHVDCLine that returns the new [`TwoTerminalGenericHVDCLine`](@ref).
This constructor is used for some backward compatibility and will be removed in a future version.
"""
function TwoTerminalHVDCLine(;
name,
available,
active_power_flow,
arc,
active_power_limits_from,
active_power_limits_to,
reactive_power_limits_from,
reactive_power_limits_to,
loss = LinearCurve(0.0),
services = Device[],
ext = Dict{String, Any}(),
internal = InfrastructureSystemsInternal(),
)
@warn(
"The TwoTerminalHVDCLine constructor is deprecated. Use TwoTerminalGenericHVDCLine instead. \
This constructor will be removed in a future version.",)
TwoTerminalGenericHVDCLine(
name,
available,
active_power_flow,
arc,
active_power_limits_from,
active_power_limits_to,
reactive_power_limits_from,
reactive_power_limits_to,
loss,
services,
ext,
internal,
)
end
================================================
FILE: src/descriptors/power_system_inputs.json
================================================
{
"dc_branch": [
{
"name": "name",
"description": "Unique ID"
},
{
"name": "connection_points_from",
"description": "From Bus ID"
},
{
"name": "connection_points_to",
"description": "To Bus ID"
},
{
"name": "active_power_flow",
"description": "Active power flow",
"unit_system": "device_base",
"default_value": 0.0,
"base_reference": "rate"
},
{
"name": "mw_load",
"description": "Power demand (MW)",
"unit_system": "device_base",
"default_value": 0.0,
"base_reference": "rate"
},
{
"name": "rate",
"unit": "MVA",
"description": "Apparent power limit rating",
"unit_system": "SYSTEM_BASE",
"default_value": "system_base_power"
},
{
"name": "rectifier_firing_angle_max",
"unit": "degree",
"value_range": [],
"description": "Nominal maximum firing angle",
"default_value": null
},
{
"name": "rectifier_firing_angle_min",
"unit": "degree",
"value_range": [],
"description": "Minimum steady state firing angle",
"default_value": null
},
{
"name": "rectifier_xrc",
"description": "Commutating transformer reactance/bridge",
"unit_system": "device_base",
"default_value": null
},
{
"name": "rectifier_tap_limits_max",
"value_range": [],
"description": "Max tap setting",
"default_value": null
},
{
"name": "rectifier_tap_limits_min",
"value_range": [],
"description": "Min tap setting",
"default_value": null
},
{
"name": "inverter_firing_angle_max",
"unit": "degree",
"value_range": [],
"description": "Nominal maximum firing angle",
"default_value": null
},
{
"name": "inverter_firing_angle_min",
"unit": "degree",
"value_range": [],
"description": "Minimum steady state firing angle",
"default_value": null
},
{
"name": "inverter_xrc",
"description": "Commutating transformer reactance/bridge",
"unit_system": "device_base",
"default_value": null
},
{
"name": "inverter_tap_limits_max",
"value_range": [],
"description": "Max tap setting",
"default_value": null
},
{
"name": "inverter_tap_limits_min",
"value_range": [],
"description": "Min tap setting",
"default_value": null
},
{
"name": "loss",
"unit": "%",
"description": "Power Losses on the Line",
"default_value": 0.0
},
{
"name": "min_active_power_limit_from",
"value_range": [],
"description": "Minimum Active Power Limit",
"unit_system": "device_base",
"default_value": null,
"base_reference": "rate"
},
{
"name": "max_active_power_limit_from",
"value_range": [],
"description": "Maximum Active Power Limit",
"unit_system": "device_base",
"default_value": null,
"base_reference": "rate"
},
{
"name": "min_active_power_limit_to",
"value_range": [],
"description": "Minimum Active Power Limit",
"unit_system": "device_base",
"default_value": null,
"base_reference": "rate"
},
{
"name": "max_active_power_limit_to",
"value_range": [],
"description": "Maximum Active Power Limit",
"unit_system": "device_base",
"default_value": null,
"base_reference": "rate"
},
{
"name": "min_reactive_power_limit_from",
"value_range": [],
"description": "Minimum reActive Power Limit",
"unit_system": "device_base",
"default_value": 0.0,
"base_reference": "rate"
},
{
"name": "max_reactive_power_limit_from",
"value_range": [],
"description": "Maximum reActive Power Limit",
"unit_system": "device_base",
"default_value": 0.0,
"base_reference": "rate"
},
{
"name": "min_reactive_power_limit_to",
"value_range": [],
"description": "Minimum reActive Power Limit",
"unit_system": "device_base",
"default_value": 0.0,
"base_reference": "rate"
},
{
"name": "max_reactive_power_limit_to",
"value_range": [],
"description": "Maximum reActive Power Limit",
"unit_system": "device_base",
"default_value": 0.0,
"base_reference": "rate"
},
{
"name": "control_mode",
"description": "Control Mode",
"default_value": "Power"
},
{
"name": "dc_line_category",
"value_options": [
"TwoTerminalLCCLine",
"TwoTerminalGenericHVDCLine"
],
"description": "Type of Struct",
"default_value": "TwoTerminalGenericHVDCLine"
}
],
"branch": [
{
"name": "name",
"description": "Unique branch ID"
},
{
"name": "connection_points_from",
"description": "From Bus ID"
},
{
"name": "connection_points_to",
"description": "To Bus ID"
},
{
"name": "r",
"description": "Branch resistance p.u.",
"unit_system": "device_base"
},
{
"name": "x",
"description": "Branch reactance p.u.",
"unit_system": "device_base"
},
{
"name": "primary_shunt",
"description": "Branch line charging susceptance p.u.",
"unit_system": "device_base"
},
{
"unit": "MW",
"name": "rate",
"description": "Continuous MW flow limit",
"unit_system": "SYSTEM_BASE"
},
{
"unit": "radian",
"name": "min_angle_limits",
"description": "Minimum Angle Limits",
"default_value": -3.1416
},
{
"unit": "radian",
"name": "max_angle_limits",
"description": "Maximum endpoint angle limits",
"default_value": 3.1416
},
{
"name": "active_power_flow",
"unit": "MW",
"description": "Active power flow",
"unit_system": "device_base",
"base_reference": "rate",
"default_value": 0.0
},
{
"name": "reactive_power_flow",
"unit": "MVAr",
"description": "Reactive power flow",
"unit_system": "device_base",
"base_reference": "rate",
"default_value": 0.0
},
{
"name": "tap",
"unit": "%",
"description": "Transformer winding ratio",
"default_value": 1.0
}
,
{
"name": "is_transformer",
"unit": "bool",
"description": "Transformer flag",
"default_value": null
}
],
"generator": [
{
"name": "name",
"description": "Unique generator ID: Concatenated from Bus ID_Unit Type_Gen ID"
},
{
"name": "available",
"description": "Availability",
"default_value": true
},
{
"name": "bus_id",
"description": "Connection Bus ID"
},
{
"name": "fuel",
"description": "Unit Fuel"
},
{
"name": "fuel_price",
"unit": "$/MMBTU",
"description": "Fuel Price"
},
{
"unit": "MW",
"name": "active_power",
"description": "Real power injection setpoint",
"unit_system": "device_base",
"base_reference": "base_mva"
},
{
"unit": "MW",
"name": "reactive_power",
"description": "Reactive power StaticInjection setpoint",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": 0.0
},
{
"unit": "MW",
"name": "active_power_limits_max",
"description": "Maximum real power StaticInjection (Unit Capacity)",
"unit_system": "device_base",
"base_reference": "base_mva"
},
{
"unit": "MW",
"name": "active_power_limits_min",
"description": "Minimum real power StaticInjection (Unit minimum stable level)",
"unit_system": "device_base",
"base_reference": "base_mva"
},
{
"unit": "MVAR",
"name": "reactive_power_limits_max",
"description": "Maximum reactive power StaticInjection",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "MVAR",
"name": "reactive_power_limits_min",
"description": "Minimum reactive power StaticInjection",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "hours",
"name": "min_down_time",
"description": "Minimum off time required before unit restart"
},
{
"unit": "hours",
"name": "min_up_time",
"description": "Minimum on time required before unit shutdown"
},
{
"unit": "MW(p.u.)/Min",
"name": "ramp_limits",
"description": "Maximum ramp up and ramp down rate",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "MW/Min",
"name": "ramp_up",
"description": "Maximum ramp up rate",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "MW/Min",
"name": "ramp_down",
"description": "Maximum ramp down rate",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "MMBTU",
"name": "startup_heat_cold_cost",
"description": "Heat required to startup from cold",
"default_value": null
},
{
"name": "heat_rate_a0",
"description": "Heat rate constant term",
"default_value": null
},
{
"name": "heat_rate_a1",
"description": "Heat rate proportional term",
"default_value": null
},
{
"name": "heat_rate_a2",
"description": "Heat rate quadratic term",
"default_value": null
},
{
"name": "heat_rate_avg_0",
"description": "Heat rate Average 0 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_1",
"description": "Heat rate Incremental 1 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_2",
"description": "Heat rate Incremental 2 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_3",
"description": "Heat rate Incremental 3 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_4",
"description": "Heat rate Incremental 4 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_5",
"description": "Heat rate Incremental 5 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_6",
"description": "Heat rate Incremental 6 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_7",
"description": "Heat rate Incremental 7 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_8",
"description": "Heat rate Incremental 8 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_9",
"description": "Heat rate Incremental 9 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_10",
"description": "Heat rate Incremental 10 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_11",
"description": "Heat rate Incremental 11 TODO",
"default_value": null
},
{
"name": "heat_rate_incr_12",
"description": "Heat rate Incremental 12 TODO",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_0",
"description": "Operating cost at output_point_0",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_1",
"description": "Operating cost at output_point_1",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_2",
"description": "Operating cost at output_point_2",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_3",
"description": "Operating cost at output_point_3",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_4",
"description": "Operating cost at output_point_4",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_5",
"description": "Operating cost at output_point_5",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_6",
"description": "Operating cost at output_point_6",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_7",
"description": "Operating cost at output_point_7",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_8",
"description": "Operating cost at output_point_8",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_9",
"description": "Operating cost at output_point_9",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_10",
"description": "Operating cost at output_point_10",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_11",
"description": "Operating cost at output_point_11",
"default_value": null
},
{
"unit": "$/hr",
"name": "cost_point_12",
"description": "Operating cost at output_point_12",
"default_value": null
},
{
"unit": "%",
"name": "output_point_0",
"description": "Output point 0 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_1",
"description": "Output point 1 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_2",
"description": "Output point 2 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_3",
"description": "Output point 3 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_4",
"description": "Output point 4 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_5",
"description": "Output point 5 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_6",
"description": "Output point 6 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_7",
"description": "Output point 7 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_8",
"description": "Output point 8 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_9",
"description": "Output point 9 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_10",
"description": "Output point 10 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_11",
"description": "Output point 11 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "%",
"name": "output_point_12",
"description": "Output point 12 on heat rate curve as a percentage of PMax",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "MVA",
"name": "base_mva",
"description": "Unit equivalent circuit base_mva",
"unit_system": "natural_units"
},
{
"unit": "$/MW",
"name": "variable_cost",
"description": "Variable Cost of Generation",
"default_value": null
},
{
"unit": "$/MW",
"name": "fixed_cost",
"description": "Fixed Cost of Generation",
"default_value": 0.0
},
{
"unit": "$/start",
"name": "startup_cost",
"description": "Cost associated with Start-up",
"default_value": null
},
{
"unit": "$/start",
"name": "shutdown_cost",
"description": "Cost associated with Shutdown",
"default_value": null
},
{
"unit": "$/MW",
"name": "curtailment_cost",
"description": "Cost of curtailing production",
"default_value": null
},
{
"unit": "%",
"name": "power_factor",
"description": "Power Factor",
"default_value": 1.0
},
{
"name": "unit_type",
"description": "Unit Prime Mover Type"
},
{
"name": "category",
"description": "Category",
"default_value": null
},
{
"name": "cold_start_time",
"description": "Time before which a Cold start is eligible",
"default_value": null
},
{
"name": "warm_start_time",
"description": "Time before which a Warm start is eligible",
"default_value": null
},
{
"name": "hot_start_time",
"description": "Time before which a Hot Start is eligible",
"default_value": null
},
{
"name": "startup_ramp",
"description": "Startup ramp capability",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"name": "shutdown_ramp",
"description": "Shutdown ramp capability",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"name": "status_at_start",
"description": "State of the generator at the start of the simulation",
"default_value": true
},
{
"name": "time_at_status",
"description": "Number of hours spent in current state ",
"default_value": null
},
{
"name": "cold_start_cost",
"description": "Cost for Cold start of ThermalGen",
"default_value": null
},
{
"name": "warm_start_cost",
"description": "Cost for Warm of ThermalGen",
"default_value": null
},
{
"name": "hot_start_cost",
"description": "Cost for Hot of ThermalGen",
"default_value": null
},
{
"name": "must_run",
"description": "Boolean that indicates if ThermalGen must be online always",
"default_value": false
},
{
"unit": "MW",
"name": "pump_load",
"description": "PHES Pump Load",
"unit_system": "device_base",
"base_reference": "pump_rating",
"default_value": null
},
{
"unit": "MW",
"name": "pump_active_power_limits_max",
"description": "Maximum real power StaticInjection (Unit Capacity)",
"unit_system": "device_base",
"base_reference": "pump_rating",
"default_value": 1.0
},
{
"unit": "MW",
"name": "pump_active_power_limits_min",
"description": "Minimum real power StaticInjection (Unit minimum stable level)",
"unit_system": "device_base",
"base_reference": "pump_rating",
"default_value": 0.0
},
{
"unit": "MVAR",
"name": "pump_reactive_power_limits_max",
"description": "Maximum reactive power StaticInjection",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "MVAR",
"name": "pump_reactive_power_limits_min",
"description": "Minimum reactive power StaticInjection",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "hours",
"name": "pump_min_down_time",
"description": "Minimum off time required before unit restart",
"default_value": null
},
{
"unit": "hours",
"name": "pump_min_up_time",
"description": "Minimum on time required before unit shutdown",
"default_value": null
},
{
"unit": "MW(p.u.)/Min",
"name": "pump_ramp_limits",
"description": "Maximum ramp up and ramp down rate",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "MW/Min",
"name": "pump_ramp_up",
"description": "Maximum ramp up rate",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"unit": "MW/Min",
"name": "pump_ramp_down",
"description": "Maximum ramp down rate",
"unit_system": "device_base",
"base_reference": "base_mva",
"default_value": null
},
{
"name": "generator_category",
"value_options": [
"HydroDispatch",
"RenewableNonDispatch",
"RenewableDispatch",
"ThermalStandard",
"ThermalMultiStart"
],
"description": "Type of Struct",
"default_value": "ThermalStandard"
}
],
"simulation_objects": [],
"reserves": [
{
"name": "name",
"description": "Reserve product name"
},
{
"name": "contributing_devices",
"description": "Contributing Devices for reserve requirement",
"default_value": null
},
{
"unit": "MW",
"name": "requirement",
"description": "reserve requirement",
"unit_system": "SYSTEM_BASE"
},
{
"unit": "seconds",
"name": "timeframe",
"description": "Response time to satisfy reserve requirement"
},
{
"name": "eligible_device_categories",
"description": "Eligible Device Categories",
"default_value": null
},
{
"name": "eligible_device_subcategories",
"description": "Eligible Device SubCategories",
"default_value": null
},
{
"name": "eligible_regions",
"description": "Eligible Regions",
"default_value": null
},
{
"name": "reserve_category",
"value_options": [
"ConstantReserve",
"VariableReserve",
"Transfer"
],
"description": "Type of Struct",
"default_value": "ConstantReserve"
},
{
"name": "direction",
"description": "Direction",
"value_options": [
"Up",
"Down"
]
}
],
"facts": [
{
"name": "name",
"description": "FACTS object name"
},
{
"name": "available",
"description": "availability",
"default_value": true
},
{
"name": "bus",
"description": "Sending end bus number",
"default_value": null
},
{
"name": "control_mode",
"value_options": [
"OOS",
"NML",
"BYP"
],
"description": "Control mode of operation",
"default_value": null
},
{
"name": "voltage_setpoint",
"description": "Voltage setpoint at sending bus in p.u,",
"unit_system": "device_base",
"default_value": 0.9
},
{
"name": "max_shunt_current",
"description": "Maximum shunt current at the sending end bus in MVA.",
"unit_system": "device_base",
"default_value": 9999.0
},
{
"name": "reactive_power_required",
"description": "Total MVAr required to hold voltage at sending bus, in %.",
"unit_system": "device_base",
"default_value": 100.0
}
],
"storage": [
{
"name": "name",
"description": "Storage object name"
},
{
"name": "position",
"description": "head or tail",
"default_value": "head"
},
{
"name": "available",
"description": "availability",
"default_value": true
},
{
"name": "generator_name",
"description": "Generator name associated with storage",
"default_value": null
},
{
"name": "bus_id",
"description": "Connection Bus ID",
"default_value": null
},
{
"name": "energy_level",
"unit": "MWh",
"description": "Energy Level setpoint",
"unit_system": "device_base",
"default_value": 0.0
},
{
"unit": "MW",
"name": "active_power",
"description": "Real power injection setpoint",
"unit_system": "device_base",
"default_value": 0.0
},
{
"unit": "MVar",
"name": "reactive_power",
"description": "Reactive power StaticInjection setpoint",
"unit_system": "device_base",
"default_value": 0.0
},
{
"unit": "MW",
"name": "input_active_power_limit_max",
"description": "Maximum real power limit on charging",
"unit_system": "device_base"
},
{
"unit": "MW",
"name": "input_active_power_limit_min",
"description": "Minimum real power limit on charging",
"unit_system": "device_base",
"default_value": 0.0
},
{
"unit": "MW",
"name": "output_active_power_limit_max",
"description": "Maximum real power StaticInjection",
"unit_system": "device_base",
"default_value": null
},
{
"unit": "MW",
"name": "output_active_power_limit_min",
"description": "Minimum real power StaticInjection",
"unit_system": "device_base",
"default_value": 0.0
},
{
"unit": "MVAR",
"name": "output_reactive_power_limits_max",
"description": "Maximum reactive power StaticInjection",
"unit_system": "device_base",
"default_value": null
},
{
"unit": "MVAR",
"name": "output_reactive_power_limits_min",
"description": "Minimum reactive power StaticInjection",
"unit_system": "device_base",
"default_value": null
},
{
"unit": "MVA",
"name": "rating",
"description": "Apparent power injection limit rating",
"unit_system": "device_base"
},
{
"unit": "MW",
"name": "base_power",
"description": "Continuous MW flow limit",
"unit_system": "natural_units"
},
{
"unit": "%",
"name": "input_efficiency",
"description": "Storage Input Efficiency",
"default_value": 1.0
},
{
"unit": "%",
"name": "output_efficiency",
"description": "Storage Output Efficiency",
"default_value": 1.0
},
{
"unit": "%",
"name": "efficiency",
"description": "Battery Efficiency",
"default_value": 1.0
},
{
"unit": "MWh",
"name": "storage_capacity",
"description": "Storage Capacity",
"unit_system": "device_base"
},
{
"unit": "MWh",
"name": "min_storage_capacity",
"description": "Storage Capacity minimum",
"unit_system": "device_base",
"default_value": 0.0
},
{
"unit": "MWh",
"name": "storage_target",
"description": "End period storage target level",
"unit_system": "device_base",
"default_value": 0.0
}
],
"bus": [
{
"name": "bus_id",
"description": "Numeric Bus ID",
"default_value": null
},
{
"name": "name",
"description": "Bus name from RTS-96"
},
{
"name": "area",
"description": "area membership",
"default_value": null
},
{
"name": "zone",
"description": "zone membership",
"default_value": null
},
{
"unit": "kV",
"name": "base_voltage",
"description": "Bus voltage rating",
"unit_system": "natural_units",
"default_value": null
},
{
"name": "bus_type",
"value_options": [
"PQ",
"PV",
"REF"
],
"description": "Bus control type",
"default_value": null
},
{
"unit": "kV",
"name": "voltage",
"description": "voltage magnitude setpoint",
"unit_system": "device_base",
"base_reference": "base_voltage",
"default_value": null
},
{
"unit": "radian",
"name": "angle",
"description": "voltage angle setpoint",
"default_value": null
},
{
"unit": "kV",
"name": "voltage_limits_min",
"description": "Minimum voltage setpoint",
"unit_system": "device_base",
"base_reference": "base_voltage",
"default_value": 0.95
},
{
"unit": "kV",
"name": "voltage_limits_max",
"description": "Maximum voltage setpoint",
"unit_system": "device_base",
"base_reference": "base_voltage",
"default_value": 1.05
},
{
"name": "max_active_power",
"description": "Maximum Active Power",
"unit_system": "device_base",
"base_reference": "base_power",
"default_value": 0
},
{
"name": "max_reactive_power",
"description": "Maximum Rective Power",
"unit_system": "device_base",
"base_reference": "base_power",
"default_value": 0
},
{
"name": "active_power",
"description": "Active Power Setpoint",
"unit_system": "device_base",
"base_reference": "base_power",
"default_value": 0
},
{
"name": "reactive_power",
"description": "Rective Power Setpoint",
"unit_system": "device_base",
"base_reference": "base_power",
"default_value": 0
},
{
"name": "base_power",
"description": "base power for demand",
"unit_system": "natural_units",
"default_value": "system_base_power"
},
{
"name": "shunt_g",
"description": "shunt conductance",
"unit_system": "device_base",
"base_reference": "base_power",
"default_value": 0
},
{
"name": "shunt_b",
"description": "shunt reactance",
"unit_system": "device_base",
"base_reference": "base_power",
"default_value": 0
}
],
"load": [
{
"name": "name",
"description": "Load Name"
},
{
"name": "available",
"description": "Availability",
"default_value": true
},
{
"name": "bus_id",
"description": "Connection Bus ID",
"default_value": null
},
{
"name": "active_power",
"description": "Active power setpoint",
"default_value": 0.0,
"unit_system": "device_base"
},
{
"name": "reactive_power",
"description": "Reactive power setpoint",
"default_value": 0.0,
"unit_system": "device_base"
},
{
"name": "base_power",
"description": "base",
"unit_system": "natural_units",
"default_value": "system_base_power"
},
{
"name": "max_active_power",
"description": "max active power",
"unit_system": "device_base"
},
{
"name": "max_reactive_power",
"description": "max reactive power",
"unit_system": "device_base",
"default_value": 0.0
}
]
}
================================================
FILE: src/descriptors/power_system_structs.json
================================================
{
"auto_generated_structs": [
{
"struct_name": "Area",
"docstring": "A collection of buses for control purposes.\n\nThe `Area` can be specified when defining each [`ACBus`](@ref) or [`DCBus`](@ref) in the area",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"name": "peak_active_power",
"comment": "Peak active power in the area",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "peak_reactive_power",
"comment": "Peak reactive power in the area",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "load_response",
"comment": "Load-frequency damping parameter modeling how much the load in the area changes due to changes in frequency (MW/Hz). [Example here.](https://doi.org/10.1109/NAPS50074.2021.9449687)",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AggregationTopology"
},
{
"struct_name": "AreaInterchange",
"docstring": "Flow exchanged between Areas. This Interchange is agnostic to the lines connecting the areas. It does not substitute Interface which is the total flow across a group of lines",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow on the line (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "Area(nothing)",
"name": "from_area",
"comment": "Area from which the power is extracted",
"data_type": "Area"
},
{
"null_value": "Area(nothing)",
"name": "to_area",
"comment": "Area to which the power is injected",
"data_type": "Area"
},
{
"name": "flow_limits",
"null_value": "(from_to=0.0, to_from=0.0)",
"comment": "Max flow between the areas. It ignores lines and other branches totals",
"data_type": "FromTo_ToFrom",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Service interfaces that this device contributes to",
"null_value": "Service[]",
"default": "Service[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Branch"
},
{
"struct_name": "LoadZone",
"docstring": "A load zone for electricity price analysis.\n\nThe load zone can be specified when defining each [`ACBus`](@ref) or [`DCBus`](@ref) in the zone",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"name": "peak_active_power",
"comment": "Peak active power in the zone (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "peak_reactive_power",
"comment": "Peak reactive power in the zone (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AggregationTopology"
},
{
"struct_name": "TransmissionInterface",
"docstring": "A collection of branches that make up an interface or corridor for the transfer of power, such as between different [`Areas`](@ref Area) or [`LoadZones`](@ref LoadZone).\n\nThe interface can be used to constrain the power flow across it",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow_limits",
"comment": "Minimum and maximum active power flow limits on the interface (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "violation_penalty",
"null_value": "0.0",
"comment": "Penalty cost for violating the flow limits in the interface",
"data_type": "Float64",
"default": "INFINITE_COST"
},
{
"name": "direction_mapping",
"comment": "Dictionary of the line `name`s in the interface and their direction of flow (1 or -1) relative to the flow of the interface",
"null_value": "Dict{String, Int}()",
"data_type": "Dict{String, Int}",
"default": "Dict{String, Int}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Service"
},
{
"struct_name": "ACBus",
"docstring": "An AC bus",
"inner_constructor_check": "check_bus_params",
"fields": [
{
"name": "number",
"comment": "A unique bus identification number (positive integer)",
"null_value": "0",
"exclude_setter": true,
"data_type": "Int"
},
{
"null_value": "init",
"name": "name",
"exclude_setter": true,
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations. This field should not be confused with the ISOLATED enum value (@ref acbustypes_list)",
"data_type": "Bool"
},
{
"name": "bustype",
"comment": "Used to describe the connectivity and behavior of this bus. [Options are listed here.](@ref acbustypes_list)",
"null_value": "nothing",
"data_type": "Union{Nothing, ACBusTypes}"
},
{
"name": "angle",
"comment": "angle of the bus in radians",
"null_value": "0.0",
"data_type": "Union{Nothing, Float64}"
},
{
"name": "magnitude",
"comment": "voltage as a multiple of `base_voltage`",
"null_value": "0.0",
"data_type": "Union{Nothing, Float64}",
"valid_range": "voltage_limits",
"validation_action": "warn"
},
{
"name": "voltage_limits",
"comment": "limits on the voltage variation as multiples of `base_voltage`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "Union{Nothing, MinMax}"
},
{
"name": "base_voltage",
"comment": "the base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "area",
"comment": "the area containing the bus",
"null_value": "nothing",
"data_type": "Union{Nothing, Area}",
"default": "nothing"
},
{
"name": "load_zone",
"comment": "the load zone containing the bus",
"null_value": "nothing",
"data_type": "Union{Nothing, LoadZone}",
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Bus"
},
{
"struct_name": "DCBus",
"docstring": "A DC bus",
"fields": [
{
"name": "number",
"comment": "A unique bus identification number (positive integer)",
"null_value": "0",
"data_type": "Int"
},
{
"null_value": "init",
"name": "name",
"exclude_setter": true,
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations.",
"data_type": "Bool"
},
{
"name": "magnitude",
"comment": "voltage as a multiple of `base_voltage`",
"null_value": "0.0",
"data_type": "Union{Nothing, Float64}",
"valid_range": "voltage_limits",
"validation_action": "warn"
},
{
"name": "voltage_limits",
"comment": "limits on the voltage variation as multiples of `base_voltage`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "Union{Nothing, MinMax}"
},
{
"name": "base_voltage",
"comment": "the base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "area",
"comment": "the area containing the DC bus",
"null_value": "nothing",
"data_type": "Union{Nothing, Area}",
"default": "nothing"
},
{
"name": "load_zone",
"comment": "the load zone containing the DC bus",
"null_value": "nothing",
"data_type": "Union{Nothing, LoadZone}",
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Bus"
},
{
"struct_name": "Arc",
"docstring": "A topological directed edge connecting two buses.\n\nArcs are used to define the `from` and `to` buses when defining a line or transformer",
"fields": [
{
"name": "from",
"comment": "The initial bus",
"null_value": "ACBus(nothing)",
"data_type": "Bus"
},
{
"name": "to",
"comment": "The terminal bus",
"null_value": "ACBus(nothing)",
"data_type": "Bus"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"custom_code": "get_name(arc::Arc) = (get_name ∘ get_from)(arc) * \" -> \" * (get_name ∘ get_to)(arc)",
"supertype": "Topology"
},
{
"struct_name": "Line",
"docstring": "An AC transmission line",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow on the line (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow",
"comment": "Initial condition of reactive power flow on the line (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this line `from` a bus `to` another bus",
"data_type": "Arc"
},
{
"null_value": "0.0",
"name": "r",
"data_type": "Float64",
"comment": "Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x",
"data_type": "Float64",
"comment": "Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"name": "b",
"null_value": "(from=0.0, to=0.0)",
"data_type": "FromTo",
"comment": "Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value",
"valid_range": {
"min": 0,
"max": 100
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"null_value": "0.0",
"name": "rating",
"comment": "Thermal rating (MVA). Flow on the line must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "angle_limits",
"comment": "Minimum and maximum angle limits (radians)",
"null_value": "(min=-3.1416, max=3.1416)",
"data_type": "MinMax"
},
{
"null_value": "0.0",
"name": "rating_b",
"comment": "Second current rating; entered in MVA.",
"data_type": "Union{Nothing, Float64}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"null_value": "0.0",
"name": "rating_c",
"comment": "Third current rating; entered in MVA.",
"data_type": "Union{Nothing, Float64}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"name": "g",
"null_value": "(from=0.0, to=0.0)",
"data_type": "FromTo",
"comment": "Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value",
"valid_range": {
"min": 0,
"max": 100
},
"validation_action": "warn",
"default": "(from=0.0, to=0.0)",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ACTransmission"
},
{
"struct_name": "GenericArcImpedance",
"docstring": "A virtual impedance between two buses that does not correspond to a physical component. This can be used to model the effects of network reductions (e.g. Ward reduction).",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow on the line (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow",
"comment": "Initial condition of reactive power flow on the line (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "max_flow",
"comment": "Maximum allowable flow on the generic impedance. When defining a GenericArcImpedance before it is attached to a `System`, `max_flow` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this line `from` a bus `to` another bus",
"data_type": "Arc"
},
{
"null_value": "0.0",
"name": "r",
"data_type": "Float64",
"comment": "Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x",
"data_type": "Float64",
"comment": "Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ACTransmission"
},
{
"struct_name": "DiscreteControlledACBranch",
"docstring": "Used to represent switches and breakers connecting AC Buses",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow on the line (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow",
"comment": "Initial condition of reactive power flow on the line (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this line `from` a bus `to` another bus",
"data_type": "Arc"
},
{
"null_value": "0.0",
"name": "r",
"data_type": "Float64",
"comment": "Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x",
"data_type": "Float64",
"comment": "Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "rating",
"comment": "Thermal rating (MVA). Flow on the branch must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "discrete_branch_type",
"comment": "Type of discrete control",
"null_value": "DiscreteControlledBranchType.BREAKER",
"data_type": "DiscreteControlledBranchType",
"default": "DiscreteControlledBranchType.OTHER"
},
{
"name": "branch_status",
"comment": "Open or Close status",
"null_value": "DiscreteControlledBranchStatus.CLOSED",
"data_type": "DiscreteControlledBranchStatus",
"default": "DiscreteControlledBranchStatus.CLOSED"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ACTransmission"
},
{
"struct_name": "MonitoredLine",
"docstring": "An AC transmission line with additional power flow constraints specified by the system operator, more restrictive than the line's thermal limits.\n\nFor example, monitored lines can be used to restrict line flow following a contingency elsewhere in the network. See the `flow_limits` parameter. If monitoring is not needed, see [`Line`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow on the line (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow",
"comment": "Initial condition of reactive power flow on the line (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this line `from` a bus `to` another bus",
"data_type": "Arc"
},
{
"null_value": "0.0",
"name": "r",
"data_type": "Float64",
"comment": "Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x",
"data_type": "Float64",
"comment": "Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"name": "b",
"null_value": "(from=0.0, to=0.0)",
"data_type": "FromTo",
"comment": "Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value",
"valid_range": {
"min": 0,
"max": 2
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"name": "flow_limits",
"null_value": "(from_to=0.0, to_from=0.0)",
"comment": "Minimum and maximum permissable flow on the line (MVA), if different from the thermal rating defined in `rating`",
"data_type": "FromTo_ToFrom",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "rating",
"data_type": "Float64",
"comment": "Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "angle_limits",
"comment": "Minimum and maximum angle limits (radians)",
"null_value": "(min=-3.1416, max=3.1416)",
"data_type": "MinMax"
},
{
"null_value": "0.0",
"name": "rating_b",
"comment": "Second current rating; entered in MVA.",
"data_type": "Union{Nothing, Float64}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"null_value": "0.0",
"name": "rating_c",
"comment": "Third current rating; entered in MVA.",
"data_type": "Union{Nothing, Float64}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"name": "g",
"null_value": "(from=0.0, to=0.0)",
"data_type": "FromTo",
"comment": "Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value",
"valid_range": {
"min": 0,
"max": 100
},
"validation_action": "warn",
"default": "(from=0.0, to=0.0)",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ACTransmission"
},
{
"struct_name": "PhaseShiftingTransformer",
"docstring": "A phase-shifting transformer regulating the phase angle between two buses to control active power flow in the system.\n\nThe model uses an equivalent circuit assuming the impedance is on the High Voltage Side of the transformer. The model allocates the iron losses and magnetizing susceptance to the primary side",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow through the transformer (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow",
"comment": "Initial condition of reactive power flow through the transformer (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this transformer `from` a bus `to` another bus",
"data_type": "Arc"
},
{
"null_value": "0.0",
"name": "r",
"data_type": "Float64",
"comment": "Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x",
"data_type": "Float64",
"comment": "Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"name": "primary_shunt",
"null_value": "0.0",
"data_type": "Complex{Float64}",
"comment": "Primary shunt admittance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"name": "tap",
"comment": "Normalized tap changer position for voltage control, varying between 0 and 2, with 1 centered at the nominal voltage",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 2
},
"validation_action": "error"
},
{
"name": "α",
"comment": "Initial condition of phase shift (radians) between the `from` and `to` buses ",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": -1.571,
"max": 1.571
},
"validation_action": "warn"
},
{
"name": "rating",
"comment": "Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to",
"null_value": "0.0",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "base_voltage_primary",
"comment": "Primary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_from(arc))"
},
{
"name": "base_voltage_secondary",
"comment": "Secondary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_to(arc))"
},
{
"null_value": "0.0",
"name": "rating_b",
"comment": "Second current rating; entered in MVA.",
"data_type": "Union{Nothing, Float64}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"null_value": "0.0",
"name": "rating_c",
"comment": "Third current rating; entered in MVA.",
"data_type": "Union{Nothing, Float64}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"name": "phase_angle_limits",
"comment": "Minimum and maximum phase angle limits (radians)",
"null_value": "(min=-3.1416, max=3.1416)",
"data_type": "MinMax",
"default": "(min=-3.1416, max=3.1416)"
},
{
"name": "control_objective",
"comment": "Control objective for the tap changer for power flow calculations. See [`TransformerControlObjective`](@ref xtf_crtl)",
"data_type": "TransformerControlObjective",
"null_value": "TransformerControlObjective.UNDEFINED",
"default": "TransformerControlObjective.UNDEFINED"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TwoWindingTransformer"
},
{
"struct_name": "TapTransformer",
"docstring": "A 2-winding transformer, with a tap changer for variable turns ratio.\n\nThe model uses an equivalent circuit assuming the impedance is on the High Voltage Side of the transformer. The model allocates the iron losses and magnetizing susceptance to the primary side",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow through the transformer (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow",
"comment": "Initial condition of reactive power flow through the transformer (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this transformer `from` a bus `to` another bus",
"data_type": "Arc"
},
{
"null_value": "0.0",
"name": "r",
"data_type": "Float64",
"comment": "Resistance in p.u. ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": -2,
"max": 2
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x",
"data_type": "Float64",
"comment": "Reactance in p.u. ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"name": "primary_shunt",
"null_value": "0.0",
"data_type": "Complex{Float64}",
"comment": "Primary shunt admittance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"name": "tap",
"comment": "Normalized tap changer position for voltage control, varying between 0 and 2, with 1 centered at the nominal voltage",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 2
},
"validation_action": "error"
},
{
"name": "rating",
"comment": "Thermal rating (MVA). Flow through the transformer must be between -`rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to",
"null_value": "0.0",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "base_voltage_primary",
"comment": "Primary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_from(arc))"
},
{
"name": "base_voltage_secondary",
"comment": "Secondary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_to(arc))"
},
{
"null_value": "0.0",
"name": "rating_b",
"comment": "Second current rating; entered in MVA.",
"data_type": "Union{Nothing, Float64}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"null_value": "0.0",
"name": "rating_c",
"comment": "Third current rating; entered in MVA.",
"data_type": "Union{Nothing, Float64}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"name": "winding_group_number",
"null_value": "WindingGroupNumber.UNDEFINED",
"data_type": "WindingGroupNumber",
"comment": "Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration",
"default": "WindingGroupNumber.UNDEFINED"
},
{
"name": "control_objective",
"comment": "Control objective for the tap changer for power flow calculations. See [`TransformerControlObjective`](@ref xtf_crtl)",
"data_type": "TransformerControlObjective",
"null_value": "TransformerControlObjective.UNDEFINED",
"default": "TransformerControlObjective.UNDEFINED"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TwoWindingTransformer"
},
{
"struct_name": "Transformer2W",
"docstring": "A basic 2-winding transformer.\n\nThe model uses an equivalent circuit assuming the impedance is on the High Voltage Side of the transformer. The model allocates the iron losses and magnetizing susceptance to the primary side",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow through the transformer (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow",
"comment": "Initial condition of reactive power flow through the transformer (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this transformer `from` a bus `to` another bus",
"data_type": "Arc"
},
{
"null_value": "0.0",
"name": "r",
"data_type": "Float64",
"comment": "Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x",
"data_type": "Float64",
"comment": "Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"name": "primary_shunt",
"null_value": "0.0",
"data_type": "Complex{Float64}",
"comment": "Primary shunt admittance in pu ([`SYSTEM_BASE`](@ref per_unit))",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"name": "rating",
"comment": "Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "base_voltage_primary",
"comment": "Primary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_from(arc))"
},
{
"name": "base_voltage_secondary",
"comment": "Secondary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_to(arc))"
},
{
"null_value": "0.0",
"name": "rating_b",
"comment": "Second current rating; entered in MVA.",
"data_type": "Union{Nothing, Float64}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"null_value": "0.0",
"name": "rating_c",
"comment": "Third current rating; entered in MVA.",
"data_type": "Union{Nothing, Float64}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"name": "winding_group_number",
"null_value": "WindingGroupNumber.UNDEFINED",
"data_type": "WindingGroupNumber",
"comment": "Vector group number ('clock number') indicating phase shift (radians) between the `from` and `to` buses",
"default": "WindingGroupNumber.UNDEFINED"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TwoWindingTransformer"
},
{
"struct_name": "Transformer3W",
"docstring": "A 3-winding transformer.\n\nThe model uses an equivalent star model with a star (hidden) bus. The user must transform the data to use `CW = CZ = CM = 1` and `COD1 = COD2 = COD3 = 0` (no voltage control) if taken from a PSS/E 3W transformer model. Three equivalent impedances (connecting each side to the star bus) are required to define the model. Shunt conductance (iron losses) and magnetizing susceptance can be considered from the star bus to ground. The model is described in Chapter 3.6 in J.D. Glover, M.S. Sarma and T. Overbye: Power Systems Analysis and Design.",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "primary_star_arc",
"comment": "An [`Arc`](@ref) defining this transformer `from` a primary bus `to` the star bus",
"data_type": "Arc"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "secondary_star_arc",
"comment": "An [`Arc`](@ref) defining this transformer `from` a secondary bus `to` the star bus",
"data_type": "Arc"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "tertiary_star_arc",
"comment": "An [`Arc`](@ref) defining this transformer `from` a tertiary bus `to` the star bus",
"data_type": "Arc"
},
{
"name": "star_bus",
"comment": "Star (hidden) Bus that this component (equivalent model) is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power_flow_primary",
"comment": "Initial condition of active power flow through the transformer primary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow_primary",
"comment": "Initial condition of reactive power flow through the transformer primary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_flow_secondary",
"comment": "Initial condition of active power flow through the transformer secondary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow_secondary",
"comment": "Initial condition of reactive power flow through the transformer secondary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_flow_tertiary",
"comment": "Initial condition of active power flow through the transformer tertiary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow_tertiary",
"comment": "Initial condition of reactive power flow through the transformer tertiary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "r_primary",
"data_type": "Float64",
"comment": "Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_primary",
"data_type": "Float64",
"comment": "Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "r_secondary",
"data_type": "Float64",
"comment": "Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_secondary",
"data_type": "Float64",
"comment": "Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "r_tertiary",
"data_type": "Float64",
"comment": "Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_tertiary",
"data_type": "Float64",
"comment": "Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"name": "rating",
"comment": "Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "r_12",
"data_type": "Float64",
"comment": "Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (R1-2 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_12",
"data_type": "Float64",
"comment": "Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (X1-2 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "r_23",
"data_type": "Float64",
"comment": "Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (R2-3 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_23",
"data_type": "Float64",
"comment": "Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (X2-3 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "r_13",
"data_type": "Float64",
"comment": "Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (R1-3 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_13",
"data_type": "Float64",
"comment": "Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (X1-3 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"name": "base_power_12",
"comment": "Base power (MVA) for [per unitization](@ref per_unit) for primary-secondary windings.",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "base_power_23",
"comment": "Base power (MVA) for [per unitization](@ref per_unit) for secondary-tertiary windings.",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "base_power_13",
"comment": "Base power (MVA) for [per unitization](@ref per_unit) for primary-tertiary windings.",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "base_voltage_primary",
"comment": "Primary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_from(primary_star_arc))"
},
{
"name": "base_voltage_secondary",
"comment": "Secondary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_from(secondary_star_arc))"
},
{
"name": "base_voltage_tertiary",
"comment": "Tertiary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_from(tertiary_star_arc))"
},
{
"name": "g",
"null_value": "0.0",
"data_type": "Float64",
"comment": "Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG1 in PSS/E).",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"name": "b",
"null_value": "0.0",
"data_type": "Float64",
"comment": "Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG2 in PSS/E).",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"null_value": "0.0",
"name": "primary_turns_ratio",
"data_type": "Float64",
"comment": "Primary side off-nominal turns ratio in p.u. with respect to connected primary bus (WINDV1 with CW = 1 in PSS/E).",
"default": "1.0"
},
{
"null_value": "0.0",
"name": "secondary_turns_ratio",
"data_type": "Float64",
"comment": "Secondary side off-nominal turns ratio in p.u. with respect to connected secondary bus (WINDV2 with CW = 1 in PSS/E).",
"default": "1.0"
},
{
"null_value": "0.0",
"name": "tertiary_turns_ratio",
"data_type": "Float64",
"comment": "Tertiary side off-nominal turns ratio in p.u. with respect to connected tertiary bus (WINDV3 with CW = 1 in PSS/E).",
"default": "1.0"
},
{
"null_value": "false",
"name": "available_primary",
"data_type": "Bool",
"comment": "Status if primary winding is available or not.",
"default": "true"
},
{
"null_value": "false",
"name": "available_secondary",
"data_type": "Bool",
"comment": "Status if primary winding is available or not.",
"default": "true"
},
{
"null_value": "false",
"name": "available_tertiary",
"data_type": "Bool",
"comment": "Status if primary winding is available or not.",
"default": "true"
},
{
"null_value": "0.0",
"name": "rating_primary",
"data_type": "Float64",
"comment": "Rating (in MVA) for primary winding.",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "rating_secondary",
"data_type": "Float64",
"comment": "Rating (in MVA) for secondary winding.",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "rating_tertiary",
"data_type": "Float64",
"comment": "Rating (in MVA) for tertiary winding.",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "primary_group_number",
"null_value": "WindingGroupNumber.UNDEFINED",
"data_type": "WindingGroupNumber",
"comment": "Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration",
"default": "WindingGroupNumber.UNDEFINED"
},
{
"name": "secondary_group_number",
"null_value": "WindingGroupNumber.UNDEFINED",
"data_type": "WindingGroupNumber",
"comment": "Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration",
"default": "WindingGroupNumber.UNDEFINED"
},
{
"name": "tertiary_group_number",
"null_value": "WindingGroupNumber.UNDEFINED",
"data_type": "WindingGroupNumber",
"comment": "Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration",
"default": "WindingGroupNumber.UNDEFINED"
},
{
"name": "control_objective_primary",
"comment": "Control objective for the tap changer for winding 1. See [`TransformerControlObjective`](@ref xtf_crtl)",
"data_type": "TransformerControlObjective",
"null_value": "TransformerControlObjective.UNDEFINED",
"default": "TransformerControlObjective.UNDEFINED"
},
{
"name": "control_objective_secondary",
"comment": "Control objective for the tap changer for winding 2. See [`TransformerControlObjective`](@ref xtf_crtl)",
"data_type": "TransformerControlObjective",
"null_value": "TransformerControlObjective.UNDEFINED",
"default": "TransformerControlObjective.UNDEFINED"
},
{
"name": "control_objective_tertiary",
"comment": "Control objective for the tap changer for winding 3. See [`TransformerControlObjective`](@ref xtf_crtl)",
"data_type": "TransformerControlObjective",
"null_value": "TransformerControlObjective.UNDEFINED",
"default": "TransformerControlObjective.UNDEFINED"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ThreeWindingTransformer"
},
{
"struct_name": "PhaseShiftingTransformer3W",
"docstring": "A 3-winding phase-shifting transformer.\n\n. Phase shifts are specified in radians for primary, secondary, and tertiary windings.",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "primary_star_arc",
"comment": "An [`Arc`](@ref) defining this transformer `from` a primary bus `to` the star bus",
"data_type": "Arc"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "secondary_star_arc",
"comment": "An [`Arc`](@ref) defining this transformer `from` a secondary bus `to` the star bus",
"data_type": "Arc"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "tertiary_star_arc",
"comment": "An [`Arc`](@ref) defining this transformer `from` a tertiary bus `to` the star bus",
"data_type": "Arc"
},
{
"name": "star_bus",
"comment": "Star (hidden) Bus that this component (equivalent model) is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power_flow_primary",
"comment": "Initial condition of active power flow through the transformer primary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow_primary",
"comment": "Initial condition of reactive power flow through the transformer primary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_flow_secondary",
"comment": "Initial condition of active power flow through the transformer secondary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow_secondary",
"comment": "Initial condition of reactive power flow through the transformer secondary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_flow_tertiary",
"comment": "Initial condition of active power flow through the transformer tertiary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_flow_tertiary",
"comment": "Initial condition of reactive power flow through the transformer tertiary side to star (hidden) bus (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "r_primary",
"data_type": "Float64",
"comment": "Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_primary",
"data_type": "Float64",
"comment": "Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "r_secondary",
"data_type": "Float64",
"comment": "Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_secondary",
"data_type": "Float64",
"comment": "Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "r_tertiary",
"data_type": "Float64",
"comment": "Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_tertiary",
"data_type": "Float64",
"comment": "Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus.",
"valid_range": {
"min": -2,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"name": "rating",
"comment": "Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "r_12",
"data_type": "Float64",
"comment": "Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (R1-2 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_12",
"data_type": "Float64",
"comment": "Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (X1-2 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "r_23",
"data_type": "Float64",
"comment": "Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (R2-3 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_23",
"data_type": "Float64",
"comment": "Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (X2-3 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "r_13",
"data_type": "Float64",
"comment": "Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (R1-3 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"null_value": "0.0",
"name": "x_13",
"data_type": "Float64",
"comment": "Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (X1-3 with CZ = 1 in PSS/E).",
"valid_range": {
"min": 0,
"max": 4
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":ohm"
},
{
"name": "α_primary",
"comment": "Initial condition of primary phase shift (radians) between the `from` and `to` buses ",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": -1.571,
"max": 1.571
},
"validation_action": "warn"
},
{
"name": "α_secondary",
"comment": "Initial condition of secondary phase shift (radians) between the `from` and `to` buses ",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": -1.571,
"max": 1.571
},
"validation_action": "warn"
},
{
"name": "α_tertiary",
"comment": "Initial condition of tertiary phase shift (radians) between the `from` and `to` buses ",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": -1.571,
"max": 1.571
},
"validation_action": "warn"
},
{
"name": "base_power_12",
"comment": "Base power (MVA) for [per unitization](@ref per_unit) for primary-secondary windings.",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "base_power_23",
"comment": "Base power (MVA) for [per unitization](@ref per_unit) for secondary-tertiary windings.",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "base_power_13",
"comment": "Base power (MVA) for [per unitization](@ref per_unit) for primary-tertiary windings.",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "base_voltage_primary",
"comment": "Primary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_from(primary_star_arc))"
},
{
"name": "base_voltage_secondary",
"comment": "Secondary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_from(secondary_star_arc))"
},
{
"name": "base_voltage_tertiary",
"comment": "Tertiary base voltage in kV",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "get_base_voltage(get_from(tertiary_star_arc))"
},
{
"name": "g",
"null_value": "0.0",
"data_type": "Float64",
"comment": "Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG1 in PSS/E).",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"name": "b",
"null_value": "0.0",
"data_type": "Float64",
"comment": "Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG2 in PSS/E).",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":siemens"
},
{
"null_value": "0.0",
"name": "primary_turns_ratio",
"data_type": "Float64",
"comment": "Primary side off-nominal turns ratio in p.u. with respect to connected primary bus (WINDV1 with CW = 1 in PSS/E).",
"default": "1.0"
},
{
"null_value": "0.0",
"name": "secondary_turns_ratio",
"data_type": "Float64",
"comment": "Secondary side off-nominal turns ratio in p.u. with respect to connected secondary bus (WINDV2 with CW = 1 in PSS/E).",
"default": "1.0"
},
{
"null_value": "0.0",
"name": "tertiary_turns_ratio",
"data_type": "Float64",
"comment": "Tertiary side off-nominal turns ratio in p.u. with respect to connected tertiary bus (WINDV3 with CW = 1 in PSS/E).",
"default": "1.0"
},
{
"null_value": "false",
"name": "available_primary",
"data_type": "Bool",
"comment": "Status if primary winding is available or not.",
"default": "true"
},
{
"null_value": "false",
"name": "available_secondary",
"data_type": "Bool",
"comment": "Status if primary winding is available or not.",
"default": "true"
},
{
"null_value": "false",
"name": "available_tertiary",
"data_type": "Bool",
"comment": "Status if primary winding is available or not.",
"default": "true"
},
{
"null_value": "0.0",
"name": "rating_primary",
"data_type": "Float64",
"comment": "Rating (in MVA) for primary winding.",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "rating_secondary",
"data_type": "Float64",
"comment": "Rating (in MVA) for secondary winding.",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "rating_tertiary",
"data_type": "Float64",
"comment": "Rating (in MVA) for tertiary winding.",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "phase_angle_limits",
"comment": "Minimum and maximum phase angle limits (radians)",
"null_value": "(min=-3.1416, max=3.1416)",
"data_type": "MinMax",
"default": "(min=-3.1416, max=3.1416)"
},
{
"name": "control_objective_primary",
"comment": "Control objective for the tap changer for winding 1. See [`TransformerControlObjective`](@ref xtf_crtl)",
"data_type": "TransformerControlObjective",
"null_value": "TransformerControlObjective.UNDEFINED",
"default": "TransformerControlObjective.UNDEFINED"
},
{
"name": "control_objective_secondary",
"comment": "Control objective for the tap changer for winding 2. See [`TransformerControlObjective`](@ref xtf_crtl)",
"data_type": "TransformerControlObjective",
"null_value": "TransformerControlObjective.UNDEFINED",
"default": "TransformerControlObjective.UNDEFINED"
},
{
"name": "control_objective_tertiary",
"comment": "Control objective for the tap changer for winding 3. See [`TransformerControlObjective`](@ref xtf_crtl)",
"data_type": "TransformerControlObjective",
"null_value": "TransformerControlObjective.UNDEFINED",
"default": "TransformerControlObjective.UNDEFINED"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ThreeWindingTransformer"
},
{
"struct_name": "TwoTerminalGenericHVDCLine",
"docstring": "A High Voltage DC line, which must be connected to an [`ACBus`](@ref) on each end.\n\nThis model is appropriate for operational simulations with a linearized DC power flow approximation with losses proportional to the power flow. For modeling a DC network, see [`TModelHVDCLine`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow on the line (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this line `from` a bus `to` another bus",
"data_type": "Arc"
},
{
"name": "active_power_limits_from",
"comment": "Minimum and maximum active power flows to the FROM node (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits_to",
"comment": "Minimum and maximum active power flows to the TO node (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits_from",
"comment": "Minimum and maximum reactive power limits to the FROM node (MVAR)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits_to",
"comment": "Minimum and maximum reactive power limits to the TO node (MVAR)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "loss",
"comment": "Loss model coefficients. It accepts a linear model with a constant loss (MW) and a proportional loss rate (MW of loss per MW of flow). It also accepts a Piecewise loss, with N segments to specify different proportional losses for different segments.",
"null_value": "LinearCurve(0.0)",
"data_type": "Union{LinearCurve, PiecewiseIncrementalCurve}",
"default": "LinearCurve(0.0)"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TwoTerminalHVDC"
},
{
"struct_name": "TwoTerminalVSCLine",
"docstring": "A High Voltage Voltage-Source Converter DC line, which must be connected to an [`ACBus`](@ref) on each end.\n\nThis model is appropriate for operational simulations with a linearized DC power flow approximation with losses using a voltage-current model. For modeling a DC network, see [`TModelHVDCLine`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this line `from` a bus `to` another bus",
"data_type": "Arc"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flowing from the from-bus to the to-bus in DC.",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "rating",
"comment": "Maximum output power rating of the converter (MVA)",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits_from",
"comment": "Minimum and maximum active power flows to the FROM node (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits_to",
"comment": "Minimum and maximum active power flows to the TO node (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "g",
"data_type": "Float64",
"comment": "Series conductance of the DC line in pu ([`SYSTEM_BASE`](@ref per_unit))",
"default": "0.0"
},
{
"name": "dc_current",
"comment": "DC current (A) on the converter flowing in the DC line, from `from` bus to `to` bus.",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0"
},
{
"name": "reactive_power_from",
"comment": "Initial condition of reactive power flowing into the from-bus.",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "0.0"
},
{
"name": "dc_voltage_control_from",
"comment": "Converter control type in the `from` bus converter. Set true for DC Voltage Control (set DC voltage on the DC side of the converter), and false for power demand in the converter.",
"null_value": "false",
"data_type": "Bool",
"default": "true"
},
{
"name": "ac_voltage_control_from",
"comment": "Converter control type in the `from` bus converter. Set true for AC Voltage Control (set AC voltage on the AC side of the converter), and false for fixed power AC factor.",
"null_value": "false",
"data_type": "Bool",
"default": "true"
},
{
"name": "dc_setpoint_from",
"comment": "Converter DC setpoint in the `from` bus converter. If `voltage_control_from = true` this number is the DC voltage on the DC side of the converter, entered in kV. If `voltage_control_from = false`, this value is the power demand in MW, if positive the converter is supplying power to the AC network at the `from` bus; if negative, the converter is withdrawing power from the AC network at the `from` bus.",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0"
},
{
"name": "ac_setpoint_from",
"comment": "Converter AC setpoint in the `from` bus converter. If `voltage_control_from = true` this number is the AC voltage on the AC side of the converter, entered in [per unit](@ref per_unit). If `voltage_control_from = false`, this value is the power factor setpoint.",
"null_value": "0.0",
"data_type": "Float64",
"default": "1.0"
},
{
"name": "converter_loss_from",
"comment": "Loss model coefficients in the `from` bus converter. It accepts a linear model or quadratic. Same converter data is used in both ends.",
"null_value": "LinearCurve(0.0)",
"data_type": "Union{LinearCurve, QuadraticCurve}",
"default": "LinearCurve(0.0)"
},
{
"name": "max_dc_current_from",
"comment": "Maximum stable dc current limits (A).",
"null_value": "0.0",
"data_type": "Float64",
"default": "1e8"
},
{
"name": "rating_from",
"comment": "Converter rating in MVA in the `from` bus.",
"null_value": "0.0",
"data_type": "Float64",
"default": "1e8",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits_from",
"comment": "Limits on the Reactive Power at the `from` side.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"default": "(min=0.0, max=0.0)",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "power_factor_weighting_fraction_from",
"comment": "Power weighting factor fraction used in reducing the active power order and either the reactive power order when the converter rating is violated. When is 0.0, only the active power is reduced; when is 1.0, only the reactive power is reduced; otherwise, a weighted reduction of both active and reactive power is applied.",
"null_value": "0.0",
"data_type": "Float64",
"default": "1.0",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "voltage_limits_from",
"comment": "Limits on the Voltage at the DC `from` Bus in [per unit](@ref per_unit.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"default": "(min=0.0, max=999.9)"
},
{
"name": "reactive_power_to",
"comment": "Initial condition of reactive power flowing into the to-bus.",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "0.0"
},
{
"name": "dc_voltage_control_to",
"comment": "Converter control type in the `to` bus converter. Set true for DC Voltage Control (set DC voltage on the DC side of the converter), and false for power demand in the converter.",
"null_value": "false",
"data_type": "Bool",
"default": "true"
},
{
"name": "ac_voltage_control_to",
"comment": "Converter control type in the `to` bus converter. Set true for AC Voltage Control (set AC voltage on the AC side of the converter), and false for fixed power AC factor.",
"null_value": "false",
"data_type": "Bool",
"default": "true"
},
{
"name": "dc_setpoint_to",
"comment": "Converter DC setpoint in the `to` bus converter. If `voltage_control_to = true` this number is the DC voltage on the DC side of the converter, entered in kV. If `voltage_control_to = false`, this value is the power demand in MW, if positive the converter is supplying power to the AC network at the `to` bus; if negative, the converter is withdrawing power from the AC network at the `to` bus.",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0"
},
{
"name": "ac_setpoint_to",
"comment": "Converter AC setpoint in the `to` bus converter. If `voltage_control_to = true` this number is the AC voltage on the AC side of the converter, entered in [per unit](@ref per_unit). If `voltage_control_to = false`, this value is the power factor setpoint.",
"null_value": "0.0",
"data_type": "Float64",
"default": "1.0"
},
{
"name": "converter_loss_to",
"comment": "Loss model coefficients in the `to` bus converter. It accepts a linear model or quadratic. Same converter data is used in both ends.",
"null_value": "LinearCurve(0.0)",
"data_type": "Union{LinearCurve, QuadraticCurve}",
"default": "LinearCurve(0.0)"
},
{
"name": "max_dc_current_to",
"comment": "Maximum stable dc current limits (A).",
"null_value": "0.0",
"data_type": "Float64",
"default": "1e8"
},
{
"name": "rating_to",
"comment": "Converter rating in MVA in the `to` bus.",
"null_value": "0.0",
"data_type": "Float64",
"default": "1e8",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits_to",
"comment": "Limits on the Reactive Power at the `to` side.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"default": "(min=0.0, max=0.0)",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "power_factor_weighting_fraction_to",
"comment": "Power weighting factor fraction used in reducing the active power order and either the reactive power order when the converter rating is violated. When is 0.0, only the active power is reduced; when is 1.0, only the reactive power is reduced; otherwise, a weighted reduction of both active and reactive power is applied.",
"null_value": "0.0",
"data_type": "Float64",
"default": "1.0",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "voltage_limits_to",
"comment": "Limits on the Voltage at the DC `to` Bus.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"default": "(min=0.0, max=999.9)"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TwoTerminalHVDC"
},
{
"struct_name": "TwoTerminalLCCLine",
"docstring": "A Non-Capacitor Line Commutated Converter (LCC)-HVDC transmission line.\n\nAs implemented in PSS/E.",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"null_value": "Arc(ACBus(nothing), ACBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this line `from` a rectifier bus `to` an inverter bus. The rectifier bus must be specified in the `from` bus and inverter bus in the `to` bus.",
"data_type": "Arc"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow on the line (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "0.0",
"name": "r",
"data_type": "Float64",
"comment": "Series resistance of the DC line in pu ([`SYSTEM_BASE`](@ref per_unit))"
},
{
"name": "transfer_setpoint",
"comment": "Desired set-point of power. If `power_mode = true` this value is in MW units, and if `power_mode = false` is in Amperes units. This parameter must not be specified in per-unit. A positive value represents the desired consumed power at the rectifier bus, while a negative value represents the desired power at the inverter bus (i.e. the absolute value of `transfer_setpoint` is the generated power at the inverter bus).",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "scheduled_dc_voltage",
"comment": "Scheduled compounded DC voltage in kV. By default this parameter is the scheduled DC voltage in the inverter bus This parameter must not be specified in per-unit.",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "rectifier_bridges",
"comment": "Number of bridges in series in the rectifier side.",
"null_value": "0",
"data_type": "Int"
},
{
"name": "rectifier_delay_angle_limits",
"comment": "Minimum and maximum rectifier firing delay angle (α) (radians)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "rectifier_rc",
"comment": "Rectifier commutating transformer resistance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "rectifier_xc",
"comment": "Rectifier commutating transformer reactance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "rectifier_base_voltage",
"comment": "Rectifier primary base AC voltage in kV, entered in kV.",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "inverter_bridges",
"comment": "Number of bridges in series in the inverter side.",
"null_value": "0",
"data_type": "Int"
},
{
"name": "inverter_extinction_angle_limits",
"comment": "Minimum and maximum inverter extinction angle (γ) (radians)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "inverter_rc",
"comment": "Inverter commutating transformer resistance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "inverter_xc",
"comment": "Inverter commutating transformer reactance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "inverter_base_voltage",
"comment": "Inverter primary base AC voltage in kV, entered in kV.",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "power_mode",
"data_type": "Bool",
"comment": "Boolean flag to identify if the LCC line is in power mode or current mode. If `power_mode = true`, setpoint values must be specified in MW, and if `power_mode = false` setpoint values must be specified in Amperes.",
"null_value": "false",
"default": "true"
},
{
"name": "switch_mode_voltage",
"data_type": "Float64",
"comment": "Mode switch DC voltage, in kV. This parameter must not be added in per-unit. If LCC line is in power mode control, and DC voltage falls below this value, the line switch to current mode control.",
"null_value": "0.0",
"default": "0.0"
},
{
"name": "compounding_resistance",
"data_type": "Float64",
"comment": "Compounding Resistance, in ohms. This parameter is for control of the DC voltage in the rectifier or inverter end. For inverter DC voltage control, the paremeter is set to zero; for rectifier DC voltage control, the paremeter is set to the DC line resistance; otherwise, set to a fraction of the DC line resistance.",
"null_value": "0.0",
"default": "0.0"
},
{
"name": "min_compounding_voltage",
"data_type": "Float64",
"comment": "Minimum compounded voltage, in kV. This parameter must not be added in per-unit. Only used in constant gamma operation (γ_min = γ_max), and the AC transformer is used to control the DC voltage.",
"null_value": "0.0",
"default": "0.0"
},
{
"name": "rectifier_transformer_ratio",
"comment": "Rectifier transformer ratio between the primary and secondary side AC voltages.",
"null_value": "0.0",
"data_type": "Float64",
"default": "1.0"
},
{
"name": "rectifier_tap_setting",
"comment": "Rectifier transformer tap setting.",
"null_value": "0.0",
"data_type": "Float64",
"default": "1.0"
},
{
"name": "rectifier_tap_limits",
"comment": "Minimum and maximum rectifier tap limits as a ratio between the primary and secondary side AC voltages.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"default": "(min=0.51, max=1.5)"
},
{
"name": "rectifier_tap_step",
"comment": "Rectifier transformer tap step value",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.00625"
},
{
"name": "rectifier_delay_angle",
"comment": "Rectifier firing delay angle (α).",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0"
},
{
"name": "rectifier_capacitor_reactance",
"comment": "Commutating rectifier capacitor reactance magnitude per bridge, in system p.u. ([`SYSTEM_BASE`](@ref per_unit)).",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0"
},
{
"name": "inverter_transformer_ratio",
"comment": "Inverter transformer ratio between the primary and secondary side AC voltages.",
"null_value": "0.0",
"data_type": "Float64",
"default": "1.0"
},
{
"name": "inverter_tap_setting",
"comment": "Inverter transformer tap setting.",
"null_value": "0.0",
"data_type": "Float64",
"default": "1.0"
},
{
"name": "inverter_tap_limits",
"comment": "Minimum and maximum inverter tap limits as a ratio between the primary and secondary side AC voltages.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"default": "(min=0.51, max=1.5)"
},
{
"name": "inverter_tap_step",
"comment": "Inverter transformer tap step value.",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.00625"
},
{
"name": "inverter_extinction_angle",
"comment": "Inverter extinction angle (γ).",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0"
},
{
"name": "inverter_capacitor_reactance",
"comment": "Commutating inverter capacitor reactance magnitude per bridge, in system p.u. ([`SYSTEM_BASE`](@ref per_unit)).",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0"
},
{
"name": "active_power_limits_from",
"comment": "Minimum and maximum active power flows to the FROM node (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "(min=0.0, max=0.0)"
},
{
"name": "active_power_limits_to",
"comment": "Minimum and maximum active power flows to the TO node (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "(min=0.0, max=0.0)"
},
{
"name": "reactive_power_limits_from",
"comment": "Minimum and maximum reactive power limits to the FROM node (MVAR)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "(min=0.0, max=0.0)"
},
{
"name": "reactive_power_limits_to",
"comment": "Minimum and maximum reactive power limits to the TO node (MVAR)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "(min=0.0, max=0.0)"
},
{
"name": "loss",
"comment": "A generic loss model coefficients. It accepts a linear model with a constant loss (MW) and a proportional loss rate (MW of loss per MW of flow). It also accepts a Piecewise loss, with N segments to specify different proportional losses for different segments.",
"null_value": "LinearCurve(0.0)",
"data_type": "Union{LinearCurve, PiecewiseIncrementalCurve}",
"default": "LinearCurve(0.0)"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TwoTerminalHVDC"
},
{
"struct_name": "TModelHVDCLine",
"docstring": "A High Voltage DC transmission line for modeling DC transmission networks.\n\nThis line must be connected to a [`DCBus`](@ref) on each end. It uses a T-Model of the line impedance. This is suitable for operational simulations with a multi-terminal DC network",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "active_power_flow",
"comment": "Initial condition of active power flow on the line (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"null_value": "Arc(DCBus(nothing), DCBus(nothing))",
"name": "arc",
"comment": "An [`Arc`](@ref) defining this line `from` a bus `to` another bus",
"data_type": "Arc"
},
{
"null_value": "0.0",
"name": "r",
"data_type": "Float64",
"comment": "Total series Resistance in p.u. ([`SYSTEM_BASE`](@ref per_unit)), split equally on both sides of the shunt capacitance"
},
{
"null_value": "0.0",
"name": "l",
"data_type": "Float64",
"comment": "Total series Inductance in p.u. ([`SYSTEM_BASE`](@ref per_unit)), split equally on both sides of the shunt capacitance"
},
{
"null_value": "0.0",
"name": "c",
"data_type": "Float64",
"comment": "Shunt capacitance in p.u. ([`SYSTEM_BASE`](@ref per_unit))"
},
{
"name": "active_power_limits_from",
"comment": "Minimum and maximum active power flows to the FROM node (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits_to",
"comment": "Minimum and maximum active power flows to the TO node (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "DCBranch"
},
{
"struct_name": "InterruptiblePowerLoad",
"docstring": "A [static](@ref S) power load that can be compensated for temporary or continuous interruptions to its requested demand.\n\n These loads are most commonly used for operational optimizations and can be used to model, for example, large commercial and industrial customers enrolled in demand response programs. This load has a target demand profile (set by a [`max_active_power` time series](@ref ts_data) for an operational simulation) that can be reduced to satisfy other system needs. For simpler loads without an operating cost for demand response, see [`PowerLoad`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial steady state active power demand (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial steady state reactive power demand (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_active_power",
"comment": "Maximum active power (MW) that this load can demand",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_reactive_power",
"comment": "Maximum reactive power (MVAR) that this load can demand",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "operation_cost",
"null_value": "LoadCost(nothing)",
"data_type": "Union{LoadCost, MarketBidCost}",
"comment": "[`OperationalCost`](@ref) of interrupting load"
},
{
"name": "conformity",
"comment": "Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list).",
"data_type": "LoadConformity",
"default": "LoadConformity.UNDEFINED"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ControllableLoad"
},
{
"struct_name": "InterruptibleStandardLoad",
"docstring": "A voltage-dependent [ZIP load](@ref Z), most commonly used for dynamics modeling.\n\nA `StandardLoad` breaks the ZIP into three pieces: Z (constant impedance), I (constant current), and P (constant power), according to `P = P_P * V^0 + P_I * V^1 + P_Z * V^2` for active power and `Q = Q_P * V^0 + Q_I * V^1 + Q_Z * V^2` for reactive power. (Voltage V is in per unit.)\n\nFor an alternative exponential formulation of the ZIP model, see [`ExponentialLoad`](@ref). For a simpler load model with no voltage dependency, see [`PowerLoad`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "base_power",
"comment": "Base power of the load (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "operation_cost",
"null_value": "LoadCost(nothing)",
"data_type": "Union{LoadCost, MarketBidCost}",
"comment": "[`OperationalCost`](@ref) of interrupting load"
},
{
"name": "conformity",
"comment": "Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list).",
"data_type": "LoadConformity",
"default": "LoadConformity.UNDEFINED"
},
{
"name": "constant_active_power",
"comment": "Constant active power demand in MW (P_P)",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "constant_reactive_power",
"comment": "Constant reactive power demand in MVAR (Q_P)",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "impedance_active_power",
"comment": "Active power coefficient in MW for constant impedance load (P_Z)",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "impedance_reactive_power",
"comment": "Reactive power coefficient in MVAR for constant impedance load (Q_Z)",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "current_active_power",
"comment": "Active power coefficient in MW for constant current load (P_I)",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "current_reactive_power",
"comment": "Reactive power coefficient in MVAR for constant current load (Q_I)",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_constant_active_power",
"comment": "Maximum active power (MW) drawn by constant power load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_constant_reactive_power",
"comment": "Maximum reactive power (MVAR) drawn by constant power load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_impedance_active_power",
"comment": "Maximum active power (MW) drawn by constant impedance load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_impedance_reactive_power",
"comment": "Maximum reactive power (MVAR) drawn by constant impedance load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_current_active_power",
"comment": "Maximum active power (MW) drawn by constant current load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_current_reactive_power",
"comment": "Maximum reactive power (MVAR) drawn by constant current load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ControllableLoad"
},
{
"struct_name": "ShiftablePowerLoad",
"docstring": "A [static](@ref S) power load that can be partially or completed shifted to later time periods.\n\n These loads are used to model demand response. This load has a target demand profile (set by a [`max_active_power` time series](@ref ts_data) for an operational simulation). Load in the profile can be shifted to later time periods to aid in satisfying other system needs; however, any shifted load must be served within a designated time horizon (e.g., 24 hours), which is set by `load_balance_time_horizon`.",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial steady state active power demand (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits",
"comment": "Minimum and maximum stable active power levels (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial steady state reactive power demand (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_active_power",
"comment": "Maximum active power (MW) that this load can demand",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_reactive_power",
"comment": "Maximum reactive power (MVAR) that this load can demand",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "load_balance_time_horizon",
"comment": "Number of time periods over which load must be balanced",
"null_value": "1",
"data_type": "Int",
"valid_range": {
"min": 1,
"max": null
},
"validation_action": "error"
},
{
"name": "operation_cost",
"null_value": "LoadCost(nothing)",
"data_type": "Union{LoadCost, MarketBidCost}",
"comment": "[`OperationalCost`](@ref) of interrupting load"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ControllableLoad"
},
{
"struct_name": "FACTSControlDevice",
"docstring": "Facts control devices.\n\nMost often used in AC power flow studies as a control of voltage and, active and reactive power.",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Sending end bus number",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "control_mode",
"comment": "Control mode. Used to describe the behavior of the control device. [Options are listed here.](@ref factsmodes_list)",
"null_value": "nothing",
"data_type": "Union{Nothing, FACTSOperationModes}"
},
{
"name": "voltage_setpoint",
"comment": "Voltage setpoint at the sending end bus, it has to be a [`PV`](@ref acbustypes_list) bus, in p.u. ([`SYSTEM_BASE`](@ref per_unit)).",
"internal_default": "1.0",
"data_type": "Float64"
},
{
"name": "max_shunt_current",
"comment": "Maximum shunt current at the sending end bus; entered in MVA at unity voltage.",
"internal_default": "9999.0",
"data_type": "Float64"
},
{
"name": "reactive_power_required",
"comment": "Total MVAr required to hold voltage at sending bus, in %.",
"internal_default": "100.0",
"data_type": "Float64"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "Corresponding dynamic injection model for FACTS control device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "StaticInjection"
},
{
"struct_name": "FixedAdmittance",
"docstring": "A fixed admittance.\n\nMost often used in dynamics or AC power flow studies as a source of reactive power",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "Y",
"comment": "Fixed admittance in p.u. ([`SYSTEM_BASE`](@ref per_unit))",
"null_value": "0.0",
"data_type": "Complex{Float64}"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection model for admittance",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ElectricLoad"
},
{
"struct_name": "SwitchedAdmittance",
"docstring": "A switched admittance, with discrete steps to adjust the admittance.\n\nMost often used in power flow studies, iterating over the steps to see impacts of admittance on the results. Total admittance is calculated as: `Y` + `number_of_steps` * `Y_increase`",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "Y",
"comment": "Initial admittance at N = 0",
"null_value": "0.0 + 0.0im",
"data_type": "Complex{Float64}"
},
{
"name": "initial_status",
"comment": "Vector of initial switched shunt status, one for in-service and zero for out-of-service for block i (1 through 8)",
"null_value": "Int[]",
"data_type": "Vector{Int}",
"default": "Int[]"
},
{
"name": "number_of_steps",
"comment": "Vector with number of steps for each adjustable shunt block. For example, `number_of_steps[2]` are the number of available steps for admittance increment at block 2.",
"null_value": "Int[]",
"data_type": "Vector{Int}",
"default": "Int[]"
},
{
"name": "Y_increase",
"comment": "Vector with admittance increment step for each adjustable shunt block. For example, `Y_increase[2]` is the complex admittance increment for each step at block 2.",
"null_value": "Complex{Float64}[]",
"data_type": "Vector{Complex{Float64}}",
"default": "Complex{Float64}[]"
},
{ "name": "admittance_limits",
"comment": "Shunt admittance limits for switched shunt model",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"default": "(min=1.0, max=1.0)"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection model for admittance",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ElectricLoad"
},
{
"struct_name": "PowerLoad",
"docstring": "A [static](@ref S) power load, most commonly used for operational models such as power flow and operational optimizations.\n\nThis load consumes a set amount of power (set by `active_power` for a power flow simulation or a `max_active_power` time series for an operational simulation). For loads that can be compensated for load interruptions through demand response programs, see [`InterruptiblePowerLoad`](@ref). For voltage-dependent loads used in [dynamics](@ref D) modeling, see [`StandardLoad`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial steady-state active power demand (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial steady-state reactive power demand (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "max_active_power",
"comment": "Maximum active power (MW) that this load can demand",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_reactive_power",
"comment": "Maximum reactive power (MVAR) that this load can demand",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "conformity",
"comment": "Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list).",
"data_type": "LoadConformity",
"default": "LoadConformity.UNDEFINED"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "StaticLoad"
},
{
"struct_name": "MotorLoad",
"docstring": "A [static](@ref S) power load, most commonly used for operational models such as power flow and operational optimizations.\n\nThis load consumes a set amount of power (set by `active_power` for a power flow simulation or a `max_active_power` time series for an operational simulation). For loads that can be compensated for load interruptions through demand response programs, see [`InterruptiblePowerLoad`](@ref). For voltage-dependent loads used in [dynamics](@ref D) modeling, see [`StandardLoad`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `MotorLoad`) must have unique names, but components of different types (e.g., `MotorLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial steady-state active power demand (MW). A positive value indicates power consumption.",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial steady-state reactive power demand (MVAR). A positive value indicates reactive power consumption.",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "rating",
"comment": "Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_active_power",
"comment": "Maximum active power (MW) that this load can demand",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits. Set to `Nothing` if not applicable",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"default": "nothing",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "motor_technology",
"comment": "AC Motor type. Options are listed [here](@ref motor_list)",
"null_value": "MotorLoadTechnology.UNDETERMINED",
"data_type": "MotorLoadTechnology",
"default": "MotorLoadTechnology.UNDETERMINED"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "StaticLoad"
},
{
"struct_name": "StandardLoad",
"docstring": "A voltage-dependent [ZIP load](@ref Z), most commonly used for dynamics modeling.\n\nA `StandardLoad` breaks the ZIP into three pieces: Z (constant impedance), I (constant current), and P (constant power), according to `P = P_P * V^0 + P_I * V^1 + P_Z * V^2` for active power and `Q = Q_P * V^0 + Q_I * V^1 + Q_Z * V^2` for reactive power. (Voltage V is in per unit.)\n\nFor an alternative exponential formulation of the ZIP model, see [`ExponentialLoad`](@ref). For a simpler load model with no voltage dependency, see [`PowerLoad`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "base_power",
"comment": "Base power of the load (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "constant_active_power",
"comment": "Constant active power demand in MW (P_P)",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "constant_reactive_power",
"comment": "Constant reactive power demand in MVAR (Q_P)",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "impedance_active_power",
"comment": "Active power coefficient in MW for constant impedance load (P_Z)",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "impedance_reactive_power",
"comment": "Reactive power coefficient in MVAR for constant impedance load (Q_Z)",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "current_active_power",
"comment": "Active power coefficient in MW for constant current load (P_I)",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "current_reactive_power",
"comment": "Reactive power coefficient in MVAR for constant current load (Q_I)",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_constant_active_power",
"comment": "Maximum active power (MW) drawn by constant power load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_constant_reactive_power",
"comment": "Maximum reactive power (MVAR) drawn by constant power load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_impedance_active_power",
"comment": "Maximum active power (MW) drawn by constant impedance load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_impedance_reactive_power",
"comment": "Maximum reactive power (MVAR) drawn by constant impedance load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_current_active_power",
"comment": "Maximum active power (MW) drawn by constant current load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_current_reactive_power",
"comment": "Maximum reactive power (MVAR) drawn by constant current load",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "conformity",
"comment": "Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list).",
"data_type": "LoadConformity",
"default": "LoadConformity.UNDEFINED"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "StaticLoad"
},
{
"struct_name": "ExponentialLoad",
"docstring": "A voltage-dependent [ZIP load](@ref Z), most commonly used for dynamics modeling.\n\nAn `ExponentialLoad` models active power as P = P0 * V^α and reactive power as Q = Q0 * V^β, where the exponents α and β select govern the voltage dependency. For an alternative three-part formulation of the ZIP model, see [`StandardLoad`](@ref). For a simpler load model with no voltage dependency, see [`PowerLoad`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Active power coefficient, P0 (MW)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Reactive power coefficient, Q0 (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "α",
"comment": "Exponent relating voltage dependency for active power. 0 = constant power only, 1 = constant current only, and 2 = constant impedance only",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "β",
"comment": "Exponent relating voltage dependency for reactive power. 0 = constant power only, 1 = constant current only, and 2 = constant impedance only",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "base_power",
"comment": "Base power (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "max_active_power",
"comment": "Maximum active power (MW) that this load can demand",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "max_reactive_power",
"comment": "Maximum reactive power (MVAR) that this load can demand",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "conformity",
"comment": "Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list).",
"data_type": "LoadConformity",
"default": "LoadConformity.UNDEFINED"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "StaticLoad"
},
{
"struct_name": "SingleCageInductionMachine",
"docstring": "Parameters of 5-states three-phase single cage induction machine with quadratic torque-speed relationship",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"name": "R_s",
"comment": "Armature stator resistance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "R_r",
"comment": "Rotor resistance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "X_ls",
"data_type": "Float64",
"null_value": 0,
"comment": "Stator Leakage Reactance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "X_lr",
"data_type": "Float64",
"null_value": 0,
"comment": "Rotor Leakage Reactance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "X_m",
"data_type": "Float64",
"null_value": 0,
"comment": "Stator-Rotor Mutual Reactance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "H",
"data_type": "Float64",
"null_value": 0,
"comment": "Motor Inertia Constant [s]",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "A",
"data_type": "Float64",
"null_value": "0.0",
"comment": "Torque-Speed Quadratic Term",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "B",
"data_type": "Float64",
"null_value": "0.0",
"comment": "Torque-Speed Linear Term",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": 100.0,
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "C",
"comment": "(**Do not modify.**) Torque-Speed Constant Term",
"internal_default": "PowerSystems.calculate_IM_torque_params(A, B)",
"data_type": "Float64"
},
{
"name": "τ_ref",
"comment": "Reference torque parameter",
"internal_default": "1.0",
"data_type": "Float64"
},
{
"name": "B_shunt",
"comment": "Susceptance Initialization Corrector Term",
"internal_default": "0.0",
"data_type": "Float64"
},
{
"name": "X_ad",
"comment": "(**Do not modify.**) Equivalent d-axis reactance",
"internal_default": "(1.0 / X_m + 1.0 / X_ls + 1.0 / X_lr)^(-1)",
"data_type": "Float64"
},
{
"name": "X_aq",
"comment": "(**Do not modify.**) Equivalent q-axis reactance",
"internal_default": "X_ad",
"data_type": "Float64"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tψ_qs: stator flux in the q-axis,\n\tψ_ds: stator flux in the d-axis,\n\tψ_qr: rotor flux in the q-axis,\n\tψ_dr: rotor flux in the d-axis, \n\tωr: Rotor speed [pu],",
"internal_default": "[:ψ_qs, :ψ_ds, :ψ_qr, :ψ_dr, :ωr]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) SingleCageInductionMachine has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "DynamicInjection"
},
{
"struct_name": "SimplifiedSingleCageInductionMachine",
"docstring": "Parameters of 3-states three-phase single cage induction machine with quadratic torque-speed relationship",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"name": "R_s",
"comment": "Armature stator resistance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "R_r",
"comment": "Rotor resistance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "X_ls",
"data_type": "Float64",
"null_value": 0,
"comment": "Stator Leakage Reactance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "X_lr",
"data_type": "Float64",
"null_value": 0,
"comment": "Rotor Leakage Reactance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "X_m",
"data_type": "Float64",
"null_value": 0,
"comment": "Stator-Rotor Mutual Reactance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "H",
"data_type": "Float64",
"null_value": 0,
"comment": "Motor Inertia Constant [s]",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "A",
"data_type": "Float64",
"null_value": "0.0",
"comment": "Torque-Speed Quadratic Term",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "B",
"data_type": "Float64",
"null_value": "0.0",
"comment": "Torque-Speed Linear Term",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": 100.0,
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "C",
"comment": "(**Do not modify.**) Torque-Speed Constant Term",
"internal_default": "PowerSystems.calculate_IM_torque_params(A, B)",
"data_type": "Float64"
},
{
"name": "τ_ref",
"comment": "Reference torque parameter",
"internal_default": "1.0",
"data_type": "Float64"
},
{
"name": "B_shunt",
"comment": "Susceptance Initialization Corrector Term",
"internal_default": "0.0",
"data_type": "Float64"
},
{
"name": "X_ss",
"comment": "(**Do not modify.**) Stator self reactance",
"internal_default": "X_ls + X_m",
"data_type": "Float64"
},
{
"name": "X_rr",
"comment": "(**Do not modify.**) Rotor self reactance",
"internal_default": "X_lr + X_m",
"data_type": "Float64"
},
{
"name": "X_p",
"comment": "(**Do not modify.**) Transient reactance",
"internal_default": "X_ss - X_m^2 / X_rr",
"data_type": "Float64"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tψ_qr: rotor flux in the q-axis,\n\tψ_dr: rotor flux in the d-axis, \n\tωr: Rotor speed [pu],",
"internal_default": "[:ψ_qr, :ψ_dr, :ωr]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) SimplifiedSingleCageInductionMachine has 3 states",
"internal_default": 3,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "DynamicInjection"
},
{
"struct_name": "DynamicExponentialLoad",
"docstring": "Parameters of 2-states of a generic dynamic load model based on [\"Voltage stability analysis using generic dynamic load models.\"](https://doi.org/10.1109/59.317575)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"name": "a",
"comment": "Active power static exponential coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "b",
"comment": "Reactive power static exponential coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "α",
"comment": "Active power transient exponential coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "β",
"comment": "Reactive power transient exponential coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T_p",
"data_type": "Float64",
"null_value": 0,
"comment": "Active Power Time Constant",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T_q",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactive Power Time Constant",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "base_power",
"comment": "Base power of the load (MVA) for [per unitization](@ref per_unit)",
"internal_default": "100.0",
"data_type": "Float64"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tx_p: Integrator state of the active power,\n\tx_q: Integrator state of the reactive power,",
"internal_default": "[:x_p, :x_q]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) DynamicExponentialLoad has 2 states",
"internal_default": 2,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "DynamicInjection"
},
{
"struct_name": "ActiveConstantPowerLoad",
"docstring": "Parameters of 12-[states](@ref S) active power load based on the paper, [\"Dynamic Stability of a Microgrid With an Active Load.\"](https://doi.org/10.1109/TPEL.2013.2241455)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"name": "r_load",
"comment": "DC-side resistor",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "c_dc",
"comment": "DC-side capacitor",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rf",
"data_type": "Float64",
"null_value": 0,
"comment": "Converter side filter resistance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "lf",
"data_type": "Float64",
"null_value": 0,
"comment": "Converter side filter inductance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "cf",
"data_type": "Float64",
"null_value": 0,
"comment": "AC Converter filter capacitance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rg",
"data_type": "Float64",
"null_value": 0,
"comment": "Network side filter resistance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "lg",
"data_type": "Float64",
"null_value": 0,
"comment": "Network side filter inductance",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kp_pll",
"data_type": "Float64",
"null_value": 0,
"comment": "Proportional constant for PI-PLL block",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ki_pll",
"data_type": "Float64",
"null_value": 0,
"comment": "Integral constant for PI-PLL block",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kpv",
"data_type": "Float64",
"null_value": 0,
"comment": "Proportional constant for Voltage Control block",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kiv",
"data_type": "Float64",
"null_value": 0,
"comment": "Integral constant for Voltage Control block",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kpc",
"data_type": "Float64",
"null_value": 0,
"comment": "Proportional constant for Current Control block",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kic",
"data_type": "Float64",
"null_value": 0,
"comment": "Integral constant for Current Control block",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": 100.0,
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "P_ref",
"comment": "Reference active power (pu)",
"internal_default": "1.0",
"data_type": "Float64"
},
{
"name": "Q_ref",
"comment": "Reference reactive power (pu)",
"internal_default": "1.0",
"data_type": "Float64"
},
{
"name": "V_ref",
"comment": "Reference voltage (pu)",
"internal_default": "1.0",
"data_type": "Float64"
},
{
"name": "ω_ref",
"comment": "Reference frequency (pu)",
"internal_default": "1.0",
"data_type": "Float64"
},
{
"name": "is_filter_differential",
"comment": "Boolean to decide if filter [states](@ref S) are differential or algebraic",
"internal_default": "1",
"data_type": "Int"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tθ_pll: PLL deviation angle, \n\tϵ_pll: PLL integrator state, \n\tη: DC-voltage controller integrator state, \n\tv_dc: DC voltage at the capacitor, \n\tγd: d-axis Current controller integrator state, \n\tγq: q-axis Current controller integrator state, \n\tir_cnv: Real current out of the converter,\n\tii_cnv: Imaginary current out of the converter,\n\tvr_filter: Real voltage at the filter's capacitor,\n\tvi_filter: Imaginary voltage at the filter's capacitor,\n\tir_filter: Real current out of the filter,\n\tii_filter: Imaginary current out of the filter",
"internal_default": "[:θ_pll, :ϵ_pll, :η, :v_dc, :γd, :γq, :ir_cnv, :ii_cnv, :vr_filter, :vi_filter, :ir_filter, :ii_filter]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ActiveConstantPowerLoad has 12 states",
"internal_default": 12,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "DynamicInjection"
},
{
"struct_name": "InterconnectingConverter",
"docstring": "Interconnecting Power Converter (IPC) for transforming power from an ACBus to a DCBus",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus on the AC side of this converter",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "dc_bus",
"comment": "Bus on the DC side of this converter",
"null_value": "DCBus(nothing)",
"data_type": "DCBus"
},
{
"name": "active_power",
"comment": "Active power (MW) on the DC side",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": "active_power_limits",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "rating",
"comment": "Maximum output power rating of the converter (MVA)",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits",
"comment": "Minimum and maximum stable active power levels (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power of the converter in MVA",
"null_value": 100.0,
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits. Set to `Nothing` if not applicable",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"needs_conversion": true,
"conversion_unit": ":mva",
"default": "nothing"
},
{
"name": "dc_current",
"comment": "DC current (A) on the converter",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0"
},
{
"name": "max_dc_current",
"comment": "Maximum stable dc current limits (A)",
"null_value": "0.0",
"data_type": "Float64",
"default": "1e8"
},
{
"name": "loss_function",
"comment": "Linear or quadratic loss function with respect to the converter current",
"null_value": "LinearCurve(0.0)",
"data_type": "Union{LinearCurve, QuadraticCurve}",
"default": "LinearCurve(0.0)"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "StaticInjection"
},
{
"struct_name": "CSVGN1",
"docstring": "Parameters of static shunt compensator: CSVGN1 in PSSE",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"name": "K",
"comment": "Gain in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T1",
"comment": "Time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T2",
"comment": "Time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T3",
"comment": "Time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
}
},
{
"name": "T4",
"comment": "Time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T5",
"comment": "Time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Rmin",
"comment": "Reactor minimum Mvar",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Vmax",
"comment": "Maximum voltage in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Vmin",
"comment": "Minimum voltage in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "CBase",
"comment": "Capacitor (MVAR)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": 100.0,
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "R_th",
"comment": "Source Thevenin resistance",
"internal_default": "0.0",
"data_type": "Float64"
},
{
"name": "X_th",
"comment": "Source Thevenin reactance",
"internal_default": "0.0",
"data_type": "Float64"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tthy: thyristor,\n\tvr1: regulator output 1,\n\tvr2: regulator output 2",
"internal_default": "[:thy, :vr1, :vr2]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) CSVGN1 has 3 states",
"internal_default": 3,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "DynamicInjection"
},
{
"struct_name": "HydroDispatch",
"docstring": "A hydropower generator without a reservoir, suitable for modeling run-of-river hydropower.\n\nFor hydro generators with an upper reservoir, see [`HydroReservoir`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial reactive power set point of the unit (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": "reactive_power_limits",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "rating",
"comment": "Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "prime_mover_type",
"comment": "Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)",
"null_value": "PrimeMovers.HY",
"data_type": "PrimeMovers"
},
{
"name": "active_power_limits",
"comment": "Minimum and maximum stable active power levels (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits. Set to `Nothing` if not applicable",
"validation_action": "warn",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "ramp_limits",
"comment": "ramp up and ramp down limits in MW/min",
"null_value": "nothing",
"data_type": "Union{Nothing, UpDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "time_limits",
"comment": "Minimum up and Minimum down time limits in hours",
"null_value": "nothing",
"data_type": "Union{Nothing, UpDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"null_value": "false",
"default": "false",
"name": "status",
"comment": "Initial commitment condition at the start of a simulation (`true` = on or `false` = off)",
"data_type": "Bool"
},
{
"null_value": "INFINITE_TIME",
"default": "INFINITE_TIME",
"name": "time_at_status",
"comment": "Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`",
"data_type": "Float64"
},
{
"name": "operation_cost",
"null_value": "HydroGenerationCost(nothing)",
"data_type": "Union{HydroGenerationCost, MarketBidCost}",
"default": "HydroGenerationCost(nothing)",
"comment": "[`OperationalCost`](@ref) of generation"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "HydroGen"
},
{
"struct_name": "HydroTurbine",
"docstring": "A hydropower generator that must have a [`HydroReservoir`](@ref) attached, suitable for modeling independent turbines and reservoirs.",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial reactive power set point of the unit (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": "reactive_power_limits",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "rating",
"comment": "Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits",
"comment": "Minimum and maximum stable active power levels (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits. Set to `Nothing` if not applicable",
"validation_action": "warn",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "operation_cost",
"null_value": "HydroGenerationCost(nothing)",
"data_type": "Union{HydroGenerationCost, MarketBidCost}",
"default": "HydroGenerationCost(nothing)",
"comment": "[`OperationalCost`](@ref) of generation"
},
{
"name": "powerhouse_elevation",
"comment": "Height level in meters above the sea level of the powerhouse on which the turbine is installed.",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"default": "0.0",
"validation_action": "error"
},
{
"name": "ramp_limits",
"comment": "ramp up and ramp down limits in MW/min",
"null_value": "nothing",
"data_type": "Union{Nothing, UpDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"default": "nothing",
"conversion_unit": ":mva"
},
{
"name": "time_limits",
"comment": "Minimum up and Minimum down time limits in hours",
"null_value": "nothing",
"data_type": "Union{Nothing, UpDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "nothing"
},
{
"name": "outflow_limits",
"comment": "Turbine outflow limits in m3/s. Set to `Nothing` if not applicable",
"validation_action": "warn",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"default": "nothing"
},
{
"name": "efficiency",
"comment": "Turbine efficiency [0, 1.0]",
"null_value": "1.0",
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "turbine_type",
"comment": "Type of the turbine",
"null_value": "HydroTurbineType.UNKNOWN",
"data_type": "HydroTurbineType",
"default": "HydroTurbineType.UNKNOWN"
},
{
"name": "conversion_factor",
"comment": "Conversion factor from flow/volume to energy: m^3 -> p.u-hr",
"null_value": "1.0",
"data_type": "Float64",
"default": "1.0"
},
{
"name": "prime_mover_type",
"comment": "Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)",
"null_value": "PrimeMovers.OT",
"data_type": "PrimeMovers",
"default": "PrimeMovers.HY"
},
{
"name": "travel_time",
"comment": "Downstream (from reservoir into turbine) travel time in hours.",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"default": "nothing"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "HydroUnit"
},
{
"struct_name": "HydroPumpTurbine",
"docstring": "A hydropower pumped turbine that needs to have two [`HydroReservoir`](@ref)s attached, suitable for modeling independent pumped hydro with reservoirs.",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial active power set point of the turbine unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial reactive power set point of the unit (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": "reactive_power_limits",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "rating",
"comment": "Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits",
"comment": "Minimum and maximum stable active power levels (MW) for the turbine",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits. Set to `Nothing` if not applicable",
"validation_action": "warn",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits_pump",
"comment": "Minimum and maximum stable active power levels (MW) for the pump",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "outflow_limits",
"comment": "Turbine/Pump outflow limits in m3/s. Set to `Nothing` if not applicable",
"validation_action": "warn",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}"
},
{
"name": "powerhouse_elevation",
"comment": "Height level in meters above the sea level of the powerhouse on which the turbine is installed.",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "ramp_limits",
"comment": "ramp up and ramp down limits in MW/min",
"null_value": "nothing",
"data_type": "Union{Nothing, UpDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "time_limits",
"comment": "Minimum up and Minimum down time limits in hours",
"null_value": "nothing",
"data_type": "Union{Nothing, UpDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"null_value": "PumpHydroStatus.OFF",
"default": "PumpHydroStatus.OFF",
"name": "status",
"comment": "Initial Operating status of a pumped‑storage hydro unit. See [PumpHydroStatus](@ref) for reference",
"data_type": "PumpHydroStatus"
},
{
"null_value": "INFINITE_TIME",
"default": "INFINITE_TIME",
"name": "time_at_status",
"comment": "Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`",
"data_type": "Float64"
},
{
"name": "operation_cost",
"null_value": "HydroGenerationCost(nothing)",
"data_type": "Union{HydroGenerationCost, MarketBidCost}",
"default": "HydroGenerationCost(nothing)",
"comment": "[`OperationalCost`](@ref) of generation"
},
{
"name": "active_power_pump",
"comment": "Initial active power set point of the pump unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "efficiency",
"comment": "Turbine/Pump efficiency [0, 1.0]",
"null_value": "(turbine = 1.0, pump = 1.0)",
"default": "(turbine = 1.0, pump = 1.0)",
"data_type": "TurbinePump"
},
{
"name": "transition_time",
"comment": "Transition time in hours to switch into the specific mode.",
"null_value": "(turbine = 0.0, pump = 0.0)",
"data_type": "TurbinePump",
"default": "(turbine = 0.0, pump = 0.0)"
},
{
"name": "minimum_time",
"comment": "Minimum operating time in hours for the specific mode.",
"null_value": "(turbine = 0.0, pump = 0.0)",
"data_type": "TurbinePump",
"default": "(turbine = 0.0, pump = 0.0)"
},
{
"name": "travel_time",
"comment": "Downstream (from reservoir into turbine) travel time in hours.",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}",
"default": "nothing"
},
{
"name": "conversion_factor",
"comment": "Conversion factor from flow/volume to energy: m^3 -> p.u-hr",
"null_value": "1.0",
"data_type": "Float64",
"default": "1.0"
},
{
"name": "must_run",
"comment": "Whether the unit must run (i.e., cannot be curtailed)",
"null_value": "false",
"data_type": "Bool",
"default": "false"
},
{
"name": "prime_mover_type",
"comment": "Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)",
"null_value": "PrimeMovers.OT",
"data_type": "PrimeMovers",
"default": "PrimeMovers.PS"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "HydroUnit"
},
{
"struct_name": "HydroReservoir",
"docstring": "A hydropower reservoir that have attached [`HydroTurbine`](@ref)(s) or [`HydroPumpTurbine`](@ref)(s) used to generate power.\nSee [How to Define Hydro Generators with Reservoirs](@ref hydro_resv) for supported configurations.",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "storage_level_limits",
"comment": "Storage level limits for the reservoir in m^3, m, or MWh, based on the [`ReservoirDataType`](@ref hydroreservoir_list) selected for `level_data_type`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "initial_level",
"comment": "Initial level of the reservoir relative to the `storage_level_limits.max`.",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "spillage_limits",
"comment": "Amount of water allowed to be spilled from the reservoir. If nothing, infinite spillage is allowed.",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}"
},
{
"name": "inflow",
"comment": "Amount of water refilling the reservoir in m^3/h or MW (if `level_data_type` is [`ReservoirDataType`](@ref hydroreservoir_list)`.ENERGY`).",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "outflow",
"comment": "Amount of water naturally going out of the reservoir in m^3/h or MW (if `level_data_type` is [`ReservoirDataType`](@ref hydroreservoir_list)`.ENERGY`).",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "level_targets",
"comment": "Reservoir level targets at the end of a simulation as a fraction of the `storage_level_limits.max`.",
"null_value": "nothing",
"data_type": "Union{Nothing, Float64}"
},
{
"name": "intake_elevation",
"comment": "Height of the intake of the reservoir, towards the downstream turbines, in meters above the sea level.",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "head_to_volume_factor",
"comment": "Head to volume relationship for the reservoir.",
"null_value": "LinearCurve(0.0)",
"data_type": "ValueCurve"
},
{
"name": "upstream_turbines",
"null_value": "Device[]",
"data_type": "Vector{HydroUnit}",
"default": "Device[]",
"comment": "Vector of [HydroUnit](@ref)(s) that are immediately upstream of this reservoir. This reservoir is the tail reservoir for these units, and their flow goes into this reservoir."
},
{
"name": "downstream_turbines",
"null_value": "Device[]",
"data_type": "Vector{HydroUnit}",
"default": "Device[]",
"comment": "Vector of [HydroUnit](@ref)(s) that are immediately downstream of this reservoir. This reservoir is the head reservoir for these units, and its feed flow into these units."
},
{
"name": "upstream_reservoirs",
"null_value": "Device[]",
"data_type": "Vector{Device}",
"default": "Device[]",
"comment": "Vector of [Device](@ref)(s) reservoirs that are immediately upstream of this reservoir. This reservoir receives the spillage flow from upstream_reservoirs."
},
{
"name": "operation_cost",
"null_value": "HydroReservoirCost(nothing)",
"data_type": "HydroReservoirCost",
"default": "HydroReservoirCost(nothing)",
"comment": "[`OperationalCost`](@ref) of reservoir."
},
{
"name": "level_data_type",
"null_value": "ReservoirDataType.USABLE_VOLUME",
"data_type": "ReservoirDataType",
"default": "ReservoirDataType.USABLE_VOLUME",
"comment": "Reservoir level data type. See [ReservoirDataType](@ref) for reference."
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Device"
},
{
"struct_name": "RenewableDispatch",
"docstring": "A renewable (e.g., wind or solar) generator whose output can be curtailed to satisfy power system constraints.\n\nThese generators can also participate in reserves markets, including upwards reserves by proactively curtailing some available power (based on its [`max_active_power` time series](@ref ts_data)). Example uses include: a utility-scale wind or solar generator whose PPA allows curtailment. For non-curtailable or must-take renewables, see [`RenewableNonDispatch`](@ref).\n\nRenewable generators do not have a `max_active_power` parameter, which is instead calculated when calling [`get_max_active_power()`](@ref get_max_active_power(d::T) where {T <: RenewableGen})",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial reactive power set point of the unit (MVAR), used in some production cost modeling simulations. To set the reactive power in a load flow, use `power_factor`",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "rating",
"comment": "Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "prime_mover_type",
"comment": "Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)",
"null_value": "PrimeMovers.OT",
"data_type": "PrimeMovers"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits, used in some production cost model simulations and in power flow if the unit is connected to a [`PV`](@ref acbustypes_list) bus. Set to `nothing` if not applicable",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "power_factor",
"comment": "Power factor [0, 1] set-point, used in some production cost modeling and in load flow if the unit is connected to a [`PQ`](@ref acbustypes_list) bus",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "operation_cost",
"null_value": "RenewableGenerationCost(nothing)",
"data_type": "Union{RenewableGenerationCost, MarketBidCost}",
"comment": "[`OperationalCost`](@ref) of generation"
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "RenewableGen"
},
{
"struct_name": "RenewableNonDispatch",
"docstring": "A non-dispatchable (i.e., non-curtailable or must-take) renewable generator.\n\nIts output is equal to its [`max_active_power` time series](@ref ts_data) by default. Example use: an aggregation of behind-the-meter distributed energy resources like rooftop solar. For curtailable or downward dispatachable generation, see [`RenewableDispatch`](@ref).\n\nRenewable generators do not have a `max_active_power` parameter, which is instead calculated when calling [`get_max_active_power()`](@ref get_max_active_power(d::T) where {T <: RenewableGen})",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial reactive power set point of the unit (MVAR), used in some production cost modeling simulations. To set the reactive power in a load flow, use `power_factor`",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "rating",
"comment": "Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "prime_mover_type",
"comment": "Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)",
"null_value": "PrimeMovers.OT",
"data_type": "PrimeMovers"
},
{
"name": "power_factor",
"comment": "Power factor [0, 1] set-point, used in some production cost modeling and in load flow if the unit is connected to a [`PQ`](@ref acbustypes_list) bus",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "RenewableGen"
},
{
"struct_name": "ThermalStandard",
"docstring": "A thermal generator, such as a fossil fuel and nuclear generator.\n\nThis is a standard representation with options to include a minimum up time, minimum down time, and ramp limits. For a more detailed representation the start-up and shut-down processes, including hot starts, see [`ThermalMultiStart`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"null_value": "false",
"name": "status",
"comment": "Initial commitment condition at the start of a simulation (`true` = on or `false` = off)",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": "active_power_limits",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial reactive power set point of the unit (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": "reactive_power_limits",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "rating",
"comment": "Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits",
"comment": "Minimum and maximum stable active power levels (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits. Set to `Nothing` if not applicable",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "ramp_limits",
"comment": "ramp up and ramp down limits in MW/min",
"null_value": "nothing",
"data_type": "Union{Nothing, UpDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "operation_cost",
"null_value": "ThermalGenerationCost(nothing)",
"data_type": "Union{ThermalGenerationCost, MarketBidCost}",
"comment": "[`OperationalCost`](@ref) of generation"
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "time_limits",
"comment": "Minimum up and Minimum down time limits in hours",
"null_value": "nothing",
"data_type": "Union{Nothing, UpDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"default": "nothing"
},
{
"name": "must_run",
"comment": "Set to `true` if the unit is must run",
"null_value": "false",
"data_type": "Bool",
"default": "false"
},
{
"name": "prime_mover_type",
"comment": "Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)",
"null_value": "PrimeMovers.OT",
"data_type": "PrimeMovers",
"default": "PrimeMovers.OT"
},
{
"name": "fuel",
"comment": "Prime mover fuel according to EIA 923. Options are listed [here](@ref tf_list)",
"null_value": "ThermalFuels.OTHER",
"data_type": "ThermalFuels",
"default": "ThermalFuels.OTHER"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"null_value": "INFINITE_TIME",
"name": "time_at_status",
"comment": "Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`",
"data_type": "Float64",
"default": "INFINITE_TIME"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ThermalGen"
},
{
"struct_name": "SynchronousCondenser",
"docstring": "A Synchronous Machine connected to the system to provide inertia or reactive power support",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "reactive_power",
"comment": "Initial reactive power set point of the unit (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": "reactive_power_limits",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "rating",
"comment": "Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits. Set to `Nothing` if not applicable",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "active_power_losses",
"comment": "Active Power Loss incurred by having the unit online.",
"null_value": "0.0",
"default": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "StaticInjection"
},
{
"struct_name": "ThermalMultiStart",
"docstring": "A thermal generator, such as a fossil fuel or nuclear generator, that can start-up again from a *hot*, *warm*, or *cold* state.\n\n`ThermalMultiStart` has a detailed representation of the start-up process based on the time elapsed since the last shut down, as well as a detailed shut-down process. The model is based on [\"Tight and Compact MILP Formulation for the Thermal Unit Commitment Problem.\"](https://doi.org/10.1109/TPWRS.2013.2251373). For a simplified representation of the start-up and shut-down processes, see [`ThermalStandard`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"null_value": "false",
"name": "status",
"comment": "Initial commitment condition at the start of a simulation (`true` = on or `false` = off)",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": "active_power_limits",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial reactive power set point of the unit (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": "reactive_power_limits",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "rating",
"comment": "Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "prime_mover_type",
"comment": "Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)",
"null_value": "PrimeMovers.OT",
"data_type": "PrimeMovers"
},
{
"name": "fuel",
"comment": "Prime mover fuel according to EIA 923. Options are listed [here](@ref tf_list)",
"null_value": "ThermalFuels.OTHER",
"data_type": "ThermalFuels"
},
{
"name": "active_power_limits",
"comment": "Minimum and maximum stable active power levels (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits. Set to `Nothing` if not applicable",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "ramp_limits",
"null_value": "nothing",
"data_type": "Union{Nothing, UpDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "power_trajectory",
"comment": "Power trajectory the unit will take during the start-up and shut-down ramp process",
"null_value": "nothing",
"data_type": "Union{Nothing, StartUpShutDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "time_limits",
"comment": "Minimum up and Minimum down time limits in hours",
"null_value": "nothing",
"data_type": "Union{Nothing, UpDown}",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "start_time_limits",
"comment": "Time limits for start-up based on turbine temperature in hours",
"null_value": "nothing",
"data_type": "Union{Nothing, StartUpStages}"
},
{
"name": "start_types",
"comment": "Number of start-up based on turbine temperature, where `1` = *hot*, `2` = *warm*, and `3` = *cold*",
"null_value": "1",
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 3
},
"validation_action": "error"
},
{
"name": "operation_cost",
"null_value": "ThermalGenerationCost(nothing)",
"data_type": "Union{ThermalGenerationCost, MarketBidCost}",
"comment": "[`OperationalCost`](@ref) of generation"
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "time_at_status",
"comment": "Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`",
"null_value": "INFINITE_TIME",
"data_type": "Float64",
"default": "INFINITE_TIME"
},
{
"name": "must_run",
"comment": "Set to `true` if the unit is must run",
"null_value": "false",
"data_type": "Bool",
"default": "false"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ThermalGen"
},
{
"struct_name": "EnergyReservoirStorage",
"docstring": "An energy storage device, modeled as a generic energy reservoir.\n\nThis is suitable for modeling storage charging and discharging with average efficiency losses, ignoring the physical dynamics of the storage unit. A variety of energy storage types and chemistries can be modeled with this approach. For pumped hydro storage, alternatively see [`HydroPumpTurbine`](@ref) and [`HydroReservoir`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "prime_mover_type",
"comment": "Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)",
"null_value": "PrimeMovers.BA",
"data_type": "PrimeMovers"
},
{
"name": "storage_technology_type",
"comment": "Storage Technology Complementary to EIA 923. Options are listed [here](@ref storagetech_list)",
"null_value": "StorageTech.OTHER_CHEM",
"data_type": "StorageTech"
},
{
"name": "storage_capacity",
"comment": "Maximum storage capacity (can be in units of, e.g., MWh for batteries or liters for hydrogen). When in MWh, this value divided by base_power (MVA) gives an approximate duration in hours, assuming unity power factor. For understanding this relationship, see [per unitization](@ref per_unit)",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "storage_level_limits",
"null_value": "(min=0.0, max=0.0)",
"comment": "Minimum and maximum allowable storage levels [0, 1], which can be used to model derates or other restrictions, such as state-of-charge restrictions on battery cycling",
"data_type": "MinMax",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "initial_storage_capacity_level",
"null_value": "0.0",
"comment": "Initial storage capacity level as a ratio [0, 1.0] of `storage_capacity`",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "rating",
"comment": "Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power",
"comment": "Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "input_active_power_limits",
"comment": "Minimum and maximum limits on the input active power (i.e., charging)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "output_active_power_limits",
"comment": "Minimum and maximum limits on the output active power (i.e., discharging)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "efficiency",
"comment": "Average efficiency [0, 1] `in` (charging/filling) and `out` (discharging/consuming) of the storage system",
"null_value": "(in=0.0, out=0.0)",
"data_type": "NamedTuple{(:in, :out), Tuple{Float64, Float64}}",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "reactive_power",
"comment": "Initial reactive power set point of the unit (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": "reactive_power_limits",
"validation_action": "warn",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits. Set to `Nothing` if not applicable",
"null_value": "(min=0.0, max=0.0)",
"data_type": "Union{Nothing, MinMax}",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": "100.0",
"data_type": "Float64",
"valid_range": {
"min": 1e-4,
"max": null
},
"validation_action": "warn"
},
{
"name": "operation_cost",
"comment": "[`OperationalCost`](@ref) of storage",
"null_value": "StorageCost(nothing)",
"data_type": "Union{StorageCost, MarketBidCost}",
"default": "StorageCost(nothing)"
},
{
"name": "conversion_factor",
"comment": "Conversion factor of `storage_capacity` to MWh, if different than 1.0. For example, X MWh/liter hydrogen",
"null_value": "0.0",
"data_type": "Float64",
"default": "1.0"
},
{
"name": "storage_target",
"comment": "Storage target at the end of simulation as ratio of storage capacity",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0"
},
{
"name": "cycle_limits",
"comment": "Storage Maximum number of cycles per year",
"null_value": "0",
"data_type": "Int",
"default": "1e4"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Storage"
},
{
"struct_name": "ConstantReserve",
"docstring": "A reserve product with a constant procurement requirement, such as 3% of the system base power at all times.\n\nThis reserve product includes online generators that can respond right away after an unexpected contingency, such as a transmission line or generator outage. When defining the reserve, the `ReserveDirection` must be specified to define this as a [`ReserveUp`](@ref), [`ReserveDown`](@ref), or [`ReserveSymmetric`](@ref)",
"parametric": "ReserveDirection",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "time_frame",
"comment": "the saturation time_frame in minutes to provide reserve contribution",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "requirement",
"comment": "the value of required reserves in p.u. ([`SYSTEM_BASE`](@ref per_unit))",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "sustained_time",
"comment": "the time in seconds reserve contribution must sustained at a specified level",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"default": "3600.0",
"validation_action": "error"
},
{
"name": "max_output_fraction",
"comment": "the maximum fraction of each device's output that can be assigned to the service",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "1.0",
"validation_action": "error"
},
{
"name": "max_participation_factor",
"comment": "the maximum portion [0, 1.0] of the reserve that can be contributed per device",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "1.0",
"validation_action": "error"
},
{
"name": "deployed_fraction",
"comment": "Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "0.0",
"validation_action": "error"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Reserve{T}"
},
{
"struct_name": "ConstantReserveNonSpinning",
"docstring": "A non-spinning reserve product with a constant procurement requirement, such as 3% of the system base power at all times.\n\nThis reserve product includes back-up generators that might not be currently synchronized with the power system, but can come online quickly after an unexpected contingency, such as a transmission line or generator outage. This is only an upwards reserve. For faster-responding upwards or downwards reserves from components already synchronized with the system, see [`ConstantReserve`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "time_frame",
"comment": "the saturation time frame in minutes that a participating device must provide its reserve contribution",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "requirement",
"comment": "the value of required reserves in p.u. ([`SYSTEM_BASE`](@ref per_unit))",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "sustained_time",
"comment": "the time in seconds reserve contribution must sustained at a specified level",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"default": "3600.0",
"validation_action": "error"
},
{
"name": "max_output_fraction",
"comment": "the maximum fraction of each device's output that can be assigned to the service",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "1.0",
"validation_action": "error"
},
{
"name": "max_participation_factor",
"comment": "the maximum portion [0, 1.0] of the reserve that can be contributed per device",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "1.0",
"validation_action": "error"
},
{
"name": "deployed_fraction",
"comment": "Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "0.0",
"validation_action": "error"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ReserveNonSpinning"
},
{
"struct_name": "ConstantReserveGroup",
"docstring": "A reserve product met by a group of individual reserves.\n\nThe group reserve requirement is added in addition to any individual reserve requirements, and devices that contribute to individual reserves within the group can also contribute to the overarching group reserve requirement. Example: A group of spinning and non-spinning reserves, where online generators providing spinning reserves can also contribute to the non-spinning reserve requirement.\n\nThis model has a constant procurement requirement, such as 3% of the system base power at all times. When defining the reserve, the `ReserveDirection` must be specified to define this as a [`ReserveUp`](@ref), [`ReserveDown`](@ref), or [`ReserveSymmetric`](@ref)",
"parametric": "ReserveDirection",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "requirement",
"comment": "the value of required reserves in p.u. ([`SYSTEM_BASE`](@ref per_unit))",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "contributing_services",
"comment": "Services that contribute to this group requirement. Services must be added for this constraint to have an effect when conducting simulations in [`PowerSimulations.jl`](https://sienna-platform.github.io/PowerSimulations.jl/latest/)",
"data_type": "Vector{Service}",
"null_value": "Vector{Service}()",
"default": "Vector{Service}()",
"exclude_setter": true
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Service"
},
{
"struct_name": "ReserveDemandCurve",
"docstring": "A reserve product with an [Operating Reserve Demand Curve (ORDC)](https://hepg.hks.harvard.edu/files/hepg/files/ordcupdate-final.pdf) for operational simulations.\n\nThe ORDC is modeled as a discretized set of `(Reserve capacity (MW), Price (\\$/MWh))` steps, which can vary with time. Use [`set_variable_cost!`](@ref) to define the ORDCs.\n\nWhen defining the reserve, the `ReserveDirection` must be specified to define this as a [`ReserveUp`](@ref), [`ReserveDown`](@ref), or [`ReserveSymmetric`](@ref)",
"parametric": "ReserveDirection",
"fields": [
{
"name": "variable",
"comment": "Create this object with `variable` = `nothing`, then add assign a cost curve or time-series of `variable_cost` using the [`set_variable_cost!`](@ref) function, which will automatically update this parameter",
"null_value": "nothing",
"data_type": "Union{Nothing, TimeSeriesKey, CostCurve{PiecewiseIncrementalCurve}}"
},
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "time_frame",
"comment": "the saturation time_frame in minutes to provide reserve contribution",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "sustained_time",
"comment": "the time in seconds that the reserve contribution must sustained at a specified level",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"default": "3600.0",
"validation_action": "error"
},
{
"name": "max_participation_factor",
"comment": "the maximum portion [0, 1.0] of the reserve that can be contributed per device",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "1.0",
"validation_action": "error"
},
{
"name": "deployed_fraction",
"comment": "Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "0.0",
"validation_action": "error"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Reserve{T}"
},
{
"struct_name": "VariableReserve",
"docstring": "A reserve product with a time-varying procurement requirement, such as a higher requirement during hours with an expected high load or high ramp.\n\nThis reserve product includes online generators that can respond right away after an unexpected contingency, such as a transmission line or generator outage. When defining the reserve, the `ReserveDirection` must be specified to define this as a [`ReserveUp`](@ref), [`ReserveDown`](@ref), or [`ReserveSymmetric`](@ref). To model the time varying requirement, a [\"`requirement`\" time series should be added](@ref ts_data) to this reserve",
"parametric": "ReserveDirection",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "time_frame",
"comment": "the saturation time_frame in minutes to provide reserve contribution",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "requirement",
"comment": "the required quantity of the product should be scaled by a TimeSeriesData",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "sustained_time",
"comment": "the time in seconds reserve contribution must sustained at a specified level",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"default": "3600.0",
"validation_action": "error"
},
{
"name": "max_output_fraction",
"comment": "the maximum fraction of each device's output that can be assigned to the service",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "1.0",
"validation_action": "error"
},
{
"name": "max_participation_factor",
"comment": "the maximum portion [0, 1.0] of the reserve that can be contributed per device",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "1.0",
"validation_action": "error"
},
{
"name": "deployed_fraction",
"comment": "Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "0.0",
"validation_action": "error"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Reserve{T}"
},
{
"struct_name": "VariableReserveNonSpinning",
"docstring": "A non-spinning reserve product with a time-varying procurement requirement, such as a higher requirement during hours with an expected high load or high ramp.\n\nThis reserve product includes back-up generators that might not be currently synchronized with the power system, but can come online quickly after an unexpected contingency, such as a transmission line or generator outage. To model the time varying requirement, a [\"`requirement`\" time series should be added](@ref ts_data) to this reserve.\n\nThis is only an upwards reserve. For faster-responding upwards or downwards reserves from components already synchronized with the system, see [`VariableReserve`](@ref)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "time_frame",
"comment": "the saturation time_frame in minutes to provide reserve contribution",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "error"
},
{
"name": "requirement",
"comment": "the required quantity of the product should be scaled by a TimeSeriesData",
"null_value": "0.0",
"data_type": "Float64",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "sustained_time",
"comment": "the time in seconds reserve contribution must sustained at a specified level",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"default": "14400.0",
"validation_action": "error"
},
{
"name": "max_output_fraction",
"comment": "the maximum fraction of each device's output that can be assigned to the service",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "1.0",
"validation_action": "error"
},
{
"name": "max_participation_factor",
"comment": "the maximum portion [0, 1.0] of the reserve that can be contributed per device",
"null_value": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "1.0",
"validation_action": "error"
},
{
"name": "deployed_fraction",
"comment": "Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0",
"null_value": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"default": "0.0",
"validation_action": "error"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "ReserveNonSpinning"
},
{
"struct_name": "AGC",
"docstring": "Automatic generation control (AGC) for the system or a certain `Area` within the system.\n\nThis model uses a proportional–integral–derivative (PID) control to simulate a \"smooth\" response of the AGC to the area control error (ACE). Refer to [\"AGC Simulation Model for Large Renewable Energy Penetration Studies.\"](https://doi.org/10.1109/NAPS50074.2021.9449687)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bias",
"comment": "Area frequency bias in MW/Hz",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "K_p",
"comment": "PID Proportional Constant",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "K_i",
"comment": "PID Integral Constant",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "K_d",
"comment": "PID Derivative Constant",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "delta_t",
"comment": "PID Discretization period [Seconds]",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "area",
"comment": "the area controlled by the AGC",
"null_value": "Area(nothing)",
"data_type": "Union{Nothing, Area}",
"default": "nothing"
},
{
"name": "initial_ace",
"comment": "Initial condition for ACE",
"default": "0.0",
"null_value": "0.0",
"data_type": "Float64"
},
{
"name": "reserves",
"data_type": "Vector{Reserve}",
"comment": "Reserves that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Service"
},
{
"struct_name": "AVRFixed",
"docstring": "Parameters of a AVR that returns a fixed voltage to the rotor winding",
"fields": [
{
"name": "Vf",
"comment": "Fixed voltage field applied to the rotor winding in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) Fixed AVR has no [states](@ref S)",
"internal_default": "Vector{Symbol}()",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) Fixed AVR has no [states](@ref S)",
"null_value": 0,
"internal_default": 0,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) Fixed AVR has no [states](@ref S)",
"internal_default": "Vector{StateTypes}()",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "AVRSimple",
"docstring": "Parameters of a simple proportional AVR in the derivative of EMF\ni.e. an integrator controller on EMF",
"fields": [
{
"name": "Kv",
"comment": "Proportional Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVf: field voltage",
"internal_default": "[:Vf]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) Fixed AVR has 1 [state](@ref S)",
"internal_default": 1,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) Simple AVR has 1 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "SEXS",
"docstring": "Parameters of Simplified Excitation System Model - SEXS in PSSE",
"fields": [
{
"name": "Ta_Tb",
"comment": "Ratio of lead and lag time constants",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tb",
"comment": "Lag time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
}
},
{
"name": "K",
"comment": "Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Te",
"comment": "Field circuit time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "V_lim",
"comment": "Field voltage limits",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\tVf: Voltage field,\tVr: Lead-lag state",
"internal_default": "[:Vf, :Vr]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) SEXS has 2 states",
"internal_default": 2,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) SEXS has 2 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "ESDC1A",
"docstring": "Self-excited shunt fields with the voltage regulator operating in a mode commonly termed buck-boost. \nParameters of IEEE Std 421.5 Type DC1A Excitacion System. This model corresponds to ESDC1A in PSSE and PSLF",
"fields": [
{
"name": "Tr",
"comment": "Voltage Measurement Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Amplifier Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 10,
"max": 500
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Amplifier Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Regulator input Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tc",
"comment": "Regulator input Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vr_lim",
"comment": "Voltage regulator limits (regulator output) (Vi_min, Vi_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Ke",
"comment": "Exciter constant related to self-excited field",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Te",
"comment": "Exciter time constant, integration rate associated with exciter control",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 1
},
"validation_action": "error"
},
{
"name": "Kf",
"comment": "Excitation control system stabilizer gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 0.3
},
"validation_action": "error"
},
{
"name": "Tf",
"comment": "Excitation control system stabilizer time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "error"
},
{
"name": "switch",
"comment": "Switch",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "E_sat",
"comment": "Exciter output voltage for saturation factor: (E1, E2)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Se",
"comment": "Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "saturation_coeffs",
"comment": "(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V",
"data_type": "Tuple{Float64, Float64}",
"null_value": "(0.0, 0.0)",
"default": "PowerSystems.get_avr_saturation(E_sat, Se)"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVt: Terminal Voltage,\n\tVr1: input lead lag,\n\tVr2: Regulator Output,\n\tVf: Exciter Output, \n\tVr3: Rate feedback integrator",
"internal_default": "[:Vt, :Vr1, :Vr2, :Vf, :Vr3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The ESDC1A has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) ESDC1A has 5 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "ESDC2A",
"docstring": "Is used to represent field-controlled dc commutator exciters with continuously acting voltage regulators having power supplies derived from the generator or auxiliaries bus.\nParameters of IEEE Std 421.5 Type DC2A Excitacion System. This model corresponds to ESDC2A in PSSE and PSLF",
"fields": [
{
"name": "Tr",
"comment": "Voltage Measurement Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Amplifier Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 10,
"max": 500
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Amplifier Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Regulator input Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tc",
"comment": "Regulator input Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vr_lim",
"comment": "Voltage regulator limits (regulator output) (Vi_min, Vi_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Ke",
"comment": "Exciter constant related to self-excited field",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": -1,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Te",
"comment": "Exciter time constant, integration rate associated with exciter control",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 2
},
"validation_action": "error"
},
{
"name": "Kf",
"comment": "Excitation control system stabilizer gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "Tf",
"comment": "Excitation control system stabilizer time constant. Appropiate Data: 5.0 <= Tf/Kf <= 15.0",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 1.5
},
"validation_action": "error"
},
{
"name": "switch",
"comment": "Switch",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "E_sat",
"comment": "Exciter output voltage for saturation factor: (E1, E2)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Se",
"comment": "Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "saturation_coeffs",
"comment": "(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V",
"data_type": "Tuple{Float64, Float64}",
"null_value": "(0.0, 0.0)",
"default": "PowerSystems.get_avr_saturation(E_sat, Se)"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVt: Terminal Voltage,\n\tVr1: input lead lag,\n\tVr2: Regulator Output,\n\tVf: Exciter Output, \n\tVr3: Rate feedback integrator",
"internal_default": "[:Vt, :Vr1, :Vr2, :Vf, :Vr3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The ESDC2A has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) ESDC2A has 5 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "IEEET1",
"docstring": "1968 IEEE type 1 excitation system model",
"fields": [
{
"name": "Tr",
"comment": "Voltage Measurement Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Amplifier Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 10,
"max": 500
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Amplifier Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Vr_lim",
"comment": "Voltage regulator limits (regulator output) (Vi_min, Vi_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Ke",
"comment": "Exciter constant related to self-excited field",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": -1,
"max": 1
}
},
{
"name": "Te",
"comment": "Exciter time constant, integration rate associated with exciter control",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 1
},
"validation_action": "error"
},
{
"name": "Kf",
"comment": "Excitation control system stabilizer gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "Tf",
"comment": "Excitation control system stabilizer time constant. Appropiate Data: 5 <= Tf/Kf <= 15",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "error"
},
{
"name": "switch",
"comment": "Switch",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "E_sat",
"comment": "Exciter output voltage for saturation factor: (E1, E2)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Se",
"comment": "Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "saturation_coeffs",
"comment": "(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V",
"data_type": "Tuple{Float64, Float64}",
"null_value": "(0.0, 0.0)",
"default": "PowerSystems.get_avr_saturation(E_sat, Se)"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVt: Terminal Voltage,\n\tVr: Regulator Output,\n\tVf: Exciter Output, \n\tVr3: Rate feedback integrator",
"internal_default": "[:Vt, :Vr1, :Vf, :Vr2]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The IEEET1 has 4 states",
"internal_default": 4,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) IEEET1 I has 4 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "AVRTypeI",
"docstring": "Parameters of an Automatic Voltage Regulator Type I - Resembles IEEE Type DC1",
"fields": [
{
"name": "Ka",
"comment": "Amplifier Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Ke",
"comment": "Field circuit integral deviation",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Kf",
"comment": "Stabilizer Gain in s * pu/pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Ta",
"comment": "Amplifier Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Te",
"comment": "Field Circuit Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tf",
"comment": "Stabilizer Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tr",
"comment": "Voltage Measurement Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Va_lim",
"comment": "Limits for pi controler `(Va_min, Va_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Ae",
"comment": "1st ceiling coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Be",
"comment": "2nd ceiling coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVf: Voltage field,\n\tVr1: Amplifier State,\n\tVr2: Stabilizing Feedback State,\n\tVm: Measured voltage",
"internal_default": "[:Vf, :Vr1, :Vr2, :Vm]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The AVR Type I has 4 states",
"internal_default": 4,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) AVR Type I has 4 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "AVRTypeII",
"docstring": "Parameters of an Automatic Voltage Regulator Type II - Typical static exciter model",
"fields": [
{
"name": "K0",
"comment": "Regulator Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T1",
"comment": "First Pole in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T2",
"comment": "First zero in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T3",
"comment": "First Pole in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T4",
"comment": "First zero in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Te",
"comment": "Field Circuit Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tr",
"comment": "Voltage Measurement Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Va_lim",
"comment": "Limits for pi controler `(Va_min, Va_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Ae",
"comment": "1st ceiling coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Be",
"comment": "2nd ceiling coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVf: Voltage field,\n\tVr1: First Lead-Lag state,\n\tVr2: Second lead-lag state,\n\tVm: Measured voltage",
"internal_default": "[:Vf, :Vr1, :Vr2, :Vm]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) AVR Type II has 4 states",
"internal_default": 4,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) AVR Type II has 4 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "SCRX",
"docstring": "This exciter is based on an IEEE type SCRX solid state exciter. The output field voltage is varied by a control system to maintain the system voltage at Vref. Please note that this exciter model has no initialization capabilities - this means that it will respond to whatever inputs it receives regardless of the state of the machine model",
"fields": [
{
"name": "Ta_Tb",
"comment": "Lead input constant ratio",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0.05,
"max": 0.3
},
"validation_action": "error"
},
{
"name": "Tb",
"comment": "Lag input constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 5,
"max": 20
},
"validation_action": "error"
},
{
"name": "K",
"comment": "Regulator Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 20,
"max": 100
},
"validation_action": "warn"
},
{
"name": "Te",
"comment": "Regulator Time Constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Efd_lim",
"comment": "Field Voltage regulator limits (regulator output) (Efd_min, Efd_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "switch",
"comment": "Switch",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "rc_rfd",
"comment": "Field current capability. Set = 0 for negative current capability. Typical value 10",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVr1: First integrator,\n\tVr2: Second integrator",
"internal_default": "[:Vr1, :Vr2]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) SCRX has 2 states",
"internal_default": 2,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) SCRX has 2 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Hybrid]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "ESAC1A",
"docstring": "This excitation systems consists of an alternator main exciter feeding its output via non-controlled rectifiers.\nThe exciter does not employ self-excitation, and the voltage regulator power is taken from a source that is not affected by external transients.\nParameters of IEEE Std 421.5 Type AC1A Excitacion System. This model corresponds to ESAC1A in PSSE and PSLF",
"fields": [
{
"name": "Tr",
"comment": "Regulator input filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Regulator denominator (lag) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Tc",
"comment": "Regulator numerator (lead) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Regulator output gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1000
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Regulator output time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
}
},
{
"name": "Va_lim",
"comment": "Limits for regulator output `(Va_min, Va_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Te",
"comment": "Exciter field time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 2
},
"validation_action": "error"
},
{
"name": "Kf",
"comment": "Rate feedback excitation system stabilizer gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "Tf",
"comment": "Rate feedback time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 1.5
},
"validation_action": "error"
},
{
"name": "Kc",
"comment": "Rectifier loading factor proportional to commutating reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Kd",
"comment": "Demagnetizing factor, function of exciter alternator reactances",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Ke",
"comment": "Exciter field proportional constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "E_sat",
"comment": "Exciter output voltage for saturation factor: (E1, E2)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Se",
"comment": "Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Vr_lim",
"comment": "Limits for exciter field voltage: `(Vr_min, Vr_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "saturation_coeffs",
"comment": "(**Do not modify.**) Coefficients (A,B) of the function: Se(x) = B(x - A)^2/x",
"data_type": "Tuple{Float64, Float64}",
"null_value": "(0.0, 0.0)",
"default": "PowerSystems.get_avr_saturation(E_sat, Se)"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tVr1: Lead-lag state,\n\tVr2: Regulator output state,\n\tVe: Integrator output state,\n\tVr3: Feedback output state",
"internal_default": "[:Vm, :Vr1, :Vr2, :Ve, :Vr3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ESAC1A has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) ESAC1A has 5 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "EXAC1A",
"docstring": "Modified ESAC1A. This excitation systems consists of an alternator main exciter feeding its output via non-controlled rectifiers.\nThe exciter does not employ self-excitation, and the voltage regulator power is taken from a source that is not affected by external transients.\nParameters of IEEE Std 421.5 Type AC1A Excitacion System. EXAC1A in PSSE and PSLF",
"fields": [
{
"name": "Tr",
"comment": "Regulator input filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Regulator denominator (lag) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Tc",
"comment": "Regulator numerator (lead) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Regulator output gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1000
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Regulator output time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
}
},
{
"name": "Va_lim",
"comment": "Limits for regulator output `(Va_min, Va_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Te",
"comment": "Exciter field time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 2
},
"validation_action": "error"
},
{
"name": "Kf",
"comment": "Rate feedback excitation system stabilizer gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "Tf",
"comment": "Rate feedback time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 1.5
},
"validation_action": "error"
},
{
"name": "Kc",
"comment": "Rectifier loading factor proportional to commutating reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Kd",
"comment": "Demagnetizing factor, function of exciter alternator reactances",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Ke",
"comment": "Exciter field proportional constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "E_sat",
"comment": "Exciter output voltage for saturation factor: (E1, E2)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Se",
"comment": "Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Vr_lim",
"comment": "Limits for exciter field voltage: `(Vr_min, Vr_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "saturation_coeffs",
"comment": "(**Do not modify.**) Coefficients (A,B) of the function: Se(x) = B(x - A)^2/x",
"data_type": "Tuple{Float64, Float64}",
"null_value": "(0.0, 0.0)",
"default": "PowerSystems.get_avr_saturation(E_sat, Se)"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tVr1: Lead-lag state,\n\tVr2: Regulator output state,\n\tVe: Integrator output state,\n\tVr3: Feedback output state",
"internal_default": "[:Vm, :Vr1, :Vr2, :Ve, :Vr3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) EXAC1A has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) EXAC1A has 5 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "EXAC1",
"docstring": "Modified ESAC1A. This excitation systems consists of an alternator main exciter feeding its output via non-controlled rectifiers.\nThe exciter does not employ self-excitation, and the voltage regulator power is taken from a source that is not affected by external transients.\nParameters of IEEE Std 421.5 Type AC1A. EXAC1 in PSSE and PSLF",
"fields": [
{
"name": "Tr",
"comment": "Regulator input filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Regulator denominator (lag) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Tc",
"comment": "Regulator numerator (lead) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Regulator output gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1000
}
},
{
"name": "Ta",
"comment": "Regulator output time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "Vr_lim",
"comment": "Limits for regulator output `(Vr_min, Vr_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Te",
"comment": "Exciter field time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 2
},
"validation_action": "error"
},
{
"name": "Kf",
"comment": "Rate feedback excitation system stabilizer gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "Tf",
"comment": "Rate feedback time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 1.5
},
"validation_action": "error"
},
{
"name": "Kc",
"comment": "Rectifier loading factor proportional to commutating reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Kd",
"comment": "Demagnetizing factor, function of exciter alternator reactances",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Ke",
"comment": "Exciter field proportional constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "E_sat",
"comment": "Exciter output voltage for saturation factor: (E1, E2)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Se",
"comment": "Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "saturation_coeffs",
"comment": "(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V",
"data_type": "Tuple{Float64, Float64}",
"null_value": "(0.0, 0.0)",
"default": "PowerSystems.get_avr_saturation(E_sat, Se)"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tVr1: Lead-lag state,\n\tVr2: Regulator output state,\n\tVe: Integrator output state,\n\tVr3: Feedback output state",
"internal_default": "[:Vm, :Vr1, :Vr2, :Ve, :Vr3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) EXAC1 has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) EXAC1 has 5 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "EXAC2",
"docstring": "Modified AC2. This excitation systems consists of an alternator main exciter feeding its output via non-controlled rectifiers.\nThe exciter does not employ self-excitation, and the voltage regulator power is taken from a source that is not affected by external transients.\nParameters of IEEE Std 421.5 Type AC2A Excitacion System. The alternator main exciter is used, feeding its output via non-controlled rectifiers. The Type AC2C model is similar to that of Type AC1C except for the inclusion of exciter time constant compensation and exciter field current limiting elements. EXAC2 in PSSE and PSLF",
"fields": [
{
"name": "Tr",
"comment": "Regulator input filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Regulator denominator (lag) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Tc",
"comment": "Regulator numerator (lead) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Regulator output gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1000
}
},
{
"name": "Ta",
"comment": "Regulator output time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "Va_lim",
"comment": "Limits for regulator output `(Va_min, Va_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Kb",
"comment": "Second Stage regulator gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 500
},
"validation_action": "error"
},
{
"name": "Vr_lim",
"comment": "Limits for exciter field voltage `(Vr_min, Vr_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Te",
"comment": "Exciter field time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 2
},
"validation_action": "error"
},
{
"name": "Kl",
"comment": "Exciter field current limiter gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1.1
},
"validation_action": "warn"
},
{
"name": "Kh",
"comment": "Exciter field current regulator feedback gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1.1
},
"validation_action": "warn"
},
{
"name": "Kf",
"comment": "Rate feedback excitation system stabilizer gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "Tf",
"comment": "Rate feedback time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "error"
},
{
"name": "Kc",
"comment": "Rectifier loading factor proportional to commutating reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Kd",
"comment": "Demagnetizing factor, function of exciter alternator reactances",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Ke",
"comment": "Exciter field proportional constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "V_lr",
"comment": "Maximum exciter field current",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "E_sat",
"comment": "Exciter output voltage for saturation factor: (E1, E2)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Se",
"comment": "Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "saturation_coeffs",
"comment": "(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V",
"data_type": "Tuple{Float64, Float64}",
"null_value": "(0.0, 0.0)",
"default": "PowerSystems.get_avr_saturation(E_sat, Se)"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tVr1: Lead-lag state,\n\tVr2: Regulator output state,\n\tVe: Integrator output state,\n\tVr3: Feedback output state",
"internal_default": "[:Vm, :Vr1, :Vr2, :Ve, :Vr3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) EXAC2 has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) EXAC2 has 5 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "ESAC6A",
"docstring": "Modified AC6A. Used to represent field-controlled alternator-rectifier excitation systems with system-supplied electronic voltage regulators. \nParameters of IEEE Std 421.5 Type AC6A Excitacion System. ESAC6A in PSSE and PSLF",
"fields": [
{
"name": "Tr",
"comment": "Regulator input filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Regulator output gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1000
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Regulator output lag time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "Tk",
"comment": "Voltage Regulator lead time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Regulator denominator (lag) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Tc",
"comment": "Regulator numerator (lead) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Va_lim",
"comment": "Limits for regulator output `(Va_min, Va_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Vr_lim",
"comment": "Limits for exciter field voltage `(Vr_min, Vr_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Te",
"comment": "Exciter field time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 2
},
"validation_action": "error"
},
{
"name": "VFE_lim",
"comment": "Exciter field current limiter reference",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": -5,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Kh",
"comment": "Exciter field current regulator feedback gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100
},
"validation_action": "warn"
},
{
"name": "VH_max",
"comment": "Exciter field current limiter maximum output",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100
},
"validation_action": "warn"
},
{
"name": "Th",
"comment": "Exciter field current limiter denominator (lag) time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Tj",
"comment": "Exciter field current limiter numerator (lead) time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Kc",
"comment": "Rectifier loading factor proportional to commutating reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Kd",
"comment": "Demagnetizing factor, function of exciter alternator reactances",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 2
},
"validation_action": "warn"
},
{
"name": "Ke",
"comment": "Exciter field proportional constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 2
},
"validation_action": "warn"
},
{
"name": "E_sat",
"comment": "Exciter output voltage for saturation factor: (E1, E2)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Se",
"comment": "Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "saturation_coeffs",
"comment": "(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V",
"data_type": "Tuple{Float64, Float64}",
"null_value": "(0.0, 0.0)",
"default": "PowerSystems.get_avr_saturation(E_sat, Se)"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tVr1: Lead-lag state,\n\tVr2: Regulator output state,\n\tVe: Integrator output state,\n\tVr3: Feedback output state",
"internal_default": "[:Vm, :Vr1, :Vr2, :Ve, :Vr3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ESAC6A has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) ESAC6A has 5 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Hybrid]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "ESAC8B",
"docstring": "Excitation System AC8B. Used to represent the Basler Digital Excitation Control System (DECS) with PID controller in PSSE.",
"fields": [
{
"name": "Tr",
"comment": "Regulator input filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Kp",
"comment": "Regulator proportional PID gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ki",
"comment": "Regulator integral PID gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Kd",
"comment": "Regulator derivative PID gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Td",
"comment": "Regulator derivative PID time constant.",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Regulator output gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1000
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Regulator output lag time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "Vr_lim",
"comment": "Limits for exciter field voltage `(Vr_min, Vr_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Te",
"comment": "Exciter field time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 2
},
"validation_action": "error"
},
{
"name": "Ke",
"comment": "Exciter field proportional constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 2
},
"validation_action": "warn"
},
{
"name": "E_sat",
"comment": "Exciter output voltage for saturation factor: (E1, E2)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Se",
"comment": "Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "saturation_coeffs",
"comment": "(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V",
"data_type": "Tuple{Float64, Float64}",
"null_value": "(0.0, 0.0)",
"default": "PowerSystems.get_avr_saturation(E_sat, Se)"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tx_i: Internal PI-block state,\n\tx_d: Internal Derivative-block state,\n\tVr: Voltage regulator state,\n\tEfd: Exciter output state",
"internal_default": "[:Vm, :x_i, :x_d, :Vr, :Efd]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ESAC8B has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) ESAC8B has 5 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential, StateTypes.Hybrid, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "ESST1A",
"docstring": "This excitation system supplies power through a transformer from the generator terminals and its regulated by a controlled rectifier (via thyristors).\nParameters of IEEE Std 421.5 Type ST1A Excitacion System. ESST1A in PSSE and PSLF",
"fields": [
{
"name": "UEL_flags",
"comment": "Code input for Underexcitization limiter (UEL) entry. Not supported",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 3
},
"validation_action": "warn"
},
{
"name": "PSS_flags",
"comment": "Code input for Power System Stabilizer (PSS) or (VOS) entry",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 2
}
},
{
"name": "Tr",
"comment": "Regulator input filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.1
},
"validation_action": "warn"
},
{
"name": "Vi_lim",
"comment": "Voltage error limits (regulator input) (Vi_min, Vi_max)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Tc",
"comment": "First regulator denominator (lead) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "First regulator denominator (lag) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
}
},
{
"name": "Tc1",
"comment": "Second regulator denominator (lead) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "Tb1",
"comment": "Second regulator denominator (lead) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Voltage regulator gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 50,
"max": 1000
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Voltage regulator time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "Va_lim",
"comment": "Limits for regulator output `(Va_min, Va_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Vr_lim",
"comment": "Limits for exciter output `(Vr_min, Vr_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Kc",
"comment": "Rectifier loading factor proportional to commutating reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "Kf",
"comment": "Rate feedback gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "Tf",
"comment": "Rate feedback time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 1.5
},
"validation_action": "error"
},
{
"name": "K_lr",
"comment": "Exciter output current limiter gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 5
},
"validation_action": "warn"
},
{
"name": "I_lr",
"comment": "Exciter output current limit reference",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 5
},
"validation_action": "warn"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tVr1: First Lead-lag state,\n\tVr2: Second lead-lag state,\n\tVa: Regulator output state,\n\tVr3: Feedback output state",
"internal_default": "[:Vm, :Vr1, :Vr2, :Va, :Vr3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ST1A has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) ST1A has 5 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "EXPIC1",
"docstring": "Generic Proportional/Integral Excitation System",
"fields": [
{
"name": "Tr",
"comment": "Regulator input filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Voltage regulator gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 1,
"max": 500
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Voltage regulator time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "Va_lim",
"comment": "Limits for pi controler `(Vr_min, Vr_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Ta_2",
"comment": "Voltage regulator time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Ta_3",
"comment": "Voltage regulator time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ta_4",
"comment": "Voltage regulator time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vr_lim",
"comment": "Voltage regulator limits (regulator output) (Vi_min, Vi_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Kf",
"comment": "Rate feedback gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "Tf_1",
"comment": "Rate Feedback time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 15
},
"validation_actions": "error"
},
{
"name": "Tf_2",
"comment": "Rate Feedback time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 5
},
"validation_action": "warn"
},
{
"name": "Efd_lim",
"comment": "Field Voltage regulator limits (regulator output) (Efd_min, Efd_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Ke",
"comment": "Exciter constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Te",
"comment": "Exciter time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 2
},
"validation_action": "warn"
},
{
"name": "E_sat",
"comment": "Exciter output voltage for saturation factor: (E1, E2)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Se",
"comment": "Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Kp",
"comment": "Potential source gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 5
},
"validation_action": "warn"
},
{
"name": "Ki",
"comment": "current source gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1.1
}
},
{
"name": "Kc",
"comment": "Exciter regulation factor",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 2
},
"validation_action": "warn"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "saturation_coeffs",
"comment": "(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V",
"data_type": "Tuple{Float64, Float64}",
"null_value": "(0.0, 0.0)",
"default": "PowerSystems.get_avr_saturation(E_sat, Se)"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tVr1: First Lead-lag state,\n\tVr2: Second regulator lead-lag state,\n\tVr2: Third regulator lead-lag state \n\tVf: Exciter output \n\tVr3: First feedback integrator,\n\tVr4: second feedback integrator",
"internal_default": "[:Vm, :Vr1, :Vr2, :Vf, :Vr3, :Vr4]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) EXPIC1 has 6 states",
"internal_default": 6,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) EXPIC has 6 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Hybrid]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "ESST4B",
"docstring": "In these excitation systems, voltage (and also current in compounded systems) is transformed to an appropriate level. Rectifiers, either controlled or non-controlled, provide the necessary direct current for the generator field.\nParameters of IEEE Std 421.5 Type ST4B Excitacion System. ESST4B in PSSE and PSLF",
"fields": [
{
"name": "Tr",
"comment": "Regulator input filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "K_pr",
"comment": "Regulator propotional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 75
},
"validation_action": "warn"
},
{
"name": "K_ir",
"comment": "Regulator integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 75
},
"validation_action": "warn"
},
{
"name": "Vr_lim",
"comment": "Voltage regulator limits (Vi_min, Vi_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Ta",
"comment": "Voltage regulator time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "K_pm",
"comment": "Voltage regulator proportional gain output",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1.2
},
"validation_action": "warn"
},
{
"name": "K_im",
"comment": "Voltage regulator integral gain output",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 18
},
"validation_action": "warn"
},
{
"name": "Vm_lim",
"comment": "Limits for inner loop output `(Vm_min, Vm_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Kg",
"comment": "Feedback gain constant of the inner loop field regulator",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1.1
},
"validation_action": "warn"
},
{
"name": "Kp",
"comment": "Potential circuit (voltage) gain coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "Ki",
"comment": "Compound circuit (current) gain coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1.1
},
"validation_action": "warn"
},
{
"name": "VB_max",
"comment": "Maximum available exciter voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 1,
"max": 20
},
"validation_action": "warn"
},
{
"name": "Kc",
"comment": "Rectifier loading factor proportional to commutating reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "Xl",
"comment": "Reactance associated with potential source",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "θp",
"comment": "Potential circuit phase angle (degrees)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": -90,
"max": 90
},
"validation_action": "error"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "θp_rad",
"comment": "(**Do not modify.**) Potential circuit phase angle (radians)",
"null_value": 0,
"default": "θp*π*inv(180)",
"data_type": "Float64"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tVt: Sensed Terminal Voltage,\n\tVr1: Regulator Integrator,\n\tVr2: Regulator Output,\n\tVm: Output integrator",
"internal_default": "[:Vt, :Vr1, :Vr2, :Vm]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ST4B has 4 states",
"internal_default": 4,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) ST4B has 4 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "ST6B",
"docstring": "In these excitation systems, voltage (and also current in compounded systems) is transformed to an appropriate level. Rectifiers, either controlled or non-controlled, provide the necessary direct current for the generator field.\nParameters of IEEE Std 421.5 Type ST6B Excitacion System. ST6B in PSSE and PSLF",
"fields": [
{
"name": "OEL_Flag",
"comment": "OEL Flag for ST6B: 1: before HV gate, 2: after HV gate",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 2
}
},
{
"name": "Tr",
"comment": "Regulator input filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_pa",
"comment": "Regulator proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_ia",
"comment": "Regulator integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_da",
"comment": "Regulator derivative gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T_da",
"comment": "Voltage regulator derivative channel time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Va_lim",
"comment": "Regulator output limits (Vi_min, Vi_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "K_ff",
"comment": "Pre-control gain of the inner loop field regulator",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_m",
"comment": "Forward gain of the inner loop field regulator",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_ci",
"comment": "Exciter output current limit adjustment gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_lr",
"comment": "Exciter output current limiter gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "I_lr",
"comment": "Exciter current limiter reference",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vr_lim",
"comment": "Voltage regulator limits (Vi_min, Vi_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Kg",
"comment": "Feedback gain constant of the inner loop field regulator",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tg",
"comment": "Feedback time constant of the inner loop field voltage regulator in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tx_i: Regulator Integrator,\n\tx_d: Regulator Derivative,\n\tVg: Regulator Feedback",
"internal_default": "[:Vm, :x_i, :x_d, :Vg]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ST6B has 4 states",
"internal_default": 4,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) ST6B has 4 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "ST8C",
"docstring": "In these excitation systems, voltage (and also current in compounded systems) is transformed to an appropriate level. Rectifiers, either controlled or non-controlled, provide the necessary direct current for the generator field.\nParameters of IEEE Std 421.5 Type ST8C Excitacion System. ST8C in PSSE and PSLF",
"fields": [
{
"name": "OEL_Flag",
"comment": "OEL Flag for ST8C: <2: Summation at Voltage Error, 2: OEL takeover at gate",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 2
}
},
{
"name": "UEL_Flag",
"comment": "UEL Flag for ST8C: <2: Summation at Voltage Error, 2: UEL takeover at gate",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 2
}
},
{
"name": "SCL_Flag",
"comment": "SCL Flag for ST8C: <2: Summation at Voltage Error, 2: SCL Takeover at UEL and OEL gates",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 2
}
},
{
"name": "SW1_Flag",
"comment": "SW1 Flag for Power Source Selector for ST8C: <2: Source from generator terminal voltage, 2: Independent power source",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 2
}
},
{
"name": "Tr",
"comment": "Regulator input filter time constant in seconds",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_pr",
"comment": "Regulator proportional gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_ir",
"comment": "Regulator integral gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vpi_lim",
"comment": "Regulator input limits (Vpi_min, Vpi_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "K_pa",
"comment": "Field current regulator proportional gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_ia",
"comment": "Field current regulator integral gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Va_lim",
"comment": "Field current regulator output limits (Va_min, Va_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "K_a",
"comment": "Field current regulator proportional gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T_a",
"comment": "Controlled rectifier bridge equivalent time constant in seconds",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vr_lim",
"comment": "Voltage regulator limits (Vr_min, Vr_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "K_f",
"comment": "Exciter field current feedback gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T_f",
"comment": "Field current feedback time constant in seconds",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_c1",
"comment": "Rectifier loading factor proportional to commutating reactance (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_p",
"comment": "Potential circuit (voltage) gain coefficient (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_i1",
"comment": "Potential circuit (current) gain coefficient (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "X_l",
"comment": "Reactance associated with potential source (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "θ_p",
"comment": "Potential circuit phase angle (degrees)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "VB1_max",
"comment": "Maximum available exciter voltage (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_c2",
"comment": "Rectifier loading factor proportional to commutating reactance (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_i2",
"comment": "Potential circuit (current) gain coefficient (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "VB2_max",
"comment": "Maximum available exciter voltage (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Ifd_ref",
"comment": "Reference Field Current Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed terminal voltage,\n\tx_a1: Regulator Integrator state,\n\tx_a2: Field Current regulator state,\n\tx_a3: Controller rectifier bridge state,\n\tx_a4: Regulator Feedback state",
"internal_default": "[:Vm, :x_a1, :x_a2, :x_a3, :x_a4]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ST8C has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) ST8C has 5 states",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "EXST1",
"docstring": "IEEE Type ST1 Excitation System (PTI version)",
"fields": [
{
"name": "Tr",
"comment": "Voltage Measurement Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vi_lim",
"comment": "Voltage input limits (Vi_min, Vi_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Tc",
"comment": "Numerator lead-lag (lead) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Denominator lead-lag (lag) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Amplifier Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Amplifier Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vr_lim",
"comment": "Voltage regulator limits (regulator output) (Vr_min, Vr_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Kc",
"comment": "Current field constant limiter multiplier",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Kf",
"comment": "Excitation control system stabilizer gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "Tf",
"comment": "Excitation control system stabilizer time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "error"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVm: Sensed Terminal Voltage,\n\tVrll: Lead-Lag state,\n\tVr: Regulator Output, \n\tVfb: Feedback state",
"internal_default": "[:Vm, :Vrll, :Vr, :Vfb]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The EXST1 has 4 states",
"internal_default": 4,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "EX4VSA",
"docstring": "IEEE Excitation System for Voltage Security Assesment",
"fields": [
{
"name": "Iflim",
"comment": "OEL Field current limit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "d",
"comment": "OEL parameter d",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "f",
"comment": "OEL parameter f",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Spar",
"comment": "OEL parameter Spar",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K1",
"comment": "OEL delay time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K2",
"comment": "OEL parameter K2",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Oel_lim",
"comment": "Oel integrator limits (Oel_min, Oel_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "G",
"comment": "AVR Exciter Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Numerator lead-lag (lag) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Denominator lead-lag (lag) time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Te",
"comment": "Exciter Time Constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "E_lim",
"comment": "Voltage regulator limits (regulator output) (E_min, E_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tVll: Lead-lag internal state,\n\tVex: Exciter Output, \n\toel: OEL integrator state",
"internal_default": "[:Vll, :Vex, :oel]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The EX4VSA has 3 states",
"internal_default": 3,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "AVR"
},
{
"struct_name": "BaseMachine",
"docstring": "Parameters of a Classic Machine: GENCLS in PSSE and PSLF",
"fields": [
{
"name": "R",
"comment": "Resistance after EMF in machine per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_p",
"comment": "Reactance after EMF in machine per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "eq_p",
"comment": "Fixed EMF behind the impedance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) BaseMachine has no [states](@ref S)",
"internal_default": "Vector{Symbol}()",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) BaseMachine has no states",
"internal_default": 0,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "RoundRotorMachine",
"docstring": "Parameters of 4-[states](@ref S) round-rotor synchronous machine with quadratic/exponential saturation:\nIEEE Std 1110 §5.3.2 (Model 2.2). GENROU or GENROE model in PSSE and PSLF",
"fields": [
{
"name": "R",
"comment": "Armature resistance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_p",
"data_type": "Float64",
"null_value": 0,
"comment": "Time constant of transient d-axis voltage",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_pp",
"data_type": "Float64",
"null_value": 0,
"comment": "Time constant of sub-transient d-axis voltage",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_p",
"data_type": "Float64",
"null_value": 0,
"comment": "Time constant of transient q-axis voltage",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_pp",
"data_type": "Float64",
"null_value": 0,
"comment": "Time constant of sub-transient q-axis voltage",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in d-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in q-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_p",
"comment": "Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_p",
"comment": "Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_pp",
"comment": "Sub-Transient reactance after EMF in d-axis per unit. Note: Xd_pp = Xq_pp",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xl",
"comment": "Stator leakage reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Se",
"comment": "Saturation factor at 1 and 1.2 pu flux: S(1.0) = B(|ψ_pp|-A)^2",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "γ_d1",
"comment": "(**Do not modify.**) γ_d1 parameter",
"internal_default": "(Xd_pp - Xl) / (Xd_p - Xl)",
"data_type": "Float64"
},
{
"name": "γ_q1",
"comment": "(**Do not modify.**) γ_q1 parameter",
"internal_default": "(Xd_pp - Xl) / (Xq_p - Xl)",
"data_type": "Float64"
},
{
"name": "γ_d2",
"comment": "(**Do not modify.**) γ_d2 parameter",
"internal_default": "(Xd_p - Xd_pp) / (Xd_p - Xl)^2",
"data_type": "Float64"
},
{
"name": "γ_q2",
"comment": "(**Do not modify.**) γ_q2 parameter",
"internal_default": "(Xq_p - Xd_pp) / (Xq_p - Xl)^2",
"data_type": "Float64"
},
{
"name": "γ_qd",
"comment": "(**Do not modify.**) γ_qd parameter",
"internal_default": "(Xq - Xl) / (Xd - Xl)",
"data_type": "Float64"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\teq_p: q-axis generator voltage behind the transient reactance,\n\ted_p: d-axis generator voltage behind the transient reactance,\n\tψ_kd: flux linkage in the first equivalent damping circuit in the d-axis,\n\tψ_kq: flux linkage in the first equivalent damping circuit in the d-axis",
"internal_default": "[:eq_p, :ed_p, :ψ_kd, :ψ_kq]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) RoundRotorMachine has 4 states",
"internal_default": 4,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "SalientPoleMachine",
"docstring": "Parameters of 3-[states](@ref S) salient-pole synchronous machine with quadratic/exponential saturation:\nIEEE Std 1110 §5.3.1 (Model 2.1). GENSAL or GENSAE model in PSSE and PSLF",
"fields": [
{
"name": "R",
"comment": "Armature resistance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_p",
"data_type": "Float64",
"null_value": 0,
"comment": "Time constant of transient d-axis voltage",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_pp",
"data_type": "Float64",
"null_value": 0,
"comment": "Time constant of sub-transient d-axis voltage",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_pp",
"data_type": "Float64",
"null_value": 0,
"comment": "Time constant of sub-transient q-axis voltage",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in d-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in q-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_p",
"comment": "Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_pp",
"comment": "Sub-Transient reactance after EMF in d-axis per unit. Note: Xd_pp = Xq_pp",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xl",
"comment": "Stator leakage reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Se",
"comment": "Saturation factor at 1 and 1.2 pu flux: Se(eq_p) = B(eq_p-A)^2",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "γ_d1",
"comment": "(**Do not modify.**) γ_d1 parameter",
"internal_default": "(Xd_pp - Xl) / (Xd_p - Xl)",
"data_type": "Float64"
},
{
"name": "γ_q1",
"comment": "(**Do not modify.**) γ_q1 parameter",
"internal_default": "(Xd_p - Xd_pp) / (Xd_p - Xl)",
"data_type": "Float64"
},
{
"name": "γ_d2",
"comment": "(**Do not modify.**) γ_d2 parameter",
"internal_default": "(Xd_p - Xd_pp) / (Xd_p - Xl)^2",
"data_type": "Float64"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\teq_p: q-axis generator voltage behind the transient reactance,\n\tψ_kd: flux linkage in the first equivalent damping circuit in the d-axis,\n\tψq_pp: phasonf of the subtransient flux linkage in the q-axis",
"internal_default": "[:eq_p, :ψ_kd, :ψq_pp]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) SalientPoleMachine has 3 states",
"internal_default": 3,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "AndersonFouadMachine",
"docstring": "Parameters of 6-[states](@ref S) synchronous machine: Anderson-Fouad model",
"fields": [
{
"name": "R",
"comment": "Resistance after EMF in machine per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in d-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in q-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_p",
"comment": "Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_p",
"comment": "Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_pp",
"comment": "Sub-Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_pp",
"comment": "Sub-Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_p",
"comment": "Time constant of transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_p",
"comment": "Time constant of transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_pp",
"comment": "Time constant of sub-transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_pp",
"comment": "Time constant of sub-transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tψq: q-axis stator flux,\n\tψd: d-axis stator flux,\n\teq_p: q-axis transient voltage,\n\ted_p: d-axis transient voltage,\n\teq_pp: q-axis subtransient voltage,\n\ted_pp: d-axis subtransient voltage",
"internal_default": "[:ψq, :ψd, :eq_p, :ed_p, :eq_pp, :ed_pp]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The states AndersonFouadMachine has 6 states",
"internal_default": 6,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "FullMachine",
"docstring": "Parameter of a full order flux stator-rotor model without zero sequence flux in the stator.\n The derivative of stator fluxes (ψd and ψq) is NOT neglected. Only one q-axis damping circuit is considered. All parameters are in machine per unit.\n Refer to Chapter 3 of [Power System Stability and Control by P. Kundur](https://www.accessengineeringlibrary.com/content/book/9781260473544) or Chapter 11 of [Power System Dynamics: Stability and Control, by J. Machowski, J. Bialek and J. Bumby](https://www.wiley.com/en-us/Power+System+Dynamics%3A+Stability+and+Control%2C+3rd+Edition-p-9781119526360), for more details.\n Note that the models are somewhat different (but equivalent) due to the different Park Transformation used in both books",
"fields": [
{
"name": "R",
"comment": "Resistance after EMF in machine per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "R_f",
"comment": "Field rotor winding resistance in per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "R_1d",
"comment": " Damping rotor winding resistance on d-axis in per unit. This value is denoted as RD in Machowski",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "R_1q",
"comment": "Damping rotor winding resistance on q-axis in per unit. This value is denoted as RQ in Machowski",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_d",
"comment": "Inductance of fictitious damping that represent the effect of the three-phase stator winding in the d-axis of the rotor, in per unit. This value is denoted as L_ad + L_l in Kundur (and Ld in Machowski)",
"null_value": 1,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_q",
"comment": "Inductance of fictitious damping that represent the effect of the three-phase stator winding in the q-axis of the rotor, in per unit. This value is denoted as L_aq + L_l in Kundur",
"null_value": 1,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_ad",
"comment": "Mutual inductance between stator winding and rotor field (and damping) winding inductance on d-axis, in per unit",
"null_value": 2,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_aq",
"comment": "Mutual inductance between stator winding and rotor damping winding inductance on q-axis, in per unit",
"null_value": 2,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_f1d",
"comment": "Mutual inductance between rotor field winding and rotor damping winding inductance on d-axis, in per unit",
"null_value": 1,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_ff",
"comment": "Field rotor winding inductance, in per unit",
"null_value": 2,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_1d",
"comment": "Inductance of the d-axis rotor damping circuit, in per unit",
"null_value": 1,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_1q",
"comment": "Inductance of the q-axis rotor damping circuit, in per unit",
"null_value": 1,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "inv_d_fluxlink",
"data_type": "Array{Float64,2}",
"internal_default": "inv([[-L_d L_ad L_ad]; [-L_ad L_ff L_f1d]; [-L_ad L_f1d L_1d]])",
"comment": "(**Do not modify.**) Equations 3.127, 3.130, 3.131 From Kundur"
},
{
"name": "inv_q_fluxlink",
"data_type": "Array{Float64,2}",
"internal_default": "inv([[-L_q L_aq]; [-L_aq L_1q]])",
"comment": "(**Do not modify.**) Equations 3.128, 3.132 From Kundur"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tψd: d-axis stator flux,\n\tψq: q-axis stator flux,\n\tψf: field rotor flux,\n\tψ1d: d-axis rotor damping flux,\n\tψ1q: q-axis rotor damping flux",
"internal_default": "[:ψd, :ψq, :ψf, :ψ1d, :ψ1q]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) FullMachine has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "SauerPaiMachine",
"docstring": "Parameters of synchronous machine: Sauer Pai model",
"fields": [
{
"name": "R",
"comment": "Resistance after EMF in machine per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in d-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in q-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_p",
"comment": "Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_p",
"comment": "Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_pp",
"comment": "Sub-Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_pp",
"comment": "Sub-Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xl",
"comment": "Stator Leakage Reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_p",
"comment": "Time constant of transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_p",
"comment": "Time constant of transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_pp",
"comment": "Time constant of sub-transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_pp",
"comment": "Time constant of sub-transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "γ_d1",
"data_type": "Float64",
"internal_default": "(Xd_pp-Xl)/(Xd_p-Xl)",
"comment": "(**Do not modify.**) Internal equation"
},
{
"name": "γ_q1",
"data_type": "Float64",
"internal_default": "(Xq_pp-Xl)/(Xq_p-Xl)",
"comment": "(**Do not modify.**) Internal equation"
},
{
"name": "γ_d2",
"data_type": "Float64",
"internal_default": "(Xd_p - Xd_pp) / (Xd_p - Xl)^2",
"comment": "(**Do not modify.**) Internal equation"
},
{
"name": "γ_q2",
"data_type": "Float64",
"internal_default": "(Xq_p - Xq_pp) / (Xq_p - Xl)^2",
"comment": "(**Do not modify.**) Internal equation"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tψq: q-axis stator flux,\n\tψd: d-axis stator flux,\n\teq_p: q-axis transient voltage,\n\ted_p: d-axis transient voltage\n\tψd_pp: subtransient flux linkage in the d-axis\n\tψq_pp: subtransient flux linkage in the q-axis",
"internal_default": "[:ψq, :ψd, :eq_p, :ed_p, :ψd_pp, :ψq_pp]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) SauerPaiMachine has 6 states",
"internal_default": 6,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "MarconatoMachine",
"docstring": "Parameters of 6-[states](@ref S) synchronous machine: Marconato model",
"fields": [
{
"name": "R",
"comment": "Resistance after EMF in machine per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in d-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in q-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_p",
"comment": "Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_p",
"comment": "Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_pp",
"comment": "Sub-Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_pp",
"comment": "Sub-Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_p",
"comment": "Time constant of transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_p",
"comment": "Time constant of transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_pp",
"comment": "Time constant of sub-transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_pp",
"comment": "Time constant of sub-transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T_AA",
"comment": "Time constant of d-axis additional leakage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "γd",
"data_type": "Float64",
"internal_default": "((Td0_pp*Xd_pp)/(Td0_p*Xd_p) )*(Xd-Xd_p)",
"comment": "(**Do not modify.**) Internal equation"
},
{
"name": "γq",
"data_type": "Float64",
"internal_default": "((Tq0_pp*Xq_pp)/(Tq0_p*Xq_p) )*(Xq-Xq_p)",
"comment": "(**Do not modify.**) Internal equation"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tψq: q-axis stator flux,\n\tψd: d-axis stator flux,\n\teq_p: q-axis transient voltage,\n\ted_p: d-axis transient voltage,\n\teq_pp: q-axis subtransient voltage,\n\ted_pp: d-axis subtransient voltage",
"internal_default": "[:ψq, :ψd, :eq_p, :ed_p, :eq_pp, :ed_pp]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) MarconatoMachine has 6 states",
"internal_default": 6,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "OneDOneQMachine",
"docstring": "Parameters of 4-[states](@ref S) synchronous machine: Simplified Marconato model\n The derivative of stator fluxes (ψd and ψq) is neglected and ωψd = ψd and\n ωψq = ψq is assumed (i.e. ω=1.0). This is standard when\n transmission network dynamics is neglected",
"fields": [
{
"name": "R",
"comment": "Resistance after EMF in machine per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in d-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in q-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_p",
"comment": "Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_p",
"comment": "Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_p",
"comment": "Time constant of transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_p",
"comment": "Time constant of transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\teq_p: q-axis transient voltage,\n\ted_p: d-axis transient voltage",
"internal_default": "[:eq_p, :ed_p]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) OneDOneQMachine has 2 states",
"internal_default": 2,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "SimpleAFMachine",
"docstring": "Parameters of 4-[states](@ref S) simplified Anderson-Fouad (SimpleAFMachine) model.\n The derivative of stator fluxes (ψd and ψq) is neglected and ωψd = ψd and\n ωψq = ψq is assumed (i.e. ω=1.0). This is standard when transmission network\n dynamics is neglected.\n If transmission dynamics is considered use the full order Anderson Fouad model",
"fields": [
{
"name": "R",
"comment": "Resistance after EMF in machine per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in d-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in q-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_p",
"comment": "Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_p",
"comment": "Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_pp",
"comment": "Sub-Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_pp",
"comment": "Sub-Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_p",
"comment": "Time constant of transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_p",
"comment": "Time constant of transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_pp",
"comment": "Time constant of sub-transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_pp",
"comment": "Time constant of sub-transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\teq_p: q-axis transient voltage,\n\ted_p: d-axis transient voltage,\n\teq_pp: q-axis subtransient voltage,\n\ted_pp: d-axis subtransient voltage",
"internal_default": "[:eq_p, :ed_p, :eq_pp, :ed_pp]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) SimpleAFMachine has 4 states",
"internal_default": 4,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "SimpleFullMachine",
"docstring": "Parameter of a full order flux stator-rotor model without zero sequence flux in the stator.\n The derivative of stator fluxes (ψd and ψq) is neglected. This is standard when\n transmission network dynamics is neglected. Only one q-axis damping circuit\n is considered. All per unit are in machine per unit.\n Refer to Chapter 3 of Power System Stability and Control by P. Kundur or Chapter 11 of Power System Dynamics: Stability and Control, by J. Machowski, J. Bialek and J. Bumby, for more details.\n Note that the models are somewhat different (but equivalent) due to the different Park Transformation used in both books",
"fields": [
{
"name": "R",
"comment": "Resistance after EMF in machine per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "R_f",
"comment": "Field rotor winding resistance in per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "R_1d",
"comment": " Damping rotor winding resistance on d-axis in per unit. This value is denoted as RD in Machowski",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "R_1q",
"comment": "Damping rotor winding resistance on q-axis in per unit. This value is denoted as RQ in Machowski",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_d",
"comment": "Inductance of fictitious damping that represent the effect of the three-phase stator winding in the d-axis of the rotor, in per unit. This value is denoted as L_ad + L_l in Kundur (and Ld in Machowski)",
"null_value": 1,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_q",
"comment": "Inductance of fictitious damping that represent the effect of the three-phase stator winding in the q-axis of the rotor, in per unit. This value is denoted as L_aq + L_l in Kundur",
"null_value": 1,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_ad",
"comment": "Mutual inductance between stator winding and rotor field (and damping) winding inductance on d-axis, in per unit",
"null_value": 2,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_aq",
"comment": "Mutual inductance between stator winding and rotor damping winding inductance on q-axis, in per unit",
"null_value": 1,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_f1d",
"comment": "Mutual inductance between rotor field winding and rotor damping winding inductance on d-axis, in per unit",
"null_value": 1,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_ff",
"comment": "Field rotor winding inductance, in per unit",
"null_value": 2,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_1d",
"comment": "Inductance of the d-axis rotor damping circuit, in per unit",
"null_value": 1,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "L_1q",
"comment": "Inductance of the q-axis rotor damping circuit, in per unit",
"null_value": 2,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "inv_d_fluxlink",
"data_type": "Array{Float64,2}",
"internal_default": "inv([[-L_d L_ad L_ad]; [-L_ad L_ff L_f1d]; [-L_ad L_f1d L_1d]])",
"comment": "(**Do not modify.**) Equations 3.127, 3.130, 3.131 From Kundur"
},
{
"name": "inv_q_fluxlink",
"data_type": "Array{Float64,2}",
"internal_default": "inv([[-L_q L_aq]; [-L_aq L_1q]])",
"comment": "(**Do not modify.**) Equations 3.128, 3.132 From Kundur"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tψf: field rotor flux,\n\tψ1d: d-axis rotor damping flux,\n\tψ1q: q-axis rotor damping flux",
"internal_default": "[:ψf, :ψ1d, :ψ1q]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) SimpleFullMachine has 3 states",
"internal_default": 3,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "SimpleMarconatoMachine",
"docstring": "Parameters of 4-[states](@ref S) synchronous machine: Simplified Marconato model\n The derivative of stator fluxes (ψd and ψq) is neglected and ωψd = ψd and\n ωψq = ψq is assumed (i.e. ω=1.0). This is standard when transmission network\n dynamics is neglected",
"fields": [
{
"name": "R",
"comment": "Resistance after EMF in machine per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in d-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq",
"data_type": "Float64",
"null_value": 0,
"comment": "Reactance after EMF in q-axis per unit",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_p",
"comment": "Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_p",
"comment": "Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xd_pp",
"comment": "Sub-Transient reactance after EMF in d-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Xq_pp",
"comment": "Sub-Transient reactance after EMF in q-axis per unit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_p",
"comment": "Time constant of transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_p",
"comment": "Time constant of transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Td0_pp",
"comment": "Time constant of sub-transient d-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tq0_pp",
"comment": "Time constant of sub-transient q-axis voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T_AA",
"comment": "Time constant of d-axis additional leakage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "γd",
"data_type": "Float64",
"internal_default": "((Td0_pp*Xd_pp)/(Td0_p*Xd_p) )*(Xd-Xd_p)",
"comment": "(**Do not modify.**) Internal equation"
},
{
"name": "γq",
"data_type": "Float64",
"internal_default": "((Tq0_pp*Xq_pp)/(Tq0_p*Xq_p) )*(Xq-Xq_p)",
"comment": "(**Do not modify.**) Internal equation"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\teq_p: q-axis transient voltage,\n\ted_p: d-axis transient voltage,\n\teq_pp: q-axis subtransient voltage,\n\ted_pp: d-axis subtransient voltage",
"internal_default": "[:eq_p, :ed_p, :eq_pp, :ed_pp]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) SimpleMarconatoMachine has 4 states",
"internal_default": 4,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Machine"
},
{
"struct_name": "PSSFixed",
"docstring": "Parameters of a PSS that returns a fixed voltage to add to the reference for the AVR",
"fields": [
{
"name": "V_pss",
"comment": "Fixed voltage stabilization signal in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) PSSFixed has no [states](@ref S)",
"internal_default": "Vector{Symbol}()",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) PSSFixed has no states",
"internal_default": 0,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "PSS"
},
{
"struct_name": "PSSSimple",
"docstring": "Parameters of a PSS that returns a proportional droop voltage to add to the reference for the AVR",
"fields": [
{
"name": "K_ω",
"comment": "Proportional gain for frequency",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_p",
"comment": "Proportional gain for active power",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) PSSSimple has no [states](@ref S)",
"internal_default": "Vector{Symbol}()",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) PSSSimple has no states",
"internal_default": 0,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "PSS"
},
{
"struct_name": "IEEEST",
"docstring": "IEEE Stabilizing Model PSS. ",
"fields": [
{
"name": "input_code",
"comment": "Code input for stabilizer",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 6
},
"validation_action": "error"
},
{
"name": "remote_bus_control",
"comment": "ACBus identification [`number`](@ref ACBus) for control. `0` identifies the bus connected to this component",
"null_value": 0,
"data_type": "Int"
},
{
"name": "A1",
"comment": "Filter coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "A2",
"comment": "Filter coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "A3",
"comment": "Filter coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "A4",
"comment": "Filter coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "A5",
"comment": "Filter coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "A6",
"comment": "Filter coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T1",
"comment": "Time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "T2",
"comment": "Time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "T3",
"comment": "Time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "T4",
"comment": "Time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "T5",
"comment": "Time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "T6",
"comment": "Time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": "2.0"
},
"validation_action": "error"
},
{
"name": "Ks",
"comment": "Proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ls_lim",
"comment": "PSS output limits for regulator output `(Ls_min, Ls_max)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Vcu",
"comment": "Cutoff limiter upper bound",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": "1.25"
},
"validation_action": "warn"
},
{
"name": "Vcl",
"comment": "Cutoff limiter lower bound",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": "1.0"
},
"validation_action": "warn"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tx_p1: 1st filter integration,\n\tx_p2: 2nd filter integration, \n\tx_p3: 3rd filter integration, \n\tx_p4: 4rd filter integration, \n\tx_p5: T1/T2 lead-lag integrator, \n\tx_p6: T3/T4 lead-lag integrator, \n\t:x_p7 last integer,",
"internal_default": "[:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) IEEEST has 7 states",
"internal_default": 7,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) IEEEST has 7 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "PSS"
},
{
"struct_name": "STAB1",
"docstring": "Speed-Sensitive Stabilizing Model",
"fields": [
{
"name": "KT",
"comment": "K/T for washout filter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T",
"comment": "Time constant for washout filter",
"null_value": 0.01,
"data_type": "Float64",
"valid_range": {
"min": 0.01,
"max": null
},
"validation_action": "warn"
},
{
"name": "T1T3",
"comment": "Time constant division T1/T3",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T3",
"comment": "Time constant",
"null_value": 0.01,
"data_type": "Float64",
"valid_range": {
"min": 0.01,
"max": null
},
"validation_action": "warn"
},
{
"name": "T2T4",
"comment": "Time constant division T2/T4",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T4",
"comment": "Time constant",
"null_value": 0.01,
"data_type": "Float64",
"valid_range": {
"min": 0.01,
"max": null
},
"validation_action": "warn"
},
{
"name": "H_lim",
"comment": "PSS output limit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tx_p1: washout filter,\n\tx_p2: T1/T3 lead-lag block, \n\tx_p3: T2/T4 lead-lag block,",
"internal_default": "[:x_p1, :x_p2, :x_p3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) STAB1 has 3 states",
"internal_default": 3,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) STAB1 has 3 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "PSS"
},
{
"struct_name": "PSS2A",
"docstring": "IEEE Dual-Input Stabilizer Model",
"fields": [
{
"name": "input_code_1",
"comment": "First Input Code for stabilizer",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 6
},
"validation_action": "error"
},
{
"name": "remote_bus_control_1",
"comment": "First Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component",
"null_value": 0,
"data_type": "Int"
},
{
"name": "input_code_2",
"comment": "Second Input Code for stabilizer",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 6
},
"validation_action": "error"
},
{
"name": "remote_bus_control_2",
"comment": "Second Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component",
"null_value": 0,
"data_type": "Int"
},
{
"name": "M_rtf",
"comment": "M parameter for ramp tracking filter",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 8
},
"validation_action": "error"
},
{
"name": "N_rtf",
"comment": "N parameter for ramp tracking filter",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 8
},
"validation_action": "error"
},
{
"name": "Tw1",
"comment": "Time constant for first washout filter for first input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Tw2",
"comment": "Time constant for second washout filter for first input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T6",
"comment": "Time constant for low-pass filter for first input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tw3",
"comment": "Time constant for first washout filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Tw4",
"comment": "Time constant for second washout filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T7",
"comment": "Time constant for low-pass filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ks2",
"comment": "Gain for low-pass filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ks3",
"comment": "Gain for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T8",
"comment": "Time constant for ramp tracking filter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T9",
"comment": "Time constant for ramp tracking filter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Ks1",
"comment": "Gain before lead-lag blocks",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T1",
"comment": "Time constant for first lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T2",
"comment": "Time constant for first lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T3",
"comment": "Time constant for second lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T4",
"comment": "Time constant for second lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vst_lim",
"comment": "PSS output limits `(Vst_min, Vst_max)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tx_p1: 1st washout 1st input, \n\tx_p2: 2nd washout 1st input, \n\tx_p3: transducer 1st input, \n\tx_p4: 1st washout 2nd input, \n\tx_p5: 2nd washout 2nd input, \n\tx_p6: transducer 2nd input, \n\tx_p7: ramp tracking filter state 1, \n\tx_p8: ramp tracking filter state 2, \n\tx_p9: ramp tracking filter state 3, \n\tx_p10: ramp tracking filter state 4, \n\tx_p11: ramp tracking filter state 5, \n\tx_p12: ramp tracking filter state 6, \n\tx_p13: ramp tracking filter state 7, \n\tx_p14: ramp tracking filter state 8, \n\tx_p15: 1st lead-lag, \n\tx_p16: 2nd lead-lag,",
"internal_default": "[:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7, :x_p8, :x_p9, :x_p10, :x_p11, :x_p12, :x_p13, :x_p14, :x_p15, :x_p16]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) IEEEST has 16 states",
"internal_default": 16,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) IEEEST has 16 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "PSS"
},
{
"struct_name": "PSS2B",
"docstring": "IEEE 421.5 2005 PSS2B IEEE Dual-Input Stabilizer Model",
"fields": [
{
"name": "input_code_1",
"comment": "First Input Code for stabilizer",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 6
},
"validation_action": "error"
},
{
"name": "remote_bus_control_1",
"comment": "First Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component",
"null_value": 0,
"data_type": "Int"
},
{
"name": "input_code_2",
"comment": "Second Input Code for stabilizer",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 6
},
"validation_action": "error"
},
{
"name": "remote_bus_control_2",
"comment": "Second Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component",
"null_value": 0,
"data_type": "Int"
},
{
"name": "M_rtf",
"comment": "M parameter for ramp tracking filter",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 8
},
"validation_action": "error"
},
{
"name": "N_rtf",
"comment": "N parameter for ramp tracking filter",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 8
},
"validation_action": "error"
},
{
"name": "Tw1",
"comment": "Time constant for first washout filter for first input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Tw2",
"comment": "Time constant for second washout filter for first input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T6",
"comment": "Time constant for low-pass filter for first input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tw3",
"comment": "Time constant for first washout filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Tw4",
"comment": "Time constant for second washout filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T7",
"comment": "Time constant for low-pass filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ks2",
"comment": "Gain for low-pass filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ks3",
"comment": "Gain for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T8",
"comment": "Time constant for ramp tracking filter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T9",
"comment": "Time constant for ramp tracking filter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Ks1",
"comment": "Gain before lead-lag blocks",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T1",
"comment": "Time constant for first lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T2",
"comment": "Time constant for first lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T3",
"comment": "Time constant for second lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T4",
"comment": "Time constant for second lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T10",
"comment": "Time constant for third lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T11",
"comment": "Time constant for third lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vs1_lim",
"comment": "First input limits `(Vs1_min, Vs1_max)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Vs2_lim",
"comment": "Second input limits `(Vs2_min, Vs2_max)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Vst_lim",
"comment": "PSS output limits `(Vst_min, Vst_max)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tx_p1: 1st washout 1st input, \n\tx_p2: 2nd washout 1st input, \n\tx_p3: transducer 1st input, \n\tx_p4: 1st washout 2nd input, \n\tx_p5: 2nd washout 2nd input, \n\tx_p6: transducer 2nd input, \n\tx_p7: ramp tracking filter state 1, \n\tx_p8: ramp tracking filter state 2, \n\tx_p9: ramp tracking filter state 3, \n\tx_p10: ramp tracking filter state 4, \n\tx_p11: ramp tracking filter state 5, \n\tx_p12: ramp tracking filter state 6, \n\tx_p13: ramp tracking filter state 7, \n\tx_p14: ramp tracking filter state 8, \n\tx_p15: 1st lead-lag, \n\tx_p16: 2nd lead-lag, \n\tx_p17: 3rd lead-lag,",
"internal_default": "[:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7, :x_p8, :x_p9, :x_p10, :x_p11, :x_p12, :x_p13, :x_p14, :x_p15, :x_p16, :x_p17]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) IEEEST has 17 states",
"internal_default": 17,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) IEEEST has 17 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "PSS"
},
{
"struct_name": "PSS2C",
"docstring": "IEEE 421.5 2016 PSS2C IEEE Dual-Input Stabilizer Model",
"fields": [
{
"name": "input_code_1",
"comment": "First Input Code for stabilizer",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 7
},
"validation_action": "error"
},
{
"name": "remote_bus_control_1",
"comment": "First Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component",
"null_value": 0,
"data_type": "Int"
},
{
"name": "input_code_2",
"comment": "Second Input Code for stabilizer",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 6
},
"validation_action": "error"
},
{
"name": "remote_bus_control_2",
"comment": "Second Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component",
"null_value": 0,
"data_type": "Int"
},
{
"name": "M_rtf",
"comment": "M parameter for ramp tracking filter",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 8
},
"validation_action": "error"
},
{
"name": "N_rtf",
"comment": "N parameter for ramp tracking filter",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 8
},
"validation_action": "error"
},
{
"name": "Tw1",
"comment": "Time constant for first washout filter for first input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Tw2",
"comment": "Time constant for second washout filter for first input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T6",
"comment": "Time constant for low-pass filter for first input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tw3",
"comment": "Time constant for first washout filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Tw4",
"comment": "Time constant for second washout filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T7",
"comment": "Time constant for low-pass filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ks2",
"comment": "Gain for low-pass filter for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ks3",
"comment": "Gain for second input",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T8",
"comment": "Time constant for ramp tracking filter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T9",
"comment": "Time constant for ramp tracking filter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Ks1",
"comment": "Gain before lead-lag blocks",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T1",
"comment": "Time constant for first lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T2",
"comment": "Time constant for first lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T3",
"comment": "Time constant for second lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T4",
"comment": "Time constant for second lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T10",
"comment": "Time constant for third lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T11",
"comment": "Time constant for third lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Vs1_lim",
"comment": "First input limits `(Vs1_min, Vs1_max)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Vs2_lim",
"comment": "Second input limits `(Vs2_min, Vs2_max)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Vst_lim",
"comment": "PSS output limits `(Vst_min, Vst_max)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "T12",
"comment": "Time constant for fourth lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T13",
"comment": "Time constant for fourth lead-lag block",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "PSS_Hysteresis_param",
"comment": "PSS output hysteresis parameters `(PSSOFF, PSSON)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Xcomp",
"comment": "Stator Leakage Reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tcomp",
"comment": "Time measured with compensated frequency",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "error"
},
{
"name": "hysteresis_binary_logic",
"comment": "Hysteresis memory variable",
"null_value": 0,
"default": "1",
"data_type": "Int"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tx_p1: 1st washout 1st input, \n\tx_p2: 2nd washout 1st input, \n\tx_p3: transducer 1st input, \n\tx_p4: 1st washout 2nd input, \n\tx_p5: 2nd washout 2nd input, \n\tx_p6: transducer 2nd input, \n\tx_p7: ramp tracking filter state 1, \n\tx_p8: ramp tracking filter state 2, \n\tx_p9: ramp tracking filter state 3, \n\tx_p10: ramp tracking filter state 4, \n\tx_p11: ramp tracking filter state 5, \n\tx_p12: ramp tracking filter state 6, \n\tx_p13: ramp tracking filter state 7, \n\tx_p14: ramp tracking filter state 8, \n\tx_p15: 1st lead-lag, \n\tx_p16: 2nd lead-lag, \n\tx_p17: 3rd lead-lag, \n\tx_p18: 4th lead-lag, \n\tx_p19: washout block for compensated frequency,",
"internal_default": "[:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7, :x_p8, :x_p9, :x_p10, :x_p11, :x_p12, :x_p13, :x_p14, :x_p15, :x_p16, :x_p17, :x_p18, :x_p19]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) IEEEST has 19 states",
"internal_default": 19,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) IEEEST has 19 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "PSS"
},
{
"struct_name": "SingleMass",
"docstring": "Parameters of single mass shaft model. Typically represents the rotor mass",
"fields": [
{
"name": "H",
"comment": "Rotor inertia constant in MWs/MVA",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D",
"comment": "Rotor natural damping in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tδ: rotor angle,\n\tω: rotor speed",
"internal_default": "[:δ, :ω]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) SingleMass has 1 state",
"internal_default": 2,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Shaft"
},
{
"struct_name": "FiveMassShaft",
"docstring": "Parameters of 5 mass-spring shaft model.\n It contains a High-Pressure (HP) steam turbine, Intermediate-Pressure (IP)\n steam turbine, Low-Pressure (LP) steam turbine, the Rotor and an Exciter (EX) mover",
"fields": [
{
"name": "H",
"comment": "Rotor inertia constant in MWs/MVA",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "H_hp",
"comment": "High pressure turbine inertia constant in MWs/MVA",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "H_ip",
"comment": "Intermediate pressure turbine inertia constant in MWs/MVA",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "H_lp",
"comment": "Low pressure turbine inertia constant in MWs/MVA",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "H_ex",
"comment": " Exciter inertia constant in MWs/MVA",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D",
"comment": "Rotor natural damping in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_hp",
"comment": "High pressure turbine natural damping in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_ip",
"comment": "Intermediate pressure turbine natural damping in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_lp",
"comment": "Low pressure turbine natural damping in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_ex",
"comment": "Exciter natural damping in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_12",
"comment": "High-Intermediate pressure turbine damping",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_23",
"comment": "Intermediate-Low pressure turbine damping",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_34",
"comment": "Low pressure turbine-Rotor damping",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_45",
"comment": "Rotor-Exciter damping",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_hp",
"comment": "High pressure turbine angle coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_ip",
"comment": "Intermediate pressure turbine angle coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_lp",
"comment": "Low pressure turbine angle coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_ex",
"comment": "Exciter angle coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\n\tδ: rotor angle,\n\tω: rotor speed,\n\tδ_hp: rotor angle of high pressure turbine,\n\tω_hp: rotor speed of high pressure turbine,\n\tδ_ip: rotor angle of intermediate pressure turbine,\n\tω_ip: rotor speed of intermediate pressure turbine,\n\tδ_lp: rotor angle of low pressure turbine,\n\tω_lp: rotor speed of low pressure turbine,\n\tδ_ex: rotor angle of exciter,\n\tω_lp: rotor speed of exciter",
"internal_default": "[:δ, :ω, :δ_hp, :ω_hp, :δ_ip, :ω_ip, :δ_lp, :ω_lp, :δ_ex, :ω_ex]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) FiveMassShaft has 10 states",
"internal_default": 10,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "Shaft"
},
{
"struct_name": "TGFixed",
"docstring": "Parameters of a fixed Turbine Governor that returns a fixed mechanical torque\n given by the product of P_ref*efficiency",
"fields": [
{
"name": "efficiency",
"comment": "Efficiency factor that multiplies `P_ref`",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) TGFixed has no [states](@ref S)",
"internal_default": "Vector{Symbol}()",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) TGFixed has no states",
"internal_default": 0,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "GasTG",
"docstring": "Parameters of Gas Turbine-Governor. GAST in PSSE and GAST_PTI in PowerWorld",
"fields": [
{
"name": "R",
"comment": "Speed droop parameter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 0.1
}
},
{
"name": "T1",
"comment": "Governor time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 0.5
}
},
{
"name": "T2",
"comment": "Combustion chamber time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 0.5
}
},
{
"name": "T3",
"comment": "Load limit time constant (exhaust gas measurement time)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 5
}
},
{
"name": "AT",
"comment": "Ambient temperature load limit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Kt",
"comment": "Load limit feedback gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 5
}
},
{
"name": "V_lim",
"comment": "Operational control limits on fuel valve opening (V_min, V_max)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "D_turb",
"comment": "Speed damping coefficient of gas turbine rotor",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
}
},
{
"name": "P_ref",
"comment": "Reference Load Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the GAST model are:\n\tx_g1: Fuel valve opening,\n\tx_g2: Fuel flow,\n\tx_g3: Exhaust temperature load",
"internal_default": "[:x_g1, :x_g2, :x_g3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) GasTG has 3 states",
"internal_default": 3,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) GAST has 3 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "DEGOV",
"docstring": "Parameters Woodward Diesel Governor Model. DEGOV in PowerWorld",
"fields": [
{
"name": "T1",
"comment": "Governor mechanism time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 100.0
}
},
{
"name": "T2",
"comment": "Turbine power time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 100.0
}
},
{
"name": "T3",
"comment": "Turbine exhaust temperature time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 100.0
}
},
{
"name": "K",
"comment": "Governor gain (reciprocal of droop)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 100.0
}
},
{
"name": "T4",
"comment": "Governor lead time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 100.0
}
},
{
"name": "T5",
"comment": "Governor lag time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 100.0
}
},
{
"name": "T6",
"comment": "Actuator time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 100.0
}
},
{
"name": "Td",
"comment": "Engine time delay",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 100.0
}
},
{
"name": "P_ref",
"comment": "Reference Load Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the DEGOV model are:\n\tx_ecb1: Electric control box 1,\n\tx_ecb2: Electric control box 2,\n\tx_a1: Actuator 1,\n\tx_a2: Actuator 2,\n\tx_a3: Actuator 3,",
"internal_default": "[:x_ecb1, :x_ecb2, :x_a1, :x_a2, :x_a3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) DEGOV has 5 states",
"internal_default": 5,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) DEGOV has 5 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "DEGOV1",
"docstring": "Parameters Woodward Diesel Governor Model. DEGOV1 in PSSE",
"fields": [
{
"name": "droop_flag",
"comment": "Droop control Flag. 0 for throttle feedback and 1 for electric power feedback",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "T1",
"comment": "Governor mechanism time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100.0
}
},
{
"name": "T2",
"comment": "Turbine power time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100.0
}
},
{
"name": "T3",
"comment": "Turbine exhaust temperature time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100.0
}
},
{
"name": "K",
"comment": "Governor gain for actuator",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100.0
}
},
{
"name": "T4",
"comment": "Governor lead time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100.0
}
},
{
"name": "T5",
"comment": "Governor lag time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100.0
}
},
{
"name": "T6",
"comment": "Actuator time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100.0
}
},
{
"name": "Td",
"comment": "Engine time delay in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100.0
}
},
{
"name": "T_lim",
"comment": "Operational control limits on actuator (T_min, T_max)",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "R",
"comment": "Steady state droop parameter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100.0
}
},
{
"name": "Te",
"comment": "Power transducer time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 100.0
}
},
{
"name": "P_ref",
"comment": "Reference Load Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the DEGOV1 model depends on the droop flag",
"internal_default": "PowerSystems.get_degov1_states(droop_flag)[1]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The number of [states](@ref S) of the DEGOV1 model depends on the droop flag",
"internal_default": "PowerSystems.get_degov1_states(droop_flag)[2]",
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "GeneralGovModel",
"docstring": "GE General Governor/Turbine Model. The GeneralGovModel (GGOV1) model is a general purpose governor model used for a variety of prime movers controlled by proportional-integral-derivative (PID) governors including gas turbines",
"fields": [
{
"name": "Rselect",
"comment": "Feedback signal for governor droop",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": -2,
"max": 1
},
"validation_action": "error"
},
{
"name": "fuel_flag",
"comment": "Flag Switch for fuel source characteristic",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "R",
"comment": "Speed droop parameter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Tpelec",
"comment": "Electrical power transducer time constant, seconds",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "speed_error_signal",
"comment": "Speed error signal limits",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Kp_gov",
"comment": "Governor proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ki_gov",
"comment": "Governor integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Kd_gov",
"comment": "Governor derivative gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Td_gov",
"comment": "Governor derivative time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "valve_position_limits",
"comment": "Valve position limits",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "T_act",
"comment": "Actuator time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "K_turb",
"comment": "Turbine gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Wf_nl",
"comment": "No load fuel flow, pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Turbine lag time constant, sec",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tc",
"comment": "Turbine lead time constant, sec",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T_eng",
"comment": "Transport lag time constant for diesel engine, sec",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tf_load",
"comment": "Load limiter time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Kp_load",
"comment": "Load limiter proportional gain for PI controller",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ki_load",
"comment": "Load integral gain for PI controller",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ld_ref",
"comment": "Load limiter integral gain for PI controller",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Dm",
"comment": "Mechanical damping coefficient, pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "R_open",
"comment": "Maximum valve opening rate, pu/sec",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "R_close",
"comment": "Maximum valve closing rate, pu/sec",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ki_mw",
"comment": "Power controller (reset) gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "A_set",
"comment": "Acceleration limiter setpoint, pu/sec",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ka",
"comment": "Acceleration limiter gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Acceleration limiter time constant ",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "error"
},
{
"name": "T_rate",
"comment": "Turbine rating",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "db",
"comment": "Speed governor deadband",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tsa",
"comment": "Temperature detection lead time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tsb",
"comment": "Temperature detection lag time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "R_lim",
"comment": "Maximum rate of load increase",
"null_value": "(up = 0.0, down = 0.0)",
"data_type": "UpDown"
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the GGOV1 model are:\n\tPe: Machine Electrical Power Measurement,\n\tx_g1: Governor differential control,\n\tx_g2: Governor integral control, \n\tx_g3: Turbine actuator, \n\tx_g4: Turbine Lead-Lag, \n\tx_g5: Turbine load limiter measurement, \n\tx_g6: Turbine Load Limiter Integral Control, \n\tx_g7: Supervisory Load Control, \n\tx_g8: Acceleration Control, \n\tx_g9 Temperature Detection Lead - Lag:",
"internal_default": "[:Pe, :x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6, :x_g7, :x_g8, :x_g9]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) GeneralGovModel has 10 states",
"internal_default": 10,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) GGOV1 has 10 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Hybrid]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "PIDGOV",
"docstring": "Hydro Turbine-Governor with PID controller.",
"fields": [
{
"name": "feedback_flag",
"comment": "Feedback signal for governor droop: 0 for electrical power, and 1 for gate position.",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "error"
},
{
"name": "Rperm",
"comment": "Speed permanent droop parameter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T_reg",
"comment": "Speed detector time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Kp",
"comment": "Governor proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ki",
"comment": "Governor integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Kd",
"comment": "Governor derivative gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Governor derivative time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Gate-servo time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "D_turb",
"comment": "Turbine damping factor",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "gate_openings",
"comment": "Gate-opening speed at different loads",
"null_value": "(0.0, 0.0, 0.0)",
"data_type": "Tuple{Float64, Float64, Float64}"
},
{
"name": "power_gate_openings",
"comment": "Power at gate_openings",
"null_value": "(0.0, 0.0, 0.0)",
"data_type": "Tuple{Float64, Float64, Float64}"
},
{
"name": "G_lim",
"comment": "Minimum/Maximum Gate openings `(G_min, G_max)`.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "A_tw",
"comment": "Factor multiplying Tw",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "Tw",
"comment": "Water inertia time constant, sec",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "V_lim",
"comment": "Gate opening velocity limits `(G_min, G_max)`.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the PIDGOV model are:\n\tx_g1: Filtered input measurement,\n\tx_g2: PI block internal state,\n\tx_g3: First regulator state, \n\tx_g4: Derivative block internal state, \n\tx_g5: Second regulator state, \n\tx_g6: Gate position state, \n\tx_g7: Water inertia state",
"internal_default": "[:x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6, :x_g7]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) PIDGOV has 7 states",
"internal_default": 7,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) PIDGOV has 7 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "WPIDHY",
"docstring": "Woodward PID Hydro Governor",
"fields": [
{
"name": "T_reg",
"comment": "Input time constant of the governor in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "reg",
"comment": "Input governor gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Kp",
"comment": "Governor proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ki",
"comment": "Governor integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Kd",
"comment": "Governor derivative gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Ta",
"comment": "Governor derivative/high-frequency time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "Tb",
"comment": "Gate-servo time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "V_lim",
"comment": "Gate opening velocity limits `(G_min, G_max)`.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "G_lim",
"comment": "Minimum/Maximum Gate velocity `(G_min, G_max)`.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Tw",
"comment": "Water inertia time constant, sec",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": null
},
"validation_action": "warn"
},
{
"name": "P_lim",
"comment": "Minimum/Maximum Gate openings `(P_min, P_max)`.",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "D",
"comment": "Turbine damping coefficient",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "gate_openings",
"comment": "Gate-opening speed at different loads",
"null_value": "(0.0, 0.0, 0.0)",
"data_type": "Tuple{Float64, Float64, Float64}"
},
{
"name": "power_gate_openings",
"comment": "Power at gate_openings",
"null_value": "(0.0, 0.0, 0.0)",
"data_type": "Tuple{Float64, Float64, Float64}"
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the PIDGOV model are:\n\tx_g1: Filtered input measurement,\n\tx_g2: PI block internal state,\n\tx_g3: First regulator state, \n\tx_g4: Derivative block internal state, \n\tx_g5: Second regulator state, \n\tx_g6: Gate position state, \n\tx_g7: Water inertia state",
"internal_default": "[:x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6, :x_g7]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) PIDGOV has 7 states",
"internal_default": 7,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) PIDGOV has 7 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "SteamTurbineGov1",
"docstring": "Steam Turbine-Governor. This model considers both TGOV1 or TGOV1DU in PSS/E",
"fields": [
{
"name": "R",
"comment": "Droop parameter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.1
},
"validation_action": "warn"
},
{
"name": "T1",
"comment": "Governor time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 0.5
},
"validation_action": "error"
},
{
"name": "valve_position_limits",
"comment": "Valve position limits",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "T2",
"comment": "Lead Lag Lead Time constant ",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T3",
"comment": "Lead Lag Lag Time constant ",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 10
},
"validation_action": "error"
},
{
"name": "D_T",
"comment": "Turbine Damping",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "DB_h",
"comment": "Deadband for overspeed",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "DB_l",
"comment": "Deadband for underspeed",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": null,
"max": 0
},
"validation_action": "warn"
},
{
"name": "T_rate",
"comment": "Turbine Rate (MW). If zero, generator base is used",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the SteamTurbineGov1 model are:\n\tx_g1: Valve Opening,\n\tx_g2: Lead-lag state",
"internal_default": "[:x_g1, :x_g2]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) TGOV1 has 2 states",
"internal_default": 2,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) TGOV1 has 2 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "HydroTurbineGov",
"docstring": "Hydro Turbine-Governor",
"fields": [
{
"name": "R",
"comment": "Permanent droop parameter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.1
},
"validation_action": "warn"
},
{
"name": "r",
"comment": "Temporary Droop",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 2
},
"validation_action": "warn"
},
{
"name": "Tr",
"comment": "Governor time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 30
},
"validation_action": "error"
},
{
"name": "Tf",
"comment": "Filter Time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 0.1
},
"valiation_action": "error"
},
{
"name": "Tg",
"comment": "Servo time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 1
},
"validation_action": "error"
},
{
"name": "VELM",
"comment": "gate velocity limit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 0.3
},
"validation_action": "error"
},
{
"name": "gate_position_limits",
"comment": "Gate position limits",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Tw",
"comment": "water time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 3
},
"validation_action": "error"
},
{
"name": "At",
"comment": "Turbine gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0.8,
"max": 1.5
},
"validation_action": "warn"
},
{
"name": "D_T",
"comment": "Turbine Damping",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "q_nl",
"comment": "No-power flow",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the HydroTurbineGov model are:\n\tx_g1: filter_output,\n\tx_g2: desired gate, \n\tx_g3: gate opening, \n\tx_g4: turbine flow",
"internal_default": "[:x_g1, :x_g2, :x_g3, :x_g4]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) HYGOV has 4 states",
"internal_default": 4,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) HYGOV has 4 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "IEEETurbineGov1",
"docstring": "IEEE Type 1 Speed-Governing Model",
"fields": [
{
"name": "K",
"comment": "Governor Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 5,
"max": 30
},
"validation_action": "warn"
},
{
"name": "T1",
"comment": "Input Filter Lag",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 5
},
"validation_action": "warn"
},
{
"name": "T2",
"comment": "Input Filter Lead",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "T3",
"comment": "Valve position Time Constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": "eps()",
"max": 1
},
"validation_action": "error"
},
{
"name": "U0",
"comment": "Maximum Valve Opening Rate",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0.01,
"max": 0.03
},
"validation_action": "warn"
},
{
"name": "U_c",
"comment": "Maximum Valve closing rate",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": -0.3,
"max": 0
},
"validation_action": "warn"
},
{
"name": "valve_position_limits",
"comment": "Valve position limits in MW",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "T4",
"comment": "Time Constant inlet steam",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
},
"validation_action": "warn"
},
{
"name": "K1",
"comment": "Fraction of high presure shaft power",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": -2,
"max": 1
},
"validation_action": "warn"
},
{
"name": "K2",
"comment": "Fraction of low presure shaft power",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"validation_action": "warn"
},
{
"name": "T5",
"comment": "Time constant for second boiler pass",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "K3",
"comment": "Fraction of high presure shaft power second boiler pass",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "K4",
"comment": "Fraction of low presure shaft power second boiler pass",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.5
},
"validation_action": "warn"
},
{
"name": "T6",
"comment": "Time constant for third boiler pass",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "K5",
"comment": "Fraction of high presure shaft power third boiler pass",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.35
},
"validation_action": "warn"
},
{
"name": "K6",
"comment": "Fraction of low presure shaft power third boiler pass",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.55
},
"validation_action": "warn"
},
{
"name": "T7",
"comment": "Time constant for fourth boiler pass",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 10
},
"validation_action": "warn"
},
{
"name": "K7",
"comment": "Fraction of high presure shaft power fourth boiler pass",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "K8",
"comment": "Fraction of low presure shaft power fourth boiler pass",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 0.3
},
"validation_action": "warn"
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the IEEETurbineGov model are:\n\tx_g1: First Governor integrator,\n\tx_g2: Governor output,\n\tx_g3: First Turbine integrator, \n\tx_g4: Second Turbine Integrator, \n\tx_g5: Third Turbine Integrator, \n\tx_g6: Fourth Turbine Integrator, ",
"internal_default": "[:x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) IEEEG1 has 6 states",
"internal_default": 6,
"data_type": "Int"
},
{
"name": "states_types",
"comment": "(**Do not modify.**) IEEEG1 has 6 [differential](@ref states_list) [states](@ref S)",
"internal_default": "[StateTypes.Differential, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid]",
"data_type": "Vector{StateTypes}"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "TGTypeI",
"docstring": "Parameters of a Turbine Governor Type I",
"fields": [
{
"name": "R",
"comment": "Droop parameter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Ts",
"comment": "Governor time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tc",
"comment": "Servo time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T3",
"comment": "Transient gain time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T4",
"comment": "Power fraction time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T5",
"comment": "Reheat time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "valve_position_limits",
"comment": "Valve position limits in MW",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the TGTypeI model are:\n\tx_g1: Governor state,\n\tx_g2: Servo state,\n\tx_g3: Reheat state",
"internal_default": "[:x_g1, :x_g2, :x_g3]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) TGTypeI has 3 states",
"internal_default": 3,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "TGTypeII",
"docstring": "Parameters of a Turbine Governor Type II",
"fields": [
{
"name": "R",
"comment": "Droop parameter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T1",
"comment": "Transient gain time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T2",
"comment": "Power fraction time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "τ_limits",
"comment": "Power into the governor limits",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the TGTypeI model are:\n\tx_g1: lead-lag state",
"internal_default": "[:xg]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) TGTypeII has 1 state",
"internal_default": 1,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "TGSimple",
"docstring": "Parameters of a Simple one-state Turbine Governor",
"fields": [
{
"name": "d_t",
"comment": "Inverse Droop parameter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tm",
"comment": "Turbine Governor Low-Pass Time Constant [s]",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the TGSimple model are:\n\tτm: mechanical torque",
"internal_default": "[:τm]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) TGSimple has 1 state",
"internal_default": 1,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "TurbineGov"
},
{
"struct_name": "AverageConverter",
"docstring": "Parameters of an average converter model",
"fields": [
{
"name": "rated_voltage",
"comment": "Rated voltage (V)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rated_current",
"comment": "Rated current (A)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) AverageConverter has no [states](@ref S)",
"internal_default": "Vector{Symbol}()",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) AverageConverter has no states",
"internal_default": 0,
"data_type": "Int"
}
],
"supertype": "Converter"
},
{
"struct_name": "RenewableEnergyConverterTypeA",
"docstring": "Parameters of a renewable energy generator/converter model, this model corresponds to REGCA1 in PSSE",
"fields": [
{
"name": "T_g",
"comment": "Converter time constant (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Rrpwr",
"comment": "Low Voltage Power Logic (LVPL) ramp rate limit (pu/s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Brkpt",
"comment": "LVPL characteristic voltage 2 (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Zerox",
"comment": "LVPL characteristic voltage 1 (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Lvpl1",
"comment": "LVPL gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Vo_lim",
"comment": "Voltage limit for high voltage reactive current management (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Lv_pnts",
"comment": "Voltage points for low voltage active current management (pu) (Lvpnt0, Lvpnt1)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Io_lim",
"comment": "Current limit (pu) for high voltage reactive current management (specified as a negative value)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": null,
"max": 0
}
},
{
"name": "T_fltr",
"comment": "Voltage filter time constant for low voltage active current management (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_hv",
"comment": "Overvoltage compensation gain used in the high voltage reactive current management",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Iqr_lims",
"comment": "Limit on rate of change for reactive current (pu/s) (Iqr_min, Iqr_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Accel",
"comment": "Acceleration factor",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Lvpl_sw",
"comment": "Low voltage power logic (LVPL) switch. (0: LVPL not present, 1: LVPL present)",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Q_ref",
"comment": "Initial condition of reactive power from power flow",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "R_source",
"comment": "Output resistor used for the Thevenin Equivalent",
"null_value": 0,
"default": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "X_source",
"comment": "Output reactance used for the Thevenin Equivalent",
"null_value": 0,
"default": "1.0e5",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\tIp: Converter lag for Ipcmd,\tIq: Converter lag for Iqcmd,\tVmeas: Voltage filter for low voltage active current management",
"internal_default": "[:Ip, :Iq, :Vmeas]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) RenewableEnergyConverterTypeA has 3 states",
"internal_default": 3,
"data_type": "Int"
}
],
"supertype": "Converter"
},
{
"struct_name": "RenewableEnergyVoltageConverterTypeA",
"docstring": "Parameters of a renewable energy generator/converter model, this model corresponds to REGCA1 in PSSE, but to be interfaced using a Voltage Source instead of a Current Source",
"fields": [
{
"name": "T_g",
"comment": "Converter time constant (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Rrpwr",
"comment": "Low Voltage Power Logic (LVPL) ramp rate limit (pu/s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Brkpt",
"comment": "LVPL characteristic voltage 2 (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Zerox",
"comment": "LVPL characteristic voltage 1 (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Lvpl1",
"comment": "LVPL gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Vo_lim",
"comment": "Voltage limit for high voltage reactive current management (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Lv_pnts",
"comment": "Voltage points for low voltage active current management (pu) (Lvpnt0, Lvpnt1)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Io_lim",
"comment": "Current limit (pu) for high voltage reactive current management (specified as a negative value)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": null,
"max": 0
}
},
{
"name": "T_fltr",
"comment": "Voltage filter time constant for low voltage active current management (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_hv",
"comment": "Overvoltage compensation gain used in the high voltage reactive current management",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Iqr_lims",
"comment": "Limit on rate of change for reactive current (pu/s) (Iqr_min, Iqr_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Accel",
"comment": "Acceleration factor",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Lvpl_sw",
"comment": "Low voltage power logic (LVPL) switch. (0: LVPL not present, 1: LVPL present)",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Q_ref",
"comment": "Initial condition of reactive power from power flow",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) are:\tIp: Converter lag for Ipcmd,\tIq: Converter lag for Iqcmd,\tVmeas: Voltage filter for low voltage active current management",
"internal_default": "[:Ip, :Iq, :Vmeas]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) RenewableEnergyVoltageConverterTypeA has 3 states",
"internal_default": 3,
"data_type": "Int"
}
],
"supertype": "Converter"
},
{
"struct_name": "FixedDCSource",
"docstring": "Parameters of a Fixed DC Source that returns a fixed DC voltage",
"fields": [
{
"name": "voltage",
"comment": "Voltage (V)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) FixedDCSource has no [states](@ref S)",
"internal_default": "Vector{Symbol}()",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) FixedDCSource has no states",
"internal_default": 0,
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "DCSource"
},
{
"struct_name": "ZeroOrderBESS",
"docstring": "Parameters for the DC-side with a Battery Energy Storage System from [\"Grid-Coupled Dynamic Response of Battery-Driven Voltage Source Converters.\"](https://arxiv.org/abs/2007.11776)",
"fields": [
{
"name": "rated_voltage",
"comment": "Rated voltage (V)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rated_current",
"comment": "Rated current (A)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "battery_voltage",
"comment": "battery voltage in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "battery_resistance",
"comment": "Battery resistance in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "dc_dc_inductor",
"comment": "DC/DC inductance in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "dc_link_capacitance",
"comment": "DC-link capacitance in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "fs",
"comment": "DC/DC converter switching frequency (kHz)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kpv",
"comment": "voltage controller proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kiv",
"comment": "voltage controller integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kpi",
"comment": "current controller proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kii",
"comment": "current controller integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Vdc_ref",
"comment": "Reference DC-Voltage Set-point in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"default": "1.1",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the ZeroOrderBESS model are:\n\tv_dc: DC-link voltage,\n\ti_b: Battery current,\n\t ν: integrator state of the voltage controller,\n\t ζ: integrator state of the PI current controller",
"internal_default": "[:v_dc, :i_b, :ν, :ζ]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ZeroOrderBESS has 4 states",
"internal_default": 4,
"data_type": "Int"
}
],
"supertype": "DCSource"
},
{
"struct_name": "LCLFilter",
"docstring": "Parameters of a LCL filter outside the converter, the [states](@ref S) are in the grid's reference frame",
"fields": [
{
"name": "lf",
"comment": "Series inductance in p.u. of converter filter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rf",
"comment": "Series resistance in p.u. of converter filter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "cf",
"comment": "Shunt capacitance in p.u. of converter filter",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "lg",
"comment": "Series inductance in p.u. of converter filter to the grid",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rg",
"comment": "Series resistance in p.u. of converter filter to the grid",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the LCLFilter model are:\n\tir_cnv: Real current out of the converter,\n\tii_cnv: Imaginary current out of the converter,\n\tvr_filter: Real voltage at the filter's capacitor,\n\tvi_filter: Imaginary voltage at the filter's capacitor,\n\tir_filter: Real current out of the filter,\n\tii_filter: Imaginary current out of the filter",
"internal_default": "[:ir_cnv, :ii_cnv, :vr_filter, :vi_filter, :ir_filter, :ii_filter]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) LCLFilter has 6 states",
"internal_default": 6,
"data_type": "Int"
}
],
"supertype": "Filter"
},
{
"struct_name": "LCFilter",
"docstring": "Parameters of a LCL filter outside the converter",
"fields": [
{
"name": "lf",
"comment": "filter inductance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rf",
"comment": "filter resistance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "cf",
"comment": "filter capacitance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the LCFilter model are:\n\tir_filter: Real current out of the filter,\n\tii_filter: Imaginary current out of the filter",
"internal_default": "[:ir_filter, :ii_filter]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) LCFilter has two states",
"internal_default": 2,
"data_type": "Int"
}
],
"supertype": "Filter"
},
{
"struct_name": "RLFilter",
"docstring": "Parameters of RL series filter in algebraic representation",
"fields": [
{
"name": "rf",
"comment": "Series resistance in p.u. of converter filter to the grid",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "lf",
"comment": "Series inductance in p.u. of converter filter to the grid",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) RLFilter has zero [states](@ref S)",
"internal_default": "Vector{Symbol}()",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) RLFilter has zero states",
"internal_default": 0,
"data_type": "Int"
}
],
"supertype": "Filter"
},
{
"struct_name": "KauraPLL",
"docstring": "Parameters of a Phase-Locked Loop (PLL) based on [\"Operation of a phase locked loop system under distorted utility conditions\"](https://doi.org/10.1109/28.567077) by Vikram Kaura, and Vladimir Blasko",
"fields": [
{
"name": "ω_lp",
"comment": "PLL low-pass filter frequency (rad/sec)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kp_pll",
"comment": "PLL proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ki_pll",
"comment": "PLL integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the KauraPLL model are:\n\tvd_pll: d-axis of the measured voltage in the PLL synchronous reference frame (SRF),\n\tvq_pll: q-axis of the measured voltage in the PLL SRF,\n\tε_pll: Integrator state of the PI controller,\n\tθ_pll: Phase angle displacement in the PLL SRF",
"internal_default": "[:vd_pll, :vq_pll, :ε_pll, :θ_pll]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) KauraPLL has 4 states",
"internal_default": 4,
"data_type": "Int"
}
],
"supertype": "FrequencyEstimator"
},
{
"struct_name": "ReducedOrderPLL",
"docstring": "Parameters of a Phase-Locked Loop (PLL) based on [\"Reduced-order Structure-preserving Model for Parallel-connected Three-phase Grid-tied Inverters.\"](https://doi.org/10.1109/COMPEL.2017.8013389)",
"fields": [
{
"name": "ω_lp",
"comment": "PLL low-pass filter frequency (rad/sec)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kp_pll",
"comment": "PLL proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ki_pll",
"comment": "PLL integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the ReducedOrderPLL model are:\n\tvq_pll: q-axis of the measured voltage in the PLL synchronous reference frame (SRF),\n\tε_pll: Integrator state of the PI controller,\n\tθ_pll: Phase angle displacement in the PLL SRF",
"internal_default": "[:vq_pll, :ε_pll, :θ_pll]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ReducedOrderPLL has 3 states",
"internal_default": 3,
"data_type": "Int"
}
],
"supertype": "FrequencyEstimator"
},
{
"struct_name": "FixedFrequency",
"docstring": "Parameters of a Fixed Frequency Estimator (i.e. no PLL)",
"fields": [
{
"name": "frequency",
"comment": "Reference Frequency (pu)",
"null_value": 0,
"data_type": "Float64",
"default": "1.0"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) FixedFrequency has no [states](@ref S)",
"internal_default": "Vector{Symbol}()",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) FixedFrequency has no states",
"internal_default": 0,
"data_type": "Int"
}
],
"supertype": "FrequencyEstimator"
},
{
"struct_name": "VirtualInertia",
"docstring": "Parameters of a Virtual Inertia with SRF using VSM for active power controller",
"fields": [
{
"name": "Ta",
"comment": "VSM inertia constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kd",
"comment": "VSM damping constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kω",
"comment": "frequency droop gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the VirtualInertia model are:\n\tθ_oc: Phase angle displacement of the virtual synchronous generator model\n\tω_oc: Speed of the rotating reference frame of the virtual synchronous generator model",
"internal_default": "[:θ_oc, :ω_oc]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) VirtualInertia has two states",
"internal_default": 2,
"data_type": "Int"
}
],
"supertype": "ActivePowerControl"
},
{
"struct_name": "ActivePowerDroop",
"docstring": "Parameters of an Active Power droop controller",
"fields": [
{
"name": "Rp",
"comment": "Droop Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ωz",
"comment": "filter frequency cutoff",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the ActivePowerDroop model are:\n\tθ_oc: Phase angle displacement of the inverter model,\n\tp_oc: Measured active power of the inverter model",
"internal_default": "[:θ_oc, :p_oc]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ActivePowerDroop has two states",
"internal_default": 2,
"data_type": "Int"
}
],
"supertype": "ActivePowerControl"
},
{
"struct_name": "ActivePowerPI",
"docstring": "Parameters of a Proportional-Integral Active Power controller for a specified power reference",
"fields": [
{
"name": "Kp_p",
"comment": "Proportional Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Ki_p",
"comment": "Integral Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ωz",
"comment": "filter frequency cutoff",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the ActivePowerPI model are:\n\tσp_oc: Integrator state of the PI Controller,\n\tp_oc: Measured active power of the inverter model",
"internal_default": "[:σp_oc, :p_oc]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ActivePowerPI has two states",
"internal_default": 2,
"data_type": "Int"
}
],
"supertype": "ActivePowerControl"
},
{
"struct_name": "ActiveVirtualOscillator",
"docstring": "Parameters of an Active Virtual Oscillator controller. Model is based on [\"Model Reduction for Inverters with Current Limiting and Dispatchable Virtual Oscillator Control.\"](https://doi.org/10.1109/TEC.2021.3083488)",
"fields": [
{
"name": "k1",
"comment": "VOC Synchronization Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ψ",
"comment": "Rotation angle of the controller",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the ActiveVirtualOscillator model are:\n\tθ_oc: Phase angle displacement of the inverter model",
"internal_default": "[:θ_oc]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ActiveVirtualOscillator has one state",
"internal_default": 1,
"data_type": "Int"
}
],
"supertype": "ActivePowerControl"
},
{
"struct_name": "ActiveRenewableControllerAB",
"docstring": "Parameters of Active Power Controller including REPCA1 and REECB1",
"fields": [
{
"name": "bus_control",
"comment": "ACBus identification [`number`](@ref ACBus) for voltage control. `0` identifies the local bus connected to this component",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "from_branch_control",
"comment": "Monitored branch FROM bus number for line drop compensation (if 0 generator power will be used)",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "to_branch_control",
"comment": "Monitored branch TO bus number for line drop compensation (if 0 generator power will be used)",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "branch_id_control",
"comment": "Branch circuit id for line drop compensation (as a string). If 0 generator power will be used",
"null_value": 0,
"data_type": "String"
},
{
"name": "Freq_Flag",
"comment": "Frequency Flag for REPCA1: 0: disable, 1:enable",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "K_pg",
"comment": "Active power PI control proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_ig",
"comment": "Active power PI control integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T_p",
"comment": "Real power measurement filter time constant (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "fdbd_pnts",
"comment": "Frequency error dead band thresholds `(fdbd1, fdbd2)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "fe_lim",
"comment": "Upper/Lower limit on frequency error `(fe_min, fe_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "P_lim",
"comment": "Upper/Lower limit on power reference `(P_min, P_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "T_g",
"comment": "Power Controller lag time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_dn",
"comment": "Droop for over-frequency conditions",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": null,
"max": 0
}
},
{
"name": "D_up",
"comment": "Droop for under-frequency conditions",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "dP_lim",
"comment": "Upper/Lower limit on power reference ramp rates`(dP_min, dP_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "P_lim_inner",
"comment": "Upper/Lower limit on power reference for REECB`(P_min_inner, P_max_inner)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "T_pord",
"comment": "Power filter time constant REECB time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "P_ref",
"comment": "Reference Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the ActiveRenewableControllerAB model depends on the Flag",
"internal_default": "PowerSystems.get_activeRETypeAB_states(Freq_Flag)[1]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The states of the ActiveRenewableControllerAB model depends on the Flag",
"internal_default": "PowerSystems.get_activeRETypeAB_states(Freq_Flag)[2]",
"data_type": "Int"
}
],
"supertype": "ActivePowerControl"
},
{
"struct_name": "ReactiveRenewableControllerAB",
"docstring": "Parameters of Reactive Power Controller including REPCA1 and REECB1",
"fields": [
{
"name": "bus_control",
"comment": "ACBus identification [`number`](@ref ACBus) for voltage control. `0` identifies the local bus connected to this component",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "from_branch_control",
"comment": "Monitored branch FROM bus identification number for line drop compensation (if 0 generator power will be used)",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "to_branch_control",
"comment": "Monitored branch TO bus identification number for line drop compensation (if 0 generator power will be used)",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "branch_id_control",
"comment": "Branch circuit id for line drop compensation (as a string). If 0 generator power will be used",
"null_value": 0,
"data_type": "String"
},
{
"name": "VC_Flag",
"comment": "Voltage Compensator Flag for REPCA1",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Ref_Flag",
"comment": "Flag for Reactive Power Control for REPCA1. 0: Q-control, 1: V-control",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "PF_Flag",
"comment": "Flag for Power Factor Control for Outer Control of REECB1. 0: Q-control, 1: Power Factor Control",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "V_Flag",
"comment": "Flag for Voltage Control for Outer Control of REECB1. 0: Voltage Control, 1: Q-Control",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "T_fltr",
"comment": "Voltage or Q-power of REPCA Filter Time Constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_p",
"comment": "Reactive power PI control proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_i",
"comment": "Reactive power PI control integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T_ft",
"comment": "Reactive power lead time constant (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T_fv",
"comment": "Reactive power lag time constant (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "V_frz",
"comment": "Voltage below which state ξq_oc (integrator state) is freeze",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "R_c",
"comment": "Line drop compensation resistance (used when VC_Flag = 1)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "X_c",
"comment": "Line drop compensation reactance (used when VC_Flag = 1)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_c",
"comment": "Reactive current compensation gain (pu) (used when VC_Flag = 0)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "e_lim",
"comment": "Upper/Lower limit on Voltage or Q-power deadband output `(e_min, e_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "dbd_pnts",
"comment": "Voltage or Q-power error dead band thresholds `(dbd1, dbd2)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "Q_lim",
"comment": "Upper/Lower limit on reactive power V/Q control in REPCA `(Q_min, Q_max)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "T_p",
"comment": "Active power lag time constant in REECB (s). Used only when PF_Flag = 1",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Q_lim_inner",
"comment": "Upper/Lower limit on reactive power input in REECB `(Q_min_inner, Q_max_inner)`. Only used when V_Flag = 1",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "V_lim",
"comment": "Upper/Lower limit on reactive power PI controller in REECB `(V_min, V_max)`. Only used when V_Flag = 1",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "K_qp",
"comment": "Reactive power regulator proportional gain (used when V_Flag = 1)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_qi",
"comment": "Reactive power regulator integral gain (used when V_Flag = 1)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Q_ref",
"comment": "Reference Reactive Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the ReactiveRenewableControllerAB model depends on the Flag",
"internal_default": "PowerSystems.get_reactiveRETypeAB_states(Ref_Flag, PF_Flag, V_Flag)[1]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The states of the ReactiveRenewableControllerAB model depends on the Flag",
"internal_default": "PowerSystems.get_reactiveRETypeAB_states(Ref_Flag, PF_Flag, V_Flag)[2]",
"data_type": "Int"
}
],
"supertype": "ReactivePowerControl"
},
{
"struct_name": "ReactivePowerDroop",
"docstring": "Parameters of a Reactive Power droop controller",
"fields": [
{
"name": "kq",
"comment": "frequency droop gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ωf",
"comment": "filter frequency cutoff",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the ReactivePowerDroop model are:\n\tq_oc: Filtered reactive output power",
"internal_default": "[:q_oc]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ReactivePowerDroop has 1 state",
"internal_default": 1,
"data_type": "Int"
}
],
"supertype": "ReactivePowerControl"
},
{
"struct_name": "ReactivePowerPI",
"docstring": "Parameters of a Proportional-Integral Reactive Power controller for a specified power reference",
"fields": [
{
"name": "Kp_q",
"comment": "Proportional Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Ki_q",
"comment": "Integral Gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ωf",
"comment": "filter frequency cutoff",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "V_ref",
"comment": "Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Q_ref",
"comment": "Reactive Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the ReactivePowerPI model are:\n\tσq_oc: Integrator state of the PI Controller,\n\tq_oc: Measured reactive power of the inverter model",
"internal_default": "[:σq_oc, :q_oc]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ReactivePowerPI has two states",
"internal_default": 2,
"data_type": "Int"
}
],
"supertype": "ReactivePowerControl"
},
{
"struct_name": "ReactiveVirtualOscillator",
"docstring": "Parameters of a Reactive Virtual Oscillator controller. Model is based on [\"Model Reduction for Inverters with Current Limiting and Dispatchable Virtual Oscillator Control.\"](https://doi.org/10.1109/TEC.2021.3083488)",
"fields": [
{
"name": "k2",
"comment": "VOC voltage-amplitude control gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "V_ref",
"comment": "Reference Voltage Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Q_ref",
"comment": "Reference Reactive Power Set-point (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the ReactiveVirtualOscilator model are:\n\tE_oc: voltage reference state for inner control in the d-axis",
"internal_default": "[:E_oc]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) ReactiveVirtualOscillator has 1 state",
"internal_default": 1,
"data_type": "Int"
}
],
"supertype": "ReactivePowerControl"
},
{
"struct_name": "VoltageModeControl",
"docstring": "Parameters of an inner loop current control PID using virtual impedance based on [\"A Virtual Synchronous Machine implementation for distributed control of power converters in SmartGrids.\"](https://doi.org/10.1016/j.epsr.2015.01.001)",
"fields": [
{
"name": "kpv",
"comment": "voltage controller proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kiv",
"comment": "voltage controller integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kffv",
"comment": "Binary variable to enable feed-forward gain of voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rv",
"comment": "virtual resistance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "lv",
"comment": "virtual inductance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kpc",
"comment": "current controller proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kic",
"comment": "current controller integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kffi",
"comment": "Binary variable to enable feed-forward gain of current",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ωad",
"comment": "active damping filter cutoff frequency (rad/sec)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kad",
"comment": "active damping gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the VoltageModeControl model are:\n\tξd_ic: d-axis integrator state of the PI voltage controller,\n\tξq_ic: q-axis integrator state of the PI voltage controller,\n\tγd_ic: d-axis integrator state of the PI current controller,\n\tγq_ic: q-axis integrator state of the PI current controller,\n\tϕd_ic: d-axis low-pass filter of active damping,\n\tϕq_ic: q-axis low-pass filter of active damping",
"internal_default": "[:ξd_ic, :ξq_ic, :γd_ic, :γq_ic, :ϕd_ic, :ϕq_ic]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) VoltageModeControl has 6 states",
"internal_default": 6,
"data_type": "Int"
}
],
"supertype": "InnerControl"
},
{
"struct_name": "CurrentModeControl",
"docstring": "Parameters of an inner loop proportional integral (PI) current control based on [\"Reduced-order Structure-preserving Model for Parallel-connected Three-phase Grid-tied Inverters.\"](https://doi.org/10.1109/COMPEL.2017.8013389)",
"fields": [
{
"name": "kpc",
"comment": "Current controller proportional gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kic",
"comment": "Current controller integral gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kffv",
"comment": "Gain to enable feed-forward gain of voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the CurrentModeControl model are:\n\tγd_ic: d-axis integrator state of the PI current controller,\n\tγq_ic: q-axis integrator state of the PI current controller",
"internal_default": "[:γd_ic, :γq_ic]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) CurrentControl has 2 states",
"internal_default": 2,
"data_type": "Int"
}
],
"supertype": "InnerControl"
},
{
"struct_name": "RECurrentControlB",
"docstring": "Parameters of the Inner Control part of the REECB model in PSS/E",
"fields": [
{
"name": "Q_Flag",
"comment": "Q Flag used for I_qinj",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "PQ_Flag",
"comment": "PQ Flag used for the Current Limit Logic",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Vdip_lim",
"comment": "Limits for Voltage Dip Logic `(Vdip, Vup)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "T_rv",
"comment": "Voltage Filter Time Constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "dbd_pnts",
"comment": "Voltage error deadband thresholds `(dbd1, dbd2)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "K_qv",
"comment": "Reactive current injection gain during over and undervoltage conditions",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Iqinj_lim",
"comment": "Limits for Iqinj `(I_qh1, I_ql1)`",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "V_ref0",
"comment": "User defined reference. If 0, [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/) initializes to initial terminal voltage",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_vp",
"comment": "Voltage regulator proportional gain (used when QFlag = 1)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "K_vi",
"comment": "Voltage regulator integral gain (used when QFlag = 1)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T_iq",
"comment": "Time constant for low-pass filter for state q_V when QFlag = 0",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "I_max",
"comment": "Maximum limit on total converter current",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of the RECurrentControlB depends on the Flags",
"internal_default": "PowerSystems.get_REControlB_states(Q_Flag)",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The states of the RECurrentControlB depends on the Flags",
"internal_default": "2",
"data_type": "Int"
}
],
"supertype": "InnerControl"
},
{
"struct_name": "MagnitudeOutputCurrentLimiter",
"docstring": "Parameters of Magnitude (Circular) Current Controller Limiter. Regulates only the magnitude of the inverter output current",
"fields": [
{
"name": "I_max",
"comment": "Maximum limit on current controller input current in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
}
],
"supertype": "OutputCurrentLimiter"
},
{
"struct_name": "InstantaneousOutputCurrentLimiter",
"docstring": "Parameters of Instantaneous (Square) Current Controller Limiter. Regulates inverter output current on the d and q axis separately",
"fields": [
{
"name": "Id_max",
"comment": "Maximum limit on d-axis current controller input current in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Iq_max",
"comment": "Maximum limit on d-axis current controller input current in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
}
],
"supertype": "OutputCurrentLimiter"
},
{
"struct_name": "PriorityOutputCurrentLimiter",
"docstring": "Parameters of Priority-Based Current Controller Limiter. Regulates the magnitude of the inverter output current and prioritizes a specific angle for the resultant current signal",
"fields": [
{
"name": "I_max",
"comment": "Maximum limit on current controller input current in pu ([`DEVICE_BASE`](@ref per_unit))",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ϕ_I",
"comment": "Pre-defined angle (measured against the d-axis) for I_ref once limit I_max is hit",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": -1.571,
"max": 1.571
}
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
}
],
"supertype": "OutputCurrentLimiter"
},
{
"struct_name": "SaturationOutputCurrentLimiter",
"docstring": "Parameters of Saturation Current Controller Limiter. Regulates the magnitude of the inverter output current, and applies a closed loop feedback regulated by a static gain which provides ant-windup",
"fields": [
{
"name": "I_max",
"comment": "Maximum limit on current controller input current (device base)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kw",
"comment": "Defined feedback gain",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
}
],
"supertype": "OutputCurrentLimiter"
},
{
"struct_name": "HybridOutputCurrentLimiter",
"docstring": "Parameters of Hybrid Current Controller Limiter. Regulates the magnitude of the inverter output current, but with a closed loop feedback regulated by a virtual impedance which provides ant-windup. Described in: Novel Hybrid Current Limiter for Grid-Forming Inverter Control During Unbalanced Faults by Baeckland and Seo, 2023 ",
"fields": [
{
"name": "I_max",
"comment": "Maximum limit on current controller input current (device base)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rv",
"comment": "Real part of the virtual impedance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "lv",
"comment": "Imaginary part of the virtual impedance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ext",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
}
],
"supertype": "OutputCurrentLimiter"
},
{
"struct_name": "AggregateDistributedGenerationA",
"docstring": "Parameters of the DERA1 model in PSS/E",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"name": "Pf_Flag",
"comment": "Flag for Power Factor Control",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Freq_Flag",
"comment": "Flag to enable/disable frequency control",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "PQ_Flag",
"comment": "Flag used to enforce maximum current",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Gen_Flag",
"comment": "Flag to specify generator or storage",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Vtrip_Flag",
"comment": "Flag to enable/disable voltage trip logic",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Ftrip_Flag",
"comment": "Flag to enable/disable frequency trip logic",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "T_rv",
"comment": "Voltage measurement transducer time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Trf",
"comment": "Frequency measurement transducer time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "dbd_pnts",
"comment": "Voltage deadband thresholds `(dbd1, dbd2)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "K_qv",
"comment": "Proportional voltage control gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tp",
"comment": "Power measurement transducer time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "T_iq",
"comment": "Time constant for low-pass filter for state q_V when QFlag = 0",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_dn",
"comment": "Reciprocal of droop for over-frequency conditions (>0) (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_up",
"comment": "Reciprocal of droop for under-frequency conditions <=0) (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "fdbd_pnts",
"comment": "Frequency control deadband thresholds `(fdbd1, fdbd2)`",
"null_value": "(0.0, 0.0)",
"data_type": "Tuple{Float64, Float64}"
},
{
"name": "fe_lim",
"comment": "Frequency error limits (femin, femax)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "P_lim",
"comment": "Power limits (Pmin, Pmax)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "dP_lim",
"comment": "Power reference ramp rate limits (dPmin, dPmax)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Tpord",
"comment": "Power filter time constant",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Kpg",
"comment": "PI controller proportional gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Kig",
"comment": "PI controller integral gain (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "I_max",
"comment": "Maximum limit on total converter current (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "vl_pnts",
"comment": "Low voltage cutout points `[(tv10, vl0), (tv11, vl1)]`",
"null_value": "[(0.0, 0.0), (0.0, 0.0)]",
"data_type": "Vector{Tuple{Float64,Float64}}"
},
{
"name": "vh_pnts",
"comment": "High voltage cutout points `[(tvh0, vh0), (tvh1, vh1)]`",
"null_value": "[(0.0, 0.0), (0.0, 0.0)]",
"data_type": "Vector{Tuple{Float64,Float64}}"
},
{
"name": "Vrfrac",
"comment": "Fraction of device that recovers after voltage comes back to within vl1 < V < vh1 (0 <= Vrfrac <= 1)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "fl",
"comment": "Inverter frequency break-point for low frequency cut-out (Hz)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "fh",
"comment": "Inverter frequency break-point for high frequency cut-out (Hz)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "tfl",
"comment": "Low frequency cut-out timer corresponding to frequency fl (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "tfh",
"comment": "High frequency cut-out timer corresponding to frequency fh (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tg",
"comment": "Current control time constant (to represent behavior of inner control loops) (> 0) (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rrpwr",
"comment": "Ramp rate for real power increase following a fault (pu/s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tv",
"comment": "Time constant on the output of the multiplier (s)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Vpr",
"comment": "Voltage below which frequency tripping is disabled (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Iq_lim",
"comment": "Reactive current injection limits (Iqll, Iqhl)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "V_ref",
"comment": "User defined voltage reference. If 0, [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/) initializes to initial terminal voltage",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Pfa_ref",
"comment": "Reference power factor",
"null_value": 0,
"default": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "ω_ref",
"comment": "Reference Frequency (pu)",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Q_ref",
"comment": "Reference reactive power, in pu",
"null_value": 0,
"default": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "P_ref",
"comment": "Reference active power, in pu",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "base_power",
"comment": "Base power (MVA) for [per unitization](@ref per_unit)",
"null_value": 0,
"data_type": "Float64",
"default": "100.0"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of AggregateDistributedGenerationA depends on the Flags",
"internal_default": "PowerSystems.get_AggregateDistributedGenerationA_states(Freq_Flag)[1]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The states of AggregateDistributedGenerationA depends on the Flags",
"internal_default": "PowerSystems.get_AggregateDistributedGenerationA_states(Freq_Flag)[2]",
"data_type": "Int"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "DynamicInjection"
},
{
"struct_name": "Source",
"docstring": "An infinite bus with a constant voltage output.\n\nCommonly used in dynamics simulations to represent a very large machine on a single bus or for the representation of import/exports in operational simulations",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"null_value": "false",
"name": "available",
"comment": "Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations",
"data_type": "Bool"
},
{
"name": "bus",
"comment": "Bus that this component is connected to",
"null_value": "ACBus(nothing)",
"data_type": "ACBus"
},
{
"name": "active_power",
"comment": "Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power",
"comment": "Initial reactive power set point of the unit (MVAR)",
"null_value": "0.0",
"data_type": "Float64",
"default": "0.0",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "active_power_limits",
"comment": "Minimum and maximum stable active power levels (MW)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax",
"default": "(min=0.0, max=0.0)",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "reactive_power_limits",
"comment": "Minimum and maximum reactive power limits. Set to `Nothing` if not applicable",
"validation_action": "warn",
"null_value": "nothing",
"data_type": "Union{Nothing, MinMax}",
"default": "(min=0.0, max=0.0)",
"needs_conversion": true,
"conversion_unit": ":mva"
},
{
"name": "R_th",
"comment": "Source Thevenin resistance. [See here:](https://en.wikipedia.org/wiki/Thevenins_theorem)",
"null_value": 0,
"data_type": "Float64",
"default": "0.0",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "X_th",
"comment": "Source Thevenin reactance. [See here:](https://en.wikipedia.org/wiki/Thevenins_theorem)",
"null_value": 0,
"default": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "internal_voltage",
"comment": "Internal Voltage (pu)",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
},
"default": "1.0"
},
{
"name": "internal_angle",
"comment": "Internal Angle",
"null_value": 0,
"data_type": "Float64",
"default": "0.0"
},
{
"name": "base_power",
"comment": "Base Power in MVA",
"null_value": 0,
"data_type": "Float64",
"default": "100.0"
},
{
"name": "operation_cost",
"null_value": "ImportExportCost(nothing)",
"data_type": "ImportExportCost",
"default": "ImportExportCost(nothing)",
"comment": "[`ImportExportCost`](@ref) of the source."
},
{
"name": "dynamic_injector",
"data_type": "Union{Nothing, DynamicInjection}",
"comment": "corresponding dynamic injection device",
"null_value": "nothing",
"exclude_setter": true,
"default": "nothing"
},
{
"name": "services",
"data_type": "Vector{Service}",
"comment": "Services that this device contributes to",
"null_value": "Device[]",
"default": "Device[]"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "StaticInjection"
},
{
"struct_name": "PeriodicVariableSource",
"docstring": "This struct acts as an infinity bus with time varying phasor values magnitude and angle V(t) \theta(t). Time varying functions are represented using fourier series",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"name": "R_th",
"comment": "Source Thevenin resistance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "X_th",
"comment": "Source Thevenin reactance",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "internal_voltage_bias",
"comment": "a0 term of the Fourier Series for the voltage",
"null_value": 0,
"data_type": "Float64",
"default": "0.0"
},
{
"name": "internal_voltage_frequencies",
"comment": "Frequencies in radians/s",
"null_value": [
0
],
"data_type": "Vector{Float64}",
"default": "[0.0]"
},
{
"name": "internal_voltage_coefficients",
"comment": "Coefficients for terms n > 1. First component corresponds to sin and second component to cos",
"null_value": "[(0.0, 0.0)]",
"data_type": "Vector{Tuple{Float64,Float64}}",
"default": "[(0.0, 0.0)]"
},
{
"name": "internal_angle_bias",
"comment": "a0 term of the Fourier Series for the angle",
"null_value": 0,
"data_type": "Float64",
"default": "0.0"
},
{
"name": "internal_angle_frequencies",
"comment": "Frequencies in radians/s",
"null_value": [
0
],
"data_type": "Vector{Float64}",
"default": "[0.0]"
},
{
"name": "internal_angle_coefficients",
"comment": "Coefficients for terms n > 1. First component corresponds to sin and second component to cos",
"null_value": "[(0.0, 0.0)]",
"data_type": "Vector{Tuple{Float64,Float64}}",
"default": "[(0.0, 0.0)]"
},
{
"name": "base_power",
"comment": "Base power of the source (MVA) for [per unitization](@ref per_unit)",
"null_value": 0,
"data_type": "Float64",
"default": "100.0"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) for time, voltage and angle",
"internal_default": "[:Vt, :θt]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) PeriodicVariableSource has 2 states",
"null_value": 2,
"internal_default": 2,
"data_type": "Int"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "DynamicInjection"
},
{
"struct_name": "GenericDER",
"docstring": "Parameters of a Generic Distributed Energy Resource Model. Based on [\"Modeling Framework and Coordination of DER and Flexible Loads for Ancillary Service Provision.\"](http://hdl.handle.net/10125/70994)",
"fields": [
{
"null_value": "init",
"name": "name",
"comment": "Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name",
"exclude_setter": true,
"data_type": "String"
},
{
"name": "Qref_Flag",
"comment": "Reactive Power Control Mode. 1 VoltVar Control, 2 Constant Q Control, 3 Constant PF Control",
"null_value": 1,
"data_type": "Int",
"valid_range": {
"min": 1,
"max": 3
}
},
{
"name": "PQ_Flag",
"comment": "Active and reactive power priority mode. 0 for Q priority, 1 for P priority",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Gen_Flag",
"comment": "Define generator or storage system. 0 unit is a storage device, 1 unit is a generator",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "PerOp_Flag",
"comment": "Defines operation of permisible region in VRT characteristic. 0 for cease, 1 for continuous operation",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Recon_Flag",
"comment": "Defines if DER can reconnect after voltage ride-through disconnection",
"null_value": 0,
"data_type": "Int",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "Trv",
"comment": "Voltage measurement transducer's time constant, in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "VV_pnts",
"comment": "Y-axis Volt-var curve points (V1,V2,V3,V4)",
"null_value": "(V1=0.0, V2=0.0, V3=0.0, V4=0.0)",
"data_type": "NamedTuple{(:V1, :V2, :V3, :V4), Tuple{Float64, Float64, Float64, Float64}}"
},
{
"name": "Q_lim",
"comment": "Reactive power limits in pu (Q_min, Q_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Tp",
"comment": "Power measurement transducer's time constant, in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "e_lim",
"comment": "Error limit in PI controller for q control (e_min, e_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Kpq",
"comment": "PI controller proportional gain for q control",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Kiq",
"comment": "PI controller integral gain for q control",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Iqr_lim",
"comment": "Limit on rate of change for reactive current (pu/s) (Iqr_min, Iqr_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "I_max",
"comment": "Max. inverter's current",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Tg",
"comment": "Current control's time constant, in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "kWh_Cap",
"comment": "BESS capacity in kWh",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "SOC_ini",
"comment": "Initial state of charge (SOC) in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": 1
}
},
{
"name": "SOC_lim",
"comment": "Battery's SOC limits (SOC_min, SOC_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Trf",
"comment": "Time constant to estimate system frequency, in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "fdbd_pnts",
"comment": "Frequency error dead band thresholds `(fdbd1, fdbd2)`",
"null_value": "(fdbd1=0.0, fdbd2=0.0)",
"data_type": "NamedTuple{(:fdbd1, :fdbd2), Tuple{Float64, Float64}}"
},
{
"name": "D_dn",
"comment": "reciprocal of droop for over-frequency conditions, in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "D_up",
"comment": "reciprocal of droop for under-frequency conditions, in pu",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "fe_lim",
"comment": "Frequency error limits in pu (fe_min, fe_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Kpp",
"comment": "PI controller proportional gain for p control",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Kip",
"comment": "PI controller integral gain for p control",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "P_lim",
"comment": "Active power limits in pu (P_min, P_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "dP_lim",
"comment": "Ramp rate limits for active power in pu/s (dP_min, dP_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "T_pord",
"comment": "Power filter time constant in s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "rrpwr",
"comment": "Ramp rate for real power increase following a fault, in pu/s",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "VRT_pnts",
"comment": "Voltage ride through v points (vrt1,vrt2,vrt3,vrt4,vrt5)",
"null_value": "(vrt1=0.0, vrt2=0.0, vrt3=0.0, vrt4=0.0, vrt5=0.0)",
"data_type": "NamedTuple{(:vrt1, :vrt2, :vrt3, :vrt4, :vrt5), Tuple{Float64, Float64, Float64, Float64, Float64}}"
},
{
"name": "TVRT_pnts",
"comment": "Voltage ride through time points (tvrt1,tvrt2,tvrt3)",
"null_value": "(tvrt1=0.0, tvrt2=0.0, tvrt3=0.0)",
"data_type": "NamedTuple{(:tvrt1, :tvrt2, :tvrt3), Tuple{Float64, Float64, Float64}}"
},
{
"name": "tV_delay",
"comment": "Time delay for reconnection after voltage ride-through disconnection",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "VES_lim",
"comment": "Min and max voltage for entering service (VES_min,VES_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "FRT_pnts",
"comment": "Frequency ride through v points (frt1,frt2,frt3,frt4)",
"null_value": "(frt1=0.0, frt2=0.0, frt3=0.0, frt4=0.0)",
"data_type": "NamedTuple{(:frt1, :frt2, :frt3, :frt4), Tuple{Float64, Float64, Float64, Float64}}"
},
{
"name": "TFRT_pnts",
"comment": "Frequency ride through time points (tfrt1,tfrt2)",
"null_value": "(tfrt1=0.0, tfrt2=0.0)",
"data_type": "NamedTuple{(:tfrt1, :tfrt2), Tuple{Float64, Float64}}"
},
{
"name": "tF_delay",
"comment": "Time delay for reconnection after frequency ride-through disconnection",
"null_value": 0,
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "FES_lim",
"comment": "Min and max frequency for entering service (FES_min,FES_max)",
"null_value": "(min=0.0, max=0.0)",
"data_type": "MinMax"
},
{
"name": "Pfa_ref",
"comment": "Reference power factor",
"null_value": 0,
"default": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "Q_ref",
"comment": "Reference reactive power, in pu",
"null_value": 0,
"default": "0.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "P_ref",
"comment": "Reference active power, in pu",
"null_value": 0,
"default": "1.0",
"data_type": "Float64",
"valid_range": {
"min": 0,
"max": null
}
},
{
"name": "base_power",
"comment": "Base power of the unit (MVA) for [per unitization](@ref per_unit)",
"null_value": 0,
"data_type": "Float64",
"default": "100.0"
},
{
"name": "states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of GenericDER depend on the Flags",
"internal_default": "PowerSystems.get_GenericDER_states(Qref_Flag)[1]",
"data_type": "Vector{Symbol}"
},
{
"name": "n_states",
"exclude_setter": true,
"comment": "(**Do not modify.**) The [states](@ref S) of GenericDER depend on the Flags",
"internal_default": "PowerSystems.get_GenericDER_states(Qref_Flag)[2]",
"data_type": "Int"
},
{
"name": "ext",
"comment": "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.",
"data_type": "Dict{String, Any}",
"null_value": "Dict{String, Any}()",
"default": "Dict{String, Any}()"
},
{
"name": "internal",
"comment": "(**Do not modify.**) PowerSystems.jl internal reference",
"data_type": "InfrastructureSystemsInternal",
"internal_default": "InfrastructureSystemsInternal()",
"exclude_setter": true
}
],
"supertype": "DynamicInjection"
}
],
"struct_validation_descriptors": [
{
"struct_name": "DynamicGenerator",
"docstring": "",
"fields": [
{
"name": "name"
},
{
"name": "ω_ref"
},
{
"name": "machine"
},
{
"name": "shaft"
},
{
"name": "avr"
},
{
"name": "prime_mover"
},
{
"name": "pss"
},
{
"name": "base_power"
},
{
"name": "n_states"
},
{
"name": "states"
},
{
"name": "ext"
},
{
"name": "internal"
}
]
},
{
"struct_name": "DynamicInverter",
"docstring": "",
"fields": [
{
"name": "name"
},
{
"name": "ω_ref"
},
{
"name": "converter"
},
{
"name": "outer_control"
},
{
"name": "inner_control"
},
{
"name": "dc_source"
},
{
"name": "freq_estimator"
},
{
"name": "filter"
},
{
"name": "limiter"
},
{
"name": "base_power"
},
{
"name": "n_states"
},
{
"name": "states"
},
{
"name": "ext"
},
{
"name": "internal"
}
]
}
]
}
================================================
FILE: src/get_components_interface.jl
================================================
# The longstanding status quo in Sienna has been for `PSY.get_components` to be distinct
# from `IS.get_components`, mostly so that PowerSystems users aren't confused by all the
# InfrastructureSystems methods. This lack of a unified interface on "things with
# components" has begun to cause problems, most notably for ComponentSelector. Therefore,
# the new plan is:
# 1. Implement, wherever relevant, methods of the IS `get_components`-like functions
# listed below on PSY data structures.
# 2. Add, in this file, methods of the PSY `get_components`-like functions that purely
# redirect to the IS versions and have the documentation PSY users should see. Never
# add actual functionality in these PSY methods; they must only redirect to the IS
# versions. Purely to facilitate neater documentation, add `ComponentSelector`-related
# methods in the follow-on file `component_selector_interface.jl` instead.
# 3. In downstream Sienna packages like PowerSimulations that seek to add their own
# `get_components`-like methods on their own data structures that show up in
# user-friendly documentation, do the same thing: add the implementation in the IS
# method and add a PSY method that purely redirects.
# 4. Internal code designed to work with all "things with components" should use the IS
# functions, not the PSY ones.
# This design preserves the simplified interface presented to the casual PSY user while
# allowing for better cross-package integration behind the scenes. It also enables a quick
# switch to a design where we no longer maintain two versions of each `get_components`-like
# function at the cost of slightly more confusing documentation -- simply import the IS
# versions into PowerSystems and delete this file (and analogous redirects in downstream
# packages). See https://github.com/Sienna-Platform/InfrastructureSystems.jl/issues/388.
# Here is the current list of "`get_components`-like functions" to which this plan applies:
# - `get_components`
# - `get_component`
# - `get_available_components`
# - `get_available_component`
# - `get_groups`
# - `get_available_groups`
# get_components
"""
Return an iterator of components of a given `Type` from a [`System`](@ref).
`T` can be a concrete or abstract [`Component`](@ref) type from the [Type Tree](@ref).
Call collect on the result if an array is desired.
# Examples
```julia
iter = get_components(ThermalStandard, sys)
iter = get_components(Generator, sys)
generators = collect(get_components(Generator, sys))
```
See also: [`iterate_components`](@ref), [`get_components` with a filter](@ref get_components(
filter_func::Function,
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component}),
[`get_available_components`](@ref), [`get_buses`](@ref)
"""
get_components(::Type{T}, sys::System; subsystem_name = nothing) where {T <: Component} =
IS.get_components(T, sys; subsystem_name = subsystem_name)
"""
Return a vector of components that are attached to the supplemental attribute.
# Arguments
- `sys::System`: the `System` to search
- `attribute::SupplementalAttribute`: Only return components associated with this attribute.
- `component_type::Union{Nothing, <:Component}`: Optional type of the components to return.
Can be concrete or abstract. If not provided, all components associated with the attribute
will be returned.
"""
function get_associated_components(
sys::System,
attribute::SupplementalAttribute;
component_type::Union{Nothing, Type{<:Component}} = nothing,
)
return IS.get_associated_components(
sys.data,
attribute;
component_type = component_type,
)
end
@deprecate get_components(sys::System, attribute::SupplementalAttribute) get_associated_components(
sys,
attribute,
)
"""
Return a vector of components that are associated to one or more supplemental attributes of
the given type.
"""
function get_associated_components(
sys::System,
attribute_type::Type{<:SupplementalAttribute};
component_type::Union{Nothing, Type{<:Component}} = nothing,
)
return IS.get_associated_components(
sys.data,
attribute_type;
component_type = component_type,
)
end
"""
Return an iterator of components of a given `Type` from a [`System`](@ref), using an
additional filter
`T` can be a concrete or abstract [`Component`](@ref) type from the [Type Tree](@ref).
Call collect on the result if an array is desired.
# Examples
```julia
iter_coal = get_components(x -> get_fuel(x) == ThermalFuels.COAL, Generator, sys)
pv_gens =
collect(get_components(x -> get_prime_mover_type(x) == PrimeMovers.PVe, Generator, sys))
```
See also: [`get_components`](@ref get_components(
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component}), [`get_available_components`](@ref),
[`get_buses`](@ref)
"""
get_components(
filter_func::Function,
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component} =
IS.get_components(filter_func, T, sys; subsystem_name = subsystem_name)
# get_component
"""
Get the component by UUID.
"""
get_component(sys::System, uuid::Base.UUID) = IS.get_component(sys, uuid)
get_component(sys::System, uuid::String) = IS.get_component(sys, uuid)
"""
Get the component of type T with name. Returns nothing if no component matches. If T is an abstract
type then the names of components across all subtypes of T must be unique.
See [`get_components_by_name`](@ref) for abstract types with non-unique names across subtypes.
Throws ArgumentError if T is not a concrete type and there is more than one component with
requested name
"""
get_component(::Type{T}, sys::System, name::AbstractString) where {T <: Component} =
IS.get_component(T, sys, name)
# get_available_components
"""
Like [`get_components`](@ref get_components(
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component}
) but returns only components that are [`get_available`](@ref).
```
"""
get_available_components(
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component} =
IS.get_available_components(T, sys; subsystem_name = subsystem_name)
"""
Like [`get_components`](@ref get_components(
sys::System,
attribute::SupplementalAttribute
) but returns only components that are [`get_available`](@ref).
"""
get_available_components(sys::System, attribute::SupplementalAttribute) =
IS.get_available_components(sys, attribute)
"""
Like [`get_components`](@ref get_components(
filter_func::Function,
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component}
) but returns only components that are [`get_available`](@ref).
"""
get_available_components(
filter_func::Function,
::Type{T},
sys::System;
subsystem_name = nothing,
) where {T <: Component} =
IS.get_available_components(filter_func, T, sys; subsystem_name = subsystem_name)
# get_available_component
"""
Get the available component by UUID.
"""
get_available_component(sys::System, uuid::Base.UUID) =
IS.get_available_component(sys, uuid)
get_available_component(sys::System, uuid::String) = IS.get_available_component(sys, uuid)
"""
Like [`get_component`](@ref) but also returns `nothing` if the component is not [`get_available`](@ref).
"""
get_available_component(::Type{T}, sys::System, args...; kwargs...) where {T <: Component} =
IS.get_available_component(T, sys, args...; kwargs...)
================================================
FILE: src/impedance_correction.jl
================================================
"""
Attribute that contains information regarding the Impedance Correction Table (ICT) rows defined in the Table.
# Arguments
- `table_number::Int64`: Row number of the ICT to be linked with a specific Transformer component.
- `impedance_correction_curve::`[`PiecewiseLinearData`](@extref InfrastructureSystems.PiecewiseLinearData): Function to define intervals (tap ratio/angle shift) in the Transformer component.
- `transformer_winding::`[`WindingCategory`](@ref): Indicates the winding to which the ICT is linked to for a Transformer component.
- `transformer_control_mode::`[`ImpedanceCorrectionTransformerControlMode`](@ref): Defines the control modes of the Transformer, whether is for off-nominal turns ratio or phase angle shifts.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems internal reference
"""
struct ImpedanceCorrectionData <: SupplementalAttribute
table_number::Int64
impedance_correction_curve::PiecewiseLinearData
transformer_winding::WindingCategory
transformer_control_mode::ImpedanceCorrectionTransformerControlMode
internal::InfrastructureSystemsInternal
end
"""
ImpedanceCorrectionData(; table_number, impedance_correction_curve, transformer_winding, transformer_control_mode, internal)
Construct an [`ImpedanceCorrectionData`](@ref).
# Arguments
- `table_number::Int64`: Row number of the ICT to be linked with a specific Transformer component.
- `impedance_correction_curve::`[`PiecewiseLinearData`](@extref InfrastructureSystems.PiecewiseLinearData): Function to define intervals (tap ratio/angle shift) in the Transformer component.
- `transformer_winding::`[`WindingCategory`](@ref): Indicates the winding to which the ICT is linked to for a Transformer component.
- `transformer_control_mode::`[`ImpedanceCorrectionTransformerControlMode`](@ref): Defines the control modes of the Transformer, whether is for off-nominal turns ratio or phase angle shifts.
- `internal::InfrastructureSystemsInternal`: (default: `InfrastructureSystemsInternal()`) (**Do not modify.**) PowerSystems internal reference
"""
function ImpedanceCorrectionData(;
table_number,
impedance_correction_curve,
transformer_winding,
transformer_control_mode,
internal = InfrastructureSystemsInternal(),
)
return ImpedanceCorrectionData(
table_number,
impedance_correction_curve,
transformer_winding,
transformer_control_mode,
internal,
)
end
"""Get [`ImpedanceCorrectionData`](@ref) `table_number`."""
get_table_number(value::ImpedanceCorrectionData) = value.table_number
"""Get [`ImpedanceCorrectionData`](@ref) `function_data`."""
get_impedance_correction_curve(value::ImpedanceCorrectionData) =
value.impedance_correction_curve
"""Get [`ImpedanceCorrectionData`](@ref) `transformer_winding`."""
get_transformer_winding(value::ImpedanceCorrectionData) = value.transformer_winding
"""Get [`ImpedanceCorrectionData`](@ref) `transformer_control_mode`."""
get_transformer_control_mode(value::ImpedanceCorrectionData) =
value.transformer_control_mode
"""Get [`ImpedanceCorrectionData`](@ref) `internal`."""
get_internal(value::ImpedanceCorrectionData) = value.internal
================================================
FILE: src/models/HybridSystem.jl
================================================
"""
mutable struct HybridSystem <: StaticInjectionSubsystem
name::String
available::Bool
status::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
base_power::Float64
operation_cost::MarketBidCost
thermal_unit::Union{Nothing, ThermalGen}
electric_load::Union{Nothing, ElectricLoad}
storage::Union{Nothing, Storage}
renewable_unit::Union{Nothing, RenewableGen}
interconnection_impedance::ComplexF64
interconnection_rating::Union{Nothing, Float64}
input_active_power_limits::Union{Nothing, MinMax}
output_active_power_limits::Union{Nothing, MinMax}
reactive_power_limits::Union{Nothing, MinMax}
interconnection_efficiency::Union{
Nothing,
NamedTuple{(:in, :out), Tuple{Float64, Float64}},
}
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A Hybrid System that includes a combination of renewable generation, load, thermal
generation and/or energy storage.
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `status::Bool`: Initial commitment condition at the start of a simulation (`true` = on or `false` = off)
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used
- `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR)
- `base_power::Float64`: Base power of the unit (MVA) for per unitization, which is commonly the same as `rating`
- `operation_cost::MarketBidCost`: Market bid cost to operate, [`MarketBidCost`](@ref)
- `thermal_unit::Union{Nothing, ThermalGen}`: A thermal generator with supertype [`ThermalGen`](@ref)
- `electric_load::Union{Nothing, ElectricLoad}`: A load with supertype [`ElectricLoad`](@ref)
- `storage::Union{Nothing, Storage}`: An energy storage system with supertype [`Storage`](@ref)
- `renewable_unit::Union{Nothing, RenewableGen}`: A renewable generator with supertype [`RenewableGen`](@ref)
- `interconnection_impedance::ComplexF64`: Impedance (typically in p.u.) between the hybrid system and the grid interconnection
- `interconnection_rating::Union{Nothing, Float64}`: Maximum rating of the hybrid system's interconnection with the transmission network (MVA)
- `input_active_power_limits::MinMax`: Minimum and maximum stable input active power levels (MW)
- `output_active_power_limits::MinMax`: Minimum and maximum stable output active power levels (MW)
- `reactive_power_limits::Union{Nothing, MinMax}`: Minimum and maximum reactive power limits (MVAR). Set to `Nothing` if not applicable.
- `interconnection_efficiency::Union{Nothing, NamedTuple{(:in, :out), Tuple{Float64, Float64}},}`: Efficiency [0, 1.0] at the grid interconnection to model losses `in` and `out` of the common DC-side conversion
- `services::Vector{Service}`: (optional) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (optional) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (optional) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference.
"""
mutable struct HybridSystem <: StaticInjectionSubsystem
name::String
available::Bool
status::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
base_power::Float64
operation_cost::MarketBidCost
thermal_unit::Union{Nothing, ThermalGen}
electric_load::Union{Nothing, ElectricLoad}
storage::Union{Nothing, Storage}
renewable_unit::Union{Nothing, RenewableGen}
# interconnection Data
"Thermal limited MVA Power Output of the unit. <= Capacity"
interconnection_impedance::ComplexF64
interconnection_rating::Union{Nothing, Float64}
input_active_power_limits::Union{Nothing, MinMax}
output_active_power_limits::Union{Nothing, MinMax}
reactive_power_limits::Union{Nothing, MinMax}
interconnection_efficiency::Union{
Nothing,
NamedTuple{(:in, :out), Tuple{Float64, Float64}},
}
"corresponding dynamic injection device"
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
"internal forecast storage"
"power system internal reference, do not modify"
internal::InfrastructureSystemsInternal
end
function HybridSystem(;
name = "init",
available = false,
status = false,
bus = ACBus(nothing),
active_power = 0.0,
reactive_power = 0.0,
base_power = 100.0,
operation_cost = MarketBidCost(nothing),
thermal_unit = nothing,
electric_load = nothing,
storage = nothing,
renewable_unit = nothing,
interconnection_impedance = 0.0,
interconnection_rating = nothing,
input_active_power_limits = nothing,
output_active_power_limits = nothing,
reactive_power_limits = nothing,
interconnection_efficiency = nothing,
services = Service[],
dynamic_injector = nothing,
ext = Dict{String, Any}(),
internal = InfrastructureSystemsInternal(),
)
return HybridSystem(
name,
available,
status,
bus,
active_power,
reactive_power,
base_power,
operation_cost,
thermal_unit,
electric_load,
storage,
renewable_unit,
interconnection_impedance,
interconnection_rating,
input_active_power_limits,
output_active_power_limits,
reactive_power_limits,
interconnection_efficiency,
services,
dynamic_injector,
ext,
internal,
)
end
# Constructor for demo purposes; non-functional.
function HybridSystem(::Nothing)
return HybridSystem(;
name = "init",
available = false,
status = false,
bus = ACBus(nothing),
active_power = 0.0,
reactive_power = 0.0,
base_power = 100.0,
operation_cost = MarketBidCost(nothing),
thermal_unit = ThermalStandard(nothing),
electric_load = PowerLoad(nothing),
storage = EnergyReservoirStorage(nothing),
renewable_unit = RenewableDispatch(nothing),
interconnection_impedance = 0.0,
interconnection_rating = nothing,
input_active_power_limits = nothing,
output_active_power_limits = nothing,
reactive_power_limits = nothing,
interconnection_efficiency = nothing,
services = Service[],
dynamic_injector = nothing,
ext = Dict{String, Any}(),
internal = InfrastructureSystemsInternal(),
)
end
get_name(value::HybridSystem) = value.name
function _get_components(value::HybridSystem)
components =
[value.thermal_unit, value.electric_load, value.storage, value.renewable_unit]
filter!(x -> !isnothing(x), components)
return components
end
function set_units_setting!(value::HybridSystem, settings::SystemUnitsSettings)
set_units_info!(get_internal(value), settings)
for component in _get_components(value)
set_units_info!(get_internal(component), settings)
end
return
end
"""Get [`HybridSystem`](@ref) `available`."""
get_available(value::HybridSystem) = value.available
"""Get [`HybridSystem`](@ref) `status`."""
get_status(value::HybridSystem) = value.status
"""Get [`HybridSystem`](@ref) `bus`."""
get_bus(value::HybridSystem) = value.bus
"""Get [`HybridSystem`](@ref) `active_power`."""
get_active_power(value::HybridSystem) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`HybridSystem`](@ref) `reactive_power`."""
get_reactive_power(value::HybridSystem) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`HybridSystem`](@ref) thermal unit"""
get_thermal_unit(value::HybridSystem) = value.thermal_unit
"""Get [`HybridSystem`](@ref) load"""
get_electric_load(value::HybridSystem) = value.electric_load
"""Get [`HybridSystem`](@ref) storage unit"""
get_storage(value::HybridSystem) = value.storage
"""Get [`HybridSystem`](@ref) renewable unit"""
get_renewable_unit(value::HybridSystem) = value.renewable_unit
"""Get [`HybridSystem`](@ref) `interconnection_rating`."""
get_interconnection_rating(value::HybridSystem) =
get_value(value, Val(:interconnection_rating), Val(:mva))
"""get [`HybridSystem`](@ref) interconnection impedance"""
get_interconnection_impedance(value::HybridSystem) = value.interconnection_impedance
"""Get [`HybridSystem`](@ref) `input_active_power_limits`."""
get_input_active_power_limits(value::HybridSystem) =
get_value(value, Val(:input_active_power_limits), Val(:mva))
"""Get [`HybridSystem`](@ref) `output_active_power_limits`."""
get_output_active_power_limits(value::HybridSystem) =
get_value(value, Val(:output_active_power_limits), Val(:mva))
"""Get [`HybridSystem`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::HybridSystem) =
get_value(value, Val(:reactive_power_limits), Val(:mva))
"""get [`HybridSystem`](@ref) interconnection efficiency"""
get_interconnection_efficiency(value::HybridSystem) = value.interconnection_efficiency
"""Get [`HybridSystem`](@ref) `base_power`."""
get_base_power(value::HybridSystem) = value.base_power
"""Get [`HybridSystem`](@ref) `operation_cost`."""
get_operation_cost(value::HybridSystem) = value.operation_cost
"""Get [`HybridSystem`](@ref) `services`."""
get_services(value::HybridSystem) = value.services
"""Get [`HybridSystem`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::HybridSystem) = value.dynamic_injector
"""Get [`HybridSystem`](@ref) `ext`."""
get_ext(value::HybridSystem) = value.ext
"""Get [`HybridSystem`](@ref) `internal`."""
get_internal(value::HybridSystem) = value.internal
"""Set [`HybridSystem`](@ref) `available`."""
set_available!(value::HybridSystem, val) = value.available = val
"""Get [`HybridSystem`](@ref) `status`."""
set_status!(value::HybridSystem, val) = value.status = val
"""Set [`HybridSystem`](@ref) `bus`."""
set_bus!(value::HybridSystem, val) = value.bus = val
"""Set [`HybridSystem`](@ref) `interconnection_rating`."""
set_interconnection_rating!(value::HybridSystem, val) = value.interconnection_rating = val
"""Set [`HybridSystem`](@ref) `active_power`."""
set_active_power!(value::HybridSystem, val) = value.active_power = val
"""Set [`HybridSystem`](@ref) `reactive_power`."""
set_reactive_power!(value::HybridSystem, val) = value.reactive_power = val
"""set [`HybridSystem`](@ref) interconnection impedance"""
set_interconnection_impedance!(value::HybridSystem, val) =
value.interconnection_impedance = val
"""Set [`HybridSystem`](@ref) `input_active_power_limits`."""
set_input_active_power_limits!(value::HybridSystem, val) =
value.input_active_power_limits = val
"""Set [`HybridSystem`](@ref) `output_active_power_limits`."""
set_output_active_power_limits!(value::HybridSystem, val) =
value.output_active_power_limits = val
"""Set [`HybridSystem`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::HybridSystem, val) = value.reactive_power_limits = val
"""Set [`HybridSystem`](@ref) `interconnection_efficiency`."""
set_interconnection_efficiency!(value::HybridSystem, val) =
value.interconnection_rating = val
"""Set [`HybridSystem`](@ref) `base_power`."""
set_base_power!(value::HybridSystem, val) = value.base_power = val
"""Set [`HybridSystem`](@ref) `operation_cost`."""
set_operation_cost!(value::HybridSystem, val) = value.operation_cost = val
"""Set [`HybridSystem`](@ref) `services`."""
set_services!(value::HybridSystem, val) = value.services = val
"""Set [`HybridSystem`](@ref) `ext`."""
set_ext!(value::HybridSystem, val) = value.ext = val
"""
Return an iterator over the subcomponents in the HybridSystem.
# Examples
```julia
for subcomponent in get_subcomponents(hybrid_sys)
@show subcomponent
end
subcomponents = collect(get_subcomponents(hybrid_sys))
```
"""
function get_subcomponents(hybrid::HybridSystem)
Channel() do channel
for field in (:thermal_unit, :electric_load, :storage, :renewable_unit)
subcomponent = getfield(hybrid, field)
if subcomponent !== nothing
put!(channel, subcomponent)
end
end
end
end
"""Set [`HybridSystem`](@ref) thermal unit"""
function set_thermal_unit!(hybrid::HybridSystem, val::ThermalGen)
_raise_if_attached_to_system(hybrid)
hybrid.thermal_unit = val
return
end
"""Set [`HybridSystem`](@ref) load"""
function set_electric_load!(hybrid::HybridSystem, val::ElectricLoad)
_raise_if_attached_to_system(hybrid)
value.electric_load = val
return
end
"""Set [`HybridSystem`](@ref) storage unit"""
function set_storage!(hybrid::HybridSystem, val::Storage)
_raise_if_attached_to_system(hybrid)
value.storage = val
return
end
"""Set [`HybridSystem`](@ref) renewable unit"""
function set_renewable_unit!(hybrid::HybridSystem, val::RenewableGen)
_raise_if_attached_to_system(hybrid)
value.renewable_unit = val
return
end
function _raise_if_attached_to_system(hybrid::HybridSystem)
if !isnothing(IS.get_time_series_manager(hybrid))
throw(
ArgumentError(
"Operation not allowed because the HybridSystem is attached to a system",
),
)
end
return
end
================================================
FILE: src/models/OuterControl.jl
================================================
"""
mutable struct OuterControl{
A <: ActivePowerControl,
R <: ReactivePowerControl
} <: DynamicInverterComponent
active_power_control::A
reactive_power_control::R
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a Outer-Loop controller using a active power controller and a reactive power droop controller.
# Arguments
- `A <: ActivePowerControl`: Active power controller (typically droop or virtual inertia).
- `R <: ReactivePowerControl`: Reactive power controller (typically droop).
- `ext::Dict{String, Any}`
- `states::Vector{Symbol}`: Vector of states (will depend on the components).
- `n_states::Int`: Number of states (will depend on the components).
"""
mutable struct OuterControl{A <: ActivePowerControl, R <: ReactivePowerControl} <:
DynamicInverterComponent
active_power_control::A
reactive_power_control::R
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
function OuterControl(
active_power_control::A,
reactive_power_control::R,
ext = Dict{String, Any}(),
) where {A <: ActivePowerControl, R <: ReactivePowerControl}
return OuterControl(
active_power_control,
reactive_power_control,
ext,
vcat(active_power_control.states, reactive_power_control.states),
active_power_control.n_states + reactive_power_control.n_states,
)
end
function OuterControl(;
active_power_control,
reactive_power_control,
ext = Dict{String, Any}(),
states = nothing,
n_states = nothing,
)
if states === nothing
@assert n_states === nothing
return OuterControl(active_power_control, reactive_power_control, ext)
end
@assert n_states !== nothing
return OuterControl(active_power_control, reactive_power_control, ext, states, n_states)
end
"""Get `active_power_control` from [`OuterControl`](@ref)."""
get_active_power_control(value::OuterControl) = value.active_power_control
"""Get `reactive_power_control` from [`OuterControl`](@ref)."""
get_reactive_power_control(value::OuterControl) = value.reactive_power_control
"""Get `ext` from [`OuterControl`](@ref)."""
get_ext(value::OuterControl) = value.ext
"""Get `states` from [`OuterControl`](@ref)."""
get_states(value::OuterControl) = value.states
"""Get `n_states` from [`OuterControl`](@ref)."""
get_n_states(value::OuterControl) = value.n_states
"""Set [`OuterControl`](@ref) `active_power_control`."""
set_active_power_control!(value::OuterControl, val) =
value.active_power_control = val
"""Set [`OuterControl`](@ref) `reactive_power_control`."""
set_reactive_power_control!(value::OuterControl, val) =
value.reactive_power_control = val
"""Set [`OuterControl`](@ref) `ext`."""
set_ext!(value::OuterControl, val) = value.ext = val
================================================
FILE: src/models/RoundRotorExponential.jl
================================================
"""
mutable struct RoundRotorExponential <: Machine
base_machine::RoundRotorMachine
saturation_coeffs::Tuple{Float64, Float64}
4-states round-rotor synchronous machine with exponential saturation:
IEEE Std 1110 §5.3.2 (Model 2.2). GENROE model in PSSE and PSLF.
# Arguments
- `base_machine::RoundRotorMachine`: Round Rotor Machine model.
- `saturation_coeffs::Tuple{Float64, Float64}``: Saturation coefficients for exponential model.
"""
mutable struct RoundRotorExponential <: Machine
base_machine::RoundRotorMachine
saturation_coeffs::Tuple{Float64, Float64}
end
IS.@forward((RoundRotorExponential, :base_machine), RoundRotorMachine)
function RoundRotorExponential(
R::Float64,
Td0_p::Float64,
Td0_pp::Float64,
Tq0_p::Float64,
Tq0_pp::Float64,
Xd::Float64,
Xq::Float64,
Xd_p::Float64,
Xq_p::Float64,
Xd_pp::Float64,
Xl::Float64,
Se::Tuple{Float64, Float64},
)
saturation_coeffs = get_exponential_saturation(Se)
return RoundRotorExponential(
RoundRotorMachine(
R,
Td0_p,
Td0_pp,
Tq0_p,
Tq0_pp,
Xd,
Xq,
Xd_p,
Xq_p,
Xd_pp,
Xl,
Se,
),
saturation_coeffs,
)
end
function RoundRotorExponential(;
R,
Td0_p,
Td0_pp,
Tq0_p,
Tq0_pp,
Xd,
Xq,
Xd_p,
Xq_p,
Xd_pp,
Xl,
Se,
)
return RoundRotorExponential(
R,
Td0_p,
Td0_pp,
Tq0_p,
Tq0_pp,
Xd,
Xq,
Xd_p,
Xq_p,
Xd_pp,
Xl,
Se,
)
end
function RoundRotorExponential(::Nothing)
return RoundRotorExponential(;
R = 0.0,
Td0_p = 0.0,
Td0_pp = 0.0,
Tq0_p = 0.0,
Tq0_pp = 0.0,
Xd = 0.0,
Xq = 0.0,
Xd_p = 0.0,
Xq_p = 0.0,
Xd_pp = 0.0,
Xl = 0.0,
Se = (0.0, 0.0),
)
end
get_base_machine(value::RoundRotorExponential) = value.base_machine
get_saturation_coeffs(value::RoundRotorExponential) = value.saturation_coeffs
set_base_machine!(value::RoundRotorExponential, val::RoundRotorMachine) =
value.base_machine = val
set_saturation_coeffs!(value::RoundRotorExponential, val::Tuple{Float64, Float64}) =
value.saturation_coeffs = val
function IS.deserialize_struct(::Type{RoundRotorExponential}, data::Dict)
vals = IS.deserialize_to_dict(RoundRotorExponential, data)
return RoundRotorExponential(vals[:base_machine], vals[:saturation_coeffs])
end
================================================
FILE: src/models/RoundRotorQuadratic.jl
================================================
"""
mutable struct RoundRotorQuadratic <: Machine
base_machine::RoundRotorMachine
saturation_coeffs::Tuple{Float64, Float64}
4-states round-rotor synchronous machine with quadratic saturation:
IEEE Std 1110 §5.3.2 (Model 2.2). GENROU model in PSSE and PSLF.
# Arguments
- `base_machine::RoundRotorMachine`: Round Rotor Machine model.
- `saturation_coeffs::Tuple{Float64, Float64}``: Saturation coefficients for quadratic model.
"""
mutable struct RoundRotorQuadratic <: Machine
base_machine::RoundRotorMachine
saturation_coeffs::Tuple{Float64, Float64}
end
IS.@forward((RoundRotorQuadratic, :base_machine), RoundRotorMachine)
function RoundRotorQuadratic(
R::Float64,
Td0_p::Float64,
Td0_pp::Float64,
Tq0_p::Float64,
Tq0_pp::Float64,
Xd::Float64,
Xq::Float64,
Xd_p::Float64,
Xq_p::Float64,
Xd_pp::Float64,
Xl::Float64,
Se::Tuple{Float64, Float64},
)
saturation_coeffs = get_quadratic_saturation(Se)
return RoundRotorQuadratic(
RoundRotorMachine(
R,
Td0_p,
Td0_pp,
Tq0_p,
Tq0_pp,
Xd,
Xq,
Xd_p,
Xq_p,
Xd_pp,
Xl,
Se,
),
saturation_coeffs,
)
end
function RoundRotorQuadratic(;
R,
Td0_p,
Td0_pp,
Tq0_p,
Tq0_pp,
Xd,
Xq,
Xd_p,
Xq_p,
Xd_pp,
Xl,
Se,
)
return RoundRotorQuadratic(
R,
Td0_p,
Td0_pp,
Tq0_p,
Tq0_pp,
Xd,
Xq,
Xd_p,
Xq_p,
Xd_pp,
Xl,
Se,
)
end
function RoundRotorQuadratic(::Nothing)
return RoundRotorQuadratic(;
R = 0.0,
Td0_p = 0.0,
Td0_pp = 0.0,
Tq0_p = 0.0,
Tq0_pp = 0.0,
Xd = 0.0,
Xq = 0.0,
Xd_p = 0.0,
Xq_p = 0.0,
Xd_pp = 0.0,
Xl = 0.0,
Se = (0.0, 0.0),
)
end
get_base_machine(value::RoundRotorQuadratic) = value.base_machine
get_saturation_coeffs(value::RoundRotorQuadratic) = value.saturation_coeffs
set_base_machine!(value::RoundRotorQuadratic, val::RoundRotorMachine) =
value.base_machine = val
set_saturation_coeffs!(value::RoundRotorQuadratic, val::Tuple{Float64, Float64}) =
value.saturation_coeffs = val
function IS.deserialize_struct(::Type{RoundRotorQuadratic}, data::Dict)
vals = IS.deserialize_to_dict(RoundRotorQuadratic, data)
return RoundRotorQuadratic(vals[:base_machine], vals[:saturation_coeffs])
end
================================================
FILE: src/models/SalientPoleExponential.jl
================================================
"""
mutable struct SalientPoleExponential <: Machine
base_machine::SalientPoleMachine
saturation_coeffs::Tuple{Float64, Float64}
3-states salient-pole synchronous machine with exponential saturation:
IEEE Std 1110 §5.3.2 (Model 2.1). GENSAE in PSSE and PSLF.
# Arguments:
- `base_machine::SalientPoleMachine`: Salient Pole Machine model.
- `saturation_coeffs::Tuple{Float64, Float64}``: Saturation coefficients for exponential model.
"""
mutable struct SalientPoleExponential <: Machine
base_machine::SalientPoleMachine
saturation_coeffs::Tuple{Float64, Float64}
end
IS.@forward((SalientPoleExponential, :base_machine), SalientPoleMachine)
function SalientPoleExponential(
R::Float64,
Td0_p::Float64,
Td0_pp::Float64,
Tq0_pp::Float64,
Xd::Float64,
Xq::Float64,
Xd_p::Float64,
Xd_pp::Float64,
Xl::Float64,
Se::Tuple{Float64, Float64},
)
saturation_coeffs = get_exponential_saturation(Se)
return SalientPoleExponential(
SalientPoleMachine(R, Td0_p, Td0_pp, Tq0_pp, Xd, Xq, Xd_p, Xd_pp, Xl, Se),
saturation_coeffs,
)
end
function SalientPoleExponential(; R, Td0_p, Td0_pp, Tq0_pp, Xd, Xq, Xd_p, Xd_pp, Xl, Se)
return SalientPoleExponential(R, Td0_p, Td0_pp, Tq0_pp, Xd, Xq, Xd_p, Xd_pp, Xl, Se)
end
function SalientPoleExponential(::Nothing)
return SalientPoleExponential(;
R = 0.0,
Td0_p = 0.0,
Td0_pp = 0.0,
Tq0_pp = 0.0,
Xd = 0.0,
Xq = 0.0,
Xd_p = 0.0,
Xd_pp = 0.0,
Xl = 0.0,
Se = (0.0, 0.0),
)
end
get_base_machine(value::SalientPoleExponential) = value.base_machine
get_saturation_coeffs(value::SalientPoleExponential) = value.saturation_coeffs
set_base_machine!(value::SalientPoleExponential, val::SalientPoleMachine) =
value.base_machine = val
set_saturation_coeffs!(value::SalientPoleExponential, val::Tuple{Float64, Float64}) =
value.saturation_coeffs = val
function IS.deserialize_struct(::Type{SalientPoleExponential}, data::Dict)
vals = IS.deserialize_to_dict(SalientPoleExponential, data)
return SalientPoleExponential(vals[:base_machine], vals[:saturation_coeffs])
end
================================================
FILE: src/models/SalientPoleQuadratic.jl
================================================
"""
mutable struct SalientPoleQuadratic <: Machine
base_machine::SalientPoleMachine
saturation_coeffs::Tuple{Float64, Float64}
3-states salient-pole synchronous machine with exponential saturation:
IEEE Std 1110 §5.3.2 (Model 2.1). GENSAL in PSSE and PSLF.
# Arguments:
- `base_machine::SalientPoleMachine`: Salient Pole Machine model.
- `saturation_coeffs::Tuple{Float64, Float64}``: Saturation coefficients for quadratic model.
"""
mutable struct SalientPoleQuadratic <: Machine
base_machine::SalientPoleMachine
saturation_coeffs::Tuple{Float64, Float64}
end
IS.@forward((SalientPoleQuadratic, :base_machine), SalientPoleMachine)
function SalientPoleQuadratic(
R::Float64,
Td0_p::Float64,
Td0_pp::Float64,
Tq0_pp::Float64,
Xd::Float64,
Xq::Float64,
Xd_p::Float64,
Xd_pp::Float64,
Xl::Float64,
Se::Tuple{Float64, Float64},
)
saturation_coeffs = get_quadratic_saturation(Se)
return SalientPoleQuadratic(
SalientPoleMachine(R, Td0_p, Td0_pp, Tq0_pp, Xd, Xq, Xd_p, Xd_pp, Xl, Se),
saturation_coeffs,
)
end
function SalientPoleQuadratic(; R, Td0_p, Td0_pp, Tq0_pp, Xd, Xq, Xd_p, Xd_pp, Xl, Se)
return SalientPoleQuadratic(R, Td0_p, Td0_pp, Tq0_pp, Xd, Xq, Xd_p, Xd_pp, Xl, Se)
end
function SalientPoleQuadratic(::Nothing)
return SalientPoleQuadratic(;
R = 0.0,
Td0_p = 0.0,
Td0_pp = 0.0,
Tq0_pp = 0.0,
Xd = 0.0,
Xq = 0.0,
Xd_p = 0.0,
Xd_pp = 0.0,
Xl = 0.0,
Se = (0.0, 0.0),
)
end
get_base_machine(value::SalientPoleQuadratic) = value.base_machine
get_saturation_coeffs(value::SalientPoleQuadratic) = value.saturation_coeffs
set_base_machine!(value::SalientPoleQuadratic, val::SalientPoleMachine) =
value.base_machine = val
set_saturation_coeffs!(value::SalientPoleQuadratic, val::Tuple{Float64, Float64}) =
value.saturation_coeffs = val
function IS.deserialize_struct(::Type{SalientPoleQuadratic}, data::Dict)
vals = IS.deserialize_to_dict(SalientPoleQuadratic, data)
return SalientPoleQuadratic(vals[:base_machine], vals[:saturation_coeffs])
end
================================================
FILE: src/models/branches.jl
================================================
""" Supertype for all branches"""
abstract type Branch <: Device end
""" Supertype for all AC branches (branches connecting AC nodes or Areas)"""
abstract type ACBranch <: Branch end
""" Supertype for all AC transmission devices (devices connecting AC nodes only)"""
abstract type ACTransmission <: ACBranch end
""" Supertype for all Two Winding Transformer types"""
abstract type TwoWindingTransformer <: ACTransmission end
""" Supertype for all Three Winding Transformer types"""
abstract type ThreeWindingTransformer <: ACTransmission end
""" Supertype for all Two Terminal HVDC transmission devices between AC Buses. Not to be confused with [DCBranch](@ref)"""
abstract type TwoTerminalHVDC <: ACBranch end
""" Supertype for all DC branches (branches that connect only DC nodes)"""
abstract type DCBranch <: Branch end
function supports_services(::ACBranch)
return true
end
get_from_bus(b::T) where {T <: Branch} = b.arc.from
get_to_bus(b::T) where {T <: Branch} = b.arc.to
================================================
FILE: src/models/components.jl
================================================
function get_system_base_power(c::Component)
return get_internal(c).units_info.base_value
end
"""
Default behavior of a component. If there is no base_power field, assume is in the system's base power.
"""
get_base_power(c::Component) = get_system_base_power(c)
_get_multiplier(c::T, conversion_unit) where {T <: Component} =
_get_multiplier(c, get_internal(c).units_info, conversion_unit)
_get_multiplier(::T, ::Nothing, conversion_unit) where {T <: Component} =
1.0
_get_multiplier(
c::T,
setting::IS.SystemUnitsSettings,
conversion_unit,
) where {T <: Component} =
_get_multiplier(c, setting, Val(setting.unit_system), conversion_unit)
# PERF: dispatching on the UnitSystem values instead of comparing with if/else avoids the
# performance hit associated with consulting the dictionary that backs the @scoped_enum --
# i.e., IS.UnitSystem.NATURAL_UNITS by itself isn't treated as a constant, it's a dictionary
# lookup each time.
_get_multiplier(
::T,
::IS.SystemUnitsSettings,
::Val{IS.UnitSystem.DEVICE_BASE},
::Any,
) where {T <: Component} =
1.0
###############
#### Power ####
###############
_get_multiplier(
c::T,
setting::IS.SystemUnitsSettings,
::Val{IS.UnitSystem.SYSTEM_BASE},
::Val{:mva},
) where {T <: Component} =
get_base_power(c) / setting.base_value
_get_multiplier(
c::T,
::IS.SystemUnitsSettings,
::Val{IS.UnitSystem.NATURAL_UNITS},
::Val{:mva},
) where {T <: Component} =
get_base_power(c)
###############
#### Ohms #####
###############
# Z_device / Z_sys = (V_device^2 / S_device) / (V_device^2 / S_sys) = S_sys / S_device
_get_multiplier(
c::T,
setting::IS.SystemUnitsSettings,
::Val{IS.UnitSystem.SYSTEM_BASE},
::Val{:ohm},
) where {T <: Branch} =
setting.base_value / get_base_power(c)
function _get_multiplier(
c::T,
::IS.SystemUnitsSettings,
::Val{IS.UnitSystem.NATURAL_UNITS},
::Val{:ohm},
) where {T <: Branch}
base_voltage = get_base_voltage(get_arc(c).from)
if isnothing(base_voltage)
error("Base voltage is not defined for $(summary(c)).")
end
return get_base_voltage(get_arc(c).from)^2 / get_base_power(c)
end
function _get_multiplier(
c::T,
::IS.SystemUnitsSettings,
::Val{IS.UnitSystem.NATURAL_UNITS},
::Val{:ohm},
) where {T <: TwoWindingTransformer}
base_voltage = get_base_voltage_primary(c)
if isnothing(base_voltage)
error("Base voltage is not defined for $(summary(c)).")
end
return base_voltage^2 / get_base_power(c)
end
##################
#### Siemens #####
##################
# Y_device / Y_sys = (S_device / V_device^2) / (S_sys / S_sys^2) = S_device / S_sys
_get_multiplier(
c::T,
setting::IS.SystemUnitsSettings,
::Val{IS.UnitSystem.SYSTEM_BASE},
::Val{:siemens},
) where {T <: Branch} =
get_base_power(c) / setting.base_value
function _get_multiplier(
c::T,
::IS.SystemUnitsSettings,
::Val{IS.UnitSystem.NATURAL_UNITS},
::Val{:siemens},
) where {T <: Branch}
base_voltage = get_base_voltage(get_arc(c).from)
if isnothing(base_voltage)
@warn "Base voltage is not set for $(c.name). Returning in DEVICE_BASE units."
return 1.0
end
return get_base_power(c) / get_base_voltage(get_arc(c).from)^2
end
function _get_multiplier(
c::T,
::IS.SystemUnitsSettings,
::Val{IS.UnitSystem.NATURAL_UNITS},
::Val{:siemens},
) where {T <: TwoWindingTransformer}
base_voltage = get_base_voltage_primary(c)
if isnothing(base_voltage)
@warn "Base voltage is not set for $(c.name). Returning in DEVICE_BASE units."
return 1.0
end
return get_base_power(c) / base_voltage^2
end
_get_multiplier(::T, ::IS.SystemUnitsSettings, _, _) where {T <: Component} =
error("Undefined Conditional")
function get_value(c::Component, ::Val{T}, conversion_unit) where {T}
value = Base.getproperty(c, T)
return _get_value(c, value, conversion_unit)
end
function _get_value(c::Component, value::Float64, conversion_unit)::Float64
return _get_multiplier(c, conversion_unit) * value
end
function _get_value(c::Component, value::ComplexF64, conversion_unit)::ComplexF64
return _get_multiplier(c, conversion_unit) * value
end
function _get_value(c::Component, value::MinMax, conversion_unit)::MinMax
m = _get_multiplier(c, conversion_unit)
return (min = value.min * m, max = value.max * m)
end
function _get_value(
c::Component,
value::StartUpShutDown,
conversion_unit,
)::StartUpShutDown
m = _get_multiplier(c, conversion_unit)
return (startup = value.startup * m, shutdown = value.shutdown * m)
end
function _get_value(c::Component, value::UpDown, conversion_unit)::UpDown
m = _get_multiplier(c, conversion_unit)
return (up = value.up * m, down = value.down * m)
end
function _get_value(c::Component, value::FromTo_ToFrom, conversion_unit)::FromTo_ToFrom
m = _get_multiplier(c, conversion_unit)
return (from_to = value.from_to * m, to_from = value.to_from * m)
end
function _get_value(c::Component, value::FromTo, conversion_unit)::FromTo
m = _get_multiplier(c, conversion_unit)
return (from = value.from * m, to = value.to * m)
end
function _get_value(::Component, ::Nothing, _)
return nothing
end
function _get_value(::T, value::V, _) where {T <: Component, V}
@warn("conversion not implemented for $(V) in component $(T)")
return value::V
end
function _get_value(::Nothing, _, _)
return
end
function set_value(c::Component, _, val, conversion_unit)
return _set_value(c, val, conversion_unit)
end
function _set_value(c::Component, value::Float64, conversion_unit)::Float64
return (1 / _get_multiplier(c, conversion_unit)) * value
end
function _set_value(c::Component, value::MinMax, conversion_unit)::MinMax
m = 1 / _get_multiplier(c, conversion_unit)
return (min = value.min * m, max = value.max * m)
end
function _set_value(
c::Component,
value::StartUpShutDown,
conversion_unit,
)::StartUpShutDown
m = 1 / _get_multiplier(c, conversion_unit)
return (startup = value.startup * m, shutdown = value.shutdown * m)
end
function _set_value(c::Component, value::UpDown, conversion_unit)::UpDown
m = 1 / _get_multiplier(c, conversion_unit)
return (up = value.up * m, down = value.down * m)
end
function _set_value(c::Component, value::FromTo_ToFrom, conversion_unit)::FromTo_ToFrom
m = 1 / _get_multiplier(c, conversion_unit)
return (from_to = value.from_to * m, to_from = value.to_from * m)
end
function _set_value(c::Component, value::FromTo, conversion_unit)::FromTo
m = 1 / _get_multiplier(c, conversion_unit)
return (from = value.from * m, to = value.to * m)
end
function _set_value(::Component, ::Nothing, _)
return nothing
end
function _set_value(c::T, value::V, _) where {T <: Component, V}
@warn("conversion not implemented for $(V) in component $(T)")
return value::V
end
function _set_value(::Nothing, _, _)
return
end
######################################
########### Transformer 3W ###########
######################################
PrimaryImpedances = Union{
Val{:r_primary},
Val{:x_primary},
Val{:r_12},
Val{:x_12},
}
PrimaryAdmittances = Union{
Val{:g},
Val{:b},
}
PrimaryPower = Union{
Val{:active_power_flow_primary},
Val{:reactive_power_flow_primary},
Val{:rating},
Val{:rating_primary},
}
SecondaryImpedances = Union{
Val{:r_secondary},
Val{:x_secondary},
Val{:r_23},
Val{:x_23},
}
SecondaryPower = Union{
Val{:active_power_flow_secondary},
Val{:reactive_power_flow_secondary},
Val{:rating_secondary},
}
TertiaryImpedances = Union{
Val{:r_tertiary},
Val{:x_tertiary},
Val{:r_13},
Val{:x_13},
}
TertiaryPower = Union{
Val{:active_power_flow_tertiary},
Val{:reactive_power_flow_tertiary},
Val{:rating_tertiary},
}
###### Multipliers ######
_get_winding_base_power(
c::ThreeWindingTransformer,
::Union{PrimaryImpedances, PrimaryAdmittances, PrimaryPower},
) = get_base_power_12(c)
_get_winding_base_power(
c::ThreeWindingTransformer,
::Union{SecondaryImpedances, SecondaryPower},
) =
get_base_power_23(c)
_get_winding_base_power(
c::ThreeWindingTransformer,
::Union{TertiaryImpedances, TertiaryPower},
) =
get_base_power_13(c)
function _get_winding_base_voltage(
c::ThreeWindingTransformer,
::Union{PrimaryImpedances, PrimaryAdmittances},
)
base_voltage = get_base_voltage_primary(c)
if isnothing(base_voltage)
error("Base voltage is not defined for $(summary(c)).")
end
return base_voltage
end
function _get_winding_base_voltage(
c::ThreeWindingTransformer,
::SecondaryImpedances,
)
base_voltage = get_base_voltage_secondary(c)
if isnothing(base_voltage)
error("Base voltage is not defined for $(summary(c)).")
end
return base_voltage
end
function _get_winding_base_voltage(
c::ThreeWindingTransformer,
::TertiaryImpedances,
)
base_voltage = get_base_voltage_tertiary(c)
if isnothing(base_voltage)
error("Base voltage is not defined for $(summary(c)).")
end
return base_voltage
end
# DEVICE_BASE
function _get_multiplier(
::ThreeWindingTransformer,
::Any,
::Val{IS.UnitSystem.DEVICE_BASE},
::Float64,
::Any,
)
return 1.0
end
###########
## Power ##
###########
# SYSTEM_BASE
function _get_multiplier(
c::ThreeWindingTransformer,
field::Any,
::Val{IS.UnitSystem.SYSTEM_BASE},
base_mva::Float64,
::Val{:mva},
)
return _get_winding_base_power(c, field) / base_mva
end
# NATURAL_UNITS
function _get_multiplier(
c::ThreeWindingTransformer,
field::Any,
::Val{IS.UnitSystem.NATURAL_UNITS},
base_mva::Float64,
::Val{:mva},
)
return _get_winding_base_power(c, field)
end
############
### Ohms ###
############
# SYSTEM_BASE
function _get_multiplier(
c::ThreeWindingTransformer,
field::Any,
::Val{IS.UnitSystem.SYSTEM_BASE},
base_mva::Float64,
::Val{:ohm},
)
return base_mva / _get_winding_base_power(c, field)
end
# NATURAL_UNITS
function _get_multiplier(
c::ThreeWindingTransformer,
field::Any,
::Val{IS.UnitSystem.NATURAL_UNITS},
base_mva::Float64,
::Val{:ohm},
)
return _get_winding_base_voltage(c, field)^2 / _get_winding_base_power(c, field)
end
#############
## Siemens ##
#############
# SYSTEM_BASE
function _get_multiplier(
c::ThreeWindingTransformer,
field::Any,
::Val{IS.UnitSystem.SYSTEM_BASE},
base_mva::Float64,
::Val{:siemens},
)
return _get_winding_base_power(c, field) / base_mva
end
# NATURAL_UNITS
function _get_multiplier(
c::ThreeWindingTransformer,
field::Any,
::Val{IS.UnitSystem.NATURAL_UNITS},
base_mva::Float64,
::Val{:siemens},
)
return _get_winding_base_power(c, field) / _get_winding_base_voltage(c, field)^2
end
function get_value(
c::ThreeWindingTransformer,
field::Val{T},
conversion_unit,
) where {T}
value = Base.getproperty(c, T)
if isnothing(value)
return nothing
end
settings = get_internal(c).units_info
if isnothing(settings)
return value
end
unit_system = settings.unit_system
base_mva = settings.base_value
multiplier = _get_multiplier(c, field, Val(unit_system), base_mva, conversion_unit)
return value * multiplier
end
function set_value(
c::ThreeWindingTransformer,
field,
val::Float64,
conversion_unit,
)
settings = get_internal(c).units_info
if isnothing(settings)
return val
end
unit_system = settings.unit_system
base_mva = settings.base_value
multiplier = _get_multiplier(c, field, Val(unit_system), base_mva, conversion_unit)
return val / multiplier
end
================================================
FILE: src/models/cost_function_timeseries.jl
================================================
# VALIDATORS
function _validate_market_bid_cost(cost, context)
(cost isa MarketBidCost) || throw(TypeError(
StackTraces.stacktrace()[2].func, context, MarketBidCost, cost))
end
function _validate_import_export_cost(cost, context)
(cost isa ImportExportCost) || throw(TypeError(
StackTraces.stacktrace()[2].func, context, ImportExportCost, cost))
end
function _validate_reserve_demand_curve(
cost::CostCurve{PiecewiseIncrementalCurve},
name::String,
)
value_curve = get_value_curve(cost)
function_data = get_function_data(value_curve)
x_coords = get_x_coords(function_data)
slopes = get_y_coords(function_data)
if first(x_coords) != 0
error(
"Reserve demand curve from $name is starting at $(first(x_coords)) and must start at zero.",
)
end
for ix in 1:(length(slopes) - 1)
if slopes[ix + 1] > slopes[ix]
error(
"Reserve demand curve from $name has increasing derivatives and should be non-increasing.",
)
end
end
end
function _validate_reserve_demand_curve(cost::T, name::String) where {T <: CostCurve}
throw(
ArgumentError(
"Reserve curve of type $(typeof(cost)) on $name cannot represent an ORDC curve, use CostCurve{PiecewiseIncrementalCurve} instead",
),
)
end
function _validate_fuel_curve(component::Component)
op_cost = get_operation_cost(component)
var_cost = get_variable(op_cost)
!(var_cost isa FuelCurve) && throw(
ArgumentError(
"Variable cost of type $(typeof(var_cost)) cannot represent a fuel cost, use FuelCurve instead",
),
)
return var_cost
end
"""
Validates if a device is eligible to contribute to a service.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `service::Service,`: Service for which the device is eligible to contribute
"""
function verify_device_eligibility(
sys::System,
component::StaticInjection,
service::Service,
)
if !has_service(component, service)
error(
"Device $(get_name(component)) isn't eligible to contribute to service $(get_name(service)).",
)
end
return
end
# GETTER HELPER FUNCTIONS
"""
Call get_time_series_array on the given time series and return a TimeArray of the results,
values mapped by `transform_fn` if it is not nothing
"""
function read_and_convert_ts(
ts::IS.TimeSeriesData,
component::Component,
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
transform_fn = nothing,
)
isnothing(start_time) && (start_time = IS.get_initial_timestamp(ts))
isnothing(transform_fn) && (transform_fn = (x -> x))
data = IS.get_time_series_array(component, ts; start_time = start_time, len = len)
time_stamps = TimeSeries.timestamp(data)
return TimeSeries.TimeArray(
time_stamps,
map(transform_fn, TimeSeries.values(data)),
)
end
"""
Helper function for cost getters.
# Arguments
- `T`: type/eltype we expect
- `component::Component`: the component
- `cost`: the data: either a single element of type `T` or a `TimeSeriesKey`
- `transform_fn`: a function to apply to the elements of the time series
- `start_time`: as in `get_time_series`
- `len`: as in `get_time_series`
"""
function _process_get_cost(::Type{T}, _, cost::T, transform_fn,
start_time::Union{Nothing, Dates.DateTime},
len::Union{Nothing, Int},
) where {T}
!isnothing(start_time) &&
throw(ArgumentError("Got non-nothing start_time but this cost is a scalar"))
!isnothing(len) &&
throw(ArgumentError("Got non-nothing len but this cost is a scalar"))
return cost
end
function _process_get_cost(::Type{T}, component::Component, cost::TimeSeriesKey,
transform_fn,
start_time::Union{Nothing, Dates.DateTime},
len::Union{Nothing, Int},
) where {T}
ts = get_time_series(component, cost; start_time = start_time, len = len, count = 1)
converted = read_and_convert_ts(ts, component, start_time, len, transform_fn)
return converted
end
# GETTER IMPLEMENTATIONS
"""
Retrieve the variable cost bid for a `StaticInjection` device with a `MarketBidCost`. If any
of the relevant fields (`incremental_offer_curves`, `incremental_initial_input`,
`no_load_cost`) are time series, the user may specify `start_time` and `len` and the
function returns a `TimeArray` of `CostCurve{PiecewiseIncrementalCurve}`s; if the field is
not a time series, the function returns a single `CostCurve{PiecewiseIncrementalCurve}`.
"""
function get_variable_cost(
device::StaticInjection,
cost::MarketBidCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
)
if typeof(get_incremental_offer_curves(cost)) <: CostCurve
return get_incremental_offer_curves(cost)
end
function_data = if (get_incremental_offer_curves(cost) isa TimeSeriesKey)
get_incremental_offer_curves(device, cost; start_time = start_time, len = len)
else
get_incremental_offer_curves(device, cost)
end
initial_input = if (get_incremental_initial_input(cost) isa TimeSeriesKey)
get_incremental_initial_input(device, cost; start_time = start_time, len = len)
else
get_incremental_initial_input(device, cost)
end
input_at_zero = if (get_no_load_cost(cost) isa TimeSeriesKey)
get_no_load_cost(device, cost; start_time = start_time, len = len)
else
get_no_load_cost(device, cost)
end
params::Vector{Any} = [function_data, initial_input, input_at_zero]
all(isnothing.(params)) && return nothing
first_time_series = findfirst(isa.(params, TimeSeries.TimeArray))
if !isnothing(first_time_series)
timestamps = TimeSeries.timestamp(params[first_time_series])
for (i, param) in enumerate(params)
if !(param isa TimeSeries.TimeArray)
params[i] =
TimeSeries.TimeArray(timestamps, fill(param, length(timestamps)))
end
end
!allequal(TimeSeries.timestamp.(params)) &&
throw(
ArgumentError(
"Time series mismatch between incremental_offer_curves, incremental_initial_input, and no_load_cost",
),
)
#@show collect(zip(collect.(TimeSeries.values.(params))...)) |> length
#@show first(collect(zip(collect.(TimeSeries.values.(params))...)))
return TimeSeries.TimeArray(TimeSeries.timestamp(function_data),
[
_make_market_bid_curve(fd; initial_input = ii, input_at_zero = iaz) for
(fd, ii, iaz) in collect(zip(collect.(TimeSeries.values.(params))...))
])
end
return make_market_bid_curve(
function_data,
initial_input;
input_at_zero = input_at_zero,
)
end
"""
Retrieve the incremental variable cost bid for a `StaticInjection` device with a
`MarketBidCost`. If any of the relevant fields (`incremental_offer_curves`,
`incremental_initial_input`, `no_load_cost`) are time series, the user may specify
`start_time` and `len` and the function returns a `TimeArray` of
`CostCurve{PiecewiseIncrementalCurve}`s; if the field is not a time series, the function
returns a single `CostCurve{PiecewiseIncrementalCurve}`.
"""
function get_incremental_variable_cost(
device::StaticInjection,
cost::MarketBidCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
)
return get_variable_cost(
device,
cost;
start_time = start_time,
len = len,
)
end
"""
Retrieve the decremental variable cost bid for a `StaticInjection` device with a
`MarketBidCost`. If any of the relevant fields (`decremental_offer_curves`,
`decremental_initial_input`, `no_load_cost`) are time series, the user may specify
`start_time` and `len` and the function returns a `TimeArray` of
`CostCurve{PiecewiseIncrementalCurve}`s; if the field is not a time series, the function
returns a single `CostCurve{PiecewiseIncrementalCurve}` or `nothing`.
"""
function get_decremental_variable_cost(
device::StaticInjection,
cost::MarketBidCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
)
if typeof(get_decremental_offer_curves(cost)) <: CostCurve
return get_decremental_offer_curves(cost)
end
function_data = if (get_decremental_offer_curves(cost) isa TimeSeriesKey)
get_decremental_offer_curves(device, cost; start_time = start_time, len = len)
else
get_decremental_offer_curves(device, cost)
end
initial_input = if (get_decremental_initial_input(cost) isa TimeSeriesKey)
get_decremental_initial_input(device, cost; start_time = start_time, len = len)
else
get_decremental_initial_input(device, cost)
end
input_at_zero = if (get_no_load_cost(cost) isa TimeSeriesKey)
get_no_load_cost(device, cost; start_time = start_time, len = len)
else
get_no_load_cost(device, cost)
end
params::Vector{Any} = [function_data, initial_input, input_at_zero]
all(isnothing.(params)) && return nothing
first_time_series = findfirst(isa.(params, TimeSeries.TimeArray))
if !isnothing(first_time_series)
timestamps = TimeSeries.timestamp(params[first_time_series])
for (i, param) in enumerate(params)
if !(param isa TimeSeries.TimeArray)
params[i] =
TimeSeries.TimeArray(timestamps, fill(param, length(timestamps)))
end
end
!allequal(TimeSeries.timestamp.(params)) &&
throw(
ArgumentError(
"Time series mismatch between incremental_offer_curves, incremental_initial_input, and no_load_cost",
),
)
#@show collect(zip(collect.(TimeSeries.values.(params))...)) |> length
#@show first(collect(zip(collect.(TimeSeries.values.(params))...)))
return TimeSeries.TimeArray(TimeSeries.timestamp(function_data),
[
_make_market_bid_curve(fd; initial_input = ii, input_at_zero = iaz) for
(fd, ii, iaz) in collect(zip(collect.(TimeSeries.values.(params))...))
])
end
return make_market_bid_curve(
function_data,
initial_input;
input_at_zero = input_at_zero,
)
end
"""
Retrieve the import variable cost bid for a `StaticInjection` device with an
`ImportExportCost`. If `import_offer_curves` is a time series, the user may specify
`start_time` and `len` and the function returns a `TimeArray` of
`CostCurve{PiecewiseIncrementalCurve}`s; if the field is not a time series, the function
returns a single `CostCurve{PiecewiseIncrementalCurve}` or `nothing`.
"""
function get_import_variable_cost(
device::StaticInjection,
cost::ImportExportCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
)
get_import_offer_curves(cost) isa CostCurve &&
return get_import_offer_curves(cost)
function_data =
get_import_offer_curves(device, cost; start_time = start_time, len = len)
return TimeSeries.TimeArray(TimeSeries.timestamp(function_data),
[make_import_export_curve(fd) for fd in TimeSeries.values(function_data)])
end
"""
Retrieve the export variable cost bid for a `StaticInjection` device with an
`ImportExportCost`. If `export_offer_curves` is a time series, the user may specify
`start_time` and `len` and the function returns a `TimeArray` of
`CostCurve{PiecewiseIncrementalCurve}`s; if the field is not a time series, the function
returns a single `CostCurve{PiecewiseIncrementalCurve}` or `nothing`.
"""
function get_export_variable_cost(
device::StaticInjection,
cost::ImportExportCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
)
get_export_offer_curves(cost) isa CostCurve &&
return get_export_offer_curves(cost)
function_data =
get_export_offer_curves(device, cost; start_time = start_time, len = len)
return TimeSeries.TimeArray(TimeSeries.timestamp(function_data),
[make_import_export_curve(fd) for fd in TimeSeries.values(function_data)])
end
"""
Retrieve the variable cost data for a `ReserveDemandCurve`. The user may specify
`start_time` and `len` and the function returns a `TimeArray` of `CostCurve`s.
"""
get_variable_cost(
service::ReserveDemandCurve;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
) = _process_get_cost(CostCurve{PiecewiseIncrementalCurve}, service, get_variable(service),
_make_market_bid_curve, start_time, len)
"""
Return service bid time series data for a `StaticInjection` device with a `MarketBidCost`.
The user may specify `start_time` and `len` and the function returns a `TimeArray` of
`CostCurve`s.
"""
function get_services_bid(
device::StaticInjection,
cost::MarketBidCost,
service::Service;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
)
variable_ts_key = get_incremental_offer_curves(cost)
ts = get_time_series(
variable_ts_key.time_series_type,
device,
get_name(service);
start_time = start_time,
len = len,
count = 1,
)
converted = read_and_convert_ts(ts, service, start_time, len, _make_market_bid_curve)
return converted
end
"""
Get the fuel cost of a [`HybridSystem`](@ref)'s thermal subunit.
[`HybridSystem`](@ref) is a [`StaticInjectionSubsystem`](@ref) that aggregates subunits; fuel cost
for thermal power comes from the [`ThermalGen`](@ref) subcomponent, not the hybrid's top-level
[`MarketBidCost`](@ref). This method delegates to [`get_fuel_cost`](@ref get_fuel_cost(component::StaticInjection))
on the thermal subunit when present.
# Arguments
- `component::HybridSystem`: The hybrid system
- `start_time`: Optional start time for time series lookup
- `len`: Optional length for time series lookup
# Returns
The fuel cost from the thermal subunit (scalar or time series per [`get_fuel_cost`](@ref get_fuel_cost(component::StaticInjection))).
# Throws
- `ArgumentError` if the hybrid has no thermal unit (`get_thermal_unit(component) === nothing`).
"""
function get_fuel_cost(component::HybridSystem;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
)
thermal = get_thermal_unit(component)
if isnothing(thermal)
throw(
ArgumentError(
"HybridSystem $(get_name(component)) has no thermal unit; fuel cost is undefined.",
),
)
end
return get_fuel_cost(thermal; start_time = start_time, len = len)
end
"Get the fuel cost of the component's variable cost, which must be a `FuelCurve`."
function get_fuel_cost(component::StaticInjection;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
)
var_cost = _validate_fuel_curve(component)
return _process_get_cost(
Float64,
component,
get_fuel_cost(var_cost),
nothing,
start_time,
len,
)
end
"""
Retrieve the `incremental_offer_curves` for a `StaticInjection` device with a
`MarketBidCost`. If this field is a time series, the user may specify `start_time` and `len`
and the function returns a `TimeArray` of `PiecewiseStepData`s; if the field is not a time
series, the function returns a single `CostCurve{PiecewiseIncrementalCurve}` or `nothing`.
"""
get_incremental_offer_curves(
device::StaticInjection,
cost::MarketBidCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
) = _process_get_cost(
Union{PiecewiseStepData, CostCurve{PiecewiseIncrementalCurve}, Nothing},
device, get_incremental_offer_curves(cost), nothing, start_time, len)
"""
Retrieve the `decremental_offer_curves` for a `StaticInjection` device with a
`MarketBidCost`. If this field is a time series, the user may specify `start_time` and `len`
and the function returns a `TimeArray` of `PiecewiseStepData`s; if the field is not a time
series, the function returns a single `CostCurve{PiecewiseIncrementalCurve}` or `nothing`.
"""
get_decremental_offer_curves(
device::StaticInjection,
cost::MarketBidCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
) = _process_get_cost(
Union{PiecewiseStepData, CostCurve{PiecewiseIncrementalCurve}, Nothing},
device, get_decremental_offer_curves(cost), nothing, start_time, len)
"""
Retrieve the `import_offer_curves` for a `StaticInjection` device with a `ImportExportCost`.
If this field is a time series, the user may specify `start_time` and `len` and the function
returns a `TimeArray` of `PiecewiseStepData`s; if the field is not a time series, the
function returns a single `CostCurve{PiecewiseIncrementalCurve}` or `nothing`.
"""
get_import_offer_curves(
device::StaticInjection,
cost::ImportExportCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
) = _process_get_cost(Union{PiecewiseStepData, CostCurve{PiecewiseIncrementalCurve}},
device, get_import_offer_curves(cost), nothing, start_time, len)
"""
Retrieve the `export_offer_curves` for a `StaticInjection` device with a `ImportExportCost`.
If this field is a time series, the user may specify `start_time` and `len` and the function
returns a `TimeArray` of `PiecewiseStepData`s; if the field is not a time series, the
function returns a single `CostCurve{PiecewiseIncrementalCurve}` or `nothing`.
"""
get_export_offer_curves(
device::StaticInjection,
cost::ImportExportCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
) = _process_get_cost(Union{PiecewiseStepData, CostCurve{PiecewiseIncrementalCurve}},
device, get_export_offer_curves(cost), nothing, start_time, len)
"""
Retrieve the no-load cost data for a `StaticInjection` device with a `MarketBidCost`. If
this field is a time series, the user may specify `start_time` and `len` and the function
returns a `TimeArray` of `Float64`s; if the field is not a time series, the function
returns a single `Float64` or `nothing`.
"""
get_no_load_cost(
device::StaticInjection,
cost::MarketBidCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
) = _process_get_cost(Union{Nothing, Float64}, device,
get_no_load_cost(cost), nothing, start_time, len)
"""
Retrieve the `incremental_initial_input` for a `StaticInjection` device with a
`MarketBidCost`. If this field is a time series, the user may specify `start_time` and `len`
and the function returns a `TimeArray` of `Float64`s; if the field is not a time series, the
function returns a single `Float64` or `nothing`.
"""
get_incremental_initial_input(
device::StaticInjection,
cost::MarketBidCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
) = _process_get_cost(Union{Nothing, Float64}, device,
get_incremental_initial_input(cost), nothing, start_time, len)
"""
Retrieve the `decremental_initial_input` for a `StaticInjection` device with a
`MarketBidCost`. If this field is a time series, the user may specify `start_time` and `len`
and the function returns a `TimeArray` of `Float64`s; if the field is not a time series, the
function returns a single `Float64` or `nothing`.
"""
get_decremental_initial_input(
device::StaticInjection,
cost::MarketBidCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
) = _process_get_cost(Union{Nothing, Float64}, device,
get_decremental_initial_input(cost), nothing, start_time, len)
"""
Retrieve the startup cost data for a `StaticInjection` device with a `MarketBidCost`. If
this field is a time series, the user may specify `start_time` and `len` and the function
returns a `TimeArray` of `StartUpStages`s; if the field is not a time series, the function
returns a single `StartUpStages`.
"""
get_start_up(
device::StaticInjection,
cost::MarketBidCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
) = _process_get_cost(StartUpStages, device,
get_start_up(cost), StartUpStages, start_time, len)
"""
Retrieve the shutdown cost data for a `StaticInjection` device with a `MarketBidCost`. If
this field is a time series, the user may specify `start_time` and `len` and the function
returns a `TimeArray` of `Float64`s; if the field is not a time series, the function
returns a single `Float64`.
"""
get_shut_down(
device::StaticInjection,
cost::MarketBidCost;
start_time::Union{Nothing, Dates.DateTime} = nothing,
len::Union{Nothing, Int} = nothing,
) = _process_get_cost(Float64, device,
get_shut_down(cost), Float64, start_time, len)
# SETTER HELPER FUNCTIONS
"""
Helper function for cost setters.
# Arguments
- `T1`: type we expect if it's not a time series
- `T2`: eltype we expect if it is a time series
- `sys::System`: the system
- `component::Component`: the component
- `cost`: the data: either a single element of type `T1` or a `IS.TimeSeriesData` of eltype `T2`
"""
_process_set_cost(_, _, _, _, ::Nothing) = nothing
_process_set_cost(::Type{T}, _, _, _, cost::T) where {T} = cost
function _process_set_cost(
::Type{_},
::Type{T},
sys::System,
component::Component,
cost::IS.TimeSeriesData,
) where {_, T}
data_type = IS.eltype_data(cost)
!(data_type <: T) && throw(TypeError(_process_set_cost, T, data_type))
key = add_time_series!(sys, component, cost)
return key
end
# SETTER IMPLEMENTATIONS
"""
Set the incremental variable cost bid for a `StaticInjection` device with a `MarketBidCost`.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `time_series_data::Union{Nothing, IS.TimeSeriesData,
CostCurve{PiecewiseIncrementalCurve}},`: the data. If using a time series, must be of eltype
`PiecewiseStepData`. `PiecewiseIncrementalCurve` is only accepted for single CostCurve and
not accepted for time series data.
- `power_units::UnitSystem`: Units to be used for data. Must be NATURAL_UNITS.
"""
function set_variable_cost!(
sys::System,
component::StaticInjection,
data::Union{Nothing, IS.TimeSeriesData, CostCurve{PiecewiseIncrementalCurve}},
power_units::UnitSystem,
)
market_bid_cost = get_operation_cost(component)
_validate_market_bid_cost(market_bid_cost, "get_operation_cost(component)")
if (typeof(data) <: CostCurve{PiecewiseIncrementalCurve}) &&
(data.power_units != power_units)
throw(
ArgumentError(
"Units specified in CostCurve data differs from the units specified in the set cost.",
),
)
end
if (typeof(data) <: IS.TimeSeriesData) && (power_units != UnitSystem.NATURAL_UNITS)
throw(ArgumentError("Time Series data for MarketBidCost must be in NATURAL_UNITS."))
end
to_set = _process_set_cost(
CostCurve{PiecewiseIncrementalCurve},
PiecewiseStepData,
sys,
component,
data,
)
set_incremental_offer_curves!(market_bid_cost, to_set)
return
end
function set_variable_cost!(
sys::System,
component::StaticInjection,
data::Union{Nothing, IS.TimeSeriesData, CostCurve{PiecewiseIncrementalCurve}},
)
@warn "Variable Cost UnitSystem not specificied for $(get_name(component)). set_variable_cost! assumes data is in UnitSystem.NATURAL_UNITS"
set_variable_cost!(sys, component, data, UnitSystem.NATURAL_UNITS)
return
end
"""
Set the incremental variable cost bid for a `StaticInjection` device with a `MarketBidCost`.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `time_series_data::Union{Nothing, IS.TimeSeriesData,
CostCurve{PiecewiseIncrementalCurve}},`: the data. If using a time series, must be of eltype
`PiecewiseStepData`. `PiecewiseIncrementalCurve` is only accepted for single CostCurve and
not accepted for time series data.
- `power_units::UnitSystem`: Units to be used for data.
"""
function set_incremental_variable_cost!(
sys::System,
component::StaticInjection,
data::Union{Nothing, IS.TimeSeriesData, CostCurve{PiecewiseIncrementalCurve}},
power_units::UnitSystem,
)
set_variable_cost!(sys, component, data, power_units)
return
end
"""
Set the decremental variable cost bid for a `StaticInjection` device with a `MarketBidCost`.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `time_series_data::Union{Nothing, IS.TimeSeriesData,
CostCurve{PiecewiseIncrementalCurve}},`: the data. If using a time series, must be of eltype
`PiecewiseStepData`. `PiecewiseIncrementalCurve` is only accepted for single CostCurve and
not accepted for time series data.
- `power_units::UnitSystem`: Units to be used for data.
"""
function set_decremental_variable_cost!(
sys::System,
component::StaticInjection,
data::Union{Nothing, IS.TimeSeriesData, CostCurve{PiecewiseIncrementalCurve}},
power_units::UnitSystem,
)
market_bid_cost = get_operation_cost(component)
_validate_market_bid_cost(market_bid_cost, "get_operation_cost(component)")
if (typeof(data) <: CostCurve{PiecewiseIncrementalCurve}) &&
(data.power_units != power_units)
throw(
ArgumentError(
"Units specified in CostCurve data differs from the units specified in the set cost.",
),
)
end
if (typeof(data) <: IS.TimeSeriesData) && (power_units != UnitSystem.NATURAL_UNITS)
throw(ArgumentError("Time Series data for MarketBidCost must be in NATURAL_UNITS."))
end
to_set = _process_set_cost(
CostCurve{PiecewiseIncrementalCurve},
PiecewiseStepData,
sys,
component,
data,
)
set_decremental_offer_curves!(market_bid_cost, to_set)
return
end
"""
Set the import variable cost bid for a `StaticInjection` device with an `ImportExportCost`.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `data::Union{Nothing, IS.TimeSeriesData, CostCurve{PiecewiseIncrementalCurve}}`: the data.
If using a time series, must be of eltype `PiecewiseStepData`. `PiecewiseIncrementalCurve`
is only accepted for single CostCurve and not accepted for time series data.
- `power_units::UnitSystem`: Units to be used for data.
"""
function set_import_variable_cost!(
sys::System,
component::StaticInjection,
data::Union{Nothing, IS.TimeSeriesData, CostCurve{PiecewiseIncrementalCurve}},
power_units::UnitSystem,
)
import_export_cost = get_operation_cost(component)
_validate_import_export_cost(import_export_cost, "get_operation_cost(component)")
if (typeof(data) <: CostCurve{PiecewiseIncrementalCurve}) &&
(data.power_units != power_units)
throw(
ArgumentError(
"Units specified in CostCurve data differs from the units specified in the set cost.",
),
)
end
if (typeof(data) <: IS.TimeSeriesData) && (power_units != UnitSystem.NATURAL_UNITS)
throw(
ArgumentError(
"Time Series data for ImportExportCost must be in NATURAL_UNITS.",
),
)
end
to_set = _process_set_cost(
CostCurve{PiecewiseIncrementalCurve},
PiecewiseStepData,
sys,
component,
data,
)
set_import_offer_curves!(import_export_cost, to_set)
return
end
"""
Set the export variable cost bid for a `StaticInjection` device with an `ImportExportCost`.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `data::Union{Nothing, IS.TimeSeriesData, CostCurve{PiecewiseIncrementalCurve}}`: the data.
If using a time series, must be of eltype `PiecewiseStepData`. `PiecewiseIncrementalCurve`
is only accepted for single CostCurve and not accepted for time series data.
- `power_units::UnitSystem`: Units to be used for data.
"""
function set_export_variable_cost!(
sys::System,
component::StaticInjection,
data::Union{Nothing, IS.TimeSeriesData, CostCurve{PiecewiseIncrementalCurve}},
power_units::UnitSystem,
)
import_export_cost = get_operation_cost(component)
_validate_import_export_cost(import_export_cost, "get_operation_cost(component)")
if (typeof(data) <: CostCurve{PiecewiseIncrementalCurve}) &&
(data.power_units != power_units)
throw(
ArgumentError(
"Units specified in CostCurve data differs from the units specified in the set cost.",
),
)
end
if (typeof(data) <: IS.TimeSeriesData) && (power_units != UnitSystem.NATURAL_UNITS)
throw(
ArgumentError(
"Time Series data for ImportExportCost must be in NATURAL_UNITS.",
),
)
end
to_set = _process_set_cost(
CostCurve{PiecewiseIncrementalCurve},
PiecewiseStepData,
sys,
component,
data,
)
set_export_offer_curves!(import_export_cost, to_set)
return
end
"""
Adds energy market bids time-series to the ReserveDemandCurve.
# Arguments
- `sys::System`: PowerSystem System
- `component::ReserveDemandCurve`: the curve
- `time_series_data::IS.TimeSeriesData`: TimeSeriesData
"""
function set_variable_cost!(
sys::System,
component::ReserveDemandCurve,
data::Union{Nothing, IS.TimeSeriesData},
)
# TODO what type checking should be enforced on this time series?
to_set = _process_set_cost(Any, Any, sys, component, data)
set_variable!(component, to_set)
end
"""
Adds fixed energy market bids to the ReserveDemandCurve.
# Arguments
- `sys::System`: PowerSystem System
- `component::ReserveDemandCurve`: the curve
- `time_series_data::CostCurve{PiecewiseIncrementalCurve}
"""
function set_variable_cost!(
::System,
component::ReserveDemandCurve,
data::CostCurve{PiecewiseIncrementalCurve},
)
name = get_name(component)
_validate_reserve_demand_curve(data, name)
set_variable!(component, data)
end
"Set the fuel cost of the component's variable cost, which must be a `FuelCurve`."
function set_fuel_cost!(
sys::System,
component::StaticInjection,
data::Union{Float64, IS.TimeSeriesData},
)
var_cost = _validate_fuel_curve(component)
to_set = _process_set_cost(Float64, Float64, sys, component, data)
op_cost = get_operation_cost(component)
new_var_cost =
FuelCurve(
get_value_curve(var_cost),
get_power_units(var_cost),
to_set,
get_startup_fuel_offtake(var_cost),
get_vom_cost(var_cost),
)
set_variable!(op_cost, new_var_cost)
end
"""
Set the no-load cost for a `StaticInjection` device with a `MarketBidCost` to either a scalar or a time series.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `time_series_data::Union{Float64, IS.TimeSeriesData},`: the data. If a time series, must be of eltype `Float64`.
"""
function set_no_load_cost!(
sys::System,
component::StaticInjection,
data::Union{Float64, IS.TimeSeriesData},
)
market_bid_cost = get_operation_cost(component)
_validate_market_bid_cost(market_bid_cost, "get_operation_cost(component)")
to_set = _process_set_cost(Union{Float64, Nothing}, Float64, sys, component, data)
set_no_load_cost!(market_bid_cost, to_set)
end
"""
Set the `incremental_initial_input` for a `StaticInjection` device with a `MarketBidCost` to either a scalar or a time series.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `time_series_data::Union{Float64, IS.TimeSeriesData},`: the data. If a time series, must be of eltype `Float64`.
"""
function set_incremental_initial_input!(
sys::System,
component::StaticInjection,
data::Union{Float64, IS.TimeSeriesData},
)
market_bid_cost = get_operation_cost(component)
_validate_market_bid_cost(market_bid_cost, "get_operation_cost(component)")
to_set = _process_set_cost(Union{Float64, Nothing}, Float64, sys, component, data)
set_incremental_initial_input!(market_bid_cost, to_set)
end
"""
Set the `decremental_initial_input` for a `StaticInjection` device with a `MarketBidCost` to either a scalar or a time series.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `time_series_data::Union{Float64, IS.TimeSeriesData},`: the data. If a time series, must be of eltype `Float64`.
"""
function set_decremental_initial_input!(
sys::System,
component::StaticInjection,
data::Union{Float64, IS.TimeSeriesData},
)
market_bid_cost = get_operation_cost(component)
_validate_market_bid_cost(market_bid_cost, "get_operation_cost(component)")
to_set = _process_set_cost(Union{Float64, Nothing}, Float64, sys, component, data)
set_decremental_initial_input!(market_bid_cost, to_set)
end
"""
Set the startup cost for a `StaticInjection` device with a `MarketBidCost` to either a
single number, a single `StartUpStages`, or a time series.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `data::Union{Float64, StartUpStages, IS.TimeSeriesData},`: the data. If a time series,
must be of eltype `NTuple{3, Float64}` -- to represent a single value in a time series,
use `(value, 0.0, 0.0)`.
"""
function set_start_up!(
sys::System,
component::StaticInjection,
data::Union{Float64, StartUpStages, IS.TimeSeriesData},
)
market_bid_cost = get_operation_cost(component)
_validate_market_bid_cost(market_bid_cost, "get_operation_cost(component)")
to_set = _process_set_cost(
Union{Float64, StartUpStages},
NTuple{3, Float64},
sys,
component,
data,
)
set_start_up!(market_bid_cost, to_set)
end
"""
Set the shutdown cost for a `StaticInjection` device with a `MarketBidCost` to either a
single number or a time series.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `data::Union{Float64, IS.TimeSeriesData},`: the data. If a time series, must be of eltype
`Float64`.
"""
function set_shut_down!(
sys::System,
component::StaticInjection,
data::Union{Float64, IS.TimeSeriesData},
)
market_bid_cost = get_operation_cost(component)
_validate_market_bid_cost(market_bid_cost, "get_operation_cost(component)")
to_set = _process_set_cost(
Float64,
Float64,
sys,
component,
data,
)
set_shut_down!(market_bid_cost, to_set)
end
"""
Adds service bids time-series data to the MarketBidCost.
# Arguments
- `sys::System`: PowerSystem System
- `component::StaticInjection`: Static injection device
- `service::Service,`: Service for which the device is eligible to contribute
- `time_series_data::IS.TimeSeriesData`: TimeSeriesData
"""
function set_service_bid!(
sys::System,
component::StaticInjection,
service::Service,
time_series_data::IS.TimeSeriesData,
power_units::UnitSystem,
)
data_type = IS.eltype_data(time_series_data)
!(data_type <: PiecewiseStepData) &&
throw(TypeError(set_service_bid!, PiecewiseStepData, data_type))
_validate_market_bid_cost(
get_operation_cost(component),
"get_operation_cost(component)",
)
if get_name(time_series_data) != get_name(service)
error(
"Name provided in the TimeSeries Data $(get_name(time_series_data)), doesn't match the Service $(get_name(service)).",
)
end
if power_units != UnitSystem.NATURAL_UNITS
throw(
ArgumentError(
"Power Unit specified for service market bids must be NATURAL_UNITS",
),
)
end
verify_device_eligibility(sys, component, service)
add_time_series!(sys, component, time_series_data)
ancillary_service_offers = get_ancillary_service_offers(get_operation_cost(component))
push!(ancillary_service_offers, service)
return
end
================================================
FILE: src/models/cost_functions/HydroGenerationCost.jl
================================================
"""
$(TYPEDEF)
$(TYPEDFIELDS)
HydroGenerationCost(variable, fixed)
HydroGenerationCost(; variable, fixed)
An operational cost of a hydropower generator which includes fixed and
variable cost. Variable costs can be used to represent the cost of curtailment if negative
values are used or the opportunity cost of water if the costs are positive. It also supports
fuel curves to model specific water intake.
The `variable` cost is a required parameter, but `zero(CostCurve)` can be used to set it to 0.
"""
@kwdef mutable struct HydroGenerationCost <: OperationalCost
"Production variable cost represented by a `FuelCurve`, where the fuel is water,
or a `CostCurve` in currency."
variable::ProductionVariableCostCurve
"(default: 0) Fixed cost of keeping the unit online. For some cost represenations this
field can be duplicative"
fixed::Float64
end
# Constructor for demo purposes; non-functional.
HydroGenerationCost(::Nothing) = HydroGenerationCost(zero(CostCurve), 0.0)
"""Get [`HydroGenerationCost`](@ref) `variable`."""
get_variable(value::HydroGenerationCost) = value.variable
"""Get [`HydroGenerationCost`](@ref) `fixed`."""
get_fixed(value::HydroGenerationCost) = value.fixed
"""Set [`HydroGenerationCost`](@ref) `variable`."""
set_variable!(value::HydroGenerationCost, val) = value.variable = val
"""Set [`HydroGenerationCost`](@ref) `fixed`."""
set_fixed!(value::HydroGenerationCost, val) = value.fixed = val
================================================
FILE: src/models/cost_functions/HydroReservoirCost.jl
================================================
"""
$(TYPEDEF)
$(TYPEDFIELDS)
HydroReservoirCost(level_shortage_cost, level_surplus_cost, spillage_cost)
StorageCost(; level_shortage_cost, level_surplus_cost, spillage_cost)
An operational cost for hydro reservoirs including shortage and surplus costs for
reservoir levels and spillage costs.
"""
@kwdef mutable struct HydroReservoirCost <: OperationalCost
"(default: 0) Cost incurred by the model for being short of the reservoir level target"
level_shortage_cost::Float64 = 0.0
"(default: 0) Cost incurred by the model for surplus of the reservoir level target"
level_surplus_cost::Float64 = 0.0
"(default: 0) Cost incurred by the model for spillage of the reservoir"
spillage_cost::Float64 = 0.0
end
# Constructor for demo purposes; non-functional.
function HydroReservoirCost(::Nothing)
HydroReservoirCost()
end
"""Get [`HydroReservoirCost`](@ref) `level_shortage_cost`."""
get_level_shortage_cost(value::HydroReservoirCost) = value.level_shortage_cost
"""Get [`HydroReservoirCost`](@ref) `level_surplus_cost`."""
get_level_surplus_cost(value::HydroReservoirCost) = value.level_surplus_cost
"""Get [`HydroReservoirCost`](@ref) `spillage_cost`."""
get_spillage_cost(value::HydroReservoirCost) = value.spillage_cost
"""Set [`HydroReservoirCost`](@ref) `level_shortage_cost`."""
set_level_shortage_cost!(value::HydroReservoirCost, val) =
value.level_shortage_cost = val
"""Set [`HydroReservoirCost`](@ref) `level_surplus_cost`."""
set_level_surplus_cost!(value::HydroReservoirCost, val) =
value.level_surplus_cost = val
"""Set [`HydroReservoirCost`](@ref) `spillage_cost`."""
set_spillage_cost!(value::HydroReservoirCost, val) =
value.spillage_cost = val
================================================
FILE: src/models/cost_functions/ImportExportCost.jl
================================================
"""
$(TYPEDEF)
$(TYPEDFIELDS)
ImportExportCost(import_offer_curves, export_offer_curves, energy_import_weekly_limit, energy_export_weekly_limits, ancillary_service_offers)
ImportExportCost(; import_offer_curves, export_offer_curves, energy_export_weekly_limits, ancillary_service_offers)
An operating cost for imports/exports and ancillary services from neighboring areas. The data model
employs a CostCurve{PiecewiseIncrementalCurve} with an implied zero cost at zero power.
"""
mutable struct ImportExportCost <: OfferCurveCost
"Buy Price Curves data to import power, which can be a time series of [`PiecewiseStepData`] or a
[`CostCurve`](@ref) of [`PiecewiseIncrementalCurve`](@ref)"
import_offer_curves::Union{
Nothing,
TimeSeriesKey, # piecewise step data
CostCurve{PiecewiseIncrementalCurve},
}
"Sell Price Curves data to export power, which can be a time series of `PiecewiseStepData` or a
[`CostCurve`](@ref) of [`PiecewiseIncrementalCurve`](@ref)"
export_offer_curves::Union{
Nothing,
TimeSeriesKey,
CostCurve{PiecewiseIncrementalCurve},
}
"Weekly limit on the amount of energy that can be imported, defined in system base p.u-hours."
energy_import_weekly_limit::Float64
"Weekly limit on the amount of energy that can be exported, defined in system base p.u-hours."
energy_export_weekly_limit::Float64
"Bids to buy or sell ancillary services in the interconnection"
ancillary_service_offers::Vector{Service}
end
ImportExportCost(;
import_offer_curves = nothing,
export_offer_curves = nothing,
energy_import_weekly_limit = INFINITE_BOUND,
energy_export_weekly_limit = INFINITE_BOUND,
ancillary_service_offers = Vector{Service}(),
) = ImportExportCost(
import_offer_curves,
export_offer_curves,
energy_import_weekly_limit,
energy_export_weekly_limit,
ancillary_service_offers,
)
# Constructor for demo purposes; non-functional.
function ImportExportCost(::Nothing)
ImportExportCost()
end
"""Get [`ImportExportCost`](@ref) `import_offer_curves`."""
get_import_offer_curves(value::ImportExportCost) = value.import_offer_curves
"""Get [`ImportExportCost`](@ref) `export_offer_curves`."""
get_export_offer_curves(value::ImportExportCost) = value.export_offer_curves
"""Get [`ImportExportCost`](@ref) `ancillary_service_offers`."""
get_ancillary_service_offers(value::ImportExportCost) = value.ancillary_service_offers
"""Get [`ImportExportCost`](@ref) `energy_import_weekly_limit`."""
get_energy_import_weekly_limit(value::ImportExportCost) = value.energy_import_weekly_limit
"""Get [`ImportExportCost`](@ref) `energy_export_weekly_limits`."""
get_energy_export_weekly_limit(value::ImportExportCost) = value.energy_export_weekly_limit
"""Set [`ImportExportCost`](@ref) `import_offer_curves`."""
set_import_offer_curves!(value::ImportExportCost, val) =
value.import_offer_curves = val
"""Set [`ImportExportCost`](@ref) `export_offer_curves`."""
set_export_offer_curves!(value::ImportExportCost, val) =
value.export_offer_curves = val
"""Set [`ImportExportCost`](@ref) `ancillary_service_offers`."""
set_ancillary_service_offers!(value::ImportExportCost, val) =
value.ancillary_service_offers = val
"""Set [`ImportExportCost`](@ref) `energy_import_weekly_limit`."""
set_energy_import_weekly_limit!(value::ImportExportCost, val) =
value.energy_import_weekly_limit = val
"""Set [`ImportExportCost`](@ref) `energy_export_weekly_limits`."""
set_energy_export_weekly_limit!(value::ImportExportCost, val) =
value.energy_export_weekly_limit = val
function is_import_export_curve(curve::ProductionVariableCostCurve)
return (curve isa CostCurve{PiecewiseIncrementalCurve}) &&
iszero(get_initial_input(get_value_curve(curve))) &&
iszero(get_input_at_zero(get_value_curve(curve))) &&
iszero(first(get_x_coords(get_value_curve(curve))))
end
"""
Make a CostCurve{PiecewiseIncrementalCurve} suitable for inclusion in a ImportExportCost from
the FunctionData that might be used to store such a cost curve in a time series.
"""
function make_import_export_curve(
curve::PiecewiseStepData,
power_units::UnitSystem = UnitSystem.NATURAL_UNITS,
)
cc = CostCurve(
PiecewiseIncrementalCurve(curve, 0.0, 0.0),
power_units,
)
@assert is_import_export_curve(cc)
return cc
end
"""
Make a CostCurve{PiecewiseIncrementalCurve} suitable for inclusion in an ImportExportCost from a
vector of power values, a vector of costs, and an optional units system.
# Examples
```julia
iec = make_import_export_curve([0.0, 100.0, 105.0, 120.0, 130.0], [25.0, 26.0, 28.0, 30.0])
iec1 = make_import_export_curve([0.0, 100.0, 105.0, 120.0, 130.0], [25.0, 26.0, 28.0, 30.0]; power_units = UnitSystem.NATURAL_UNITS)
```
"""
function make_import_export_curve(
powers::Vector{Float64},
prices::Vector{Float64},
power_units::UnitSystem = UnitSystem.NATURAL_UNITS,
)
valid_data = (length(powers) == length(prices) + 1)
if valid_data
curve = PiecewiseStepData(powers, prices)
return make_import_export_curve(
curve,
power_units,
)
else
throw(
ArgumentError(
"Must specify exactly one more number of powers points than prices",
),
)
end
end
function make_import_export_curve(
max_power::Float64,
price::Float64,
power_units::UnitSystem = UnitSystem.NATURAL_UNITS,
)
return make_import_export_curve(
[0.0, max_power],
[price],
power_units,
)
end
function make_import_export_curve(;
powers,
prices,
power_units = UnitSystem.NATURAL_UNITS,
)
return make_import_export_curve(
powers,
prices,
power_units,
)
end
"""
Make an import CostCurve{PiecewiseIncrementalCurve} suitable for inclusion in an ImportExportCost from a
vector of power values, a vector of costs, and an optional units system.
# Examples
```julia
ic = make_import_curve([0.0, 100.0, 105.0, 120.0, 130.0], [25.0, 26.0, 28.0, 30.0])
ic1 = make_import_curve(power = [0.0, 100.0, 105.0, 120.0, 130.0], price = [25.0, 26.0, 28.0, 30.0], power_units = UnitSystem.NATURAL_UNITS)
```
"""
function make_import_curve(
power::Vector{Float64},
price::Vector{Float64},
power_units::UnitSystem = UnitSystem.NATURAL_UNITS,
)
curve = PiecewiseStepData(power, price)
convex = is_convex(curve)
if convex
return make_import_export_curve(
power,
price,
power_units,
)
else
throw(
ArgumentError(
"Import Curve does not have incremental slopes. Check slopes.",
),
)
end
end
"""
Make a CostCurve{PiecewiseIncrementalCurve} from suitable for inclusion in an ImportExportCost from
a max import power, a single price and an optional units system. Assume the minimum import is 0.0
# Examples
```julia
ic = make_import_curve(power = 100.0, price = 25.0)
ic1 = make_import_curve(power = 100.0, price = 25.0, power_units = UnitSystem.NATURAL_UNITS)
```
"""
function make_import_curve(
power::Float64,
price::Float64,
power_units::UnitSystem = UnitSystem.NATURAL_UNITS,
)
return make_import_export_curve(
power,
price,
power_units,
)
end
function make_import_curve(;
power,
price,
power_units = UnitSystem.NATURAL_UNITS,
)
return make_import_curve(
power,
price,
power_units,
)
end
"""
Make an export CostCurve{PiecewiseIncrementalCurve} suitable for inclusion in an ImportExportCost from a
vector of power values, a vector of costs, and an optional units system.
# Examples
```julia
ec = make_export_curve([0.0, 100.0, 105.0, 120.0, 130.0], [30.0, 28.0, 26.0, 25.0])
ec1 = make_export_curve(power = [0.0, 100.0, 105.0, 120.0, 130.0], price = [30.0, 28.0, 26.0, 25.0], power_units = UnitSystem.NATURAL_UNITS)
```
"""
function make_export_curve(
power::Vector{Float64},
price::Vector{Float64},
power_units::UnitSystem = UnitSystem.NATURAL_UNITS,
)
curve = PiecewiseStepData(power, price)
concave = is_concave(curve)
if concave
return make_import_export_curve(
power,
price,
power_units,
)
else
throw(
ArgumentError(
"Export Curve does not have decremental slopes. Check slopes.",
),
)
end
end
"""
Make a CostCurve{PiecewiseIncrementalCurve} from suitable for inclusion in an ImportExportCost from a
a max export power, a single price and an optional units system. Assume the minimum export is 0.0.
# Examples
```julia
ec = make_export_curve(power = 100.0, price = 30.0)
ec1 = make_export_curve(power = 100.0, price = 30.0, power_units = UnitSystem.NATURAL_UNITS)
```
"""
function make_export_curve(
power::Float64,
price::Float64,
power_units::UnitSystem = UnitSystem.NATURAL_UNITS,
)
return make_import_export_curve(
power,
price,
power_units,
)
end
function make_export_curve(;
power,
price,
power_units = UnitSystem.NATURAL_UNITS,
)
return make_export_curve(
power,
price,
power_units,
)
end
================================================
FILE: src/models/cost_functions/LoadCost.jl
================================================
"""
$(TYPEDEF)
$(TYPEDFIELDS)
LoadCost(variable, fixed)
LoadCost(; variable, fixed)
An operational cost for controllable loads (e.g., InterruptiblePowerLoad), including
fixed and variable cost components.
The `variable` cost is a required parameter, but `zero(CostCurve)` can be used to set it to 0.
"""
@kwdef mutable struct LoadCost <: OperationalCost
"Variable cost represented as a [`CostCurve`](@ref)"
variable::CostCurve
"(default: 0) Fixed cost. For some cost represenations this field can be
duplicative"
fixed::Float64
end
# Constructor for demo purposes; non-functional.
LoadCost(::Nothing) = LoadCost(zero(CostCurve), 0.0)
"""Get [`LoadCost`](@ref) `variable`."""
get_variable(value::LoadCost) = value.variable
"""Get [`LoadCost`](@ref) `fixed`."""
get_fixed(value::LoadCost) = value.fixed
"""Set [`LoadCost`](@ref) `variable`."""
set_variable!(value::LoadCost, val) = value.variable = val
"""Set [`LoadCost`](@ref) `fixed`."""
set_fixed!(value::LoadCost, val) = value.fixed = val
================================================
FILE: src/models/cost_functions/MarketBidCost.jl
================================================
"""
$(TYPEDEF)
$(TYPEDFIELDS)
MarketBidCost(no_load_cost, start_up, shut_down, incremental_offer_curves, decremental_offer_curves, ancillary_service_offers)
MarketBidCost(; no_load_cost, start_up, shut_down, incremental_offer_curves, decremental_offer_curves, ancillary_service_offers)
MarketBidCost(no_load_cost, start_up::Real, shut_down, incremental_offer_curves, decremental_offer_curves, ancillary_service_offers)
An operating cost for market bids of energy and ancilliary services for any asset.
Compatible with most US Market bidding mechanisms that support demand and generation side.
"""
mutable struct MarketBidCost <: OfferCurveCost
"No load cost"
no_load_cost::Union{TimeSeriesKey, Nothing, Float64}
"Start-up cost at different stages of the thermal cycle as the unit cools after a
shutdown (e.g., *hot*, *warm*, or *cold* starts). Warm is also referred to as
intermediate in some markets. Can also accept a single value if there is only one
start-up cost"
start_up::Union{TimeSeriesKey, StartUpStages}
"Shut-down cost"
shut_down::Union{TimeSeriesKey, Float64}
"Sell Offer Curves data, which can be a time series of `PiecewiseStepData` or a
[`CostCurve`](@ref) of [`PiecewiseIncrementalCurve`](@ref)"
incremental_offer_curves::Union{
Nothing,
TimeSeriesKey, # piecewise step data
CostCurve{PiecewiseIncrementalCurve},
}
"Buy Offer Curves data, which can be a time series of `PiecewiseStepData` or a
[`CostCurve`](@ref) of [`PiecewiseIncrementalCurve`](@ref)"
decremental_offer_curves::Union{
Nothing,
TimeSeriesKey,
CostCurve{PiecewiseIncrementalCurve},
}
"If using a time series for incremental_offer_curves, this is a time series of `Float64` representing the `initial_input`"
incremental_initial_input::Union{Nothing, TimeSeriesKey}
"If using a time series for decremental_offer_curves, this is a time series of `Float64` representing the `initial_input`"
decremental_initial_input::Union{Nothing, TimeSeriesKey}
"Bids for the ancillary services"
ancillary_service_offers::Vector{Service}
end
"Auxiliary constructor for shut_down::Integer"
MarketBidCost(
no_load_cost::Union{TimeSeriesKey, Nothing, Float64},
start_up::Union{TimeSeriesKey, StartUpStages},
shut_down::Integer,
incremental_offer_curves,
decremental_offer_curves,
incremental_initial_input,
decremental_initial_input,
ancillary_service_offers,
) = MarketBidCost(
no_load_cost,
start_up,
Float64(shut_down),
incremental_offer_curves,
decremental_offer_curves,
incremental_initial_input,
decremental_initial_input,
ancillary_service_offers,
)
"Auxiliary constructor for no_load_cost::Integer"
MarketBidCost(
no_load_cost::Integer,
start_up::Union{TimeSeriesKey, StartUpStages},
shut_down::Union{TimeSeriesKey, Float64},
incremental_offer_curves,
decremental_offer_curves,
incremental_initial_input,
decremental_initial_input,
ancillary_service_offers,
) =
MarketBidCost(
Float64(no_load_cost),
start_up,
shut_down,
incremental_offer_curves,
decremental_offer_curves,
incremental_initial_input,
decremental_initial_input,
ancillary_service_offers,
)
"""Auxiliary Constructor for TestData"""
MarketBidCost(
no_load_cost::Float64,
start_up::Union{TimeSeriesKey, StartUpStages},
shut_down::Union{TimeSeriesKey, Float64},
incremental_offer_curves,
decremental_offer_curves,
ancillary_service_offers,
) =
MarketBidCost(
Float64(no_load_cost),
start_up,
shut_down,
incremental_offer_curves,
decremental_offer_curves,
nothing,
nothing,
ancillary_service_offers,
)
# Constructor that sets the startup cost to a small constant and the rest to 0.0.
function MarketBidCost(::Nothing)
MarketBidCost(;
no_load_cost = nothing,
start_up = (hot = START_COST, warm = START_COST, cold = START_COST),
shut_down = 0.0,
)
end
MarketBidCost(;
no_load_cost = nothing,
start_up,
shut_down,
incremental_offer_curves = nothing,
decremental_offer_curves = nothing,
incremental_initial_input = nothing,
decremental_initial_input = nothing,
ancillary_service_offers = Vector{Service}(),
) = MarketBidCost(
no_load_cost, start_up, shut_down, incremental_offer_curves,
decremental_offer_curves, incremental_initial_input, decremental_initial_input,
ancillary_service_offers,
)
"""
Accepts a single `start_up` value to use as the `hot` value, with `warm` and `cold` set to
`0.0`.
"""
function MarketBidCost(
no_load_cost,
start_up::Real,
shut_down;
incremental_offer_curves = nothing,
decremental_offer_curves = nothing,
incremental_initial_input = nothing,
decremental_initial_input = nothing,
ancillary_service_offers = Vector{Service}(),
)
# Intended for use with generators that are not multi-start (e.g. ThermalStandard).
# Operators use `hot` when they don’t have multiple stages.
start_up_multi = single_start_up_to_stages(start_up)
return MarketBidCost(;
no_load_cost = no_load_cost,
start_up = start_up_multi,
shut_down = shut_down,
incremental_offer_curves = incremental_offer_curves,
decremental_offer_curves = decremental_offer_curves,
incremental_initial_input = incremental_initial_input,
decremental_initial_input = decremental_initial_input,
ancillary_service_offers = ancillary_service_offers,
)
end
"""Get [`MarketBidCost`](@ref) `no_load_cost`."""
get_no_load_cost(value::MarketBidCost) = value.no_load_cost
"""Get [`MarketBidCost`](@ref) `start_up`."""
get_start_up(value::MarketBidCost) = value.start_up
"""Get [`MarketBidCost`](@ref) `shut_down`."""
get_shut_down(value::MarketBidCost) = value.shut_down
"""Get [`MarketBidCost`](@ref) `incremental_offer_curves`."""
get_incremental_offer_curves(value::MarketBidCost) = value.incremental_offer_curves
"""Get [`MarketBidCost`](@ref) `decremental_offer_curves`."""
get_decremental_offer_curves(value::MarketBidCost) = value.decremental_offer_curves
"""Get [`MarketBidCost`](@ref) `incremental_initial_input`."""
get_incremental_initial_input(value::MarketBidCost) = value.incremental_initial_input
"""Get [`MarketBidCost`](@ref) `decremental_initial_input`."""
get_decremental_initial_input(value::MarketBidCost) = value.decremental_initial_input
"""Get [`MarketBidCost`](@ref) `ancillary_service_offers`."""
get_ancillary_service_offers(value::MarketBidCost) = value.ancillary_service_offers
"""Set [`MarketBidCost`](@ref) `no_load_cost`."""
set_no_load_cost!(value::MarketBidCost, val) = value.no_load_cost = val
"""Set [`MarketBidCost`](@ref) `start_up`."""
set_start_up!(value::MarketBidCost, val) = value.start_up = val
"""Set [`MarketBidCost`](@ref) `shut_down`."""
set_shut_down!(value::MarketBidCost, val) = value.shut_down = val
"""Set [`MarketBidCost`](@ref) `incremental_offer_curves`."""
set_incremental_offer_curves!(value::MarketBidCost, val) =
value.incremental_offer_curves = val
"""Set [`MarketBidCost`](@ref) `incremental_initial_input`."""
set_incremental_initial_input!(value::MarketBidCost, val) =
value.incremental_initial_input = val
"""Set [`MarketBidCost`](@ref) `incremental_offer_curves`."""
set_decremental_offer_curves!(value::MarketBidCost, val) =
value.decremental_offer_curves = val
"""Set [`MarketBidCost`](@ref) `decremental_initial_input`."""
set_decremental_initial_input!(value::MarketBidCost, val) =
value.decremental_initial_input = val
"""Set [`MarketBidCost`](@ref) `ancillary_service_offers`."""
set_ancillary_service_offers!(value::MarketBidCost, val) =
value.ancillary_service_offers = val
"""Auxiliary Method for setting up start up that are not multi-start"""
function set_start_up!(value::MarketBidCost, val::Real)
start_up_multi = single_start_up_to_stages(val)
set_start_up!(value, start_up_multi)
end
"""
Return `true` if the given [`ProductionVariableCostCurve`](@ref) is a market bid curve
(a `CostCurve{PiecewiseIncrementalCurve}` as used in [`MarketBidCost`](@ref)).
"""
function is_market_bid_curve(curve::ProductionVariableCostCurve)
return (curve isa CostCurve{PiecewiseIncrementalCurve})
end
"""
Make a CostCurve{PiecewiseIncrementalCurve} suitable for inclusion in a MarketBidCost from a
vector of power values, a vector of marginal costs, a float of initial input, and an optional units system and input at zero.
# Examples
```julia
mbc = make_market_bid_curve([0.0, 100.0, 105.0, 120.0, 130.0], [25.0, 26.0, 28.0, 30.0], 10.0)
mbc2 = make_market_bid_curve([0.0, 100.0, 105.0, 120.0, 130.0], [25.0, 26.0, 28.0, 30.0], 10.0; input_at_zero = 10.0)
mbc3 = make_market_bid_curve([0.0, 100.0, 105.0, 120.0, 130.0], [25.0, 26.0, 28.0, 30.0], 10.0; power_inputs = UnitSystem.NATURAL_UNITS)
```
"""
function make_market_bid_curve(powers::Vector{Float64},
marginal_costs::Vector{Float64},
initial_input::Float64;
power_units::UnitSystem = UnitSystem.NATURAL_UNITS,
input_at_zero::Union{Nothing, Float64} = nothing)
if length(powers) == length(marginal_costs) + 1
fd = PiecewiseStepData(powers, marginal_costs)
return make_market_bid_curve(
fd,
initial_input;
power_units = power_units,
input_at_zero,
)
else
throw(
ArgumentError(
"Must specify exactly one more number of powers ($(length(powers))) than marginal_costs ($(length(marginal_costs)))",
),
)
end
end
"""
Make a CostCurve{PiecewiseIncrementalCurve} suitable for inclusion in a MarketBidCost from
the FunctionData that might be used to store such a cost curve in a time series.
"""
function make_market_bid_curve(data::PiecewiseStepData,
initial_input::Float64;
power_units::UnitSystem = UnitSystem.NATURAL_UNITS,
input_at_zero::Union{Nothing, Float64} = nothing)
cc = CostCurve(IncrementalCurve(data, initial_input, input_at_zero), power_units)
@assert is_market_bid_curve(cc)
return cc
end
"""
Auxiliary make market bid curve for timeseries with nothing inputs.
"""
function _make_market_bid_curve(data::PiecewiseStepData;
initial_input::Union{Nothing, Float64} = nothing,
power_units::UnitSystem = UnitSystem.NATURAL_UNITS,
input_at_zero::Union{Nothing, Float64} = nothing)
cc = CostCurve(IncrementalCurve(data, initial_input, input_at_zero), power_units)
@assert is_market_bid_curve(cc)
return cc
end
================================================
FILE: src/models/cost_functions/OfferCurveCost.jl
================================================
"""
OfferCurveCost
Abstract type for representing cost curves used in market bidding and offer mechanisms.
This serves as the base type for various cost curve implementations including:
- [`MarketBidCost`](@ref)
- [`ImportExportCost`](@ref)
All concrete subtypes must implement the required interface methods for cost calculation
and curve evaluation in power system market operations.
"""
abstract type OfferCurveCost <: OperationalCost end
================================================
FILE: src/models/cost_functions/RenewableGenerationCost.jl
================================================
"""
$(TYPEDEF)
$(TYPEDFIELDS)
RenewableGenerationCost(variable, curtailment_cost, fixed)
RenewableGenerationCost(; variable, curtailment_cost, fixed)
An operational cost of renewable generators which includes the variable cost of energy
(like a [PPA](@ref P)), the cost of curtailing power, and a fixed cost of keeping the unit online.
For example, curtailment costs can be used to represent the loss of tax incentives.
The `variable` cost is a required parameter, but `zero(CostCurve)` can be used to set it to 0.
"""
@kwdef mutable struct RenewableGenerationCost <: OperationalCost
"Variable cost represented as a [`CostCurve`](@ref)"
variable::CostCurve
"(default of 0) Cost of curtailing power represented as a [`CostCurve`](@ref)"
curtailment_cost::CostCurve = zero(CostCurve)
"Fixed cost of keeping the unit online. For some cost representations this field can be duplicative with respect to the data in the VOM field."
fixed::Float64 = 0.0
end
RenewableGenerationCost(variable) = RenewableGenerationCost(; variable)
# Constructor for demo purposes; non-functional.
RenewableGenerationCost(::Nothing) = RenewableGenerationCost(zero(CostCurve))
"""Get [`RenewableGenerationCost`](@ref) `variable`."""
get_variable(value::RenewableGenerationCost) = value.variable
"""Get [`RenewableGenerationCost`](@ref) `curtailment_cost`."""
get_curtailment_cost(value::RenewableGenerationCost) = value.curtailment_cost
"""Get [`RenewableGenerationCost`](@ref) `fixed`."""
get_fixed(value::RenewableGenerationCost) = value.fixed
"""Set [`RenewableGenerationCost`](@ref) `variable`."""
set_variable!(value::RenewableGenerationCost, val) = value.variable = val
"""Set [`RenewableGenerationCost`](@ref) `curtailment_cost`."""
set_curtailment_cost!(value::RenewableGenerationCost, val) = value.curtailment_cost = val
"""Set [`RenewableGenerationCost`](@ref) `fixed`."""
set_fixed!(value::RenewableGenerationCost, val) = value.fixed = val
================================================
FILE: src/models/cost_functions/StorageCost.jl
================================================
const STORAGE_OPERATION_MODES = NamedTuple{(:charge, :discharge), NTuple{2, Float64}}
"""
$(TYPEDEF)
$(TYPEDFIELDS)
StorageCost(charge_variable_cost, discharge_variable_cost, fixed, start_up, shut_down, energy_shortage_cost, energy_surplus_cost)
StorageCost(; charge_variable_cost, discharge_variable_cost, fixed, start_up, shut_down, energy_shortage_cost, energy_surplus_cost)
An operational cost for storage units including fixed costs and variable costs to charge
or discharge.
This data structure is not intended to represent market storage systems market operations
like the submission of buy/sell bids -- see [`MarketBidCost`](@ref) instead.
"""
@kwdef mutable struct StorageCost <: OperationalCost
"(default of 0) Variable cost of charging represented as a [`CostCurve`](@ref)"
charge_variable_cost::CostCurve = zero(CostCurve)
"(default of 0) Variable cost of discharging represented as a [`CostCurve`](@ref)"
discharge_variable_cost::CostCurve = zero(CostCurve)
"(default: 0) Fixed cost of operating the storage system"
fixed::Float64 = 0.0
"(default: 0) Start-up cost"
start_up::Union{STORAGE_OPERATION_MODES, Float64} = 0.0
"(default: 0) Shut-down cost"
shut_down::Float64 = 0.0
"(default: 0) Cost incurred by the model for being short of the energy target"
energy_shortage_cost::Float64 = 0.0
"(default: 0) Cost incurred by the model for surplus energy stored"
energy_surplus_cost::Float64 = 0.0
end
StorageCost(
charge_variable_cost::CostCurve,
discharge_variable_cost::CostCurve,
fixed::Float64,
start_up::Real,
shut_down::Float64,
energy_shortage_cost::Float64,
energy_surplus_cost::Float64,
) =
StorageCost(
charge_variable_cost,
discharge_variable_cost,
fixed,
Float64(start_up),
shut_down,
energy_shortage_cost,
energy_surplus_cost,
)
# Constructor for demo purposes; non-functional.
function StorageCost(::Nothing)
StorageCost()
end
"""Get [`StorageCost`](@ref) `charge_variable_cost`."""
get_charge_variable_cost(value::StorageCost) = value.charge_variable_cost
"""Get [`StorageCost`](@ref) `discharge_variable_cost`."""
get_discharge_variable_cost(value::StorageCost) = value.discharge_variable_cost
"""Get [`StorageCost`](@ref) `fixed`."""
get_fixed(value::StorageCost) = value.fixed
"""Get [`StorageCost`](@ref) `start_up`."""
get_start_up(value::StorageCost) = value.start_up
"""Get [`StorageCost`](@ref) `shut_down`."""
get_shut_down(value::StorageCost) = value.shut_down
"""Get [`StorageCost`](@ref) `energy_shortage_cost`."""
get_energy_shortage_cost(value::StorageCost) = value.energy_shortage_cost
"""Get [`StorageCost`](@ref) `energy_surplus_cost`."""
get_energy_surplus_cost(value::StorageCost) = value.energy_surplus_cost
"""Set [`StorageCost`](@ref) `charge_variable_cost`."""
set_charge_variable_cost!(value::StorageCost, val) = value.charge_variable_cost = val
"""Set [`StorageCost`](@ref) `discharge_variable_cost`."""
set_discharge_variable_cost!(value::StorageCost, val) = value.discharge_variable_cost = val
"""Set [`StorageCost`](@ref) `fixed`."""
set_fixed!(value::StorageCost, val) = value.fixed = val
"""Set [`StorageCost`](@ref) `start_up`."""
set_start_up!(value::StorageCost, val) = value.start_up = val
"""Set [`StorageCost`](@ref) `shut_down`."""
set_shut_down!(value::StorageCost, val) = value.shut_down = val
"""Set [`StorageCost`](@ref) `energy_shortage_cost`."""
set_energy_shortage_cost!(value::StorageCost, val) =
value.energy_shortage_cost = val
"""Set [`StorageCost`](@ref) `energy_surplus_cost`."""
set_energy_surplus_cost!(value::StorageCost, val) =
value.energy_surplus_cost = val
================================================
FILE: src/models/cost_functions/ThermalGenerationCost.jl
================================================
"""
$(TYPEDEF)
$(TYPEDFIELDS)
ThermalGenerationCost(variable, fixed, start_up, shut_down)
ThermalGenerationCost(; variable, fixed, start_up, shut_down)
An operational cost for thermal generators which includes fixed cost, variable cost, shut-down
cost, and multiple options for start up costs.
"""
@kwdef mutable struct ThermalGenerationCost <: OperationalCost
"Variable production cost. Can take a [`CostCurve`](@ref) or [`FuelCurve`](@ref)"
variable::ProductionVariableCostCurve
"Fixed cost of keeping the unit online. For some cost represenations this field can be
duplicative"
fixed::Float64
"Start-up cost can take linear or multi-stage cost"
start_up::Union{StartUpStages, Float64}
"Cost to turn the unit off"
shut_down::Float64
end
ThermalGenerationCost(variable, fixed, start_up::Integer, shut_down) =
ThermalGenerationCost(variable, fixed, convert(Float64, start_up), shut_down)
# Constructor for demo purposes; non-functional.
function ThermalGenerationCost(::Nothing)
ThermalGenerationCost(;
variable = zero(CostCurve),
fixed = 0.0,
start_up = 0.0,
shut_down = 0.0,
)
end
"""Get [`ThermalGenerationCost`](@ref) `variable`."""
get_variable(value::ThermalGenerationCost) = value.variable
"""Get [`ThermalGenerationCost`](@ref) `fixed`."""
get_fixed(value::ThermalGenerationCost) = value.fixed
"""Get [`ThermalGenerationCost`](@ref) `start_up`."""
get_start_up(value::ThermalGenerationCost) = value.start_up
"""Get [`ThermalGenerationCost`](@ref) `shut_down`."""
get_shut_down(value::ThermalGenerationCost) = value.shut_down
"""Set [`ThermalGenerationCost`](@ref) `variable`."""
set_variable!(value::ThermalGenerationCost, val) = value.variable = val
"""Set [`ThermalGenerationCost`](@ref) `fixed`."""
set_fixed!(value::ThermalGenerationCost, val) = value.fixed = val
"""Set [`ThermalGenerationCost`](@ref) `start_up`."""
set_start_up!(value::ThermalGenerationCost, val) = value.start_up = val
"""Set [`ThermalGenerationCost`](@ref) `shut_down`."""
set_shut_down!(value::ThermalGenerationCost, val) = value.shut_down = val
================================================
FILE: src/models/cost_functions/operational_cost.jl
================================================
"""
Supertype for operational cost representations
Current abstract type for representing operational costs associated with power system devices.
- [`OfferCurveCost`](@ref)
Current concrete types include:
- [`ThermalGenerationCost`](@ref)
- [`HydroGenerationCost`](@ref)
- [`RenewableGenerationCost`](@ref)
- [`StorageCost`](@ref)
- [`LoadCost`](@ref)
- [`ImportExportCost`](@ref)
- [`MarketBidCost`](@ref)
"""
abstract type OperationalCost <: DeviceParameter end
IS.serialize(val::OperationalCost) = IS.serialize_struct(val)
IS.deserialize(T::Type{<:OperationalCost}, val::Dict) = IS.deserialize_struct(T, val)
# NOTE MarketBidCost serialization is handled in serialization.jl
================================================
FILE: src/models/devices.jl
================================================
"""
This function add a service to the component without checking if the component and the service are attached to the same system
"""
function add_service_internal!(device::Device, service::Service)
services = get_services(device)
for _service in services
if IS.get_uuid(service) == IS.get_uuid(_service)
throw(
ArgumentError(
"service $(get_name(service)) is already attached to $(get_name(device))",
),
)
end
end
push!(services, service)
@debug "Add $service to $(get_name(device))" _group = IS.LOG_GROUP_SYSTEM
end
function add_service_internal!(device::AGC, service::Service)
reserves = get_reserves(device)
for _reserve in reserves
if IS.get_uuid(service) == IS.get_uuid(_reserve)
throw(
ArgumentError(
"service $(get_name(service)) is already attached to $(get_name(device))",
),
)
end
end
push!(reserves, service)
@debug "Add $service to $(get_name(device))" _group = IS.LOG_GROUP_SYSTEM
end
"""
Remove a service from a device.
Throws ArgumentError if the service is not attached to the device.
"""
function remove_service!(device::Device, service::Service)
if !_remove_service!(device, service)
throw(
ArgumentError(
"service $(get_name(service)) was not attached to $(get_name(device))",
),
)
end
end
"""
Return true if the service is attached to the device.
"""
function has_service(device::Device, service::Service)
for _service in get_services(device)
if IS.get_uuid(_service) == IS.get_uuid(service)
return true
end
end
return false
end
"""
Return true if a service with type T is attached to the device.
"""
function has_service(device::Device, ::Type{T}) where {T <: Service}
if !supports_services(device)
return false
end
for _service in get_services(device)
if isa(_service, T)
return true
end
end
return false
end
has_service(T::Type{<:Service}, device::Device) = has_service(device, T)
"""
Remove service from device if it is attached.
"""
function _remove_service!(device::Device, service::Service)
removed = false
services = get_services(device)
# The expectation is that there won't be many services in each device, and so
# a faster lookup method is not needed.
for (i, _service) in enumerate(services)
if IS.get_uuid(_service) == IS.get_uuid(service)
deleteat!(services, i)
removed = true
@debug "Removed service $(get_name(service)) from $(get_name(device))" _group =
IS.LOG_GROUP_SYSTEM
break
end
end
return removed
end
"""
Remove all services attached to the device.
"""
function clear_services!(device::Device)
if !supports_services(device)
return
end
@debug "Clearing all services from $(get_name(device))" _group = IS.LOG_GROUP_SYSTEM
services = get_services(device)
empty!(services)
return
end
""" Ensures that reservoirs cannot provide services """
supports_services(::HydroReservoir) = false
"""
Remove a reservoir from a device.
Throws ArgumentError if the reservoir is not attached to the device.
"""
function remove_turbine!(reservoir::HydroReservoir, device::HydroTurbine)
if !_remove_turbine!(reservoir, device)
throw(
ArgumentError(
"turbine $(get_name(device)) was not attached to $(get_name(reservoir))",
),
)
end
end
"""
Return true if the reservoir has attached the upstream turbine.
"""
function has_upstream_turbine(reservoir::HydroReservoir, turbine::HydroUnit)
for _turbine in get_upstream_turbines(reservoir)
if IS.get_uuid(_turbine) == IS.get_uuid(turbine)
return true
end
end
return false
end
"""
Return true if the reservoir has attached the upstream turbine.
"""
function has_downstream_turbine(reservoir::HydroReservoir, turbine::HydroUnit)
for _turbine in get_downstream_turbines(reservoir)
if IS.get_uuid(_turbine) == IS.get_uuid(turbine)
return true
end
end
return false
end
"""
Return true if any upstream hydro unit is attached to the reservoir.
"""
function has_upstream_turbine(reservoir::HydroReservoir)
return !isempty(get_upstream_turbines(reservoir))
end
"""
Return true if any downstream hydro unit is attached to the reservoir.
"""
function has_downstream_turbine(reservoir::HydroReservoir)
return !isempty(get_downstream_turbines(reservoir))
end
"""
Remove turbine from reservoir if it is attached.
"""
function _remove_turbine!(reservoir::HydroReservoir, device::HydroUnit)
removed = false
up_turbines = get_upstream_turbines(reservoir)
down_turbines = get_downstream_turbines(reservoir)
# The expectation is that there won't be many services in each device, and so
# a faster lookup method is not needed.
for (i, _turbine) in enumerate(down_turbines)
if IS.get_uuid(_turbine) == IS.get_uuid(device)
deleteat!(down_turbines, i)
removed = true
@debug "Removed turbine $(get_name(_turbine)) from $(get_name(reservoir))" _group =
IS.LOG_GROUP_SYSTEM
break
end
end
if !removed
for (i, _turbine) in enumerate(up_turbines)
if IS.get_uuid(_turbine) == IS.get_uuid(device)
deleteat!(up_turbines, i)
removed = true
@debug "Removed turbine $(get_name(_turbine)) from $(get_name(reservoir))" _group =
IS.LOG_GROUP_SYSTEM
break
end
end
end
return removed
end
"""
Remove all turbines attached to the reservoir.
"""
function clear_turbines!(device::HydroReservoir)
turbines = get_upstream_turbines(device)
empty!(turbines)
turbines = get_downstream_turbines(device)
empty!(turbines)
return
end
================================================
FILE: src/models/dynamic_branch.jl
================================================
"""
Extends the branch type to add the information required for dynamic modeling of branches. Includes the fields for the states and the number of states
# Arguments
- `branch::ACTransmission`
"""
mutable struct DynamicBranch <: ACTransmission
branch::ACTransmission
n_states::Int
states::Vector{Symbol}
internal::IS.InfrastructureSystemsInternal
function DynamicBranch(branch, n_states, states, internal)
@assert length(states) == n_states
new(branch, n_states, states, internal)
end
end
const DEFAULT_DYNAMIC_BRANCH_STATES = [:Il_R, :Il_I]
function DynamicBranch(
branch::T;
internal = IS.InfrastructureSystemsInternal(),
) where {T <: ACTransmission}
states = DEFAULT_DYNAMIC_BRANCH_STATES
n_states = length(states)
return DynamicBranch(branch, n_states, states, internal)
end
function DynamicBranch(;
branch,
n_states = length(DEFAULT_DYNAMIC_BRANCH_STATES),
states = DEFAULT_DYNAMIC_BRANCH_STATES,
internal = IS.InfrastructureSystemsInternal(),
)
return DynamicBranch(branch, n_states, states, internal)
end
function DynamicBranch(::Nothing)
return DynamicBranch(Line(nothing))
end
"Get branch"
get_branch(value::DynamicBranch) = value.branch
"Get n_states"
get_n_states(value::DynamicBranch) = value.n_states
"Get states"
get_states(value::DynamicBranch) = value.states
"""Get DynamicBranch internal."""
get_internal(value::DynamicBranch) = value.internal
get_name(value::DynamicBranch) = IS.get_name(value.branch)
"""Get DynamicBranch available."""
get_available(value::DynamicBranch) = get_available(value.branch)
"""Get DynamicBranch active_power_flow."""
get_active_power_flow(value::DynamicBranch) = get_active_power(value.branch)
"""Get DynamicBranch reactive_power_flow."""
get_reactive_power_flow(value::DynamicBranch) = get_reactive_power(value.branch)
"""Get DynamicBranch arc."""
get_arc(value::DynamicBranch) = get_arc(value.branch)
"""Get DynamicBranch r."""
get_r(value::DynamicBranch) = get_r(value.branch)
"""Get DynamicBranch x."""
get_x(value::DynamicBranch) = get_x(value.branch)
"""Get DynamicBranch b."""
get_b(value::DynamicBranch) = get_b(value.branch)
"""Get DynamicBranch A rating."""
get_rating(value::DynamicBranch) = get_rating(value.branch)
"""Get DynamicBranch angle_limits."""
get_angle_limits(value::DynamicBranch) = get_angle_limits(value.branch)
"""Get DynamicBranch B rating."""
get_rating_b(value::DynamicBranch) = get_rating_b(value.branch)
"""Get DynamicBranch C rating."""
get_rating_c(value::DynamicBranch) = get_rating_c(value.branch)
"""Get DynamicBranch services."""
get_services(value::DynamicBranch) = get_services(value.branch)
"""Get DynamicBranch ext."""
get_ext(value::DynamicBranch) = get_ext(value.branch)
"""Set DynamicBranch available."""
set_available!(value::DynamicBranch, val::Bool) = set_available!(value.branch, val)
"""Set DynamicBranch active_power_flow."""
set_active_power_flow!(value::DynamicBranch, val::Float64) =
set_active_power_flow!(value.branch, val)
"""Set DynamicBranch reactive_power_flow."""
set_reactive_power_flow!(value::DynamicBranch, val::Float64) =
set_reactive_power_flow!(value.branch, val)
"""Set DynamicBranch arc."""
set_arc!(value::DynamicBranch, val::Arc) = set_arc!(value.branch, val)
"""Set DynamicBranch r."""
set_r!(value::DynamicBranch, val::Float64) = set_r!(value.branch, val)
"""Set DynamicBranch x."""
set_x!(value::DynamicBranch, val::Float64) = set_x!(value.branch, val)
"""Set DynamicBranch b."""
set_b!(value::DynamicBranch, val) = set_b!(value.branch, val)
"""Set DynamicBranch rating."""
set_rating!(value::DynamicBranch, val::Float64) = set_rating!(value.branch, val)
"""Set DynamicBranch angle_limits."""
set_angle_limits!(
value::DynamicBranch,
val::NamedTuple{(:min, :max), Tuple{Float64, Float64}},
) = set_angle_limits!(value.branch, val)
"""Set DynamicBranch services."""
set_services!(value::DynamicBranch, val::Vector{Service}) = set_services!(value.branch, val)
"""Set DynamicBranch ext."""
set_ext!(value::DynamicBranch, val::Dict{String, Any}) = set_ext!(value.branch, val)
"Set branch"
set_branch!(value::DynamicBranch, val::ACTransmission) = value.branch = val
"Set n_states"
set_n_states!(value::DynamicBranch, val::Int) = value.n_states = val
"Set states"
set_states!(value::DynamicBranch, val::Vector{Symbol}) = value.states = val
================================================
FILE: src/models/dynamic_generator.jl
================================================
"""
mutable struct DynamicGenerator{
M <: Machine,
S <: Shaft,
A <: AVR,
TG <: TurbineGov,
P <: PSS,
} <: DynamicInjection
name::String
ω_ref::Float64
machine::M
shaft::S
avr::A
prime_mover::TG
pss::P
base_power::Float64
n_states::Int
states::Vector{Symbol}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A dynamic generator with the necessary data for modeling the dynamic response of a generator
in a phasor or electromagnetic transient simulation.
Dynamic generator is composed by 5 components, namely a [Machine](@ref), a [Shaft](@ref),
an Automatic Voltage Regulator ([AVR](@ref)), a
[Prime Mover and Turbine Governor](@ref "TurbineGov"),
and Power System Stabilizer ([PSS](@ref)). It must be attached to a
[`StaticInjection`](@ref) device using [`add_component!`](@ref add_component!(
sys::System,
dyn_injector::DynamicInjection,
static_injector::StaticInjection;
kwargs...,
)), which contains all the rest of the generator's data that isn't specific to its dynamic
response.
# Arguments
- `name::String`: Name of generator.
- `ω_ref::Float64`: Frequency reference set-point in pu.
- `machine <: Machine`: [Machine](@ref) model for modeling the electro-magnetic phenomena.
- `shaft <: Shaft`: [Shaft](@ref) model for modeling the electro-mechanical phenomena.
- `avr <: AVR`: [AVR](@ref) model of the excitacion system.
- `prime_mover <: TurbineGov`: [Prime Mover and Turbine Governor model](@ref "TurbineGov") for mechanical power.
- `pss <: PSS`: [PSS](@ref) model.
- `base_power::Float64`: (default: `100.0`) Base power of the unit (MVA) for [per unitization](@ref per_unit). Although this has a default, in almost all cases `base_power` should be updated to equal the `base_power` field of the [`StaticInjection`](@ref) device that this dynamic generator will be attached to.
- `n_states::Int`: (**Do not modify.**) Number of states (will depend on the inputs above).
- `states::Vector{Symbol}`: (**Do not modify.**) Vector of states (will depend on the inputs above).
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct DynamicGenerator{
M <: Machine,
S <: Shaft,
A <: AVR,
TG <: TurbineGov,
P <: PSS,
} <: DynamicInjection
name::String
ω_ref::Float64
machine::M
shaft::S
avr::A
prime_mover::TG
pss::P
base_power::Float64
n_states::Int
states::Vector{Symbol}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
function DynamicGenerator(
name::String,
ω_ref::Float64,
machine::M,
shaft::S,
avr::A,
prime_mover::TG,
pss::P,
base_power::Float64 = 100.0,
ext::Dict{String, Any} = Dict{String, Any}(),
) where {M <: Machine, S <: Shaft, A <: AVR, TG <: TurbineGov, P <: PSS}
n_states = _calc_n_states(machine, shaft, avr, prime_mover, pss)
states = _calc_states(machine, shaft, avr, prime_mover, pss)
return DynamicGenerator{M, S, A, TG, P}(
name,
ω_ref,
machine,
shaft,
avr,
prime_mover,
pss,
base_power,
n_states,
states,
ext,
InfrastructureSystemsInternal(),
)
end
function DynamicGenerator(;
name::String,
ω_ref::Float64,
machine::M,
shaft::S,
avr::A,
prime_mover::TG,
pss::P,
base_power::Float64 = 100.0,
n_states = _calc_n_states(machine, shaft, avr, prime_mover, pss),
states = _calc_states(machine, shaft, avr, prime_mover, pss),
ext::Dict{String, Any} = Dict{String, Any}(),
internal = InfrastructureSystemsInternal(),
) where {M <: Machine, S <: Shaft, A <: AVR, TG <: TurbineGov, P <: PSS}
return DynamicGenerator(
name,
ω_ref,
machine,
shaft,
avr,
prime_mover,
pss,
base_power,
n_states,
states,
ext,
internal,
)
end
get_name(device::DynamicGenerator) = device.name
get_states(device::DynamicGenerator) = device.states
get_n_states(device::DynamicGenerator) = device.n_states
get_ω_ref(device::DynamicGenerator) = device.ω_ref
"""Get the [`Machine`](@ref) component of a [`DynamicGenerator`](@ref)."""
get_machine(device::DynamicGenerator) = device.machine
"""Get the [`Shaft`](@ref) component of a [`DynamicGenerator`](@ref)."""
get_shaft(device::DynamicGenerator) = device.shaft
"""Get the [`AVR`](@ref) component of a [`DynamicGenerator`](@ref)."""
get_avr(device::DynamicGenerator) = device.avr
"""Get the [`TurbineGov`](@ref) (prime mover) component of a [`DynamicGenerator`](@ref)."""
get_prime_mover(device::DynamicGenerator) = device.prime_mover
"""Get the [`PSS`](@ref) component of a [`DynamicGenerator`](@ref)."""
get_pss(device::DynamicGenerator) = device.pss
get_base_power(device::DynamicGenerator) = device.base_power
get_ext(device::DynamicGenerator) = device.ext
get_internal(device::DynamicGenerator) = device.internal
get_V_ref(value::DynamicGenerator) = get_V_ref(get_avr(value))
get_P_ref(value::DynamicGenerator) = get_P_ref(get_prime_mover(value))
set_base_power!(value::DynamicGenerator, val) = value.base_power = val
function _calc_n_states(machine, shaft, avr, prime_mover, pss)
return get_n_states(machine) +
get_n_states(shaft) +
get_n_states(avr) +
get_n_states(prime_mover) +
get_n_states(pss)
end
function _calc_states(machine, shaft, avr, prime_mover, pss)
return vcat(
get_states(machine),
get_states(shaft),
get_states(avr),
get_states(prime_mover),
get_states(pss),
)
end
function get_degov1_states(droop_flag::Int)
if droop_flag == 0
return [:x_g1, :x_g2, :x_g3, :x_g4, :x_g5], 5
elseif droop_flag == 1
return [:x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6], 6
else
error("Unsupported value of droop_flag on DEGOV1")
end
end
"""
Get the frequency droop parameter from the prime mover of a [`DynamicGenerator`](@ref).
"""
function get_frequency_droop(dyn_gen::DynamicGenerator)
return get_frequency_droop(get_prime_mover(dyn_gen))
end
function get_frequency_droop(::V) where {V <: TurbineGov}
throw(
ArgumentError(
"get_frequency_droop not implemented for prime mover $V.",
),
)
end
get_frequency_droop(pm::DEGOV) = 1 / get_K(pm)
get_frequency_droop(pm::DEGOV1) = get_R(pm)
get_frequency_droop(pm::GasTG) = get_R(pm)
get_frequency_droop(pm::GeneralGovModel) = get_R(pm)
get_frequency_droop(pm::HydroTurbineGov) = get_R(pm)
get_frequency_droop(pm::IEEETurbineGov1) = 1 / get_K(pm)
get_frequency_droop(pm::PIDGOV) = 1 / get_Rperm(pm)
get_frequency_droop(pm::SteamTurbineGov1) = get_R(pm)
get_frequency_droop(pm::TGSimple) = 1 / d_t(pm)
get_frequency_droop(pm::TGTypeI) = get_R(pm)
get_frequency_droop(pm::TGTypeII) = get_R(pm)
get_frequency_droop(pm::WPIDHY) = 1 / get_reg(pm)
================================================
FILE: src/models/dynamic_generator_components.jl
================================================
abstract type DynamicGeneratorComponent <: DynamicComponent end
"""
Supertype for all Automatic Voltage Regulator (AVR) models for
[`DynamicGenerator`](@ref) components.
Concrete subtypes include [`AVRFixed`](@ref), [`AVRSimple`](@ref), [`AVRTypeI`](@ref),
[`AVRTypeII`](@ref), [`IEEET1`](@ref), [`ESDC1A`](@ref), [`ESAC1A`](@ref),
[`SEXS`](@ref), [`SCRX`](@ref), and others.
"""
abstract type AVR <: DynamicGeneratorComponent end
"""
Supertype for all synchronous machine models for [`DynamicGenerator`](@ref) components.
Concrete subtypes include [`BaseMachine`](@ref), [`OneDOneQMachine`](@ref),
[`SauerPaiMachine`](@ref), [`MarconatoMachine`](@ref), [`RoundRotorMachine`](@ref),
[`SalientPoleMachine`](@ref), [`AndersonFouadMachine`](@ref), [`FullMachine`](@ref),
and others.
"""
abstract type Machine <: DynamicGeneratorComponent end
"""
Supertype for all Power System Stabilizer (PSS) models for
[`DynamicGenerator`](@ref) components.
Concrete subtypes include [`PSSFixed`](@ref), [`PSSSimple`](@ref), [`IEEEST`](@ref),
[`PSS2A`](@ref), [`PSS2B`](@ref), [`PSS2C`](@ref), [`STAB1`](@ref), and [`CSVGN1`](@ref).
"""
abstract type PSS <: DynamicGeneratorComponent end
"""
Supertype for all shaft and rotor models for [`DynamicGenerator`](@ref) components.
Concrete subtypes include [`SingleMass`](@ref) and [`FiveMassShaft`](@ref).
"""
abstract type Shaft <: DynamicGeneratorComponent end
"""
Supertype for all turbine governor models for [`DynamicGenerator`](@ref) components.
Concrete subtypes include [`TGFixed`](@ref), [`TGTypeI`](@ref), [`TGTypeII`](@ref),
[`GasTG`](@ref), [`GeneralGovModel`](@ref), [`HydroTurbineGov`](@ref),
[`IEEETurbineGov1`](@ref), [`SteamTurbineGov1`](@ref), [`DEGOV`](@ref),
[`DEGOV1`](@ref), and others.
"""
abstract type TurbineGov <: DynamicGeneratorComponent end
"""
Obtain coefficients (A, B) of the function Se(x) = B(x - A)^2/x for
Se(E1) = B(E1 - A)^2/E1 and Se(E2) = B(E2 - A)^2/E2
and uses the negative solution of the quadratic equation
"""
function calculate_saturation_coefficients(
E::Tuple{Float64, Float64},
Se::Tuple{Float64, Float64},
)
if ((E[1] == 0.0) || (E[2] == 0.0)) || ((Se[1] == 0.0) || (Se[2] == 0.0))
return (0.0, 0.0)
end
if (E[2] <= E[1]) || (Se[2] <= Se[1])
throw(
IS.ConflictingInputsError(
"E2 <= E1 or Se1 <= Se2. Saturation data is inconsistent.",
),
)
end
A =
(1.0 / (Se[2] * E[2] - Se[1] * E[1])) * (
E[1] * E[2] * (Se[2] - Se[1]) -
sqrt(E[1] * E[2] * Se[1] * Se[2] * (E[1] - E[2])^2)
)
B = Se[2] * E[2] / (E[2] - A)^2
@assert abs(B - Se[1] * E[1] / (E[1] - A)^2) <= 1e-2
return (A, B)
end
"""
Obtain coefficients for an AVR
"""
function get_avr_saturation(E::Tuple{Float64, Float64}, Se::Tuple{Float64, Float64})
return calculate_saturation_coefficients(E, Se)
end
================================================
FILE: src/models/dynamic_inverter.jl
================================================
abstract type InverterComponent <: DynamicComponent end
"""
mutable struct DynamicInverter{
C <: Converter,
O <: OuterControl,
IC <: InnerControl,
DC <: DCSource,
P <: FrequencyEstimator,
F <: Filter,
} <: DynamicInjection
name::String
ω_ref::Float64
converter::C
outer_control::O
inner_control::IC
dc_source::DC
freq_estimator::P
filter::F
limiter::Union{nothing, OutputCurrentLimiter}
base_power::Float64
n_states::Int
states::Vector{Symbol}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A dynamic inverter with the necessary data for modeling the dynamic response of an inverter
in a phasor or electromagnetic transient simulation.
A dynamic inverter is composed by 6 components, namely a [Converter](@ref),
[Outer Loop Control](@ref OuterControl), [Inner Loop Control](@ref InnerControl),
a [DC Source](@ref DCSource), a [Frequency Estimator](@ref FrequencyEstimator) and a
[Filter](@ref).
It must be attached to a
[`StaticInjection`](@ref) device using [`add_component!`](@ref add_component!(
sys::System,
dyn_injector::DynamicInjection,
static_injector::StaticInjection;
kwargs...,
)), which contains all the rest of the generator's data that isn't specific to its dynamic
response.
# Arguments
- `name::String`: Name of inverter.
- `ω_ref::Float64`: Frequency reference set-point in pu.
- `converter <: Converter`: Converter model for the PWM transformation.
- `outer_control <: OuterControl`: An [OuterControl](@ref) controller model.
- `inner_control <: InnerControl`: An [InnerControl](@ref) controller model.
- `dc_source <: DCSource`: [DCSource](@ref) model.
- `freq_estimator <: FrequencyEstimator`: a [FrequencyEstimator](@ref) (typically a [PLL](@ref P)) model.
- `filter <: Filter`: [Filter](@ref) model.
- `limiter <: Union{nothing, OutputCurrentLimiter}`: (default: nothing) Inner Control [Current Limiter](@ref OutputCurrentLimiter) model
- `base_power::Float64`: (default: `100.0`) Base power of the unit (MVA) for [per unitization](@ref per_unit). Although this has a default, in almost all cases `base_power` should be updated to equal the `base_power` field of the [`StaticInjection`](@ref) device that this dynamic generator will be attached to.
- `n_states::Int`: (**Do not modify.**) Number of states (will depend on the inputs above).
- `states::Vector{Symbol}`: (**Do not modify.**) Vector of states (will depend on the inputs above).
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct DynamicInverter{
C <: Converter,
O <: OuterControl,
IC <: InnerControl,
DC <: DCSource,
P <: FrequencyEstimator,
F <: Filter,
L <: Union{Nothing, OutputCurrentLimiter},
} <: DynamicInjection
name::String
ω_ref::Float64
converter::C
outer_control::O
inner_control::IC
dc_source::DC
freq_estimator::P
filter::F
limiter::L
base_power::Float64
n_states::Int
states::Vector{Symbol}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
function DynamicInverter(
name::String,
ω_ref::Float64,
converter::C,
outer_control::O,
inner_control::IC,
dc_source::DC,
freq_estimator::P,
filter::F,
limiter::L = nothing,
base_power::Float64 = 100.0,
ext::Dict{String, Any} = Dict{String, Any}(),
) where {
C <: Converter,
O <: OuterControl,
IC <: InnerControl,
DC <: DCSource,
P <: FrequencyEstimator,
F <: Filter,
L <: Union{Nothing, OutputCurrentLimiter},
}
n_states = _calc_n_states(
converter,
outer_control,
inner_control,
dc_source,
freq_estimator,
filter,
)
states = _calc_states(
converter,
outer_control,
inner_control,
dc_source,
freq_estimator,
filter,
)
return DynamicInverter{C, O, IC, DC, P, F, L}(
name,
ω_ref,
converter,
outer_control,
inner_control,
dc_source,
freq_estimator,
filter,
limiter,
base_power,
n_states,
states,
ext,
InfrastructureSystemsInternal(),
)
end
function DynamicInverter(;
name::String,
ω_ref::Float64,
converter::C,
outer_control::O,
inner_control::IC,
dc_source::DC,
freq_estimator::P,
filter::F,
limiter::L = nothing,
base_power::Float64 = 100.0,
n_states = _calc_n_states(
converter,
outer_control,
inner_control,
dc_source,
freq_estimator,
filter,
),
states = _calc_states(
converter,
outer_control,
inner_control,
dc_source,
freq_estimator,
filter,
),
ext::Dict{String, Any} = Dict{String, Any}(),
internal = IS.InfrastructureSystemsInternal(),
) where {
C <: Converter,
O <: OuterControl,
IC <: InnerControl,
DC <: DCSource,
P <: FrequencyEstimator,
F <: Filter,
L <: Union{Nothing, OutputCurrentLimiter},
}
return DynamicInverter(
name,
ω_ref,
converter,
outer_control,
inner_control,
dc_source,
freq_estimator,
filter,
limiter,
base_power,
n_states,
states,
ext,
internal,
)
end
function DynamicInverter(
name::String,
ω_ref::Float64,
converter::C,
active_power_control::AC,
reactive_power_control::RC,
inner_control::IC,
dc_source::DC,
freq_estimator::P,
ac_filter::F,
) where {
C <: Converter,
AC <: ActivePowerControl,
RC <: ReactivePowerControl,
IC <: InnerControl,
DC <: DCSource,
P <: FrequencyEstimator,
F <: Filter,
}
outer_control = OuterControl(active_power_control, reactive_power_control)
return DynamicInverter(
name,
ω_ref,
converter,
outer_control,
inner_control,
dc_source,
freq_estimator,
ac_filter,
)
end
get_name(device::DynamicInverter) = device.name
get_ω_ref(device::DynamicInverter) = device.ω_ref
get_ext(device::DynamicInverter) = device.ext
get_states(device::DynamicInverter) = device.states
get_n_states(device::DynamicInverter) = device.n_states
"""Get the [`Converter`](@ref) component of a [`DynamicInverter`](@ref)."""
get_converter(device::DynamicInverter) = device.converter
"""Get the [`OuterControl`](@ref) component of a [`DynamicInverter`](@ref)."""
get_outer_control(device::DynamicInverter) = device.outer_control
"""Get the [`InnerControl`](@ref) component of a [`DynamicInverter`](@ref)."""
get_inner_control(device::DynamicInverter) = device.inner_control
"""Get the [`DCSource`](@ref) component of a [`DynamicInverter`](@ref)."""
get_dc_source(device::DynamicInverter) = device.dc_source
"""Get the [`FrequencyEstimator`](@ref) component of a [`DynamicInverter`](@ref)."""
get_freq_estimator(device::DynamicInverter) = device.freq_estimator
"""Get the [`Filter`](@ref) component of a [`DynamicInverter`](@ref)."""
get_filter(device::DynamicInverter) = device.filter
get_limiter(device::DynamicInverter) = device.limiter
get_base_power(device::DynamicInverter) = device.base_power
get_internal(device::DynamicInverter) = device.internal
get_P_ref(value::DynamicInverter) =
get_P_ref(get_active_power_control(get_outer_control(value)))
get_V_ref(value::DynamicInverter) =
get_V_ref(get_reactive_power_control(get_outer_control(value)))
set_base_power!(value::DynamicInverter, val) = value.base_power = val
function _calc_n_states(
converter,
outer_control,
inner_control,
dc_source,
freq_estimator,
filter,
)
return converter.n_states +
outer_control.n_states +
inner_control.n_states +
dc_source.n_states +
freq_estimator.n_states +
filter.n_states
end
function _calc_states(
converter,
outer_control,
inner_control,
dc_source,
freq_estimator,
filter,
)
return vcat(
converter.states,
outer_control.states,
inner_control.states,
dc_source.states,
freq_estimator.states,
filter.states,
)
end
function get_REControlB_states(Q_Flag::Int)
if Q_Flag == 0
return [:Vt_filt, :I_icv]
elseif Q_Flag == 1
return [:Vt_filt, :ξ_icv]
else
error("Unsupported value of Q_Flag")
end
end
function get_activeRETypeAB_states(Freq_Flag::Int)
if Freq_Flag == 1
return [:p_flt, :ξ_P, :p_ext, :p_ord], 4
elseif Freq_Flag == 0
return [:p_ord], 1
else
error("Unsupported value of Freq_Flag")
end
end
function get_reactiveRETypeAB_states(Ref_Flag::Int, PF_Flag::Int, V_Flag::Int)
if (Ref_Flag == 0) && ((PF_Flag == 1) && (V_Flag == 1))
return [:pr_flt, :ξ_Q], 2
elseif (Ref_Flag == 0) && ((PF_Flag == 1) && (V_Flag == 0))
return [:pr_flt], 1
elseif (Ref_Flag == 0) && ((PF_Flag == 0) && (V_Flag == 1))
return [:q_flt, :ξq_oc, :q_LL, :ξ_Q], 4
elseif (Ref_Flag == 0) && ((PF_Flag == 0) && (V_Flag == 0))
return [:q_flt, :ξq_oc, :q_LL], 3
elseif (Ref_Flag == 1) && ((PF_Flag == 1) && (V_Flag == 1))
return [:pr_flt, :ξ_Q], 2
elseif (Ref_Flag == 1) && ((PF_Flag == 1) && (V_Flag == 0))
return [:pr_flt], 1
elseif (Ref_Flag == 1) && ((PF_Flag == 0) && (V_Flag == 1))
return [:V_cflt, :ξq_oc, :q_LL, :ξ_Q], 4
elseif (Ref_Flag == 1) && ((PF_Flag == 0) && (V_Flag == 0))
return [:V_cflt, :ξq_oc, :q_LL], 3
else
error("Unsupported value of Ref_Flag, PF_Flag or V_Flag")
end
end
================================================
FILE: src/models/dynamic_inverter_components.jl
================================================
abstract type DynamicInverterComponent <: DynamicComponent end
"""
Supertype for all power electronic converter models for
[`DynamicInverter`](@ref) components.
Concrete subtypes include [`AverageConverter`](@ref),
[`RenewableEnergyConverterTypeA`](@ref), and
[`RenewableEnergyVoltageConverterTypeA`](@ref).
"""
abstract type Converter <: DynamicInverterComponent end
"""
Supertype for all DC source models for [`DynamicInverter`](@ref) components.
Concrete subtypes include [`FixedDCSource`](@ref) and [`ZeroOrderBESS`](@ref).
"""
abstract type DCSource <: DynamicInverterComponent end
"""
Supertype for all output filter models for [`DynamicInverter`](@ref) components.
Concrete subtypes include [`LCLFilter`](@ref), [`LCFilter`](@ref), and [`RLFilter`](@ref).
"""
abstract type Filter <: DynamicInverterComponent end
"""
Supertype for all frequency estimator models for
[`DynamicInverter`](@ref) components.
Concrete subtypes include [`KauraPLL`](@ref), [`ReducedOrderPLL`](@ref), and
[`FixedFrequency`](@ref).
"""
abstract type FrequencyEstimator <: DynamicInverterComponent end
"""
Supertype for all inner control loop models for
[`DynamicInverter`](@ref) components.
Concrete subtypes include [`VoltageModeControl`](@ref), [`CurrentModeControl`](@ref),
and [`RECurrentControlB`](@ref).
"""
abstract type InnerControl <: DynamicInverterComponent end
"""
Supertype for all output current limiter models for
[`DynamicInverter`](@ref) components.
Concrete subtypes include [`MagnitudeOutputCurrentLimiter`](@ref),
[`InstantaneousOutputCurrentLimiter`](@ref), [`PriorityOutputCurrentLimiter`](@ref),
[`SaturationOutputCurrentLimiter`](@ref), and [`HybridOutputCurrentLimiter`](@ref).
"""
abstract type OutputCurrentLimiter <: DynamicInverterComponent end
abstract type ActivePowerControl <: DeviceParameter end
abstract type ReactivePowerControl <: DeviceParameter end
================================================
FILE: src/models/dynamic_loads.jl
================================================
function get_GenericDER_states(Qref_Flag::Int)
if Qref_Flag == 1
return [:x1, :x2, :x3, :x4, :x5, :x6, :x7, :x8, :x9], 9
elseif Qref_Flag == 2 || Qref_Flag == 3
return [:x2, :x3, :x4, :x5, :x6, :x7, :x8, :x9], 8
else
error("Unsupported value of Qref_Flag")
end
end
function get_AggregateDistributedGenerationA_states(Freq_Flag::Int)
if Freq_Flag == 0
return [:Vmeas, :Pmeas, :Q_V, :Iq, :Mult, :Fmeas, :Ip], 7
elseif Freq_Flag == 1
return [:Vmeas, :Pmeas, :Q_V, :Iq, :Mult, :Fmeas, :Power_PI, :dPord, :Pord, :Ip], 10
else
error("Unsupported value of Freq_Flag")
end
end
function calculate_IM_torque_params(A::Float64, B::Float64)
C = 1.0 - A - B
if A < 0.0 || B < 0.0 || C < 0.0
error(
"Unsupported values of A = $(A), B = $(B) or C = $(C). A, B and C must be positive and add up to 1.0",
)
end
return C
end
================================================
FILE: src/models/dynamic_machines.jl
================================================
"""
Obtain coefficients (A, B) of the function Se = B(x - A)^2/x for
Se(1.2) = B(1.2 - A)^2/1.2 and Se(1.0) = B(1.0 - A)^2/1.0 as:
Se(1.0) = (Se(1.2) * 1.2) /(1.2 - A)^2 * (1.0 - A)^2/1.0 that yields
(1.2 - A)^2 Se(1.0) = Se(1.2) * 1.2 * (1.0 - A)^2 or expanding:
(1.2 * Se(1.2) - Se(1.0)) A^2 + (2.4 Se(1.0) - 2 * 1.2 * Se(1.2)) A + (1.2 * Se(1.2) - 1.44 Se(1.0)) = 0
and uses the negative solution of the quadratic equation.
"""
function get_quadratic_saturation(Se::Tuple{Float64, Float64})
return calculate_saturation_coefficients((1.0, 1.2), Se)
end
"""
Obtain coefficients (A, B) of the function Se = Bx^A for
Se(1.2) = B(1.2)^A and Se(1.0) = B(1.0)^A as:
B = Se(1.0) and hence
(1.2)^A = Se(1.2)/B -> A = log(Se(1.2)/B) / log(1.2)
"""
function get_exponential_saturation(Se::Tuple{Float64, Float64})
if Se[1] == 0.0 || Se[2] == 0.0
@warn "$(Se[1]) or $(Se[2]) equals to zero. Ignoring saturation."
return (0.0, 0.0)
end
if Se[2] <= Se[1]
throw(
IS.ConflictingInputsError(
"Se(1.2) <= Se(1.0). Saturation data is inconsistent.",
),
)
end
B = Se[1]
A = log(Se[2] / B) / log(1.2)
return (A, B)
end
================================================
FILE: src/models/dynamic_models.jl
================================================
"""
Abstract type for all components used to compose a [`DynamicInjection`](@ref) device
"""
abstract type DynamicComponent <: DeviceParameter end
"""
Abstract type for all [Dynamic Devices](@ref)
A [dynamic](@ref D) [injection](@ref I) is the continuous time response of a generator,
typically modeled with differential equations.
`DynamicInjection` components can added on to [`StaticInjection`](@ref) components,
which together define all the information needed to model the device in a dynamic
simulation.
"""
abstract type DynamicInjection <: Device end
"""
Return all the dynamic components of a [`DynamicInjection`](@ref) device
"""
function get_dynamic_components(device::T) where {T <: DynamicInjection}
return (
getfield(device, x) for
(x, y) in zip(fieldnames(T), fieldtypes(T)) if y <: DynamicComponent
)
end
supports_services(::DynamicInjection) = false
get_states(::DynamicInjection) = Vector{Symbol}()
"""
Default implementation of get_state_types for dynamic components. Assumes all states are
Differential
"""
function get_states_types(d::DynamicComponent)
return fill(StateTypes.Differential, get_n_states(d))
end
function get_frequency_droop(::V) where {V <: DynamicInjection}
throw(
ArgumentError(
"get_frequency_droop not implemented for type $V.",
),
)
end
================================================
FILE: src/models/generated/ACBus.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ACBus <: Bus
number::Int
name::String
available::Bool
bustype::Union{Nothing, ACBusTypes}
angle::Union{Nothing, Float64}
magnitude::Union{Nothing, Float64}
voltage_limits::Union{Nothing, MinMax}
base_voltage::Union{Nothing, Float64}
area::Union{Nothing, Area}
load_zone::Union{Nothing, LoadZone}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
An AC bus
# Arguments
- `number::Int`: A unique bus identification number (positive integer)
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations. This field should not be confused with the ISOLATED enum value (@ref acbustypes_list)
- `bustype::Union{Nothing, ACBusTypes}`: Used to describe the connectivity and behavior of this bus. [Options are listed here.](@ref acbustypes_list)
- `angle::Union{Nothing, Float64}`: angle of the bus in radians
- `magnitude::Union{Nothing, Float64}`: voltage as a multiple of `base_voltage`, validation range: `voltage_limits`
- `voltage_limits::Union{Nothing, MinMax}`: limits on the voltage variation as multiples of `base_voltage`
- `base_voltage::Union{Nothing, Float64}`: the base voltage in kV, validation range: `(0, nothing)`
- `area::Union{Nothing, Area}`: (default: `nothing`) the area containing the bus
- `load_zone::Union{Nothing, LoadZone}`: (default: `nothing`) the load zone containing the bus
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ACBus <: Bus
"A unique bus identification number (positive integer)"
number::Int
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations. This field should not be confused with the ISOLATED enum value (@ref acbustypes_list)"
available::Bool
"Used to describe the connectivity and behavior of this bus. [Options are listed here.](@ref acbustypes_list)"
bustype::Union{Nothing, ACBusTypes}
"angle of the bus in radians"
angle::Union{Nothing, Float64}
"voltage as a multiple of `base_voltage`"
magnitude::Union{Nothing, Float64}
"limits on the voltage variation as multiples of `base_voltage`"
voltage_limits::Union{Nothing, MinMax}
"the base voltage in kV"
base_voltage::Union{Nothing, Float64}
"the area containing the bus"
area::Union{Nothing, Area}
"the load zone containing the bus"
load_zone::Union{Nothing, LoadZone}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
function ACBus(number, name, available, bustype, angle, magnitude, voltage_limits, base_voltage, area, load_zone, ext, internal, )
(number, name, available, bustype, angle, magnitude, voltage_limits, base_voltage, area, load_zone, ext, internal, ) = check_bus_params(
number,
name,
available,
bustype,
angle,
magnitude,
voltage_limits,
base_voltage,
area,
load_zone,
ext,
internal,
)
new(number, name, available, bustype, angle, magnitude, voltage_limits, base_voltage, area, load_zone, ext, internal, )
end
end
function ACBus(number, name, available, bustype, angle, magnitude, voltage_limits, base_voltage, area=nothing, load_zone=nothing, ext=Dict{String, Any}(), )
ACBus(number, name, available, bustype, angle, magnitude, voltage_limits, base_voltage, area, load_zone, ext, InfrastructureSystemsInternal(), )
end
function ACBus(; number, name, available, bustype, angle, magnitude, voltage_limits, base_voltage, area=nothing, load_zone=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
ACBus(number, name, available, bustype, angle, magnitude, voltage_limits, base_voltage, area, load_zone, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function ACBus(::Nothing)
ACBus(;
number=0,
name="init",
available=false,
bustype=nothing,
angle=0.0,
magnitude=0.0,
voltage_limits=(min=0.0, max=0.0),
base_voltage=nothing,
area=nothing,
load_zone=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`ACBus`](@ref) `number`."""
get_number(value::ACBus) = value.number
"""Get [`ACBus`](@ref) `name`."""
get_name(value::ACBus) = value.name
"""Get [`ACBus`](@ref) `available`."""
get_available(value::ACBus) = value.available
"""Get [`ACBus`](@ref) `bustype`."""
get_bustype(value::ACBus) = value.bustype
"""Get [`ACBus`](@ref) `angle`."""
get_angle(value::ACBus) = value.angle
"""Get [`ACBus`](@ref) `magnitude`."""
get_magnitude(value::ACBus) = value.magnitude
"""Get [`ACBus`](@ref) `voltage_limits`."""
get_voltage_limits(value::ACBus) = value.voltage_limits
"""Get [`ACBus`](@ref) `base_voltage`."""
get_base_voltage(value::ACBus) = value.base_voltage
"""Get [`ACBus`](@ref) `area`."""
get_area(value::ACBus) = value.area
"""Get [`ACBus`](@ref) `load_zone`."""
get_load_zone(value::ACBus) = value.load_zone
"""Get [`ACBus`](@ref) `ext`."""
get_ext(value::ACBus) = value.ext
"""Get [`ACBus`](@ref) `internal`."""
get_internal(value::ACBus) = value.internal
"""Set [`ACBus`](@ref) `available`."""
set_available!(value::ACBus, val) = value.available = val
"""Set [`ACBus`](@ref) `bustype`."""
set_bustype!(value::ACBus, val) = value.bustype = val
"""Set [`ACBus`](@ref) `angle`."""
set_angle!(value::ACBus, val) = value.angle = val
"""Set [`ACBus`](@ref) `magnitude`."""
set_magnitude!(value::ACBus, val) = value.magnitude = val
"""Set [`ACBus`](@ref) `voltage_limits`."""
set_voltage_limits!(value::ACBus, val) = value.voltage_limits = val
"""Set [`ACBus`](@ref) `base_voltage`."""
set_base_voltage!(value::ACBus, val) = value.base_voltage = val
"""Set [`ACBus`](@ref) `area`."""
set_area!(value::ACBus, val) = value.area = val
"""Set [`ACBus`](@ref) `load_zone`."""
set_load_zone!(value::ACBus, val) = value.load_zone = val
"""Set [`ACBus`](@ref) `ext`."""
set_ext!(value::ACBus, val) = value.ext = val
================================================
FILE: src/models/generated/AGC.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct AGC <: Service
name::String
available::Bool
bias::Float64
K_p::Float64
K_i::Float64
K_d::Float64
delta_t::Float64
area::Union{Nothing, Area}
initial_ace::Float64
reserves::Vector{Reserve}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
Automatic generation control (AGC) for the system or a certain `Area` within the system.
This model uses a proportional–integral–derivative (PID) control to simulate a "smooth" response of the AGC to the area control error (ACE). Refer to ["AGC Simulation Model for Large Renewable Energy Penetration Studies."](https://doi.org/10.1109/NAPS50074.2021.9449687)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bias::Float64`: Area frequency bias in MW/Hz
- `K_p::Float64`: PID Proportional Constant
- `K_i::Float64`: PID Integral Constant
- `K_d::Float64`: PID Derivative Constant
- `delta_t::Float64`: PID Discretization period [Seconds]
- `area::Union{Nothing, Area}`: (default: `nothing`) the area controlled by the AGC
- `initial_ace::Float64`: (default: `0.0`) Initial condition for ACE
- `reserves::Vector{Reserve}`: (default: `Device[]`) Reserves that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct AGC <: Service
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Area frequency bias in MW/Hz"
bias::Float64
"PID Proportional Constant"
K_p::Float64
"PID Integral Constant"
K_i::Float64
"PID Derivative Constant"
K_d::Float64
"PID Discretization period [Seconds]"
delta_t::Float64
"the area controlled by the AGC"
area::Union{Nothing, Area}
"Initial condition for ACE"
initial_ace::Float64
"Reserves that this device contributes to"
reserves::Vector{Reserve}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function AGC(name, available, bias, K_p, K_i, K_d, delta_t, area=nothing, initial_ace=0.0, reserves=Device[], ext=Dict{String, Any}(), )
AGC(name, available, bias, K_p, K_i, K_d, delta_t, area, initial_ace, reserves, ext, InfrastructureSystemsInternal(), )
end
function AGC(; name, available, bias, K_p, K_i, K_d, delta_t, area=nothing, initial_ace=0.0, reserves=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
AGC(name, available, bias, K_p, K_i, K_d, delta_t, area, initial_ace, reserves, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function AGC(::Nothing)
AGC(;
name="init",
available=false,
bias=0.0,
K_p=0.0,
K_i=0.0,
K_d=0.0,
delta_t=0.0,
area=Area(nothing),
initial_ace=0.0,
reserves=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`AGC`](@ref) `name`."""
get_name(value::AGC) = value.name
"""Get [`AGC`](@ref) `available`."""
get_available(value::AGC) = value.available
"""Get [`AGC`](@ref) `bias`."""
get_bias(value::AGC) = value.bias
"""Get [`AGC`](@ref) `K_p`."""
get_K_p(value::AGC) = value.K_p
"""Get [`AGC`](@ref) `K_i`."""
get_K_i(value::AGC) = value.K_i
"""Get [`AGC`](@ref) `K_d`."""
get_K_d(value::AGC) = value.K_d
"""Get [`AGC`](@ref) `delta_t`."""
get_delta_t(value::AGC) = value.delta_t
"""Get [`AGC`](@ref) `area`."""
get_area(value::AGC) = value.area
"""Get [`AGC`](@ref) `initial_ace`."""
get_initial_ace(value::AGC) = value.initial_ace
"""Get [`AGC`](@ref) `reserves`."""
get_reserves(value::AGC) = value.reserves
"""Get [`AGC`](@ref) `ext`."""
get_ext(value::AGC) = value.ext
"""Get [`AGC`](@ref) `internal`."""
get_internal(value::AGC) = value.internal
"""Set [`AGC`](@ref) `available`."""
set_available!(value::AGC, val) = value.available = val
"""Set [`AGC`](@ref) `bias`."""
set_bias!(value::AGC, val) = value.bias = val
"""Set [`AGC`](@ref) `K_p`."""
set_K_p!(value::AGC, val) = value.K_p = val
"""Set [`AGC`](@ref) `K_i`."""
set_K_i!(value::AGC, val) = value.K_i = val
"""Set [`AGC`](@ref) `K_d`."""
set_K_d!(value::AGC, val) = value.K_d = val
"""Set [`AGC`](@ref) `delta_t`."""
set_delta_t!(value::AGC, val) = value.delta_t = val
"""Set [`AGC`](@ref) `area`."""
set_area!(value::AGC, val) = value.area = val
"""Set [`AGC`](@ref) `initial_ace`."""
set_initial_ace!(value::AGC, val) = value.initial_ace = val
"""Set [`AGC`](@ref) `reserves`."""
set_reserves!(value::AGC, val) = value.reserves = val
"""Set [`AGC`](@ref) `ext`."""
set_ext!(value::AGC, val) = value.ext = val
================================================
FILE: src/models/generated/AVRFixed.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct AVRFixed <: AVR
Vf::Float64
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Parameters of a AVR that returns a fixed voltage to the rotor winding
# Arguments
- `Vf::Float64`: Fixed voltage field applied to the rotor winding in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) Fixed AVR has no [states](@ref S)
- `n_states::Int`: (**Do not modify.**) Fixed AVR has no [states](@ref S)
- `states_types::Vector{StateTypes}`: (**Do not modify.**) Fixed AVR has no [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct AVRFixed <: AVR
"Fixed voltage field applied to the rotor winding in pu ([`DEVICE_BASE`](@ref per_unit))"
Vf::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) Fixed AVR has no [states](@ref S)"
states::Vector{Symbol}
"(**Do not modify.**) Fixed AVR has no [states](@ref S)"
n_states::Int
"(**Do not modify.**) Fixed AVR has no [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function AVRFixed(Vf, V_ref=1.0, ext=Dict{String, Any}(), )
AVRFixed(Vf, V_ref, ext, Vector{Symbol}(), 0, Vector{StateTypes}(), InfrastructureSystemsInternal(), )
end
function AVRFixed(; Vf, V_ref=1.0, ext=Dict{String, Any}(), states=Vector{Symbol}(), n_states=0, states_types=Vector{StateTypes}(), internal=InfrastructureSystemsInternal(), )
AVRFixed(Vf, V_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function AVRFixed(::Nothing)
AVRFixed(;
Vf=0,
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`AVRFixed`](@ref) `Vf`."""
get_Vf(value::AVRFixed) = value.Vf
"""Get [`AVRFixed`](@ref) `V_ref`."""
get_V_ref(value::AVRFixed) = value.V_ref
"""Get [`AVRFixed`](@ref) `ext`."""
get_ext(value::AVRFixed) = value.ext
"""Get [`AVRFixed`](@ref) `states`."""
get_states(value::AVRFixed) = value.states
"""Get [`AVRFixed`](@ref) `n_states`."""
get_n_states(value::AVRFixed) = value.n_states
"""Get [`AVRFixed`](@ref) `states_types`."""
get_states_types(value::AVRFixed) = value.states_types
"""Get [`AVRFixed`](@ref) `internal`."""
get_internal(value::AVRFixed) = value.internal
"""Set [`AVRFixed`](@ref) `Vf`."""
set_Vf!(value::AVRFixed, val) = value.Vf = val
"""Set [`AVRFixed`](@ref) `V_ref`."""
set_V_ref!(value::AVRFixed, val) = value.V_ref = val
"""Set [`AVRFixed`](@ref) `ext`."""
set_ext!(value::AVRFixed, val) = value.ext = val
"""Set [`AVRFixed`](@ref) `states_types`."""
set_states_types!(value::AVRFixed, val) = value.states_types = val
================================================
FILE: src/models/generated/AVRSimple.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct AVRSimple <: AVR
Kv::Float64
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Parameters of a simple proportional AVR in the derivative of EMF
i.e. an integrator controller on EMF
# Arguments
- `Kv::Float64`: Proportional Gain, validation range: `(0, nothing)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vf: field voltage
- `n_states::Int`: (**Do not modify.**) Fixed AVR has 1 [state](@ref S)
- `states_types::Vector{StateTypes}`: (**Do not modify.**) Simple AVR has 1 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct AVRSimple <: AVR
"Proportional Gain"
Kv::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vf: field voltage"
states::Vector{Symbol}
"(**Do not modify.**) Fixed AVR has 1 [state](@ref S)"
n_states::Int
"(**Do not modify.**) Simple AVR has 1 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function AVRSimple(Kv, V_ref=1.0, ext=Dict{String, Any}(), )
AVRSimple(Kv, V_ref, ext, [:Vf], 1, [StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function AVRSimple(; Kv, V_ref=1.0, ext=Dict{String, Any}(), states=[:Vf], n_states=1, states_types=[StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
AVRSimple(Kv, V_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function AVRSimple(::Nothing)
AVRSimple(;
Kv=0,
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`AVRSimple`](@ref) `Kv`."""
get_Kv(value::AVRSimple) = value.Kv
"""Get [`AVRSimple`](@ref) `V_ref`."""
get_V_ref(value::AVRSimple) = value.V_ref
"""Get [`AVRSimple`](@ref) `ext`."""
get_ext(value::AVRSimple) = value.ext
"""Get [`AVRSimple`](@ref) `states`."""
get_states(value::AVRSimple) = value.states
"""Get [`AVRSimple`](@ref) `n_states`."""
get_n_states(value::AVRSimple) = value.n_states
"""Get [`AVRSimple`](@ref) `states_types`."""
get_states_types(value::AVRSimple) = value.states_types
"""Get [`AVRSimple`](@ref) `internal`."""
get_internal(value::AVRSimple) = value.internal
"""Set [`AVRSimple`](@ref) `Kv`."""
set_Kv!(value::AVRSimple, val) = value.Kv = val
"""Set [`AVRSimple`](@ref) `V_ref`."""
set_V_ref!(value::AVRSimple, val) = value.V_ref = val
"""Set [`AVRSimple`](@ref) `ext`."""
set_ext!(value::AVRSimple, val) = value.ext = val
"""Set [`AVRSimple`](@ref) `states_types`."""
set_states_types!(value::AVRSimple, val) = value.states_types = val
================================================
FILE: src/models/generated/AVRTypeI.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct AVRTypeI <: AVR
Ka::Float64
Ke::Float64
Kf::Float64
Ta::Float64
Te::Float64
Tf::Float64
Tr::Float64
Va_lim::MinMax
Ae::Float64
Be::Float64
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Parameters of an Automatic Voltage Regulator Type I - Resembles IEEE Type DC1
# Arguments
- `Ka::Float64`: Amplifier Gain, validation range: `(0, nothing)`
- `Ke::Float64`: Field circuit integral deviation, validation range: `(0, nothing)`
- `Kf::Float64`: Stabilizer Gain in s * pu/pu, validation range: `(0, nothing)`
- `Ta::Float64`: Amplifier Time Constant in s, validation range: `(0, nothing)`
- `Te::Float64`: Field Circuit Time Constant in s, validation range: `(0, nothing)`
- `Tf::Float64`: Stabilizer Time Constant in s, validation range: `(0, nothing)`
- `Tr::Float64`: Voltage Measurement Time Constant in s, validation range: `(0, nothing)`
- `Va_lim::MinMax`: Limits for pi controler `(Va_min, Va_max)`
- `Ae::Float64`: 1st ceiling coefficient, validation range: `(0, nothing)`
- `Be::Float64`: 2nd ceiling coefficient, validation range: `(0, nothing)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vf: Voltage field,
Vr1: Amplifier State,
Vr2: Stabilizing Feedback State,
Vm: Measured voltage
- `n_states::Int`: (**Do not modify.**) The AVR Type I has 4 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) AVR Type I has 4 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct AVRTypeI <: AVR
"Amplifier Gain"
Ka::Float64
"Field circuit integral deviation"
Ke::Float64
"Stabilizer Gain in s * pu/pu"
Kf::Float64
"Amplifier Time Constant in s"
Ta::Float64
"Field Circuit Time Constant in s"
Te::Float64
"Stabilizer Time Constant in s"
Tf::Float64
"Voltage Measurement Time Constant in s"
Tr::Float64
"Limits for pi controler `(Va_min, Va_max)`"
Va_lim::MinMax
"1st ceiling coefficient"
Ae::Float64
"2nd ceiling coefficient"
Be::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vf: Voltage field,
Vr1: Amplifier State,
Vr2: Stabilizing Feedback State,
Vm: Measured voltage"
states::Vector{Symbol}
"(**Do not modify.**) The AVR Type I has 4 states"
n_states::Int
"(**Do not modify.**) AVR Type I has 4 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function AVRTypeI(Ka, Ke, Kf, Ta, Te, Tf, Tr, Va_lim, Ae, Be, V_ref=1.0, ext=Dict{String, Any}(), )
AVRTypeI(Ka, Ke, Kf, Ta, Te, Tf, Tr, Va_lim, Ae, Be, V_ref, ext, [:Vf, :Vr1, :Vr2, :Vm], 4, [StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function AVRTypeI(; Ka, Ke, Kf, Ta, Te, Tf, Tr, Va_lim, Ae, Be, V_ref=1.0, ext=Dict{String, Any}(), states=[:Vf, :Vr1, :Vr2, :Vm], n_states=4, states_types=[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
AVRTypeI(Ka, Ke, Kf, Ta, Te, Tf, Tr, Va_lim, Ae, Be, V_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function AVRTypeI(::Nothing)
AVRTypeI(;
Ka=0,
Ke=0,
Kf=0,
Ta=0,
Te=0,
Tf=0,
Tr=0,
Va_lim=(min=0.0, max=0.0),
Ae=0,
Be=0,
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`AVRTypeI`](@ref) `Ka`."""
get_Ka(value::AVRTypeI) = value.Ka
"""Get [`AVRTypeI`](@ref) `Ke`."""
get_Ke(value::AVRTypeI) = value.Ke
"""Get [`AVRTypeI`](@ref) `Kf`."""
get_Kf(value::AVRTypeI) = value.Kf
"""Get [`AVRTypeI`](@ref) `Ta`."""
get_Ta(value::AVRTypeI) = value.Ta
"""Get [`AVRTypeI`](@ref) `Te`."""
get_Te(value::AVRTypeI) = value.Te
"""Get [`AVRTypeI`](@ref) `Tf`."""
get_Tf(value::AVRTypeI) = value.Tf
"""Get [`AVRTypeI`](@ref) `Tr`."""
get_Tr(value::AVRTypeI) = value.Tr
"""Get [`AVRTypeI`](@ref) `Va_lim`."""
get_Va_lim(value::AVRTypeI) = value.Va_lim
"""Get [`AVRTypeI`](@ref) `Ae`."""
get_Ae(value::AVRTypeI) = value.Ae
"""Get [`AVRTypeI`](@ref) `Be`."""
get_Be(value::AVRTypeI) = value.Be
"""Get [`AVRTypeI`](@ref) `V_ref`."""
get_V_ref(value::AVRTypeI) = value.V_ref
"""Get [`AVRTypeI`](@ref) `ext`."""
get_ext(value::AVRTypeI) = value.ext
"""Get [`AVRTypeI`](@ref) `states`."""
get_states(value::AVRTypeI) = value.states
"""Get [`AVRTypeI`](@ref) `n_states`."""
get_n_states(value::AVRTypeI) = value.n_states
"""Get [`AVRTypeI`](@ref) `states_types`."""
get_states_types(value::AVRTypeI) = value.states_types
"""Get [`AVRTypeI`](@ref) `internal`."""
get_internal(value::AVRTypeI) = value.internal
"""Set [`AVRTypeI`](@ref) `Ka`."""
set_Ka!(value::AVRTypeI, val) = value.Ka = val
"""Set [`AVRTypeI`](@ref) `Ke`."""
set_Ke!(value::AVRTypeI, val) = value.Ke = val
"""Set [`AVRTypeI`](@ref) `Kf`."""
set_Kf!(value::AVRTypeI, val) = value.Kf = val
"""Set [`AVRTypeI`](@ref) `Ta`."""
set_Ta!(value::AVRTypeI, val) = value.Ta = val
"""Set [`AVRTypeI`](@ref) `Te`."""
set_Te!(value::AVRTypeI, val) = value.Te = val
"""Set [`AVRTypeI`](@ref) `Tf`."""
set_Tf!(value::AVRTypeI, val) = value.Tf = val
"""Set [`AVRTypeI`](@ref) `Tr`."""
set_Tr!(value::AVRTypeI, val) = value.Tr = val
"""Set [`AVRTypeI`](@ref) `Va_lim`."""
set_Va_lim!(value::AVRTypeI, val) = value.Va_lim = val
"""Set [`AVRTypeI`](@ref) `Ae`."""
set_Ae!(value::AVRTypeI, val) = value.Ae = val
"""Set [`AVRTypeI`](@ref) `Be`."""
set_Be!(value::AVRTypeI, val) = value.Be = val
"""Set [`AVRTypeI`](@ref) `V_ref`."""
set_V_ref!(value::AVRTypeI, val) = value.V_ref = val
"""Set [`AVRTypeI`](@ref) `ext`."""
set_ext!(value::AVRTypeI, val) = value.ext = val
"""Set [`AVRTypeI`](@ref) `states_types`."""
set_states_types!(value::AVRTypeI, val) = value.states_types = val
================================================
FILE: src/models/generated/AVRTypeII.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct AVRTypeII <: AVR
K0::Float64
T1::Float64
T2::Float64
T3::Float64
T4::Float64
Te::Float64
Tr::Float64
Va_lim::MinMax
Ae::Float64
Be::Float64
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Parameters of an Automatic Voltage Regulator Type II - Typical static exciter model
# Arguments
- `K0::Float64`: Regulator Gain, validation range: `(0, nothing)`
- `T1::Float64`: First Pole in s, validation range: `(0, nothing)`
- `T2::Float64`: First zero in s, validation range: `(0, nothing)`
- `T3::Float64`: First Pole in s, validation range: `(0, nothing)`
- `T4::Float64`: First zero in s, validation range: `(0, nothing)`
- `Te::Float64`: Field Circuit Time Constant in s, validation range: `(0, nothing)`
- `Tr::Float64`: Voltage Measurement Time Constant in s, validation range: `(0, nothing)`
- `Va_lim::MinMax`: Limits for pi controler `(Va_min, Va_max)`
- `Ae::Float64`: 1st ceiling coefficient, validation range: `(0, nothing)`
- `Be::Float64`: 2nd ceiling coefficient, validation range: `(0, nothing)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vf: Voltage field,
Vr1: First Lead-Lag state,
Vr2: Second lead-lag state,
Vm: Measured voltage
- `n_states::Int`: (**Do not modify.**) AVR Type II has 4 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) AVR Type II has 4 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct AVRTypeII <: AVR
"Regulator Gain"
K0::Float64
"First Pole in s"
T1::Float64
"First zero in s"
T2::Float64
"First Pole in s"
T3::Float64
"First zero in s"
T4::Float64
"Field Circuit Time Constant in s"
Te::Float64
"Voltage Measurement Time Constant in s"
Tr::Float64
"Limits for pi controler `(Va_min, Va_max)`"
Va_lim::MinMax
"1st ceiling coefficient"
Ae::Float64
"2nd ceiling coefficient"
Be::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vf: Voltage field,
Vr1: First Lead-Lag state,
Vr2: Second lead-lag state,
Vm: Measured voltage"
states::Vector{Symbol}
"(**Do not modify.**) AVR Type II has 4 states"
n_states::Int
"(**Do not modify.**) AVR Type II has 4 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function AVRTypeII(K0, T1, T2, T3, T4, Te, Tr, Va_lim, Ae, Be, V_ref=1.0, ext=Dict{String, Any}(), )
AVRTypeII(K0, T1, T2, T3, T4, Te, Tr, Va_lim, Ae, Be, V_ref, ext, [:Vf, :Vr1, :Vr2, :Vm], 4, [StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function AVRTypeII(; K0, T1, T2, T3, T4, Te, Tr, Va_lim, Ae, Be, V_ref=1.0, ext=Dict{String, Any}(), states=[:Vf, :Vr1, :Vr2, :Vm], n_states=4, states_types=[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
AVRTypeII(K0, T1, T2, T3, T4, Te, Tr, Va_lim, Ae, Be, V_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function AVRTypeII(::Nothing)
AVRTypeII(;
K0=0,
T1=0,
T2=0,
T3=0,
T4=0,
Te=0,
Tr=0,
Va_lim=(min=0.0, max=0.0),
Ae=0,
Be=0,
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`AVRTypeII`](@ref) `K0`."""
get_K0(value::AVRTypeII) = value.K0
"""Get [`AVRTypeII`](@ref) `T1`."""
get_T1(value::AVRTypeII) = value.T1
"""Get [`AVRTypeII`](@ref) `T2`."""
get_T2(value::AVRTypeII) = value.T2
"""Get [`AVRTypeII`](@ref) `T3`."""
get_T3(value::AVRTypeII) = value.T3
"""Get [`AVRTypeII`](@ref) `T4`."""
get_T4(value::AVRTypeII) = value.T4
"""Get [`AVRTypeII`](@ref) `Te`."""
get_Te(value::AVRTypeII) = value.Te
"""Get [`AVRTypeII`](@ref) `Tr`."""
get_Tr(value::AVRTypeII) = value.Tr
"""Get [`AVRTypeII`](@ref) `Va_lim`."""
get_Va_lim(value::AVRTypeII) = value.Va_lim
"""Get [`AVRTypeII`](@ref) `Ae`."""
get_Ae(value::AVRTypeII) = value.Ae
"""Get [`AVRTypeII`](@ref) `Be`."""
get_Be(value::AVRTypeII) = value.Be
"""Get [`AVRTypeII`](@ref) `V_ref`."""
get_V_ref(value::AVRTypeII) = value.V_ref
"""Get [`AVRTypeII`](@ref) `ext`."""
get_ext(value::AVRTypeII) = value.ext
"""Get [`AVRTypeII`](@ref) `states`."""
get_states(value::AVRTypeII) = value.states
"""Get [`AVRTypeII`](@ref) `n_states`."""
get_n_states(value::AVRTypeII) = value.n_states
"""Get [`AVRTypeII`](@ref) `states_types`."""
get_states_types(value::AVRTypeII) = value.states_types
"""Get [`AVRTypeII`](@ref) `internal`."""
get_internal(value::AVRTypeII) = value.internal
"""Set [`AVRTypeII`](@ref) `K0`."""
set_K0!(value::AVRTypeII, val) = value.K0 = val
"""Set [`AVRTypeII`](@ref) `T1`."""
set_T1!(value::AVRTypeII, val) = value.T1 = val
"""Set [`AVRTypeII`](@ref) `T2`."""
set_T2!(value::AVRTypeII, val) = value.T2 = val
"""Set [`AVRTypeII`](@ref) `T3`."""
set_T3!(value::AVRTypeII, val) = value.T3 = val
"""Set [`AVRTypeII`](@ref) `T4`."""
set_T4!(value::AVRTypeII, val) = value.T4 = val
"""Set [`AVRTypeII`](@ref) `Te`."""
set_Te!(value::AVRTypeII, val) = value.Te = val
"""Set [`AVRTypeII`](@ref) `Tr`."""
set_Tr!(value::AVRTypeII, val) = value.Tr = val
"""Set [`AVRTypeII`](@ref) `Va_lim`."""
set_Va_lim!(value::AVRTypeII, val) = value.Va_lim = val
"""Set [`AVRTypeII`](@ref) `Ae`."""
set_Ae!(value::AVRTypeII, val) = value.Ae = val
"""Set [`AVRTypeII`](@ref) `Be`."""
set_Be!(value::AVRTypeII, val) = value.Be = val
"""Set [`AVRTypeII`](@ref) `V_ref`."""
set_V_ref!(value::AVRTypeII, val) = value.V_ref = val
"""Set [`AVRTypeII`](@ref) `ext`."""
set_ext!(value::AVRTypeII, val) = value.ext = val
"""Set [`AVRTypeII`](@ref) `states_types`."""
set_states_types!(value::AVRTypeII, val) = value.states_types = val
================================================
FILE: src/models/generated/ActiveConstantPowerLoad.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ActiveConstantPowerLoad <: DynamicInjection
name::String
r_load::Float64
c_dc::Float64
rf::Float64
lf::Float64
cf::Float64
rg::Float64
lg::Float64
kp_pll::Float64
ki_pll::Float64
kpv::Float64
kiv::Float64
kpc::Float64
kic::Float64
base_power::Float64
ext::Dict{String, Any}
P_ref::Float64
Q_ref::Float64
V_ref::Float64
ω_ref::Float64
is_filter_differential::Int
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 12-[states](@ref S) active power load based on the paper, ["Dynamic Stability of a Microgrid With an Active Load."](https://doi.org/10.1109/TPEL.2013.2241455)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `r_load::Float64`: DC-side resistor, validation range: `(0, nothing)`
- `c_dc::Float64`: DC-side capacitor, validation range: `(0, nothing)`
- `rf::Float64`: Converter side filter resistance, validation range: `(0, nothing)`
- `lf::Float64`: Converter side filter inductance, validation range: `(0, nothing)`
- `cf::Float64`: AC Converter filter capacitance, validation range: `(0, nothing)`
- `rg::Float64`: Network side filter resistance, validation range: `(0, nothing)`
- `lg::Float64`: Network side filter inductance, validation range: `(0, nothing)`
- `kp_pll::Float64`: Proportional constant for PI-PLL block, validation range: `(0, nothing)`
- `ki_pll::Float64`: Integral constant for PI-PLL block, validation range: `(0, nothing)`
- `kpv::Float64`: Proportional constant for Voltage Control block, validation range: `(0, nothing)`
- `kiv::Float64`: Integral constant for Voltage Control block, validation range: `(0, nothing)`
- `kpc::Float64`: Proportional constant for Current Control block, validation range: `(0, nothing)`
- `kic::Float64`: Integral constant for Current Control block, validation range: `(0, nothing)`
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `P_ref::Float64`: Reference active power (pu)
- `Q_ref::Float64`: Reference reactive power (pu)
- `V_ref::Float64`: Reference voltage (pu)
- `ω_ref::Float64`: Reference frequency (pu)
- `is_filter_differential::Int`: Boolean to decide if filter [states](@ref S) are differential or algebraic
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
θ_pll: PLL deviation angle,
ϵ_pll: PLL integrator state,
η: DC-voltage controller integrator state,
v_dc: DC voltage at the capacitor,
γd: d-axis Current controller integrator state,
γq: q-axis Current controller integrator state,
ir_cnv: Real current out of the converter,
ii_cnv: Imaginary current out of the converter,
vr_filter: Real voltage at the filter's capacitor,
vi_filter: Imaginary voltage at the filter's capacitor,
ir_filter: Real current out of the filter,
ii_filter: Imaginary current out of the filter
- `n_states::Int`: (**Do not modify.**) ActiveConstantPowerLoad has 12 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ActiveConstantPowerLoad <: DynamicInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"DC-side resistor"
r_load::Float64
"DC-side capacitor"
c_dc::Float64
"Converter side filter resistance"
rf::Float64
"Converter side filter inductance"
lf::Float64
"AC Converter filter capacitance"
cf::Float64
"Network side filter resistance"
rg::Float64
"Network side filter inductance"
lg::Float64
"Proportional constant for PI-PLL block"
kp_pll::Float64
"Integral constant for PI-PLL block"
ki_pll::Float64
"Proportional constant for Voltage Control block"
kpv::Float64
"Integral constant for Voltage Control block"
kiv::Float64
"Proportional constant for Current Control block"
kpc::Float64
"Integral constant for Current Control block"
kic::Float64
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"Reference active power (pu)"
P_ref::Float64
"Reference reactive power (pu)"
Q_ref::Float64
"Reference voltage (pu)"
V_ref::Float64
"Reference frequency (pu)"
ω_ref::Float64
"Boolean to decide if filter [states](@ref S) are differential or algebraic"
is_filter_differential::Int
"(**Do not modify.**) The [states](@ref S) are:
θ_pll: PLL deviation angle,
ϵ_pll: PLL integrator state,
η: DC-voltage controller integrator state,
v_dc: DC voltage at the capacitor,
γd: d-axis Current controller integrator state,
γq: q-axis Current controller integrator state,
ir_cnv: Real current out of the converter,
ii_cnv: Imaginary current out of the converter,
vr_filter: Real voltage at the filter's capacitor,
vi_filter: Imaginary voltage at the filter's capacitor,
ir_filter: Real current out of the filter,
ii_filter: Imaginary current out of the filter"
states::Vector{Symbol}
"(**Do not modify.**) ActiveConstantPowerLoad has 12 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ActiveConstantPowerLoad(name, r_load, c_dc, rf, lf, cf, rg, lg, kp_pll, ki_pll, kpv, kiv, kpc, kic, base_power, ext=Dict{String, Any}(), )
ActiveConstantPowerLoad(name, r_load, c_dc, rf, lf, cf, rg, lg, kp_pll, ki_pll, kpv, kiv, kpc, kic, base_power, ext, 1.0, 1.0, 1.0, 1.0, 1, [:θ_pll, :ϵ_pll, :η, :v_dc, :γd, :γq, :ir_cnv, :ii_cnv, :vr_filter, :vi_filter, :ir_filter, :ii_filter], 12, InfrastructureSystemsInternal(), )
end
function ActiveConstantPowerLoad(; name, r_load, c_dc, rf, lf, cf, rg, lg, kp_pll, ki_pll, kpv, kiv, kpc, kic, base_power, ext=Dict{String, Any}(), P_ref=1.0, Q_ref=1.0, V_ref=1.0, ω_ref=1.0, is_filter_differential=1, states=[:θ_pll, :ϵ_pll, :η, :v_dc, :γd, :γq, :ir_cnv, :ii_cnv, :vr_filter, :vi_filter, :ir_filter, :ii_filter], n_states=12, internal=InfrastructureSystemsInternal(), )
ActiveConstantPowerLoad(name, r_load, c_dc, rf, lf, cf, rg, lg, kp_pll, ki_pll, kpv, kiv, kpc, kic, base_power, ext, P_ref, Q_ref, V_ref, ω_ref, is_filter_differential, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function ActiveConstantPowerLoad(::Nothing)
ActiveConstantPowerLoad(;
name="init",
r_load=0,
c_dc=0,
rf=0,
lf=0,
cf=0,
rg=0,
lg=0,
kp_pll=0,
ki_pll=0,
kpv=0,
kiv=0,
kpc=0,
kic=0,
base_power=100,
ext=Dict{String, Any}(),
)
end
"""Get [`ActiveConstantPowerLoad`](@ref) `name`."""
get_name(value::ActiveConstantPowerLoad) = value.name
"""Get [`ActiveConstantPowerLoad`](@ref) `r_load`."""
get_r_load(value::ActiveConstantPowerLoad) = value.r_load
"""Get [`ActiveConstantPowerLoad`](@ref) `c_dc`."""
get_c_dc(value::ActiveConstantPowerLoad) = value.c_dc
"""Get [`ActiveConstantPowerLoad`](@ref) `rf`."""
get_rf(value::ActiveConstantPowerLoad) = value.rf
"""Get [`ActiveConstantPowerLoad`](@ref) `lf`."""
get_lf(value::ActiveConstantPowerLoad) = value.lf
"""Get [`ActiveConstantPowerLoad`](@ref) `cf`."""
get_cf(value::ActiveConstantPowerLoad) = value.cf
"""Get [`ActiveConstantPowerLoad`](@ref) `rg`."""
get_rg(value::ActiveConstantPowerLoad) = value.rg
"""Get [`ActiveConstantPowerLoad`](@ref) `lg`."""
get_lg(value::ActiveConstantPowerLoad) = value.lg
"""Get [`ActiveConstantPowerLoad`](@ref) `kp_pll`."""
get_kp_pll(value::ActiveConstantPowerLoad) = value.kp_pll
"""Get [`ActiveConstantPowerLoad`](@ref) `ki_pll`."""
get_ki_pll(value::ActiveConstantPowerLoad) = value.ki_pll
"""Get [`ActiveConstantPowerLoad`](@ref) `kpv`."""
get_kpv(value::ActiveConstantPowerLoad) = value.kpv
"""Get [`ActiveConstantPowerLoad`](@ref) `kiv`."""
get_kiv(value::ActiveConstantPowerLoad) = value.kiv
"""Get [`ActiveConstantPowerLoad`](@ref) `kpc`."""
get_kpc(value::ActiveConstantPowerLoad) = value.kpc
"""Get [`ActiveConstantPowerLoad`](@ref) `kic`."""
get_kic(value::ActiveConstantPowerLoad) = value.kic
"""Get [`ActiveConstantPowerLoad`](@ref) `base_power`."""
get_base_power(value::ActiveConstantPowerLoad) = value.base_power
"""Get [`ActiveConstantPowerLoad`](@ref) `ext`."""
get_ext(value::ActiveConstantPowerLoad) = value.ext
"""Get [`ActiveConstantPowerLoad`](@ref) `P_ref`."""
get_P_ref(value::ActiveConstantPowerLoad) = value.P_ref
"""Get [`ActiveConstantPowerLoad`](@ref) `Q_ref`."""
get_Q_ref(value::ActiveConstantPowerLoad) = value.Q_ref
"""Get [`ActiveConstantPowerLoad`](@ref) `V_ref`."""
get_V_ref(value::ActiveConstantPowerLoad) = value.V_ref
"""Get [`ActiveConstantPowerLoad`](@ref) `ω_ref`."""
get_ω_ref(value::ActiveConstantPowerLoad) = value.ω_ref
"""Get [`ActiveConstantPowerLoad`](@ref) `is_filter_differential`."""
get_is_filter_differential(value::ActiveConstantPowerLoad) = value.is_filter_differential
"""Get [`ActiveConstantPowerLoad`](@ref) `states`."""
get_states(value::ActiveConstantPowerLoad) = value.states
"""Get [`ActiveConstantPowerLoad`](@ref) `n_states`."""
get_n_states(value::ActiveConstantPowerLoad) = value.n_states
"""Get [`ActiveConstantPowerLoad`](@ref) `internal`."""
get_internal(value::ActiveConstantPowerLoad) = value.internal
"""Set [`ActiveConstantPowerLoad`](@ref) `r_load`."""
set_r_load!(value::ActiveConstantPowerLoad, val) = value.r_load = val
"""Set [`ActiveConstantPowerLoad`](@ref) `c_dc`."""
set_c_dc!(value::ActiveConstantPowerLoad, val) = value.c_dc = val
"""Set [`ActiveConstantPowerLoad`](@ref) `rf`."""
set_rf!(value::ActiveConstantPowerLoad, val) = value.rf = val
"""Set [`ActiveConstantPowerLoad`](@ref) `lf`."""
set_lf!(value::ActiveConstantPowerLoad, val) = value.lf = val
"""Set [`ActiveConstantPowerLoad`](@ref) `cf`."""
set_cf!(value::ActiveConstantPowerLoad, val) = value.cf = val
"""Set [`ActiveConstantPowerLoad`](@ref) `rg`."""
set_rg!(value::ActiveConstantPowerLoad, val) = value.rg = val
"""Set [`ActiveConstantPowerLoad`](@ref) `lg`."""
set_lg!(value::ActiveConstantPowerLoad, val) = value.lg = val
"""Set [`ActiveConstantPowerLoad`](@ref) `kp_pll`."""
set_kp_pll!(value::ActiveConstantPowerLoad, val) = value.kp_pll = val
"""Set [`ActiveConstantPowerLoad`](@ref) `ki_pll`."""
set_ki_pll!(value::ActiveConstantPowerLoad, val) = value.ki_pll = val
"""Set [`ActiveConstantPowerLoad`](@ref) `kpv`."""
set_kpv!(value::ActiveConstantPowerLoad, val) = value.kpv = val
"""Set [`ActiveConstantPowerLoad`](@ref) `kiv`."""
set_kiv!(value::ActiveConstantPowerLoad, val) = value.kiv = val
"""Set [`ActiveConstantPowerLoad`](@ref) `kpc`."""
set_kpc!(value::ActiveConstantPowerLoad, val) = value.kpc = val
"""Set [`ActiveConstantPowerLoad`](@ref) `kic`."""
set_kic!(value::ActiveConstantPowerLoad, val) = value.kic = val
"""Set [`ActiveConstantPowerLoad`](@ref) `base_power`."""
set_base_power!(value::ActiveConstantPowerLoad, val) = value.base_power = val
"""Set [`ActiveConstantPowerLoad`](@ref) `ext`."""
set_ext!(value::ActiveConstantPowerLoad, val) = value.ext = val
"""Set [`ActiveConstantPowerLoad`](@ref) `P_ref`."""
set_P_ref!(value::ActiveConstantPowerLoad, val) = value.P_ref = val
"""Set [`ActiveConstantPowerLoad`](@ref) `Q_ref`."""
set_Q_ref!(value::ActiveConstantPowerLoad, val) = value.Q_ref = val
"""Set [`ActiveConstantPowerLoad`](@ref) `V_ref`."""
set_V_ref!(value::ActiveConstantPowerLoad, val) = value.V_ref = val
"""Set [`ActiveConstantPowerLoad`](@ref) `ω_ref`."""
set_ω_ref!(value::ActiveConstantPowerLoad, val) = value.ω_ref = val
"""Set [`ActiveConstantPowerLoad`](@ref) `is_filter_differential`."""
set_is_filter_differential!(value::ActiveConstantPowerLoad, val) = value.is_filter_differential = val
================================================
FILE: src/models/generated/ActivePowerDroop.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ActivePowerDroop <: ActivePowerControl
Rp::Float64
ωz::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of an Active Power droop controller
# Arguments
- `Rp::Float64`: Droop Gain, validation range: `(0, nothing)`
- `ωz::Float64`: filter frequency cutoff, validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the ActivePowerDroop model are:
θ_oc: Phase angle displacement of the inverter model,
p_oc: Measured active power of the inverter model
- `n_states::Int`: (**Do not modify.**) ActivePowerDroop has two states
"""
mutable struct ActivePowerDroop <: ActivePowerControl
"Droop Gain"
Rp::Float64
"filter frequency cutoff"
ωz::Float64
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the ActivePowerDroop model are:
θ_oc: Phase angle displacement of the inverter model,
p_oc: Measured active power of the inverter model"
states::Vector{Symbol}
"(**Do not modify.**) ActivePowerDroop has two states"
n_states::Int
end
function ActivePowerDroop(Rp, ωz, P_ref=1.0, ext=Dict{String, Any}(), )
ActivePowerDroop(Rp, ωz, P_ref, ext, [:θ_oc, :p_oc], 2, )
end
function ActivePowerDroop(; Rp, ωz, P_ref=1.0, ext=Dict{String, Any}(), states=[:θ_oc, :p_oc], n_states=2, )
ActivePowerDroop(Rp, ωz, P_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function ActivePowerDroop(::Nothing)
ActivePowerDroop(;
Rp=0,
ωz=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ActivePowerDroop`](@ref) `Rp`."""
get_Rp(value::ActivePowerDroop) = value.Rp
"""Get [`ActivePowerDroop`](@ref) `ωz`."""
get_ωz(value::ActivePowerDroop) = value.ωz
"""Get [`ActivePowerDroop`](@ref) `P_ref`."""
get_P_ref(value::ActivePowerDroop) = value.P_ref
"""Get [`ActivePowerDroop`](@ref) `ext`."""
get_ext(value::ActivePowerDroop) = value.ext
"""Get [`ActivePowerDroop`](@ref) `states`."""
get_states(value::ActivePowerDroop) = value.states
"""Get [`ActivePowerDroop`](@ref) `n_states`."""
get_n_states(value::ActivePowerDroop) = value.n_states
"""Set [`ActivePowerDroop`](@ref) `Rp`."""
set_Rp!(value::ActivePowerDroop, val) = value.Rp = val
"""Set [`ActivePowerDroop`](@ref) `ωz`."""
set_ωz!(value::ActivePowerDroop, val) = value.ωz = val
"""Set [`ActivePowerDroop`](@ref) `P_ref`."""
set_P_ref!(value::ActivePowerDroop, val) = value.P_ref = val
"""Set [`ActivePowerDroop`](@ref) `ext`."""
set_ext!(value::ActivePowerDroop, val) = value.ext = val
================================================
FILE: src/models/generated/ActivePowerPI.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ActivePowerPI <: ActivePowerControl
Kp_p::Float64
Ki_p::Float64
ωz::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a Proportional-Integral Active Power controller for a specified power reference
# Arguments
- `Kp_p::Float64`: Proportional Gain, validation range: `(0, nothing)`
- `Ki_p::Float64`: Integral Gain, validation range: `(0, nothing)`
- `ωz::Float64`: filter frequency cutoff, validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the ActivePowerPI model are:
σp_oc: Integrator state of the PI Controller,
p_oc: Measured active power of the inverter model
- `n_states::Int`: (**Do not modify.**) ActivePowerPI has two states
"""
mutable struct ActivePowerPI <: ActivePowerControl
"Proportional Gain"
Kp_p::Float64
"Integral Gain"
Ki_p::Float64
"filter frequency cutoff"
ωz::Float64
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the ActivePowerPI model are:
σp_oc: Integrator state of the PI Controller,
p_oc: Measured active power of the inverter model"
states::Vector{Symbol}
"(**Do not modify.**) ActivePowerPI has two states"
n_states::Int
end
function ActivePowerPI(Kp_p, Ki_p, ωz, P_ref=1.0, ext=Dict{String, Any}(), )
ActivePowerPI(Kp_p, Ki_p, ωz, P_ref, ext, [:σp_oc, :p_oc], 2, )
end
function ActivePowerPI(; Kp_p, Ki_p, ωz, P_ref=1.0, ext=Dict{String, Any}(), states=[:σp_oc, :p_oc], n_states=2, )
ActivePowerPI(Kp_p, Ki_p, ωz, P_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function ActivePowerPI(::Nothing)
ActivePowerPI(;
Kp_p=0,
Ki_p=0,
ωz=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ActivePowerPI`](@ref) `Kp_p`."""
get_Kp_p(value::ActivePowerPI) = value.Kp_p
"""Get [`ActivePowerPI`](@ref) `Ki_p`."""
get_Ki_p(value::ActivePowerPI) = value.Ki_p
"""Get [`ActivePowerPI`](@ref) `ωz`."""
get_ωz(value::ActivePowerPI) = value.ωz
"""Get [`ActivePowerPI`](@ref) `P_ref`."""
get_P_ref(value::ActivePowerPI) = value.P_ref
"""Get [`ActivePowerPI`](@ref) `ext`."""
get_ext(value::ActivePowerPI) = value.ext
"""Get [`ActivePowerPI`](@ref) `states`."""
get_states(value::ActivePowerPI) = value.states
"""Get [`ActivePowerPI`](@ref) `n_states`."""
get_n_states(value::ActivePowerPI) = value.n_states
"""Set [`ActivePowerPI`](@ref) `Kp_p`."""
set_Kp_p!(value::ActivePowerPI, val) = value.Kp_p = val
"""Set [`ActivePowerPI`](@ref) `Ki_p`."""
set_Ki_p!(value::ActivePowerPI, val) = value.Ki_p = val
"""Set [`ActivePowerPI`](@ref) `ωz`."""
set_ωz!(value::ActivePowerPI, val) = value.ωz = val
"""Set [`ActivePowerPI`](@ref) `P_ref`."""
set_P_ref!(value::ActivePowerPI, val) = value.P_ref = val
"""Set [`ActivePowerPI`](@ref) `ext`."""
set_ext!(value::ActivePowerPI, val) = value.ext = val
================================================
FILE: src/models/generated/ActiveRenewableControllerAB.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ActiveRenewableControllerAB <: ActivePowerControl
bus_control::Int
from_branch_control::Int
to_branch_control::Int
branch_id_control::String
Freq_Flag::Int
K_pg::Float64
K_ig::Float64
T_p::Float64
fdbd_pnts::Tuple{Float64, Float64}
fe_lim::MinMax
P_lim::MinMax
T_g::Float64
D_dn::Float64
D_up::Float64
dP_lim::MinMax
P_lim_inner::MinMax
T_pord::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of Active Power Controller including REPCA1 and REECB1
# Arguments
- `bus_control::Int`: ACBus identification [`number`](@ref ACBus) for voltage control. `0` identifies the local bus connected to this component, validation range: `(0, nothing)`
- `from_branch_control::Int`: Monitored branch FROM bus number for line drop compensation (if 0 generator power will be used), validation range: `(0, nothing)`
- `to_branch_control::Int`: Monitored branch TO bus number for line drop compensation (if 0 generator power will be used), validation range: `(0, nothing)`
- `branch_id_control::String`: Branch circuit id for line drop compensation (as a string). If 0 generator power will be used
- `Freq_Flag::Int`: Frequency Flag for REPCA1: 0: disable, 1:enable, validation range: `(0, 1)`
- `K_pg::Float64`: Active power PI control proportional gain, validation range: `(0, nothing)`
- `K_ig::Float64`: Active power PI control integral gain, validation range: `(0, nothing)`
- `T_p::Float64`: Real power measurement filter time constant (s), validation range: `(0, nothing)`
- `fdbd_pnts::Tuple{Float64, Float64}`: Frequency error dead band thresholds `(fdbd1, fdbd2)`
- `fe_lim::MinMax`: Upper/Lower limit on frequency error `(fe_min, fe_max)`
- `P_lim::MinMax`: Upper/Lower limit on power reference `(P_min, P_max)`
- `T_g::Float64`: Power Controller lag time constant, validation range: `(0, nothing)`
- `D_dn::Float64`: Droop for over-frequency conditions, validation range: `(nothing, 0)`
- `D_up::Float64`: Droop for under-frequency conditions, validation range: `(0, nothing)`
- `dP_lim::MinMax`: Upper/Lower limit on power reference ramp rates`(dP_min, dP_max)`
- `P_lim_inner::MinMax`: Upper/Lower limit on power reference for REECB`(P_min_inner, P_max_inner)`
- `T_pord::Float64`: Power filter time constant REECB time constant, validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the ActiveRenewableControllerAB model depends on the Flag
- `n_states::Int`: (**Do not modify.**) The states of the ActiveRenewableControllerAB model depends on the Flag
"""
mutable struct ActiveRenewableControllerAB <: ActivePowerControl
"ACBus identification [`number`](@ref ACBus) for voltage control. `0` identifies the local bus connected to this component"
bus_control::Int
"Monitored branch FROM bus number for line drop compensation (if 0 generator power will be used)"
from_branch_control::Int
"Monitored branch TO bus number for line drop compensation (if 0 generator power will be used)"
to_branch_control::Int
"Branch circuit id for line drop compensation (as a string). If 0 generator power will be used"
branch_id_control::String
"Frequency Flag for REPCA1: 0: disable, 1:enable"
Freq_Flag::Int
"Active power PI control proportional gain"
K_pg::Float64
"Active power PI control integral gain"
K_ig::Float64
"Real power measurement filter time constant (s)"
T_p::Float64
"Frequency error dead band thresholds `(fdbd1, fdbd2)`"
fdbd_pnts::Tuple{Float64, Float64}
"Upper/Lower limit on frequency error `(fe_min, fe_max)`"
fe_lim::MinMax
"Upper/Lower limit on power reference `(P_min, P_max)`"
P_lim::MinMax
"Power Controller lag time constant"
T_g::Float64
"Droop for over-frequency conditions"
D_dn::Float64
"Droop for under-frequency conditions"
D_up::Float64
"Upper/Lower limit on power reference ramp rates`(dP_min, dP_max)`"
dP_lim::MinMax
"Upper/Lower limit on power reference for REECB`(P_min_inner, P_max_inner)`"
P_lim_inner::MinMax
"Power filter time constant REECB time constant"
T_pord::Float64
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the ActiveRenewableControllerAB model depends on the Flag"
states::Vector{Symbol}
"(**Do not modify.**) The states of the ActiveRenewableControllerAB model depends on the Flag"
n_states::Int
end
function ActiveRenewableControllerAB(bus_control, from_branch_control, to_branch_control, branch_id_control, Freq_Flag, K_pg, K_ig, T_p, fdbd_pnts, fe_lim, P_lim, T_g, D_dn, D_up, dP_lim, P_lim_inner, T_pord, P_ref=1.0, ext=Dict{String, Any}(), )
ActiveRenewableControllerAB(bus_control, from_branch_control, to_branch_control, branch_id_control, Freq_Flag, K_pg, K_ig, T_p, fdbd_pnts, fe_lim, P_lim, T_g, D_dn, D_up, dP_lim, P_lim_inner, T_pord, P_ref, ext, PowerSystems.get_activeRETypeAB_states(Freq_Flag)[1], PowerSystems.get_activeRETypeAB_states(Freq_Flag)[2], )
end
function ActiveRenewableControllerAB(; bus_control, from_branch_control, to_branch_control, branch_id_control, Freq_Flag, K_pg, K_ig, T_p, fdbd_pnts, fe_lim, P_lim, T_g, D_dn, D_up, dP_lim, P_lim_inner, T_pord, P_ref=1.0, ext=Dict{String, Any}(), states=PowerSystems.get_activeRETypeAB_states(Freq_Flag)[1], n_states=PowerSystems.get_activeRETypeAB_states(Freq_Flag)[2], )
ActiveRenewableControllerAB(bus_control, from_branch_control, to_branch_control, branch_id_control, Freq_Flag, K_pg, K_ig, T_p, fdbd_pnts, fe_lim, P_lim, T_g, D_dn, D_up, dP_lim, P_lim_inner, T_pord, P_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function ActiveRenewableControllerAB(::Nothing)
ActiveRenewableControllerAB(;
bus_control=0,
from_branch_control=0,
to_branch_control=0,
branch_id_control="0",
Freq_Flag=0,
K_pg=0,
K_ig=0,
T_p=0,
fdbd_pnts=(0.0, 0.0),
fe_lim=(min=0.0, max=0.0),
P_lim=(min=0.0, max=0.0),
T_g=0,
D_dn=0,
D_up=0,
dP_lim=(min=0.0, max=0.0),
P_lim_inner=(min=0.0, max=0.0),
T_pord=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ActiveRenewableControllerAB`](@ref) `bus_control`."""
get_bus_control(value::ActiveRenewableControllerAB) = value.bus_control
"""Get [`ActiveRenewableControllerAB`](@ref) `from_branch_control`."""
get_from_branch_control(value::ActiveRenewableControllerAB) = value.from_branch_control
"""Get [`ActiveRenewableControllerAB`](@ref) `to_branch_control`."""
get_to_branch_control(value::ActiveRenewableControllerAB) = value.to_branch_control
"""Get [`ActiveRenewableControllerAB`](@ref) `branch_id_control`."""
get_branch_id_control(value::ActiveRenewableControllerAB) = value.branch_id_control
"""Get [`ActiveRenewableControllerAB`](@ref) `Freq_Flag`."""
get_Freq_Flag(value::ActiveRenewableControllerAB) = value.Freq_Flag
"""Get [`ActiveRenewableControllerAB`](@ref) `K_pg`."""
get_K_pg(value::ActiveRenewableControllerAB) = value.K_pg
"""Get [`ActiveRenewableControllerAB`](@ref) `K_ig`."""
get_K_ig(value::ActiveRenewableControllerAB) = value.K_ig
"""Get [`ActiveRenewableControllerAB`](@ref) `T_p`."""
get_T_p(value::ActiveRenewableControllerAB) = value.T_p
"""Get [`ActiveRenewableControllerAB`](@ref) `fdbd_pnts`."""
get_fdbd_pnts(value::ActiveRenewableControllerAB) = value.fdbd_pnts
"""Get [`ActiveRenewableControllerAB`](@ref) `fe_lim`."""
get_fe_lim(value::ActiveRenewableControllerAB) = value.fe_lim
"""Get [`ActiveRenewableControllerAB`](@ref) `P_lim`."""
get_P_lim(value::ActiveRenewableControllerAB) = value.P_lim
"""Get [`ActiveRenewableControllerAB`](@ref) `T_g`."""
get_T_g(value::ActiveRenewableControllerAB) = value.T_g
"""Get [`ActiveRenewableControllerAB`](@ref) `D_dn`."""
get_D_dn(value::ActiveRenewableControllerAB) = value.D_dn
"""Get [`ActiveRenewableControllerAB`](@ref) `D_up`."""
get_D_up(value::ActiveRenewableControllerAB) = value.D_up
"""Get [`ActiveRenewableControllerAB`](@ref) `dP_lim`."""
get_dP_lim(value::ActiveRenewableControllerAB) = value.dP_lim
"""Get [`ActiveRenewableControllerAB`](@ref) `P_lim_inner`."""
get_P_lim_inner(value::ActiveRenewableControllerAB) = value.P_lim_inner
"""Get [`ActiveRenewableControllerAB`](@ref) `T_pord`."""
get_T_pord(value::ActiveRenewableControllerAB) = value.T_pord
"""Get [`ActiveRenewableControllerAB`](@ref) `P_ref`."""
get_P_ref(value::ActiveRenewableControllerAB) = value.P_ref
"""Get [`ActiveRenewableControllerAB`](@ref) `ext`."""
get_ext(value::ActiveRenewableControllerAB) = value.ext
"""Get [`ActiveRenewableControllerAB`](@ref) `states`."""
get_states(value::ActiveRenewableControllerAB) = value.states
"""Get [`ActiveRenewableControllerAB`](@ref) `n_states`."""
get_n_states(value::ActiveRenewableControllerAB) = value.n_states
"""Set [`ActiveRenewableControllerAB`](@ref) `bus_control`."""
set_bus_control!(value::ActiveRenewableControllerAB, val) = value.bus_control = val
"""Set [`ActiveRenewableControllerAB`](@ref) `from_branch_control`."""
set_from_branch_control!(value::ActiveRenewableControllerAB, val) = value.from_branch_control = val
"""Set [`ActiveRenewableControllerAB`](@ref) `to_branch_control`."""
set_to_branch_control!(value::ActiveRenewableControllerAB, val) = value.to_branch_control = val
"""Set [`ActiveRenewableControllerAB`](@ref) `branch_id_control`."""
set_branch_id_control!(value::ActiveRenewableControllerAB, val) = value.branch_id_control = val
"""Set [`ActiveRenewableControllerAB`](@ref) `Freq_Flag`."""
set_Freq_Flag!(value::ActiveRenewableControllerAB, val) = value.Freq_Flag = val
"""Set [`ActiveRenewableControllerAB`](@ref) `K_pg`."""
set_K_pg!(value::ActiveRenewableControllerAB, val) = value.K_pg = val
"""Set [`ActiveRenewableControllerAB`](@ref) `K_ig`."""
set_K_ig!(value::ActiveRenewableControllerAB, val) = value.K_ig = val
"""Set [`ActiveRenewableControllerAB`](@ref) `T_p`."""
set_T_p!(value::ActiveRenewableControllerAB, val) = value.T_p = val
"""Set [`ActiveRenewableControllerAB`](@ref) `fdbd_pnts`."""
set_fdbd_pnts!(value::ActiveRenewableControllerAB, val) = value.fdbd_pnts = val
"""Set [`ActiveRenewableControllerAB`](@ref) `fe_lim`."""
set_fe_lim!(value::ActiveRenewableControllerAB, val) = value.fe_lim = val
"""Set [`ActiveRenewableControllerAB`](@ref) `P_lim`."""
set_P_lim!(value::ActiveRenewableControllerAB, val) = value.P_lim = val
"""Set [`ActiveRenewableControllerAB`](@ref) `T_g`."""
set_T_g!(value::ActiveRenewableControllerAB, val) = value.T_g = val
"""Set [`ActiveRenewableControllerAB`](@ref) `D_dn`."""
set_D_dn!(value::ActiveRenewableControllerAB, val) = value.D_dn = val
"""Set [`ActiveRenewableControllerAB`](@ref) `D_up`."""
set_D_up!(value::ActiveRenewableControllerAB, val) = value.D_up = val
"""Set [`ActiveRenewableControllerAB`](@ref) `dP_lim`."""
set_dP_lim!(value::ActiveRenewableControllerAB, val) = value.dP_lim = val
"""Set [`ActiveRenewableControllerAB`](@ref) `P_lim_inner`."""
set_P_lim_inner!(value::ActiveRenewableControllerAB, val) = value.P_lim_inner = val
"""Set [`ActiveRenewableControllerAB`](@ref) `T_pord`."""
set_T_pord!(value::ActiveRenewableControllerAB, val) = value.T_pord = val
"""Set [`ActiveRenewableControllerAB`](@ref) `P_ref`."""
set_P_ref!(value::ActiveRenewableControllerAB, val) = value.P_ref = val
"""Set [`ActiveRenewableControllerAB`](@ref) `ext`."""
set_ext!(value::ActiveRenewableControllerAB, val) = value.ext = val
================================================
FILE: src/models/generated/ActiveVirtualOscillator.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ActiveVirtualOscillator <: ActivePowerControl
k1::Float64
ψ::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of an Active Virtual Oscillator controller. Model is based on ["Model Reduction for Inverters with Current Limiting and Dispatchable Virtual Oscillator Control."](https://doi.org/10.1109/TEC.2021.3083488)
# Arguments
- `k1::Float64`: VOC Synchronization Gain, validation range: `(0, nothing)`
- `ψ::Float64`: Rotation angle of the controller, validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the ActiveVirtualOscillator model are:
θ_oc: Phase angle displacement of the inverter model
- `n_states::Int`: (**Do not modify.**) ActiveVirtualOscillator has one state
"""
mutable struct ActiveVirtualOscillator <: ActivePowerControl
"VOC Synchronization Gain"
k1::Float64
"Rotation angle of the controller"
ψ::Float64
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the ActiveVirtualOscillator model are:
θ_oc: Phase angle displacement of the inverter model"
states::Vector{Symbol}
"(**Do not modify.**) ActiveVirtualOscillator has one state"
n_states::Int
end
function ActiveVirtualOscillator(k1, ψ, P_ref=1.0, ext=Dict{String, Any}(), )
ActiveVirtualOscillator(k1, ψ, P_ref, ext, [:θ_oc], 1, )
end
function ActiveVirtualOscillator(; k1, ψ, P_ref=1.0, ext=Dict{String, Any}(), states=[:θ_oc], n_states=1, )
ActiveVirtualOscillator(k1, ψ, P_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function ActiveVirtualOscillator(::Nothing)
ActiveVirtualOscillator(;
k1=0,
ψ=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ActiveVirtualOscillator`](@ref) `k1`."""
get_k1(value::ActiveVirtualOscillator) = value.k1
"""Get [`ActiveVirtualOscillator`](@ref) `ψ`."""
get_ψ(value::ActiveVirtualOscillator) = value.ψ
"""Get [`ActiveVirtualOscillator`](@ref) `P_ref`."""
get_P_ref(value::ActiveVirtualOscillator) = value.P_ref
"""Get [`ActiveVirtualOscillator`](@ref) `ext`."""
get_ext(value::ActiveVirtualOscillator) = value.ext
"""Get [`ActiveVirtualOscillator`](@ref) `states`."""
get_states(value::ActiveVirtualOscillator) = value.states
"""Get [`ActiveVirtualOscillator`](@ref) `n_states`."""
get_n_states(value::ActiveVirtualOscillator) = value.n_states
"""Set [`ActiveVirtualOscillator`](@ref) `k1`."""
set_k1!(value::ActiveVirtualOscillator, val) = value.k1 = val
"""Set [`ActiveVirtualOscillator`](@ref) `ψ`."""
set_ψ!(value::ActiveVirtualOscillator, val) = value.ψ = val
"""Set [`ActiveVirtualOscillator`](@ref) `P_ref`."""
set_P_ref!(value::ActiveVirtualOscillator, val) = value.P_ref = val
"""Set [`ActiveVirtualOscillator`](@ref) `ext`."""
set_ext!(value::ActiveVirtualOscillator, val) = value.ext = val
================================================
FILE: src/models/generated/AggregateDistributedGenerationA.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct AggregateDistributedGenerationA <: DynamicInjection
name::String
Pf_Flag::Int
Freq_Flag::Int
PQ_Flag::Int
Gen_Flag::Int
Vtrip_Flag::Int
Ftrip_Flag::Int
T_rv::Float64
Trf::Float64
dbd_pnts::Tuple{Float64, Float64}
K_qv::Float64
Tp::Float64
T_iq::Float64
D_dn::Float64
D_up::Float64
fdbd_pnts::Tuple{Float64, Float64}
fe_lim::MinMax
P_lim::MinMax
dP_lim::MinMax
Tpord::Float64
Kpg::Float64
Kig::Float64
I_max::Float64
vl_pnts::Vector{Tuple{Float64,Float64}}
vh_pnts::Vector{Tuple{Float64,Float64}}
Vrfrac::Float64
fl::Float64
fh::Float64
tfl::Float64
tfh::Float64
Tg::Float64
rrpwr::Float64
Tv::Float64
Vpr::Float64
Iq_lim::MinMax
V_ref::Float64
Pfa_ref::Float64
ω_ref::Float64
Q_ref::Float64
P_ref::Float64
base_power::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of the DERA1 model in PSS/E
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `Pf_Flag::Int`: Flag for Power Factor Control, validation range: `(0, 1)`
- `Freq_Flag::Int`: Flag to enable/disable frequency control, validation range: `(0, 1)`
- `PQ_Flag::Int`: Flag used to enforce maximum current, validation range: `(0, 1)`
- `Gen_Flag::Int`: Flag to specify generator or storage, validation range: `(0, 1)`
- `Vtrip_Flag::Int`: Flag to enable/disable voltage trip logic, validation range: `(0, 1)`
- `Ftrip_Flag::Int`: Flag to enable/disable frequency trip logic, validation range: `(0, 1)`
- `T_rv::Float64`: Voltage measurement transducer time constant, validation range: `(0, nothing)`
- `Trf::Float64`: Frequency measurement transducer time constant, validation range: `(0, nothing)`
- `dbd_pnts::Tuple{Float64, Float64}`: Voltage deadband thresholds `(dbd1, dbd2)`
- `K_qv::Float64`: Proportional voltage control gain (pu), validation range: `(0, nothing)`
- `Tp::Float64`: Power measurement transducer time constant, validation range: `(0, nothing)`
- `T_iq::Float64`: Time constant for low-pass filter for state q_V when QFlag = 0, validation range: `(0, nothing)`
- `D_dn::Float64`: Reciprocal of droop for over-frequency conditions (>0) (pu), validation range: `(0, nothing)`
- `D_up::Float64`: Reciprocal of droop for under-frequency conditions <=0) (pu), validation range: `(0, nothing)`
- `fdbd_pnts::Tuple{Float64, Float64}`: Frequency control deadband thresholds `(fdbd1, fdbd2)`
- `fe_lim::MinMax`: Frequency error limits (femin, femax)
- `P_lim::MinMax`: Power limits (Pmin, Pmax)
- `dP_lim::MinMax`: Power reference ramp rate limits (dPmin, dPmax)
- `Tpord::Float64`: Power filter time constant, validation range: `(0, nothing)`
- `Kpg::Float64`: PI controller proportional gain (pu), validation range: `(0, nothing)`
- `Kig::Float64`: PI controller integral gain (pu), validation range: `(0, nothing)`
- `I_max::Float64`: Maximum limit on total converter current (pu), validation range: `(0, nothing)`
- `vl_pnts::Vector{Tuple{Float64,Float64}}`: Low voltage cutout points `[(tv10, vl0), (tv11, vl1)]`
- `vh_pnts::Vector{Tuple{Float64,Float64}}`: High voltage cutout points `[(tvh0, vh0), (tvh1, vh1)]`
- `Vrfrac::Float64`: Fraction of device that recovers after voltage comes back to within vl1 < V < vh1 (0 <= Vrfrac <= 1), validation range: `(0, 1)`
- `fl::Float64`: Inverter frequency break-point for low frequency cut-out (Hz), validation range: `(0, nothing)`
- `fh::Float64`: Inverter frequency break-point for high frequency cut-out (Hz), validation range: `(0, nothing)`
- `tfl::Float64`: Low frequency cut-out timer corresponding to frequency fl (s), validation range: `(0, nothing)`
- `tfh::Float64`: High frequency cut-out timer corresponding to frequency fh (s), validation range: `(0, nothing)`
- `Tg::Float64`: Current control time constant (to represent behavior of inner control loops) (> 0) (s), validation range: `(0, nothing)`
- `rrpwr::Float64`: Ramp rate for real power increase following a fault (pu/s), validation range: `(0, nothing)`
- `Tv::Float64`: Time constant on the output of the multiplier (s), validation range: `(0, nothing)`
- `Vpr::Float64`: Voltage below which frequency tripping is disabled (pu), validation range: `(0, nothing)`
- `Iq_lim::MinMax`: Reactive current injection limits (Iqll, Iqhl)
- `V_ref::Float64`: (default: `1.0`) User defined voltage reference. If 0, [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/) initializes to initial terminal voltage, validation range: `(0, nothing)`
- `Pfa_ref::Float64`: (default: `0.0`) Reference power factor, validation range: `(0, nothing)`
- `ω_ref::Float64`: (default: `1.0`) Reference Frequency (pu), validation range: `(0, nothing)`
- `Q_ref::Float64`: (default: `0.0`) Reference reactive power, in pu, validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference active power, in pu, validation range: `(0, nothing)`
- `base_power::Float64`: (default: `100.0`) Base power (MVA) for [per unitization](@ref per_unit)
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of AggregateDistributedGenerationA depends on the Flags
- `n_states::Int`: (**Do not modify.**) The states of AggregateDistributedGenerationA depends on the Flags
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct AggregateDistributedGenerationA <: DynamicInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Flag for Power Factor Control"
Pf_Flag::Int
"Flag to enable/disable frequency control"
Freq_Flag::Int
"Flag used to enforce maximum current"
PQ_Flag::Int
"Flag to specify generator or storage"
Gen_Flag::Int
"Flag to enable/disable voltage trip logic"
Vtrip_Flag::Int
"Flag to enable/disable frequency trip logic"
Ftrip_Flag::Int
"Voltage measurement transducer time constant"
T_rv::Float64
"Frequency measurement transducer time constant"
Trf::Float64
"Voltage deadband thresholds `(dbd1, dbd2)`"
dbd_pnts::Tuple{Float64, Float64}
"Proportional voltage control gain (pu)"
K_qv::Float64
"Power measurement transducer time constant"
Tp::Float64
"Time constant for low-pass filter for state q_V when QFlag = 0"
T_iq::Float64
"Reciprocal of droop for over-frequency conditions (>0) (pu)"
D_dn::Float64
"Reciprocal of droop for under-frequency conditions <=0) (pu)"
D_up::Float64
"Frequency control deadband thresholds `(fdbd1, fdbd2)`"
fdbd_pnts::Tuple{Float64, Float64}
"Frequency error limits (femin, femax)"
fe_lim::MinMax
"Power limits (Pmin, Pmax)"
P_lim::MinMax
"Power reference ramp rate limits (dPmin, dPmax)"
dP_lim::MinMax
"Power filter time constant"
Tpord::Float64
"PI controller proportional gain (pu)"
Kpg::Float64
"PI controller integral gain (pu)"
Kig::Float64
"Maximum limit on total converter current (pu)"
I_max::Float64
"Low voltage cutout points `[(tv10, vl0), (tv11, vl1)]`"
vl_pnts::Vector{Tuple{Float64,Float64}}
"High voltage cutout points `[(tvh0, vh0), (tvh1, vh1)]`"
vh_pnts::Vector{Tuple{Float64,Float64}}
"Fraction of device that recovers after voltage comes back to within vl1 < V < vh1 (0 <= Vrfrac <= 1)"
Vrfrac::Float64
"Inverter frequency break-point for low frequency cut-out (Hz)"
fl::Float64
"Inverter frequency break-point for high frequency cut-out (Hz)"
fh::Float64
"Low frequency cut-out timer corresponding to frequency fl (s)"
tfl::Float64
"High frequency cut-out timer corresponding to frequency fh (s)"
tfh::Float64
"Current control time constant (to represent behavior of inner control loops) (> 0) (s)"
Tg::Float64
"Ramp rate for real power increase following a fault (pu/s)"
rrpwr::Float64
"Time constant on the output of the multiplier (s)"
Tv::Float64
"Voltage below which frequency tripping is disabled (pu)"
Vpr::Float64
"Reactive current injection limits (Iqll, Iqhl)"
Iq_lim::MinMax
"User defined voltage reference. If 0, [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/) initializes to initial terminal voltage"
V_ref::Float64
"Reference power factor"
Pfa_ref::Float64
"Reference Frequency (pu)"
ω_ref::Float64
"Reference reactive power, in pu"
Q_ref::Float64
"Reference active power, in pu"
P_ref::Float64
"Base power (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of AggregateDistributedGenerationA depends on the Flags"
states::Vector{Symbol}
"(**Do not modify.**) The states of AggregateDistributedGenerationA depends on the Flags"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function AggregateDistributedGenerationA(name, Pf_Flag, Freq_Flag, PQ_Flag, Gen_Flag, Vtrip_Flag, Ftrip_Flag, T_rv, Trf, dbd_pnts, K_qv, Tp, T_iq, D_dn, D_up, fdbd_pnts, fe_lim, P_lim, dP_lim, Tpord, Kpg, Kig, I_max, vl_pnts, vh_pnts, Vrfrac, fl, fh, tfl, tfh, Tg, rrpwr, Tv, Vpr, Iq_lim, V_ref=1.0, Pfa_ref=0.0, ω_ref=1.0, Q_ref=0.0, P_ref=1.0, base_power=100.0, ext=Dict{String, Any}(), )
AggregateDistributedGenerationA(name, Pf_Flag, Freq_Flag, PQ_Flag, Gen_Flag, Vtrip_Flag, Ftrip_Flag, T_rv, Trf, dbd_pnts, K_qv, Tp, T_iq, D_dn, D_up, fdbd_pnts, fe_lim, P_lim, dP_lim, Tpord, Kpg, Kig, I_max, vl_pnts, vh_pnts, Vrfrac, fl, fh, tfl, tfh, Tg, rrpwr, Tv, Vpr, Iq_lim, V_ref, Pfa_ref, ω_ref, Q_ref, P_ref, base_power, ext, PowerSystems.get_AggregateDistributedGenerationA_states(Freq_Flag)[1], PowerSystems.get_AggregateDistributedGenerationA_states(Freq_Flag)[2], InfrastructureSystemsInternal(), )
end
function AggregateDistributedGenerationA(; name, Pf_Flag, Freq_Flag, PQ_Flag, Gen_Flag, Vtrip_Flag, Ftrip_Flag, T_rv, Trf, dbd_pnts, K_qv, Tp, T_iq, D_dn, D_up, fdbd_pnts, fe_lim, P_lim, dP_lim, Tpord, Kpg, Kig, I_max, vl_pnts, vh_pnts, Vrfrac, fl, fh, tfl, tfh, Tg, rrpwr, Tv, Vpr, Iq_lim, V_ref=1.0, Pfa_ref=0.0, ω_ref=1.0, Q_ref=0.0, P_ref=1.0, base_power=100.0, ext=Dict{String, Any}(), states=PowerSystems.get_AggregateDistributedGenerationA_states(Freq_Flag)[1], n_states=PowerSystems.get_AggregateDistributedGenerationA_states(Freq_Flag)[2], internal=InfrastructureSystemsInternal(), )
AggregateDistributedGenerationA(name, Pf_Flag, Freq_Flag, PQ_Flag, Gen_Flag, Vtrip_Flag, Ftrip_Flag, T_rv, Trf, dbd_pnts, K_qv, Tp, T_iq, D_dn, D_up, fdbd_pnts, fe_lim, P_lim, dP_lim, Tpord, Kpg, Kig, I_max, vl_pnts, vh_pnts, Vrfrac, fl, fh, tfl, tfh, Tg, rrpwr, Tv, Vpr, Iq_lim, V_ref, Pfa_ref, ω_ref, Q_ref, P_ref, base_power, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function AggregateDistributedGenerationA(::Nothing)
AggregateDistributedGenerationA(;
name="init",
Pf_Flag=0,
Freq_Flag=0,
PQ_Flag=0,
Gen_Flag=0,
Vtrip_Flag=0,
Ftrip_Flag=0,
T_rv=0,
Trf=0,
dbd_pnts=(0.0, 0.0),
K_qv=0,
Tp=0,
T_iq=0,
D_dn=0,
D_up=0,
fdbd_pnts=(0.0, 0.0),
fe_lim=(min=0.0, max=0.0),
P_lim=(min=0.0, max=0.0),
dP_lim=(min=0.0, max=0.0),
Tpord=0,
Kpg=0,
Kig=0,
I_max=0,
vl_pnts=[(0.0, 0.0), (0.0, 0.0)],
vh_pnts=[(0.0, 0.0), (0.0, 0.0)],
Vrfrac=0,
fl=0,
fh=0,
tfl=0,
tfh=0,
Tg=0,
rrpwr=0,
Tv=0,
Vpr=0,
Iq_lim=(min=0.0, max=0.0),
V_ref=0,
Pfa_ref=0,
ω_ref=0,
Q_ref=0,
P_ref=0,
base_power=0,
ext=Dict{String, Any}(),
)
end
"""Get [`AggregateDistributedGenerationA`](@ref) `name`."""
get_name(value::AggregateDistributedGenerationA) = value.name
"""Get [`AggregateDistributedGenerationA`](@ref) `Pf_Flag`."""
get_Pf_Flag(value::AggregateDistributedGenerationA) = value.Pf_Flag
"""Get [`AggregateDistributedGenerationA`](@ref) `Freq_Flag`."""
get_Freq_Flag(value::AggregateDistributedGenerationA) = value.Freq_Flag
"""Get [`AggregateDistributedGenerationA`](@ref) `PQ_Flag`."""
get_PQ_Flag(value::AggregateDistributedGenerationA) = value.PQ_Flag
"""Get [`AggregateDistributedGenerationA`](@ref) `Gen_Flag`."""
get_Gen_Flag(value::AggregateDistributedGenerationA) = value.Gen_Flag
"""Get [`AggregateDistributedGenerationA`](@ref) `Vtrip_Flag`."""
get_Vtrip_Flag(value::AggregateDistributedGenerationA) = value.Vtrip_Flag
"""Get [`AggregateDistributedGenerationA`](@ref) `Ftrip_Flag`."""
get_Ftrip_Flag(value::AggregateDistributedGenerationA) = value.Ftrip_Flag
"""Get [`AggregateDistributedGenerationA`](@ref) `T_rv`."""
get_T_rv(value::AggregateDistributedGenerationA) = value.T_rv
"""Get [`AggregateDistributedGenerationA`](@ref) `Trf`."""
get_Trf(value::AggregateDistributedGenerationA) = value.Trf
"""Get [`AggregateDistributedGenerationA`](@ref) `dbd_pnts`."""
get_dbd_pnts(value::AggregateDistributedGenerationA) = value.dbd_pnts
"""Get [`AggregateDistributedGenerationA`](@ref) `K_qv`."""
get_K_qv(value::AggregateDistributedGenerationA) = value.K_qv
"""Get [`AggregateDistributedGenerationA`](@ref) `Tp`."""
get_Tp(value::AggregateDistributedGenerationA) = value.Tp
"""Get [`AggregateDistributedGenerationA`](@ref) `T_iq`."""
get_T_iq(value::AggregateDistributedGenerationA) = value.T_iq
"""Get [`AggregateDistributedGenerationA`](@ref) `D_dn`."""
get_D_dn(value::AggregateDistributedGenerationA) = value.D_dn
"""Get [`AggregateDistributedGenerationA`](@ref) `D_up`."""
get_D_up(value::AggregateDistributedGenerationA) = value.D_up
"""Get [`AggregateDistributedGenerationA`](@ref) `fdbd_pnts`."""
get_fdbd_pnts(value::AggregateDistributedGenerationA) = value.fdbd_pnts
"""Get [`AggregateDistributedGenerationA`](@ref) `fe_lim`."""
get_fe_lim(value::AggregateDistributedGenerationA) = value.fe_lim
"""Get [`AggregateDistributedGenerationA`](@ref) `P_lim`."""
get_P_lim(value::AggregateDistributedGenerationA) = value.P_lim
"""Get [`AggregateDistributedGenerationA`](@ref) `dP_lim`."""
get_dP_lim(value::AggregateDistributedGenerationA) = value.dP_lim
"""Get [`AggregateDistributedGenerationA`](@ref) `Tpord`."""
get_Tpord(value::AggregateDistributedGenerationA) = value.Tpord
"""Get [`AggregateDistributedGenerationA`](@ref) `Kpg`."""
get_Kpg(value::AggregateDistributedGenerationA) = value.Kpg
"""Get [`AggregateDistributedGenerationA`](@ref) `Kig`."""
get_Kig(value::AggregateDistributedGenerationA) = value.Kig
"""Get [`AggregateDistributedGenerationA`](@ref) `I_max`."""
get_I_max(value::AggregateDistributedGenerationA) = value.I_max
"""Get [`AggregateDistributedGenerationA`](@ref) `vl_pnts`."""
get_vl_pnts(value::AggregateDistributedGenerationA) = value.vl_pnts
"""Get [`AggregateDistributedGenerationA`](@ref) `vh_pnts`."""
get_vh_pnts(value::AggregateDistributedGenerationA) = value.vh_pnts
"""Get [`AggregateDistributedGenerationA`](@ref) `Vrfrac`."""
get_Vrfrac(value::AggregateDistributedGenerationA) = value.Vrfrac
"""Get [`AggregateDistributedGenerationA`](@ref) `fl`."""
get_fl(value::AggregateDistributedGenerationA) = value.fl
"""Get [`AggregateDistributedGenerationA`](@ref) `fh`."""
get_fh(value::AggregateDistributedGenerationA) = value.fh
"""Get [`AggregateDistributedGenerationA`](@ref) `tfl`."""
get_tfl(value::AggregateDistributedGenerationA) = value.tfl
"""Get [`AggregateDistributedGenerationA`](@ref) `tfh`."""
get_tfh(value::AggregateDistributedGenerationA) = value.tfh
"""Get [`AggregateDistributedGenerationA`](@ref) `Tg`."""
get_Tg(value::AggregateDistributedGenerationA) = value.Tg
"""Get [`AggregateDistributedGenerationA`](@ref) `rrpwr`."""
get_rrpwr(value::AggregateDistributedGenerationA) = value.rrpwr
"""Get [`AggregateDistributedGenerationA`](@ref) `Tv`."""
get_Tv(value::AggregateDistributedGenerationA) = value.Tv
"""Get [`AggregateDistributedGenerationA`](@ref) `Vpr`."""
get_Vpr(value::AggregateDistributedGenerationA) = value.Vpr
"""Get [`AggregateDistributedGenerationA`](@ref) `Iq_lim`."""
get_Iq_lim(value::AggregateDistributedGenerationA) = value.Iq_lim
"""Get [`AggregateDistributedGenerationA`](@ref) `V_ref`."""
get_V_ref(value::AggregateDistributedGenerationA) = value.V_ref
"""Get [`AggregateDistributedGenerationA`](@ref) `Pfa_ref`."""
get_Pfa_ref(value::AggregateDistributedGenerationA) = value.Pfa_ref
"""Get [`AggregateDistributedGenerationA`](@ref) `ω_ref`."""
get_ω_ref(value::AggregateDistributedGenerationA) = value.ω_ref
"""Get [`AggregateDistributedGenerationA`](@ref) `Q_ref`."""
get_Q_ref(value::AggregateDistributedGenerationA) = value.Q_ref
"""Get [`AggregateDistributedGenerationA`](@ref) `P_ref`."""
get_P_ref(value::AggregateDistributedGenerationA) = value.P_ref
"""Get [`AggregateDistributedGenerationA`](@ref) `base_power`."""
get_base_power(value::AggregateDistributedGenerationA) = value.base_power
"""Get [`AggregateDistributedGenerationA`](@ref) `ext`."""
get_ext(value::AggregateDistributedGenerationA) = value.ext
"""Get [`AggregateDistributedGenerationA`](@ref) `states`."""
get_states(value::AggregateDistributedGenerationA) = value.states
"""Get [`AggregateDistributedGenerationA`](@ref) `n_states`."""
get_n_states(value::AggregateDistributedGenerationA) = value.n_states
"""Get [`AggregateDistributedGenerationA`](@ref) `internal`."""
get_internal(value::AggregateDistributedGenerationA) = value.internal
"""Set [`AggregateDistributedGenerationA`](@ref) `Pf_Flag`."""
set_Pf_Flag!(value::AggregateDistributedGenerationA, val) = value.Pf_Flag = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Freq_Flag`."""
set_Freq_Flag!(value::AggregateDistributedGenerationA, val) = value.Freq_Flag = val
"""Set [`AggregateDistributedGenerationA`](@ref) `PQ_Flag`."""
set_PQ_Flag!(value::AggregateDistributedGenerationA, val) = value.PQ_Flag = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Gen_Flag`."""
set_Gen_Flag!(value::AggregateDistributedGenerationA, val) = value.Gen_Flag = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Vtrip_Flag`."""
set_Vtrip_Flag!(value::AggregateDistributedGenerationA, val) = value.Vtrip_Flag = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Ftrip_Flag`."""
set_Ftrip_Flag!(value::AggregateDistributedGenerationA, val) = value.Ftrip_Flag = val
"""Set [`AggregateDistributedGenerationA`](@ref) `T_rv`."""
set_T_rv!(value::AggregateDistributedGenerationA, val) = value.T_rv = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Trf`."""
set_Trf!(value::AggregateDistributedGenerationA, val) = value.Trf = val
"""Set [`AggregateDistributedGenerationA`](@ref) `dbd_pnts`."""
set_dbd_pnts!(value::AggregateDistributedGenerationA, val) = value.dbd_pnts = val
"""Set [`AggregateDistributedGenerationA`](@ref) `K_qv`."""
set_K_qv!(value::AggregateDistributedGenerationA, val) = value.K_qv = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Tp`."""
set_Tp!(value::AggregateDistributedGenerationA, val) = value.Tp = val
"""Set [`AggregateDistributedGenerationA`](@ref) `T_iq`."""
set_T_iq!(value::AggregateDistributedGenerationA, val) = value.T_iq = val
"""Set [`AggregateDistributedGenerationA`](@ref) `D_dn`."""
set_D_dn!(value::AggregateDistributedGenerationA, val) = value.D_dn = val
"""Set [`AggregateDistributedGenerationA`](@ref) `D_up`."""
set_D_up!(value::AggregateDistributedGenerationA, val) = value.D_up = val
"""Set [`AggregateDistributedGenerationA`](@ref) `fdbd_pnts`."""
set_fdbd_pnts!(value::AggregateDistributedGenerationA, val) = value.fdbd_pnts = val
"""Set [`AggregateDistributedGenerationA`](@ref) `fe_lim`."""
set_fe_lim!(value::AggregateDistributedGenerationA, val) = value.fe_lim = val
"""Set [`AggregateDistributedGenerationA`](@ref) `P_lim`."""
set_P_lim!(value::AggregateDistributedGenerationA, val) = value.P_lim = val
"""Set [`AggregateDistributedGenerationA`](@ref) `dP_lim`."""
set_dP_lim!(value::AggregateDistributedGenerationA, val) = value.dP_lim = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Tpord`."""
set_Tpord!(value::AggregateDistributedGenerationA, val) = value.Tpord = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Kpg`."""
set_Kpg!(value::AggregateDistributedGenerationA, val) = value.Kpg = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Kig`."""
set_Kig!(value::AggregateDistributedGenerationA, val) = value.Kig = val
"""Set [`AggregateDistributedGenerationA`](@ref) `I_max`."""
set_I_max!(value::AggregateDistributedGenerationA, val) = value.I_max = val
"""Set [`AggregateDistributedGenerationA`](@ref) `vl_pnts`."""
set_vl_pnts!(value::AggregateDistributedGenerationA, val) = value.vl_pnts = val
"""Set [`AggregateDistributedGenerationA`](@ref) `vh_pnts`."""
set_vh_pnts!(value::AggregateDistributedGenerationA, val) = value.vh_pnts = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Vrfrac`."""
set_Vrfrac!(value::AggregateDistributedGenerationA, val) = value.Vrfrac = val
"""Set [`AggregateDistributedGenerationA`](@ref) `fl`."""
set_fl!(value::AggregateDistributedGenerationA, val) = value.fl = val
"""Set [`AggregateDistributedGenerationA`](@ref) `fh`."""
set_fh!(value::AggregateDistributedGenerationA, val) = value.fh = val
"""Set [`AggregateDistributedGenerationA`](@ref) `tfl`."""
set_tfl!(value::AggregateDistributedGenerationA, val) = value.tfl = val
"""Set [`AggregateDistributedGenerationA`](@ref) `tfh`."""
set_tfh!(value::AggregateDistributedGenerationA, val) = value.tfh = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Tg`."""
set_Tg!(value::AggregateDistributedGenerationA, val) = value.Tg = val
"""Set [`AggregateDistributedGenerationA`](@ref) `rrpwr`."""
set_rrpwr!(value::AggregateDistributedGenerationA, val) = value.rrpwr = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Tv`."""
set_Tv!(value::AggregateDistributedGenerationA, val) = value.Tv = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Vpr`."""
set_Vpr!(value::AggregateDistributedGenerationA, val) = value.Vpr = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Iq_lim`."""
set_Iq_lim!(value::AggregateDistributedGenerationA, val) = value.Iq_lim = val
"""Set [`AggregateDistributedGenerationA`](@ref) `V_ref`."""
set_V_ref!(value::AggregateDistributedGenerationA, val) = value.V_ref = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Pfa_ref`."""
set_Pfa_ref!(value::AggregateDistributedGenerationA, val) = value.Pfa_ref = val
"""Set [`AggregateDistributedGenerationA`](@ref) `ω_ref`."""
set_ω_ref!(value::AggregateDistributedGenerationA, val) = value.ω_ref = val
"""Set [`AggregateDistributedGenerationA`](@ref) `Q_ref`."""
set_Q_ref!(value::AggregateDistributedGenerationA, val) = value.Q_ref = val
"""Set [`AggregateDistributedGenerationA`](@ref) `P_ref`."""
set_P_ref!(value::AggregateDistributedGenerationA, val) = value.P_ref = val
"""Set [`AggregateDistributedGenerationA`](@ref) `base_power`."""
set_base_power!(value::AggregateDistributedGenerationA, val) = value.base_power = val
"""Set [`AggregateDistributedGenerationA`](@ref) `ext`."""
set_ext!(value::AggregateDistributedGenerationA, val) = value.ext = val
================================================
FILE: src/models/generated/AndersonFouadMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct AndersonFouadMachine <: Machine
R::Float64
Xd::Float64
Xq::Float64
Xd_p::Float64
Xq_p::Float64
Xd_pp::Float64
Xq_pp::Float64
Td0_p::Float64
Tq0_p::Float64
Td0_pp::Float64
Tq0_pp::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 6-[states](@ref S) synchronous machine: Anderson-Fouad model
# Arguments
- `R::Float64`: Resistance after EMF in machine per unit, validation range: `(0, nothing)`
- `Xd::Float64`: Reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq::Float64`: Reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_p::Float64`: Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_p::Float64`: Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_pp::Float64`: Sub-Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_pp::Float64`: Sub-Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Td0_p::Float64`: Time constant of transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_p::Float64`: Time constant of transient q-axis voltage, validation range: `(0, nothing)`
- `Td0_pp::Float64`: Time constant of sub-transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_pp::Float64`: Time constant of sub-transient q-axis voltage, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
ψq: q-axis stator flux,
ψd: d-axis stator flux,
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage,
eq_pp: q-axis subtransient voltage,
ed_pp: d-axis subtransient voltage
- `n_states::Int`: (**Do not modify.**) The states AndersonFouadMachine has 6 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct AndersonFouadMachine <: Machine
"Resistance after EMF in machine per unit"
R::Float64
"Reactance after EMF in d-axis per unit"
Xd::Float64
"Reactance after EMF in q-axis per unit"
Xq::Float64
"Transient reactance after EMF in d-axis per unit"
Xd_p::Float64
"Transient reactance after EMF in q-axis per unit"
Xq_p::Float64
"Sub-Transient reactance after EMF in d-axis per unit"
Xd_pp::Float64
"Sub-Transient reactance after EMF in q-axis per unit"
Xq_pp::Float64
"Time constant of transient d-axis voltage"
Td0_p::Float64
"Time constant of transient q-axis voltage"
Tq0_p::Float64
"Time constant of sub-transient d-axis voltage"
Td0_pp::Float64
"Time constant of sub-transient q-axis voltage"
Tq0_pp::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
ψq: q-axis stator flux,
ψd: d-axis stator flux,
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage,
eq_pp: q-axis subtransient voltage,
ed_pp: d-axis subtransient voltage"
states::Vector{Symbol}
"(**Do not modify.**) The states AndersonFouadMachine has 6 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function AndersonFouadMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext=Dict{String, Any}(), )
AndersonFouadMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext, [:ψq, :ψd, :eq_p, :ed_p, :eq_pp, :ed_pp], 6, InfrastructureSystemsInternal(), )
end
function AndersonFouadMachine(; R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext=Dict{String, Any}(), states=[:ψq, :ψd, :eq_p, :ed_p, :eq_pp, :ed_pp], n_states=6, internal=InfrastructureSystemsInternal(), )
AndersonFouadMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function AndersonFouadMachine(::Nothing)
AndersonFouadMachine(;
R=0,
Xd=0,
Xq=0,
Xd_p=0,
Xq_p=0,
Xd_pp=0,
Xq_pp=0,
Td0_p=0,
Tq0_p=0,
Td0_pp=0,
Tq0_pp=0,
ext=Dict{String, Any}(),
)
end
"""Get [`AndersonFouadMachine`](@ref) `R`."""
get_R(value::AndersonFouadMachine) = value.R
"""Get [`AndersonFouadMachine`](@ref) `Xd`."""
get_Xd(value::AndersonFouadMachine) = value.Xd
"""Get [`AndersonFouadMachine`](@ref) `Xq`."""
get_Xq(value::AndersonFouadMachine) = value.Xq
"""Get [`AndersonFouadMachine`](@ref) `Xd_p`."""
get_Xd_p(value::AndersonFouadMachine) = value.Xd_p
"""Get [`AndersonFouadMachine`](@ref) `Xq_p`."""
get_Xq_p(value::AndersonFouadMachine) = value.Xq_p
"""Get [`AndersonFouadMachine`](@ref) `Xd_pp`."""
get_Xd_pp(value::AndersonFouadMachine) = value.Xd_pp
"""Get [`AndersonFouadMachine`](@ref) `Xq_pp`."""
get_Xq_pp(value::AndersonFouadMachine) = value.Xq_pp
"""Get [`AndersonFouadMachine`](@ref) `Td0_p`."""
get_Td0_p(value::AndersonFouadMachine) = value.Td0_p
"""Get [`AndersonFouadMachine`](@ref) `Tq0_p`."""
get_Tq0_p(value::AndersonFouadMachine) = value.Tq0_p
"""Get [`AndersonFouadMachine`](@ref) `Td0_pp`."""
get_Td0_pp(value::AndersonFouadMachine) = value.Td0_pp
"""Get [`AndersonFouadMachine`](@ref) `Tq0_pp`."""
get_Tq0_pp(value::AndersonFouadMachine) = value.Tq0_pp
"""Get [`AndersonFouadMachine`](@ref) `ext`."""
get_ext(value::AndersonFouadMachine) = value.ext
"""Get [`AndersonFouadMachine`](@ref) `states`."""
get_states(value::AndersonFouadMachine) = value.states
"""Get [`AndersonFouadMachine`](@ref) `n_states`."""
get_n_states(value::AndersonFouadMachine) = value.n_states
"""Get [`AndersonFouadMachine`](@ref) `internal`."""
get_internal(value::AndersonFouadMachine) = value.internal
"""Set [`AndersonFouadMachine`](@ref) `R`."""
set_R!(value::AndersonFouadMachine, val) = value.R = val
"""Set [`AndersonFouadMachine`](@ref) `Xd`."""
set_Xd!(value::AndersonFouadMachine, val) = value.Xd = val
"""Set [`AndersonFouadMachine`](@ref) `Xq`."""
set_Xq!(value::AndersonFouadMachine, val) = value.Xq = val
"""Set [`AndersonFouadMachine`](@ref) `Xd_p`."""
set_Xd_p!(value::AndersonFouadMachine, val) = value.Xd_p = val
"""Set [`AndersonFouadMachine`](@ref) `Xq_p`."""
set_Xq_p!(value::AndersonFouadMachine, val) = value.Xq_p = val
"""Set [`AndersonFouadMachine`](@ref) `Xd_pp`."""
set_Xd_pp!(value::AndersonFouadMachine, val) = value.Xd_pp = val
"""Set [`AndersonFouadMachine`](@ref) `Xq_pp`."""
set_Xq_pp!(value::AndersonFouadMachine, val) = value.Xq_pp = val
"""Set [`AndersonFouadMachine`](@ref) `Td0_p`."""
set_Td0_p!(value::AndersonFouadMachine, val) = value.Td0_p = val
"""Set [`AndersonFouadMachine`](@ref) `Tq0_p`."""
set_Tq0_p!(value::AndersonFouadMachine, val) = value.Tq0_p = val
"""Set [`AndersonFouadMachine`](@ref) `Td0_pp`."""
set_Td0_pp!(value::AndersonFouadMachine, val) = value.Td0_pp = val
"""Set [`AndersonFouadMachine`](@ref) `Tq0_pp`."""
set_Tq0_pp!(value::AndersonFouadMachine, val) = value.Tq0_pp = val
"""Set [`AndersonFouadMachine`](@ref) `ext`."""
set_ext!(value::AndersonFouadMachine, val) = value.ext = val
================================================
FILE: src/models/generated/Arc.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct Arc <: Topology
from::Bus
to::Bus
internal::InfrastructureSystemsInternal
end
A topological directed edge connecting two buses.
Arcs are used to define the `from` and `to` buses when defining a line or transformer
# Arguments
- `from::Bus`: The initial bus
- `to::Bus`: The terminal bus
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct Arc <: Topology
"The initial bus"
from::Bus
"The terminal bus"
to::Bus
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function Arc(from, to, )
Arc(from, to, InfrastructureSystemsInternal(), )
end
function Arc(; from, to, internal=InfrastructureSystemsInternal(), )
Arc(from, to, internal, )
end
# Constructor for demo purposes; non-functional.
function Arc(::Nothing)
Arc(;
from=ACBus(nothing),
to=ACBus(nothing),
)
end
"""Get [`Arc`](@ref) `from`."""
get_from(value::Arc) = value.from
"""Get [`Arc`](@ref) `to`."""
get_to(value::Arc) = value.to
"""Get [`Arc`](@ref) `internal`."""
get_internal(value::Arc) = value.internal
"""Set [`Arc`](@ref) `from`."""
set_from!(value::Arc, val) = value.from = val
"""Set [`Arc`](@ref) `to`."""
set_to!(value::Arc, val) = value.to = val
get_name(arc::Arc) = (get_name ∘ get_from)(arc) * " -> " * (get_name ∘ get_to)(arc)
================================================
FILE: src/models/generated/Area.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct Area <: AggregationTopology
name::String
peak_active_power::Float64
peak_reactive_power::Float64
load_response::Float64
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A collection of buses for control purposes.
The `Area` can be specified when defining each [`ACBus`](@ref) or [`DCBus`](@ref) in the area
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `peak_active_power::Float64`: (default: `0.0`) Peak active power in the area
- `peak_reactive_power::Float64`: (default: `0.0`) Peak reactive power in the area
- `load_response::Float64`: (default: `0.0`) Load-frequency damping parameter modeling how much the load in the area changes due to changes in frequency (MW/Hz). [Example here.](https://doi.org/10.1109/NAPS50074.2021.9449687)
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct Area <: AggregationTopology
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Peak active power in the area"
peak_active_power::Float64
"Peak reactive power in the area"
peak_reactive_power::Float64
"Load-frequency damping parameter modeling how much the load in the area changes due to changes in frequency (MW/Hz). [Example here.](https://doi.org/10.1109/NAPS50074.2021.9449687)"
load_response::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function Area(name, peak_active_power=0.0, peak_reactive_power=0.0, load_response=0.0, ext=Dict{String, Any}(), )
Area(name, peak_active_power, peak_reactive_power, load_response, ext, InfrastructureSystemsInternal(), )
end
function Area(; name, peak_active_power=0.0, peak_reactive_power=0.0, load_response=0.0, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
Area(name, peak_active_power, peak_reactive_power, load_response, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function Area(::Nothing)
Area(;
name="init",
peak_active_power=0.0,
peak_reactive_power=0.0,
load_response=0.0,
ext=Dict{String, Any}(),
)
end
"""Get [`Area`](@ref) `name`."""
get_name(value::Area) = value.name
"""Get [`Area`](@ref) `peak_active_power`."""
get_peak_active_power(value::Area) = get_value(value, Val(:peak_active_power), Val(:mva))
"""Get [`Area`](@ref) `peak_reactive_power`."""
get_peak_reactive_power(value::Area) = get_value(value, Val(:peak_reactive_power), Val(:mva))
"""Get [`Area`](@ref) `load_response`."""
get_load_response(value::Area) = value.load_response
"""Get [`Area`](@ref) `ext`."""
get_ext(value::Area) = value.ext
"""Get [`Area`](@ref) `internal`."""
get_internal(value::Area) = value.internal
"""Set [`Area`](@ref) `peak_active_power`."""
set_peak_active_power!(value::Area, val) = value.peak_active_power = set_value(value, Val(:peak_active_power), val, Val(:mva))
"""Set [`Area`](@ref) `peak_reactive_power`."""
set_peak_reactive_power!(value::Area, val) = value.peak_reactive_power = set_value(value, Val(:peak_reactive_power), val, Val(:mva))
"""Set [`Area`](@ref) `load_response`."""
set_load_response!(value::Area, val) = value.load_response = val
"""Set [`Area`](@ref) `ext`."""
set_ext!(value::Area, val) = value.ext = val
================================================
FILE: src/models/generated/AreaInterchange.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct AreaInterchange <: Branch
name::String
available::Bool
active_power_flow::Float64
from_area::Area
to_area::Area
flow_limits::FromTo_ToFrom
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
Flow exchanged between Areas. This Interchange is agnostic to the lines connecting the areas. It does not substitute Interface which is the total flow across a group of lines
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow::Float64`: Initial condition of active power flow on the line (MW)
- `from_area::Area`: Area from which the power is extracted
- `to_area::Area`: Area to which the power is injected
- `flow_limits::FromTo_ToFrom`: Max flow between the areas. It ignores lines and other branches totals
- `services::Vector{Service}`: (default: `Service[]`) Service interfaces that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct AreaInterchange <: Branch
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial condition of active power flow on the line (MW)"
active_power_flow::Float64
"Area from which the power is extracted"
from_area::Area
"Area to which the power is injected"
to_area::Area
"Max flow between the areas. It ignores lines and other branches totals"
flow_limits::FromTo_ToFrom
"Service interfaces that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function AreaInterchange(name, available, active_power_flow, from_area, to_area, flow_limits, services=Service[], ext=Dict{String, Any}(), )
AreaInterchange(name, available, active_power_flow, from_area, to_area, flow_limits, services, ext, InfrastructureSystemsInternal(), )
end
function AreaInterchange(; name, available, active_power_flow, from_area, to_area, flow_limits, services=Service[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
AreaInterchange(name, available, active_power_flow, from_area, to_area, flow_limits, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function AreaInterchange(::Nothing)
AreaInterchange(;
name="init",
available=false,
active_power_flow=0.0,
from_area=Area(nothing),
to_area=Area(nothing),
flow_limits=(from_to=0.0, to_from=0.0),
services=Service[],
ext=Dict{String, Any}(),
)
end
"""Get [`AreaInterchange`](@ref) `name`."""
get_name(value::AreaInterchange) = value.name
"""Get [`AreaInterchange`](@ref) `available`."""
get_available(value::AreaInterchange) = value.available
"""Get [`AreaInterchange`](@ref) `active_power_flow`."""
get_active_power_flow(value::AreaInterchange) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`AreaInterchange`](@ref) `from_area`."""
get_from_area(value::AreaInterchange) = value.from_area
"""Get [`AreaInterchange`](@ref) `to_area`."""
get_to_area(value::AreaInterchange) = value.to_area
"""Get [`AreaInterchange`](@ref) `flow_limits`."""
get_flow_limits(value::AreaInterchange) = get_value(value, Val(:flow_limits), Val(:mva))
"""Get [`AreaInterchange`](@ref) `services`."""
get_services(value::AreaInterchange) = value.services
"""Get [`AreaInterchange`](@ref) `ext`."""
get_ext(value::AreaInterchange) = value.ext
"""Get [`AreaInterchange`](@ref) `internal`."""
get_internal(value::AreaInterchange) = value.internal
"""Set [`AreaInterchange`](@ref) `available`."""
set_available!(value::AreaInterchange, val) = value.available = val
"""Set [`AreaInterchange`](@ref) `active_power_flow`."""
set_active_power_flow!(value::AreaInterchange, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`AreaInterchange`](@ref) `from_area`."""
set_from_area!(value::AreaInterchange, val) = value.from_area = val
"""Set [`AreaInterchange`](@ref) `to_area`."""
set_to_area!(value::AreaInterchange, val) = value.to_area = val
"""Set [`AreaInterchange`](@ref) `flow_limits`."""
set_flow_limits!(value::AreaInterchange, val) = value.flow_limits = set_value(value, Val(:flow_limits), val, Val(:mva))
"""Set [`AreaInterchange`](@ref) `services`."""
set_services!(value::AreaInterchange, val) = value.services = val
"""Set [`AreaInterchange`](@ref) `ext`."""
set_ext!(value::AreaInterchange, val) = value.ext = val
================================================
FILE: src/models/generated/AverageConverter.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct AverageConverter <: Converter
rated_voltage::Float64
rated_current::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of an average converter model
# Arguments
- `rated_voltage::Float64`: Rated voltage (V), validation range: `(0, nothing)`
- `rated_current::Float64`: Rated current (A), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) AverageConverter has no [states](@ref S)
- `n_states::Int`: (**Do not modify.**) AverageConverter has no states
"""
mutable struct AverageConverter <: Converter
"Rated voltage (V)"
rated_voltage::Float64
"Rated current (A)"
rated_current::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) AverageConverter has no [states](@ref S)"
states::Vector{Symbol}
"(**Do not modify.**) AverageConverter has no states"
n_states::Int
end
function AverageConverter(rated_voltage, rated_current, ext=Dict{String, Any}(), )
AverageConverter(rated_voltage, rated_current, ext, Vector{Symbol}(), 0, )
end
function AverageConverter(; rated_voltage, rated_current, ext=Dict{String, Any}(), states=Vector{Symbol}(), n_states=0, )
AverageConverter(rated_voltage, rated_current, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function AverageConverter(::Nothing)
AverageConverter(;
rated_voltage=0,
rated_current=0,
ext=Dict{String, Any}(),
)
end
"""Get [`AverageConverter`](@ref) `rated_voltage`."""
get_rated_voltage(value::AverageConverter) = value.rated_voltage
"""Get [`AverageConverter`](@ref) `rated_current`."""
get_rated_current(value::AverageConverter) = value.rated_current
"""Get [`AverageConverter`](@ref) `ext`."""
get_ext(value::AverageConverter) = value.ext
"""Get [`AverageConverter`](@ref) `states`."""
get_states(value::AverageConverter) = value.states
"""Get [`AverageConverter`](@ref) `n_states`."""
get_n_states(value::AverageConverter) = value.n_states
"""Set [`AverageConverter`](@ref) `rated_voltage`."""
set_rated_voltage!(value::AverageConverter, val) = value.rated_voltage = val
"""Set [`AverageConverter`](@ref) `rated_current`."""
set_rated_current!(value::AverageConverter, val) = value.rated_current = val
"""Set [`AverageConverter`](@ref) `ext`."""
set_ext!(value::AverageConverter, val) = value.ext = val
================================================
FILE: src/models/generated/BaseMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct BaseMachine <: Machine
R::Float64
Xd_p::Float64
eq_p::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of a Classic Machine: GENCLS in PSSE and PSLF
# Arguments
- `R::Float64`: Resistance after EMF in machine per unit, validation range: `(0, nothing)`
- `Xd_p::Float64`: Reactance after EMF in machine per unit, validation range: `(0, nothing)`
- `eq_p::Float64`: Fixed EMF behind the impedance, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) BaseMachine has no [states](@ref S)
- `n_states::Int`: (**Do not modify.**) BaseMachine has no states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct BaseMachine <: Machine
"Resistance after EMF in machine per unit"
R::Float64
"Reactance after EMF in machine per unit"
Xd_p::Float64
"Fixed EMF behind the impedance"
eq_p::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) BaseMachine has no [states](@ref S)"
states::Vector{Symbol}
"(**Do not modify.**) BaseMachine has no states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function BaseMachine(R, Xd_p, eq_p, ext=Dict{String, Any}(), )
BaseMachine(R, Xd_p, eq_p, ext, Vector{Symbol}(), 0, InfrastructureSystemsInternal(), )
end
function BaseMachine(; R, Xd_p, eq_p, ext=Dict{String, Any}(), states=Vector{Symbol}(), n_states=0, internal=InfrastructureSystemsInternal(), )
BaseMachine(R, Xd_p, eq_p, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function BaseMachine(::Nothing)
BaseMachine(;
R=0,
Xd_p=0,
eq_p=0,
ext=Dict{String, Any}(),
)
end
"""Get [`BaseMachine`](@ref) `R`."""
get_R(value::BaseMachine) = value.R
"""Get [`BaseMachine`](@ref) `Xd_p`."""
get_Xd_p(value::BaseMachine) = value.Xd_p
"""Get [`BaseMachine`](@ref) `eq_p`."""
get_eq_p(value::BaseMachine) = value.eq_p
"""Get [`BaseMachine`](@ref) `ext`."""
get_ext(value::BaseMachine) = value.ext
"""Get [`BaseMachine`](@ref) `states`."""
get_states(value::BaseMachine) = value.states
"""Get [`BaseMachine`](@ref) `n_states`."""
get_n_states(value::BaseMachine) = value.n_states
"""Get [`BaseMachine`](@ref) `internal`."""
get_internal(value::BaseMachine) = value.internal
"""Set [`BaseMachine`](@ref) `R`."""
set_R!(value::BaseMachine, val) = value.R = val
"""Set [`BaseMachine`](@ref) `Xd_p`."""
set_Xd_p!(value::BaseMachine, val) = value.Xd_p = val
"""Set [`BaseMachine`](@ref) `eq_p`."""
set_eq_p!(value::BaseMachine, val) = value.eq_p = val
"""Set [`BaseMachine`](@ref) `ext`."""
set_ext!(value::BaseMachine, val) = value.ext = val
================================================
FILE: src/models/generated/CSVGN1.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct CSVGN1 <: DynamicInjection
name::String
K::Float64
T1::Float64
T2::Float64
T3::Float64
T4::Float64
T5::Float64
Rmin::Float64
Vmax::Float64
Vmin::Float64
CBase::Float64
base_power::Float64
ext::Dict{String, Any}
R_th::Float64
X_th::Float64
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of static shunt compensator: CSVGN1 in PSSE
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `K::Float64`: Gain in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `T1::Float64`: Time constant in s, validation range: `(0, nothing)`
- `T2::Float64`: Time constant in s, validation range: `(0, nothing)`
- `T3::Float64`: Time constant in s, validation range: `(eps(), nothing)`
- `T4::Float64`: Time constant in s, validation range: `(0, nothing)`
- `T5::Float64`: Time constant in s, validation range: `(0, nothing)`
- `Rmin::Float64`: Reactor minimum Mvar, validation range: `(0, nothing)`
- `Vmax::Float64`: Maximum voltage in pu, validation range: `(0, nothing)`
- `Vmin::Float64`: Minimum voltage in pu, validation range: `(0, nothing)`
- `CBase::Float64`: Capacitor (MVAR), validation range: `(0, nothing)`
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `R_th::Float64`: Source Thevenin resistance
- `X_th::Float64`: Source Thevenin reactance
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
thy: thyristor,
vr1: regulator output 1,
vr2: regulator output 2
- `n_states::Int`: (**Do not modify.**) CSVGN1 has 3 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct CSVGN1 <: DynamicInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Gain in pu ([`DEVICE_BASE`](@ref per_unit))"
K::Float64
"Time constant in s"
T1::Float64
"Time constant in s"
T2::Float64
"Time constant in s"
T3::Float64
"Time constant in s"
T4::Float64
"Time constant in s"
T5::Float64
"Reactor minimum Mvar"
Rmin::Float64
"Maximum voltage in pu"
Vmax::Float64
"Minimum voltage in pu"
Vmin::Float64
"Capacitor (MVAR)"
CBase::Float64
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"Source Thevenin resistance"
R_th::Float64
"Source Thevenin reactance"
X_th::Float64
"(**Do not modify.**) The [states](@ref S) are:
thy: thyristor,
vr1: regulator output 1,
vr2: regulator output 2"
states::Vector{Symbol}
"(**Do not modify.**) CSVGN1 has 3 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function CSVGN1(name, K, T1, T2, T3, T4, T5, Rmin, Vmax, Vmin, CBase, base_power, ext=Dict{String, Any}(), )
CSVGN1(name, K, T1, T2, T3, T4, T5, Rmin, Vmax, Vmin, CBase, base_power, ext, 0.0, 0.0, [:thy, :vr1, :vr2], 3, InfrastructureSystemsInternal(), )
end
function CSVGN1(; name, K, T1, T2, T3, T4, T5, Rmin, Vmax, Vmin, CBase, base_power, ext=Dict{String, Any}(), R_th=0.0, X_th=0.0, states=[:thy, :vr1, :vr2], n_states=3, internal=InfrastructureSystemsInternal(), )
CSVGN1(name, K, T1, T2, T3, T4, T5, Rmin, Vmax, Vmin, CBase, base_power, ext, R_th, X_th, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function CSVGN1(::Nothing)
CSVGN1(;
name="init",
K=0,
T1=0,
T2=0,
T3=0,
T4=0,
T5=0,
Rmin=0,
Vmax=0,
Vmin=0,
CBase=0,
base_power=100,
ext=Dict{String, Any}(),
)
end
"""Get [`CSVGN1`](@ref) `name`."""
get_name(value::CSVGN1) = value.name
"""Get [`CSVGN1`](@ref) `K`."""
get_K(value::CSVGN1) = value.K
"""Get [`CSVGN1`](@ref) `T1`."""
get_T1(value::CSVGN1) = value.T1
"""Get [`CSVGN1`](@ref) `T2`."""
get_T2(value::CSVGN1) = value.T2
"""Get [`CSVGN1`](@ref) `T3`."""
get_T3(value::CSVGN1) = value.T3
"""Get [`CSVGN1`](@ref) `T4`."""
get_T4(value::CSVGN1) = value.T4
"""Get [`CSVGN1`](@ref) `T5`."""
get_T5(value::CSVGN1) = value.T5
"""Get [`CSVGN1`](@ref) `Rmin`."""
get_Rmin(value::CSVGN1) = value.Rmin
"""Get [`CSVGN1`](@ref) `Vmax`."""
get_Vmax(value::CSVGN1) = value.Vmax
"""Get [`CSVGN1`](@ref) `Vmin`."""
get_Vmin(value::CSVGN1) = value.Vmin
"""Get [`CSVGN1`](@ref) `CBase`."""
get_CBase(value::CSVGN1) = value.CBase
"""Get [`CSVGN1`](@ref) `base_power`."""
get_base_power(value::CSVGN1) = value.base_power
"""Get [`CSVGN1`](@ref) `ext`."""
get_ext(value::CSVGN1) = value.ext
"""Get [`CSVGN1`](@ref) `R_th`."""
get_R_th(value::CSVGN1) = value.R_th
"""Get [`CSVGN1`](@ref) `X_th`."""
get_X_th(value::CSVGN1) = value.X_th
"""Get [`CSVGN1`](@ref) `states`."""
get_states(value::CSVGN1) = value.states
"""Get [`CSVGN1`](@ref) `n_states`."""
get_n_states(value::CSVGN1) = value.n_states
"""Get [`CSVGN1`](@ref) `internal`."""
get_internal(value::CSVGN1) = value.internal
"""Set [`CSVGN1`](@ref) `K`."""
set_K!(value::CSVGN1, val) = value.K = val
"""Set [`CSVGN1`](@ref) `T1`."""
set_T1!(value::CSVGN1, val) = value.T1 = val
"""Set [`CSVGN1`](@ref) `T2`."""
set_T2!(value::CSVGN1, val) = value.T2 = val
"""Set [`CSVGN1`](@ref) `T3`."""
set_T3!(value::CSVGN1, val) = value.T3 = val
"""Set [`CSVGN1`](@ref) `T4`."""
set_T4!(value::CSVGN1, val) = value.T4 = val
"""Set [`CSVGN1`](@ref) `T5`."""
set_T5!(value::CSVGN1, val) = value.T5 = val
"""Set [`CSVGN1`](@ref) `Rmin`."""
set_Rmin!(value::CSVGN1, val) = value.Rmin = val
"""Set [`CSVGN1`](@ref) `Vmax`."""
set_Vmax!(value::CSVGN1, val) = value.Vmax = val
"""Set [`CSVGN1`](@ref) `Vmin`."""
set_Vmin!(value::CSVGN1, val) = value.Vmin = val
"""Set [`CSVGN1`](@ref) `CBase`."""
set_CBase!(value::CSVGN1, val) = value.CBase = val
"""Set [`CSVGN1`](@ref) `base_power`."""
set_base_power!(value::CSVGN1, val) = value.base_power = val
"""Set [`CSVGN1`](@ref) `ext`."""
set_ext!(value::CSVGN1, val) = value.ext = val
"""Set [`CSVGN1`](@ref) `R_th`."""
set_R_th!(value::CSVGN1, val) = value.R_th = val
"""Set [`CSVGN1`](@ref) `X_th`."""
set_X_th!(value::CSVGN1, val) = value.X_th = val
================================================
FILE: src/models/generated/ConstantReserve.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ConstantReserve{T <: ReserveDirection} <: Reserve{T}
name::String
available::Bool
time_frame::Float64
requirement::Float64
sustained_time::Float64
max_output_fraction::Float64
max_participation_factor::Float64
deployed_fraction::Float64
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A reserve product with a constant procurement requirement, such as 3% of the system base power at all times.
This reserve product includes online generators that can respond right away after an unexpected contingency, such as a transmission line or generator outage. When defining the reserve, the `ReserveDirection` must be specified to define this as a [`ReserveUp`](@ref), [`ReserveDown`](@ref), or [`ReserveSymmetric`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `time_frame::Float64`: the saturation time_frame in minutes to provide reserve contribution, validation range: `(0, nothing)`
- `requirement::Float64`: the value of required reserves in p.u. ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `sustained_time::Float64`: (default: `3600.0`) the time in seconds reserve contribution must sustained at a specified level, validation range: `(0, nothing)`
- `max_output_fraction::Float64`: (default: `1.0`) the maximum fraction of each device's output that can be assigned to the service, validation range: `(0, 1)`
- `max_participation_factor::Float64`: (default: `1.0`) the maximum portion [0, 1.0] of the reserve that can be contributed per device, validation range: `(0, 1)`
- `deployed_fraction::Float64`: (default: `0.0`) Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0, validation range: `(0, 1)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ConstantReserve{T <: ReserveDirection} <: Reserve{T}
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"the saturation time_frame in minutes to provide reserve contribution"
time_frame::Float64
"the value of required reserves in p.u. ([`SYSTEM_BASE`](@ref per_unit))"
requirement::Float64
"the time in seconds reserve contribution must sustained at a specified level"
sustained_time::Float64
"the maximum fraction of each device's output that can be assigned to the service"
max_output_fraction::Float64
"the maximum portion [0, 1.0] of the reserve that can be contributed per device"
max_participation_factor::Float64
"Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0"
deployed_fraction::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ConstantReserve{T}(name, available, time_frame, requirement, sustained_time=3600.0, max_output_fraction=1.0, max_participation_factor=1.0, deployed_fraction=0.0, ext=Dict{String, Any}(), ) where T <: ReserveDirection
ConstantReserve{T}(name, available, time_frame, requirement, sustained_time, max_output_fraction, max_participation_factor, deployed_fraction, ext, InfrastructureSystemsInternal(), )
end
function ConstantReserve{T}(; name, available, time_frame, requirement, sustained_time=3600.0, max_output_fraction=1.0, max_participation_factor=1.0, deployed_fraction=0.0, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), ) where T <: ReserveDirection
ConstantReserve{T}(name, available, time_frame, requirement, sustained_time, max_output_fraction, max_participation_factor, deployed_fraction, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function ConstantReserve{T}(::Nothing) where T <: ReserveDirection
ConstantReserve{T}(;
name="init",
available=false,
time_frame=0.0,
requirement=0.0,
sustained_time=0.0,
max_output_fraction=1.0,
max_participation_factor=1.0,
deployed_fraction=0.0,
ext=Dict{String, Any}(),
)
end
"""Get [`ConstantReserve`](@ref) `name`."""
get_name(value::ConstantReserve) = value.name
"""Get [`ConstantReserve`](@ref) `available`."""
get_available(value::ConstantReserve) = value.available
"""Get [`ConstantReserve`](@ref) `time_frame`."""
get_time_frame(value::ConstantReserve) = value.time_frame
"""Get [`ConstantReserve`](@ref) `requirement`."""
get_requirement(value::ConstantReserve) = get_value(value, Val(:requirement), Val(:mva))
"""Get [`ConstantReserve`](@ref) `sustained_time`."""
get_sustained_time(value::ConstantReserve) = value.sustained_time
"""Get [`ConstantReserve`](@ref) `max_output_fraction`."""
get_max_output_fraction(value::ConstantReserve) = value.max_output_fraction
"""Get [`ConstantReserve`](@ref) `max_participation_factor`."""
get_max_participation_factor(value::ConstantReserve) = value.max_participation_factor
"""Get [`ConstantReserve`](@ref) `deployed_fraction`."""
get_deployed_fraction(value::ConstantReserve) = value.deployed_fraction
"""Get [`ConstantReserve`](@ref) `ext`."""
get_ext(value::ConstantReserve) = value.ext
"""Get [`ConstantReserve`](@ref) `internal`."""
get_internal(value::ConstantReserve) = value.internal
"""Set [`ConstantReserve`](@ref) `available`."""
set_available!(value::ConstantReserve, val) = value.available = val
"""Set [`ConstantReserve`](@ref) `time_frame`."""
set_time_frame!(value::ConstantReserve, val) = value.time_frame = val
"""Set [`ConstantReserve`](@ref) `requirement`."""
set_requirement!(value::ConstantReserve, val) = value.requirement = set_value(value, Val(:requirement), val, Val(:mva))
"""Set [`ConstantReserve`](@ref) `sustained_time`."""
set_sustained_time!(value::ConstantReserve, val) = value.sustained_time = val
"""Set [`ConstantReserve`](@ref) `max_output_fraction`."""
set_max_output_fraction!(value::ConstantReserve, val) = value.max_output_fraction = val
"""Set [`ConstantReserve`](@ref) `max_participation_factor`."""
set_max_participation_factor!(value::ConstantReserve, val) = value.max_participation_factor = val
"""Set [`ConstantReserve`](@ref) `deployed_fraction`."""
set_deployed_fraction!(value::ConstantReserve, val) = value.deployed_fraction = val
"""Set [`ConstantReserve`](@ref) `ext`."""
set_ext!(value::ConstantReserve, val) = value.ext = val
================================================
FILE: src/models/generated/ConstantReserveGroup.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ConstantReserveGroup{T <: ReserveDirection} <: Service
name::String
available::Bool
requirement::Float64
ext::Dict{String, Any}
contributing_services::Vector{Service}
internal::InfrastructureSystemsInternal
end
A reserve product met by a group of individual reserves.
The group reserve requirement is added in addition to any individual reserve requirements, and devices that contribute to individual reserves within the group can also contribute to the overarching group reserve requirement. Example: A group of spinning and non-spinning reserves, where online generators providing spinning reserves can also contribute to the non-spinning reserve requirement.
This model has a constant procurement requirement, such as 3% of the system base power at all times. When defining the reserve, the `ReserveDirection` must be specified to define this as a [`ReserveUp`](@ref), [`ReserveDown`](@ref), or [`ReserveSymmetric`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `requirement::Float64`: the value of required reserves in p.u. ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `contributing_services::Vector{Service}`: (default: `Vector{Service}()`) Services that contribute to this group requirement. Services must be added for this constraint to have an effect when conducting simulations in [`PowerSimulations.jl`](https://sienna-platform.github.io/PowerSimulations.jl/latest/)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ConstantReserveGroup{T <: ReserveDirection} <: Service
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"the value of required reserves in p.u. ([`SYSTEM_BASE`](@ref per_unit))"
requirement::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"Services that contribute to this group requirement. Services must be added for this constraint to have an effect when conducting simulations in [`PowerSimulations.jl`](https://sienna-platform.github.io/PowerSimulations.jl/latest/)"
contributing_services::Vector{Service}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ConstantReserveGroup{T}(name, available, requirement, ext=Dict{String, Any}(), contributing_services=Vector{Service}(), ) where T <: ReserveDirection
ConstantReserveGroup{T}(name, available, requirement, ext, contributing_services, InfrastructureSystemsInternal(), )
end
function ConstantReserveGroup{T}(; name, available, requirement, ext=Dict{String, Any}(), contributing_services=Vector{Service}(), internal=InfrastructureSystemsInternal(), ) where T <: ReserveDirection
ConstantReserveGroup{T}(name, available, requirement, ext, contributing_services, internal, )
end
# Constructor for demo purposes; non-functional.
function ConstantReserveGroup{T}(::Nothing) where T <: ReserveDirection
ConstantReserveGroup{T}(;
name="init",
available=false,
requirement=0.0,
ext=Dict{String, Any}(),
contributing_services=Vector{Service}(),
)
end
"""Get [`ConstantReserveGroup`](@ref) `name`."""
get_name(value::ConstantReserveGroup) = value.name
"""Get [`ConstantReserveGroup`](@ref) `available`."""
get_available(value::ConstantReserveGroup) = value.available
"""Get [`ConstantReserveGroup`](@ref) `requirement`."""
get_requirement(value::ConstantReserveGroup) = get_value(value, Val(:requirement), Val(:mva))
"""Get [`ConstantReserveGroup`](@ref) `ext`."""
get_ext(value::ConstantReserveGroup) = value.ext
"""Get [`ConstantReserveGroup`](@ref) `contributing_services`."""
get_contributing_services(value::ConstantReserveGroup) = value.contributing_services
"""Get [`ConstantReserveGroup`](@ref) `internal`."""
get_internal(value::ConstantReserveGroup) = value.internal
"""Set [`ConstantReserveGroup`](@ref) `available`."""
set_available!(value::ConstantReserveGroup, val) = value.available = val
"""Set [`ConstantReserveGroup`](@ref) `requirement`."""
set_requirement!(value::ConstantReserveGroup, val) = value.requirement = set_value(value, Val(:requirement), val, Val(:mva))
"""Set [`ConstantReserveGroup`](@ref) `ext`."""
set_ext!(value::ConstantReserveGroup, val) = value.ext = val
================================================
FILE: src/models/generated/ConstantReserveNonSpinning.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ConstantReserveNonSpinning <: ReserveNonSpinning
name::String
available::Bool
time_frame::Float64
requirement::Float64
sustained_time::Float64
max_output_fraction::Float64
max_participation_factor::Float64
deployed_fraction::Float64
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A non-spinning reserve product with a constant procurement requirement, such as 3% of the system base power at all times.
This reserve product includes back-up generators that might not be currently synchronized with the power system, but can come online quickly after an unexpected contingency, such as a transmission line or generator outage. This is only an upwards reserve. For faster-responding upwards or downwards reserves from components already synchronized with the system, see [`ConstantReserve`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `time_frame::Float64`: the saturation time frame in minutes that a participating device must provide its reserve contribution, validation range: `(0, nothing)`
- `requirement::Float64`: the value of required reserves in p.u. ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `sustained_time::Float64`: (default: `3600.0`) the time in seconds reserve contribution must sustained at a specified level, validation range: `(0, nothing)`
- `max_output_fraction::Float64`: (default: `1.0`) the maximum fraction of each device's output that can be assigned to the service, validation range: `(0, 1)`
- `max_participation_factor::Float64`: (default: `1.0`) the maximum portion [0, 1.0] of the reserve that can be contributed per device, validation range: `(0, 1)`
- `deployed_fraction::Float64`: (default: `0.0`) Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0, validation range: `(0, 1)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ConstantReserveNonSpinning <: ReserveNonSpinning
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"the saturation time frame in minutes that a participating device must provide its reserve contribution"
time_frame::Float64
"the value of required reserves in p.u. ([`SYSTEM_BASE`](@ref per_unit))"
requirement::Float64
"the time in seconds reserve contribution must sustained at a specified level"
sustained_time::Float64
"the maximum fraction of each device's output that can be assigned to the service"
max_output_fraction::Float64
"the maximum portion [0, 1.0] of the reserve that can be contributed per device"
max_participation_factor::Float64
"Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0"
deployed_fraction::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ConstantReserveNonSpinning(name, available, time_frame, requirement, sustained_time=3600.0, max_output_fraction=1.0, max_participation_factor=1.0, deployed_fraction=0.0, ext=Dict{String, Any}(), )
ConstantReserveNonSpinning(name, available, time_frame, requirement, sustained_time, max_output_fraction, max_participation_factor, deployed_fraction, ext, InfrastructureSystemsInternal(), )
end
function ConstantReserveNonSpinning(; name, available, time_frame, requirement, sustained_time=3600.0, max_output_fraction=1.0, max_participation_factor=1.0, deployed_fraction=0.0, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
ConstantReserveNonSpinning(name, available, time_frame, requirement, sustained_time, max_output_fraction, max_participation_factor, deployed_fraction, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function ConstantReserveNonSpinning(::Nothing)
ConstantReserveNonSpinning(;
name="init",
available=false,
time_frame=0.0,
requirement=0.0,
sustained_time=0.0,
max_output_fraction=1.0,
max_participation_factor=1.0,
deployed_fraction=0.0,
ext=Dict{String, Any}(),
)
end
"""Get [`ConstantReserveNonSpinning`](@ref) `name`."""
get_name(value::ConstantReserveNonSpinning) = value.name
"""Get [`ConstantReserveNonSpinning`](@ref) `available`."""
get_available(value::ConstantReserveNonSpinning) = value.available
"""Get [`ConstantReserveNonSpinning`](@ref) `time_frame`."""
get_time_frame(value::ConstantReserveNonSpinning) = value.time_frame
"""Get [`ConstantReserveNonSpinning`](@ref) `requirement`."""
get_requirement(value::ConstantReserveNonSpinning) = get_value(value, Val(:requirement), Val(:mva))
"""Get [`ConstantReserveNonSpinning`](@ref) `sustained_time`."""
get_sustained_time(value::ConstantReserveNonSpinning) = value.sustained_time
"""Get [`ConstantReserveNonSpinning`](@ref) `max_output_fraction`."""
get_max_output_fraction(value::ConstantReserveNonSpinning) = value.max_output_fraction
"""Get [`ConstantReserveNonSpinning`](@ref) `max_participation_factor`."""
get_max_participation_factor(value::ConstantReserveNonSpinning) = value.max_participation_factor
"""Get [`ConstantReserveNonSpinning`](@ref) `deployed_fraction`."""
get_deployed_fraction(value::ConstantReserveNonSpinning) = value.deployed_fraction
"""Get [`ConstantReserveNonSpinning`](@ref) `ext`."""
get_ext(value::ConstantReserveNonSpinning) = value.ext
"""Get [`ConstantReserveNonSpinning`](@ref) `internal`."""
get_internal(value::ConstantReserveNonSpinning) = value.internal
"""Set [`ConstantReserveNonSpinning`](@ref) `available`."""
set_available!(value::ConstantReserveNonSpinning, val) = value.available = val
"""Set [`ConstantReserveNonSpinning`](@ref) `time_frame`."""
set_time_frame!(value::ConstantReserveNonSpinning, val) = value.time_frame = val
"""Set [`ConstantReserveNonSpinning`](@ref) `requirement`."""
set_requirement!(value::ConstantReserveNonSpinning, val) = value.requirement = set_value(value, Val(:requirement), val, Val(:mva))
"""Set [`ConstantReserveNonSpinning`](@ref) `sustained_time`."""
set_sustained_time!(value::ConstantReserveNonSpinning, val) = value.sustained_time = val
"""Set [`ConstantReserveNonSpinning`](@ref) `max_output_fraction`."""
set_max_output_fraction!(value::ConstantReserveNonSpinning, val) = value.max_output_fraction = val
"""Set [`ConstantReserveNonSpinning`](@ref) `max_participation_factor`."""
set_max_participation_factor!(value::ConstantReserveNonSpinning, val) = value.max_participation_factor = val
"""Set [`ConstantReserveNonSpinning`](@ref) `deployed_fraction`."""
set_deployed_fraction!(value::ConstantReserveNonSpinning, val) = value.deployed_fraction = val
"""Set [`ConstantReserveNonSpinning`](@ref) `ext`."""
set_ext!(value::ConstantReserveNonSpinning, val) = value.ext = val
================================================
FILE: src/models/generated/CurrentModeControl.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct CurrentModeControl <: InnerControl
kpc::Float64
kic::Float64
kffv::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of an inner loop proportional integral (PI) current control based on ["Reduced-order Structure-preserving Model for Parallel-connected Three-phase Grid-tied Inverters."](https://doi.org/10.1109/COMPEL.2017.8013389)
# Arguments
- `kpc::Float64`: Current controller proportional gain, validation range: `(0, nothing)`
- `kic::Float64`: Current controller integral gain, validation range: `(0, nothing)`
- `kffv::Float64`: Gain to enable feed-forward gain of voltage, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the CurrentModeControl model are:
γd_ic: d-axis integrator state of the PI current controller,
γq_ic: q-axis integrator state of the PI current controller
- `n_states::Int`: (**Do not modify.**) CurrentControl has 2 states
"""
mutable struct CurrentModeControl <: InnerControl
"Current controller proportional gain"
kpc::Float64
"Current controller integral gain"
kic::Float64
"Gain to enable feed-forward gain of voltage"
kffv::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the CurrentModeControl model are:
γd_ic: d-axis integrator state of the PI current controller,
γq_ic: q-axis integrator state of the PI current controller"
states::Vector{Symbol}
"(**Do not modify.**) CurrentControl has 2 states"
n_states::Int
end
function CurrentModeControl(kpc, kic, kffv, ext=Dict{String, Any}(), )
CurrentModeControl(kpc, kic, kffv, ext, [:γd_ic, :γq_ic], 2, )
end
function CurrentModeControl(; kpc, kic, kffv, ext=Dict{String, Any}(), states=[:γd_ic, :γq_ic], n_states=2, )
CurrentModeControl(kpc, kic, kffv, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function CurrentModeControl(::Nothing)
CurrentModeControl(;
kpc=0,
kic=0,
kffv=0,
ext=Dict{String, Any}(),
)
end
"""Get [`CurrentModeControl`](@ref) `kpc`."""
get_kpc(value::CurrentModeControl) = value.kpc
"""Get [`CurrentModeControl`](@ref) `kic`."""
get_kic(value::CurrentModeControl) = value.kic
"""Get [`CurrentModeControl`](@ref) `kffv`."""
get_kffv(value::CurrentModeControl) = value.kffv
"""Get [`CurrentModeControl`](@ref) `ext`."""
get_ext(value::CurrentModeControl) = value.ext
"""Get [`CurrentModeControl`](@ref) `states`."""
get_states(value::CurrentModeControl) = value.states
"""Get [`CurrentModeControl`](@ref) `n_states`."""
get_n_states(value::CurrentModeControl) = value.n_states
"""Set [`CurrentModeControl`](@ref) `kpc`."""
set_kpc!(value::CurrentModeControl, val) = value.kpc = val
"""Set [`CurrentModeControl`](@ref) `kic`."""
set_kic!(value::CurrentModeControl, val) = value.kic = val
"""Set [`CurrentModeControl`](@ref) `kffv`."""
set_kffv!(value::CurrentModeControl, val) = value.kffv = val
"""Set [`CurrentModeControl`](@ref) `ext`."""
set_ext!(value::CurrentModeControl, val) = value.ext = val
================================================
FILE: src/models/generated/DCBus.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct DCBus <: Bus
number::Int
name::String
available::Bool
magnitude::Union{Nothing, Float64}
voltage_limits::Union{Nothing, MinMax}
base_voltage::Union{Nothing, Float64}
area::Union{Nothing, Area}
load_zone::Union{Nothing, LoadZone}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A DC bus
# Arguments
- `number::Int`: A unique bus identification number (positive integer)
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations.
- `magnitude::Union{Nothing, Float64}`: voltage as a multiple of `base_voltage`, validation range: `voltage_limits`
- `voltage_limits::Union{Nothing, MinMax}`: limits on the voltage variation as multiples of `base_voltage`
- `base_voltage::Union{Nothing, Float64}`: the base voltage in kV, validation range: `(0, nothing)`
- `area::Union{Nothing, Area}`: (default: `nothing`) the area containing the DC bus
- `load_zone::Union{Nothing, LoadZone}`: (default: `nothing`) the load zone containing the DC bus
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct DCBus <: Bus
"A unique bus identification number (positive integer)"
number::Int
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations."
available::Bool
"voltage as a multiple of `base_voltage`"
magnitude::Union{Nothing, Float64}
"limits on the voltage variation as multiples of `base_voltage`"
voltage_limits::Union{Nothing, MinMax}
"the base voltage in kV"
base_voltage::Union{Nothing, Float64}
"the area containing the DC bus"
area::Union{Nothing, Area}
"the load zone containing the DC bus"
load_zone::Union{Nothing, LoadZone}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function DCBus(number, name, available, magnitude, voltage_limits, base_voltage, area=nothing, load_zone=nothing, ext=Dict{String, Any}(), )
DCBus(number, name, available, magnitude, voltage_limits, base_voltage, area, load_zone, ext, InfrastructureSystemsInternal(), )
end
function DCBus(; number, name, available, magnitude, voltage_limits, base_voltage, area=nothing, load_zone=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
DCBus(number, name, available, magnitude, voltage_limits, base_voltage, area, load_zone, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function DCBus(::Nothing)
DCBus(;
number=0,
name="init",
available=false,
magnitude=0.0,
voltage_limits=(min=0.0, max=0.0),
base_voltage=nothing,
area=nothing,
load_zone=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`DCBus`](@ref) `number`."""
get_number(value::DCBus) = value.number
"""Get [`DCBus`](@ref) `name`."""
get_name(value::DCBus) = value.name
"""Get [`DCBus`](@ref) `available`."""
get_available(value::DCBus) = value.available
"""Get [`DCBus`](@ref) `magnitude`."""
get_magnitude(value::DCBus) = value.magnitude
"""Get [`DCBus`](@ref) `voltage_limits`."""
get_voltage_limits(value::DCBus) = value.voltage_limits
"""Get [`DCBus`](@ref) `base_voltage`."""
get_base_voltage(value::DCBus) = value.base_voltage
"""Get [`DCBus`](@ref) `area`."""
get_area(value::DCBus) = value.area
"""Get [`DCBus`](@ref) `load_zone`."""
get_load_zone(value::DCBus) = value.load_zone
"""Get [`DCBus`](@ref) `ext`."""
get_ext(value::DCBus) = value.ext
"""Get [`DCBus`](@ref) `internal`."""
get_internal(value::DCBus) = value.internal
"""Set [`DCBus`](@ref) `number`."""
set_number!(value::DCBus, val) = value.number = val
"""Set [`DCBus`](@ref) `available`."""
set_available!(value::DCBus, val) = value.available = val
"""Set [`DCBus`](@ref) `magnitude`."""
set_magnitude!(value::DCBus, val) = value.magnitude = val
"""Set [`DCBus`](@ref) `voltage_limits`."""
set_voltage_limits!(value::DCBus, val) = value.voltage_limits = val
"""Set [`DCBus`](@ref) `base_voltage`."""
set_base_voltage!(value::DCBus, val) = value.base_voltage = val
"""Set [`DCBus`](@ref) `area`."""
set_area!(value::DCBus, val) = value.area = val
"""Set [`DCBus`](@ref) `load_zone`."""
set_load_zone!(value::DCBus, val) = value.load_zone = val
"""Set [`DCBus`](@ref) `ext`."""
set_ext!(value::DCBus, val) = value.ext = val
================================================
FILE: src/models/generated/DEGOV.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct DEGOV <: TurbineGov
T1::Float64
T2::Float64
T3::Float64
K::Float64
T4::Float64
T5::Float64
T6::Float64
Td::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Parameters Woodward Diesel Governor Model. DEGOV in PowerWorld
# Arguments
- `T1::Float64`: Governor mechanism time constant, validation range: `(eps(), 100)`
- `T2::Float64`: Turbine power time constant, validation range: `(eps(), 100)`
- `T3::Float64`: Turbine exhaust temperature time constant, validation range: `(eps(), 100)`
- `K::Float64`: Governor gain (reciprocal of droop), validation range: `(eps(), 100)`
- `T4::Float64`: Governor lead time constant, validation range: `(eps(), 100)`
- `T5::Float64`: Governor lag time constant, validation range: `(eps(), 100)`
- `T6::Float64`: Actuator time constant, validation range: `(eps(), 100)`
- `Td::Float64`: Engine time delay, validation range: `(eps(), 100)`
- `P_ref::Float64`: (default: `1.0`) Reference Load Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the DEGOV model are:
x_ecb1: Electric control box 1,
x_ecb2: Electric control box 2,
x_a1: Actuator 1,
x_a2: Actuator 2,
x_a3: Actuator 3,
- `n_states::Int`: (**Do not modify.**) DEGOV has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) DEGOV has 5 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct DEGOV <: TurbineGov
"Governor mechanism time constant"
T1::Float64
"Turbine power time constant"
T2::Float64
"Turbine exhaust temperature time constant"
T3::Float64
"Governor gain (reciprocal of droop)"
K::Float64
"Governor lead time constant"
T4::Float64
"Governor lag time constant"
T5::Float64
"Actuator time constant"
T6::Float64
"Engine time delay"
Td::Float64
"Reference Load Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the DEGOV model are:
x_ecb1: Electric control box 1,
x_ecb2: Electric control box 2,
x_a1: Actuator 1,
x_a2: Actuator 2,
x_a3: Actuator 3,"
states::Vector{Symbol}
"(**Do not modify.**) DEGOV has 5 states"
n_states::Int
"(**Do not modify.**) DEGOV has 5 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function DEGOV(T1, T2, T3, K, T4, T5, T6, Td, P_ref=1.0, ext=Dict{String, Any}(), )
DEGOV(T1, T2, T3, K, T4, T5, T6, Td, P_ref, ext, [:x_ecb1, :x_ecb2, :x_a1, :x_a2, :x_a3], 5, [StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function DEGOV(; T1, T2, T3, K, T4, T5, T6, Td, P_ref=1.0, ext=Dict{String, Any}(), states=[:x_ecb1, :x_ecb2, :x_a1, :x_a2, :x_a3], n_states=5, states_types=[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
DEGOV(T1, T2, T3, K, T4, T5, T6, Td, P_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function DEGOV(::Nothing)
DEGOV(;
T1=0,
T2=0,
T3=0,
K=0,
T4=0,
T5=0,
T6=0,
Td=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`DEGOV`](@ref) `T1`."""
get_T1(value::DEGOV) = value.T1
"""Get [`DEGOV`](@ref) `T2`."""
get_T2(value::DEGOV) = value.T2
"""Get [`DEGOV`](@ref) `T3`."""
get_T3(value::DEGOV) = value.T3
"""Get [`DEGOV`](@ref) `K`."""
get_K(value::DEGOV) = value.K
"""Get [`DEGOV`](@ref) `T4`."""
get_T4(value::DEGOV) = value.T4
"""Get [`DEGOV`](@ref) `T5`."""
get_T5(value::DEGOV) = value.T5
"""Get [`DEGOV`](@ref) `T6`."""
get_T6(value::DEGOV) = value.T6
"""Get [`DEGOV`](@ref) `Td`."""
get_Td(value::DEGOV) = value.Td
"""Get [`DEGOV`](@ref) `P_ref`."""
get_P_ref(value::DEGOV) = value.P_ref
"""Get [`DEGOV`](@ref) `ext`."""
get_ext(value::DEGOV) = value.ext
"""Get [`DEGOV`](@ref) `states`."""
get_states(value::DEGOV) = value.states
"""Get [`DEGOV`](@ref) `n_states`."""
get_n_states(value::DEGOV) = value.n_states
"""Get [`DEGOV`](@ref) `states_types`."""
get_states_types(value::DEGOV) = value.states_types
"""Get [`DEGOV`](@ref) `internal`."""
get_internal(value::DEGOV) = value.internal
"""Set [`DEGOV`](@ref) `T1`."""
set_T1!(value::DEGOV, val) = value.T1 = val
"""Set [`DEGOV`](@ref) `T2`."""
set_T2!(value::DEGOV, val) = value.T2 = val
"""Set [`DEGOV`](@ref) `T3`."""
set_T3!(value::DEGOV, val) = value.T3 = val
"""Set [`DEGOV`](@ref) `K`."""
set_K!(value::DEGOV, val) = value.K = val
"""Set [`DEGOV`](@ref) `T4`."""
set_T4!(value::DEGOV, val) = value.T4 = val
"""Set [`DEGOV`](@ref) `T5`."""
set_T5!(value::DEGOV, val) = value.T5 = val
"""Set [`DEGOV`](@ref) `T6`."""
set_T6!(value::DEGOV, val) = value.T6 = val
"""Set [`DEGOV`](@ref) `Td`."""
set_Td!(value::DEGOV, val) = value.Td = val
"""Set [`DEGOV`](@ref) `P_ref`."""
set_P_ref!(value::DEGOV, val) = value.P_ref = val
"""Set [`DEGOV`](@ref) `ext`."""
set_ext!(value::DEGOV, val) = value.ext = val
"""Set [`DEGOV`](@ref) `states_types`."""
set_states_types!(value::DEGOV, val) = value.states_types = val
================================================
FILE: src/models/generated/DEGOV1.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct DEGOV1 <: TurbineGov
droop_flag::Int
T1::Float64
T2::Float64
T3::Float64
K::Float64
T4::Float64
T5::Float64
T6::Float64
Td::Float64
T_lim::Tuple{Float64, Float64}
R::Float64
Te::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters Woodward Diesel Governor Model. DEGOV1 in PSSE
# Arguments
- `droop_flag::Int`: Droop control Flag. 0 for throttle feedback and 1 for electric power feedback, validation range: `(0, 1)`
- `T1::Float64`: Governor mechanism time constant in s, validation range: `(0, 100)`
- `T2::Float64`: Turbine power time constant in s, validation range: `(0, 100)`
- `T3::Float64`: Turbine exhaust temperature time constant in s, validation range: `(0, 100)`
- `K::Float64`: Governor gain for actuator, validation range: `(0, 100)`
- `T4::Float64`: Governor lead time constant in s, validation range: `(0, 100)`
- `T5::Float64`: Governor lag time constant in s, validation range: `(0, 100)`
- `T6::Float64`: Actuator time constant in s, validation range: `(0, 100)`
- `Td::Float64`: Engine time delay in s, validation range: `(0, 100)`
- `T_lim::Tuple{Float64, Float64}`: Operational control limits on actuator (T_min, T_max)
- `R::Float64`: Steady state droop parameter, validation range: `(0, 100)`
- `Te::Float64`: Power transducer time constant in s, validation range: `(0, 100)`
- `P_ref::Float64`: (default: `1.0`) Reference Load Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the DEGOV1 model depends on the droop flag
- `n_states::Int`: (**Do not modify.**) The number of [states](@ref S) of the DEGOV1 model depends on the droop flag
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct DEGOV1 <: TurbineGov
"Droop control Flag. 0 for throttle feedback and 1 for electric power feedback"
droop_flag::Int
"Governor mechanism time constant in s"
T1::Float64
"Turbine power time constant in s"
T2::Float64
"Turbine exhaust temperature time constant in s"
T3::Float64
"Governor gain for actuator"
K::Float64
"Governor lead time constant in s"
T4::Float64
"Governor lag time constant in s"
T5::Float64
"Actuator time constant in s"
T6::Float64
"Engine time delay in s"
Td::Float64
"Operational control limits on actuator (T_min, T_max)"
T_lim::Tuple{Float64, Float64}
"Steady state droop parameter"
R::Float64
"Power transducer time constant in s"
Te::Float64
"Reference Load Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the DEGOV1 model depends on the droop flag"
states::Vector{Symbol}
"(**Do not modify.**) The number of [states](@ref S) of the DEGOV1 model depends on the droop flag"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function DEGOV1(droop_flag, T1, T2, T3, K, T4, T5, T6, Td, T_lim, R, Te, P_ref=1.0, ext=Dict{String, Any}(), )
DEGOV1(droop_flag, T1, T2, T3, K, T4, T5, T6, Td, T_lim, R, Te, P_ref, ext, PowerSystems.get_degov1_states(droop_flag)[1], PowerSystems.get_degov1_states(droop_flag)[2], InfrastructureSystemsInternal(), )
end
function DEGOV1(; droop_flag, T1, T2, T3, K, T4, T5, T6, Td, T_lim, R, Te, P_ref=1.0, ext=Dict{String, Any}(), states=PowerSystems.get_degov1_states(droop_flag)[1], n_states=PowerSystems.get_degov1_states(droop_flag)[2], internal=InfrastructureSystemsInternal(), )
DEGOV1(droop_flag, T1, T2, T3, K, T4, T5, T6, Td, T_lim, R, Te, P_ref, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function DEGOV1(::Nothing)
DEGOV1(;
droop_flag=0,
T1=0,
T2=0,
T3=0,
K=0,
T4=0,
T5=0,
T6=0,
Td=0,
T_lim=(0.0, 0.0),
R=0,
Te=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`DEGOV1`](@ref) `droop_flag`."""
get_droop_flag(value::DEGOV1) = value.droop_flag
"""Get [`DEGOV1`](@ref) `T1`."""
get_T1(value::DEGOV1) = value.T1
"""Get [`DEGOV1`](@ref) `T2`."""
get_T2(value::DEGOV1) = value.T2
"""Get [`DEGOV1`](@ref) `T3`."""
get_T3(value::DEGOV1) = value.T3
"""Get [`DEGOV1`](@ref) `K`."""
get_K(value::DEGOV1) = value.K
"""Get [`DEGOV1`](@ref) `T4`."""
get_T4(value::DEGOV1) = value.T4
"""Get [`DEGOV1`](@ref) `T5`."""
get_T5(value::DEGOV1) = value.T5
"""Get [`DEGOV1`](@ref) `T6`."""
get_T6(value::DEGOV1) = value.T6
"""Get [`DEGOV1`](@ref) `Td`."""
get_Td(value::DEGOV1) = value.Td
"""Get [`DEGOV1`](@ref) `T_lim`."""
get_T_lim(value::DEGOV1) = value.T_lim
"""Get [`DEGOV1`](@ref) `R`."""
get_R(value::DEGOV1) = value.R
"""Get [`DEGOV1`](@ref) `Te`."""
get_Te(value::DEGOV1) = value.Te
"""Get [`DEGOV1`](@ref) `P_ref`."""
get_P_ref(value::DEGOV1) = value.P_ref
"""Get [`DEGOV1`](@ref) `ext`."""
get_ext(value::DEGOV1) = value.ext
"""Get [`DEGOV1`](@ref) `states`."""
get_states(value::DEGOV1) = value.states
"""Get [`DEGOV1`](@ref) `n_states`."""
get_n_states(value::DEGOV1) = value.n_states
"""Get [`DEGOV1`](@ref) `internal`."""
get_internal(value::DEGOV1) = value.internal
"""Set [`DEGOV1`](@ref) `droop_flag`."""
set_droop_flag!(value::DEGOV1, val) = value.droop_flag = val
"""Set [`DEGOV1`](@ref) `T1`."""
set_T1!(value::DEGOV1, val) = value.T1 = val
"""Set [`DEGOV1`](@ref) `T2`."""
set_T2!(value::DEGOV1, val) = value.T2 = val
"""Set [`DEGOV1`](@ref) `T3`."""
set_T3!(value::DEGOV1, val) = value.T3 = val
"""Set [`DEGOV1`](@ref) `K`."""
set_K!(value::DEGOV1, val) = value.K = val
"""Set [`DEGOV1`](@ref) `T4`."""
set_T4!(value::DEGOV1, val) = value.T4 = val
"""Set [`DEGOV1`](@ref) `T5`."""
set_T5!(value::DEGOV1, val) = value.T5 = val
"""Set [`DEGOV1`](@ref) `T6`."""
set_T6!(value::DEGOV1, val) = value.T6 = val
"""Set [`DEGOV1`](@ref) `Td`."""
set_Td!(value::DEGOV1, val) = value.Td = val
"""Set [`DEGOV1`](@ref) `T_lim`."""
set_T_lim!(value::DEGOV1, val) = value.T_lim = val
"""Set [`DEGOV1`](@ref) `R`."""
set_R!(value::DEGOV1, val) = value.R = val
"""Set [`DEGOV1`](@ref) `Te`."""
set_Te!(value::DEGOV1, val) = value.Te = val
"""Set [`DEGOV1`](@ref) `P_ref`."""
set_P_ref!(value::DEGOV1, val) = value.P_ref = val
"""Set [`DEGOV1`](@ref) `ext`."""
set_ext!(value::DEGOV1, val) = value.ext = val
================================================
FILE: src/models/generated/DiscreteControlledACBranch.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct DiscreteControlledACBranch <: ACTransmission
name::String
available::Bool
active_power_flow::Float64
reactive_power_flow::Float64
arc::Arc
r::Float64
x::Float64
rating::Float64
discrete_branch_type::DiscreteControlledBranchType
branch_status::DiscreteControlledBranchStatus
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
Used to represent switches and breakers connecting AC Buses
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow::Float64`: Initial condition of active power flow on the line (MW)
- `reactive_power_flow::Float64`: Initial condition of reactive power flow on the line (MVAR)
- `arc::Arc`: An [`Arc`](@ref) defining this line `from` a bus `to` another bus
- `r::Float64`: Resistance in pu ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(0, 4)`
- `x::Float64`: Reactance in pu ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(0, 4)`
- `rating::Float64`: Thermal rating (MVA). Flow on the branch must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to
- `discrete_branch_type::DiscreteControlledBranchType`: (default: `DiscreteControlledBranchType.OTHER`) Type of discrete control
- `branch_status::DiscreteControlledBranchStatus`: (default: `DiscreteControlledBranchStatus.CLOSED`) Open or Close status
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct DiscreteControlledACBranch <: ACTransmission
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial condition of active power flow on the line (MW)"
active_power_flow::Float64
"Initial condition of reactive power flow on the line (MVAR)"
reactive_power_flow::Float64
"An [`Arc`](@ref) defining this line `from` a bus `to` another bus"
arc::Arc
"Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))"
r::Float64
"Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))"
x::Float64
"Thermal rating (MVA). Flow on the branch must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to"
rating::Float64
"Type of discrete control"
discrete_branch_type::DiscreteControlledBranchType
"Open or Close status"
branch_status::DiscreteControlledBranchStatus
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function DiscreteControlledACBranch(name, available, active_power_flow, reactive_power_flow, arc, r, x, rating, discrete_branch_type=DiscreteControlledBranchType.OTHER, branch_status=DiscreteControlledBranchStatus.CLOSED, ext=Dict{String, Any}(), )
DiscreteControlledACBranch(name, available, active_power_flow, reactive_power_flow, arc, r, x, rating, discrete_branch_type, branch_status, ext, InfrastructureSystemsInternal(), )
end
function DiscreteControlledACBranch(; name, available, active_power_flow, reactive_power_flow, arc, r, x, rating, discrete_branch_type=DiscreteControlledBranchType.OTHER, branch_status=DiscreteControlledBranchStatus.CLOSED, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
DiscreteControlledACBranch(name, available, active_power_flow, reactive_power_flow, arc, r, x, rating, discrete_branch_type, branch_status, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function DiscreteControlledACBranch(::Nothing)
DiscreteControlledACBranch(;
name="init",
available=false,
active_power_flow=0.0,
reactive_power_flow=0.0,
arc=Arc(ACBus(nothing), ACBus(nothing)),
r=0.0,
x=0.0,
rating=0.0,
discrete_branch_type=DiscreteControlledBranchType.BREAKER,
branch_status=DiscreteControlledBranchStatus.CLOSED,
ext=Dict{String, Any}(),
)
end
"""Get [`DiscreteControlledACBranch`](@ref) `name`."""
get_name(value::DiscreteControlledACBranch) = value.name
"""Get [`DiscreteControlledACBranch`](@ref) `available`."""
get_available(value::DiscreteControlledACBranch) = value.available
"""Get [`DiscreteControlledACBranch`](@ref) `active_power_flow`."""
get_active_power_flow(value::DiscreteControlledACBranch) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`DiscreteControlledACBranch`](@ref) `reactive_power_flow`."""
get_reactive_power_flow(value::DiscreteControlledACBranch) = get_value(value, Val(:reactive_power_flow), Val(:mva))
"""Get [`DiscreteControlledACBranch`](@ref) `arc`."""
get_arc(value::DiscreteControlledACBranch) = value.arc
"""Get [`DiscreteControlledACBranch`](@ref) `r`."""
get_r(value::DiscreteControlledACBranch) = get_value(value, Val(:r), Val(:ohm))
"""Get [`DiscreteControlledACBranch`](@ref) `x`."""
get_x(value::DiscreteControlledACBranch) = get_value(value, Val(:x), Val(:ohm))
"""Get [`DiscreteControlledACBranch`](@ref) `rating`."""
get_rating(value::DiscreteControlledACBranch) = get_value(value, Val(:rating), Val(:mva))
"""Get [`DiscreteControlledACBranch`](@ref) `discrete_branch_type`."""
get_discrete_branch_type(value::DiscreteControlledACBranch) = value.discrete_branch_type
"""Get [`DiscreteControlledACBranch`](@ref) `branch_status`."""
get_branch_status(value::DiscreteControlledACBranch) = value.branch_status
"""Get [`DiscreteControlledACBranch`](@ref) `ext`."""
get_ext(value::DiscreteControlledACBranch) = value.ext
"""Get [`DiscreteControlledACBranch`](@ref) `internal`."""
get_internal(value::DiscreteControlledACBranch) = value.internal
"""Set [`DiscreteControlledACBranch`](@ref) `available`."""
set_available!(value::DiscreteControlledACBranch, val) = value.available = val
"""Set [`DiscreteControlledACBranch`](@ref) `active_power_flow`."""
set_active_power_flow!(value::DiscreteControlledACBranch, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`DiscreteControlledACBranch`](@ref) `reactive_power_flow`."""
set_reactive_power_flow!(value::DiscreteControlledACBranch, val) = value.reactive_power_flow = set_value(value, Val(:reactive_power_flow), val, Val(:mva))
"""Set [`DiscreteControlledACBranch`](@ref) `arc`."""
set_arc!(value::DiscreteControlledACBranch, val) = value.arc = val
"""Set [`DiscreteControlledACBranch`](@ref) `r`."""
set_r!(value::DiscreteControlledACBranch, val) = value.r = set_value(value, Val(:r), val, Val(:ohm))
"""Set [`DiscreteControlledACBranch`](@ref) `x`."""
set_x!(value::DiscreteControlledACBranch, val) = value.x = set_value(value, Val(:x), val, Val(:ohm))
"""Set [`DiscreteControlledACBranch`](@ref) `rating`."""
set_rating!(value::DiscreteControlledACBranch, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`DiscreteControlledACBranch`](@ref) `discrete_branch_type`."""
set_discrete_branch_type!(value::DiscreteControlledACBranch, val) = value.discrete_branch_type = val
"""Set [`DiscreteControlledACBranch`](@ref) `branch_status`."""
set_branch_status!(value::DiscreteControlledACBranch, val) = value.branch_status = val
"""Set [`DiscreteControlledACBranch`](@ref) `ext`."""
set_ext!(value::DiscreteControlledACBranch, val) = value.ext = val
================================================
FILE: src/models/generated/DynamicExponentialLoad.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct DynamicExponentialLoad <: DynamicInjection
name::String
a::Float64
b::Float64
α::Float64
β::Float64
T_p::Float64
T_q::Float64
ext::Dict{String, Any}
base_power::Float64
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 2-states of a generic dynamic load model based on ["Voltage stability analysis using generic dynamic load models."](https://doi.org/10.1109/59.317575)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `a::Float64`: Active power static exponential coefficient, validation range: `(0, nothing)`
- `b::Float64`: Reactive power static exponential coefficient, validation range: `(0, nothing)`
- `α::Float64`: Active power transient exponential coefficient, validation range: `(0, nothing)`
- `β::Float64`: Reactive power transient exponential coefficient, validation range: `(0, nothing)`
- `T_p::Float64`: Active Power Time Constant, validation range: `(0, nothing)`
- `T_q::Float64`: Reactive Power Time Constant, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `base_power::Float64`: Base power of the load (MVA) for [per unitization](@ref per_unit)
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
x_p: Integrator state of the active power,
x_q: Integrator state of the reactive power,
- `n_states::Int`: (**Do not modify.**) DynamicExponentialLoad has 2 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct DynamicExponentialLoad <: DynamicInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Active power static exponential coefficient"
a::Float64
"Reactive power static exponential coefficient"
b::Float64
"Active power transient exponential coefficient"
α::Float64
"Reactive power transient exponential coefficient"
β::Float64
"Active Power Time Constant"
T_p::Float64
"Reactive Power Time Constant"
T_q::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"Base power of the load (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"(**Do not modify.**) The [states](@ref S) are:
x_p: Integrator state of the active power,
x_q: Integrator state of the reactive power,"
states::Vector{Symbol}
"(**Do not modify.**) DynamicExponentialLoad has 2 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function DynamicExponentialLoad(name, a, b, α, β, T_p, T_q, ext=Dict{String, Any}(), )
DynamicExponentialLoad(name, a, b, α, β, T_p, T_q, ext, 100.0, [:x_p, :x_q], 2, InfrastructureSystemsInternal(), )
end
function DynamicExponentialLoad(; name, a, b, α, β, T_p, T_q, ext=Dict{String, Any}(), base_power=100.0, states=[:x_p, :x_q], n_states=2, internal=InfrastructureSystemsInternal(), )
DynamicExponentialLoad(name, a, b, α, β, T_p, T_q, ext, base_power, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function DynamicExponentialLoad(::Nothing)
DynamicExponentialLoad(;
name="init",
a=0,
b=0,
α=0,
β=0,
T_p=0,
T_q=0,
ext=Dict{String, Any}(),
)
end
"""Get [`DynamicExponentialLoad`](@ref) `name`."""
get_name(value::DynamicExponentialLoad) = value.name
"""Get [`DynamicExponentialLoad`](@ref) `a`."""
get_a(value::DynamicExponentialLoad) = value.a
"""Get [`DynamicExponentialLoad`](@ref) `b`."""
get_b(value::DynamicExponentialLoad) = value.b
"""Get [`DynamicExponentialLoad`](@ref) `α`."""
get_α(value::DynamicExponentialLoad) = value.α
"""Get [`DynamicExponentialLoad`](@ref) `β`."""
get_β(value::DynamicExponentialLoad) = value.β
"""Get [`DynamicExponentialLoad`](@ref) `T_p`."""
get_T_p(value::DynamicExponentialLoad) = value.T_p
"""Get [`DynamicExponentialLoad`](@ref) `T_q`."""
get_T_q(value::DynamicExponentialLoad) = value.T_q
"""Get [`DynamicExponentialLoad`](@ref) `ext`."""
get_ext(value::DynamicExponentialLoad) = value.ext
"""Get [`DynamicExponentialLoad`](@ref) `base_power`."""
get_base_power(value::DynamicExponentialLoad) = value.base_power
"""Get [`DynamicExponentialLoad`](@ref) `states`."""
get_states(value::DynamicExponentialLoad) = value.states
"""Get [`DynamicExponentialLoad`](@ref) `n_states`."""
get_n_states(value::DynamicExponentialLoad) = value.n_states
"""Get [`DynamicExponentialLoad`](@ref) `internal`."""
get_internal(value::DynamicExponentialLoad) = value.internal
"""Set [`DynamicExponentialLoad`](@ref) `a`."""
set_a!(value::DynamicExponentialLoad, val) = value.a = val
"""Set [`DynamicExponentialLoad`](@ref) `b`."""
set_b!(value::DynamicExponentialLoad, val) = value.b = val
"""Set [`DynamicExponentialLoad`](@ref) `α`."""
set_α!(value::DynamicExponentialLoad, val) = value.α = val
"""Set [`DynamicExponentialLoad`](@ref) `β`."""
set_β!(value::DynamicExponentialLoad, val) = value.β = val
"""Set [`DynamicExponentialLoad`](@ref) `T_p`."""
set_T_p!(value::DynamicExponentialLoad, val) = value.T_p = val
"""Set [`DynamicExponentialLoad`](@ref) `T_q`."""
set_T_q!(value::DynamicExponentialLoad, val) = value.T_q = val
"""Set [`DynamicExponentialLoad`](@ref) `ext`."""
set_ext!(value::DynamicExponentialLoad, val) = value.ext = val
"""Set [`DynamicExponentialLoad`](@ref) `base_power`."""
set_base_power!(value::DynamicExponentialLoad, val) = value.base_power = val
================================================
FILE: src/models/generated/ESAC1A.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ESAC1A <: AVR
Tr::Float64
Tb::Float64
Tc::Float64
Ka::Float64
Ta::Float64
Va_lim::MinMax
Te::Float64
Kf::Float64
Tf::Float64
Kc::Float64
Kd::Float64
Ke::Float64
E_sat::Tuple{Float64, Float64}
Se::Tuple{Float64, Float64}
Vr_lim::MinMax
V_ref::Float64
saturation_coeffs::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
This excitation systems consists of an alternator main exciter feeding its output via non-controlled rectifiers.
The exciter does not employ self-excitation, and the voltage regulator power is taken from a source that is not affected by external transients.
Parameters of IEEE Std 421.5 Type AC1A Excitacion System. This model corresponds to ESAC1A in PSSE and PSLF
# Arguments
- `Tr::Float64`: Regulator input filter time constant in s, validation range: `(0, 0.5)`
- `Tb::Float64`: Regulator denominator (lag) time constant in s, validation range: `(0, 20)`
- `Tc::Float64`: Regulator numerator (lead) time constant in s, validation range: `(0, 20)`
- `Ka::Float64`: Regulator output gain, validation range: `(0, 1000)`
- `Ta::Float64`: Regulator output time constant in s, validation range: `(0, 10)`
- `Va_lim::MinMax`: Limits for regulator output `(Va_min, Va_max)`
- `Te::Float64`: Exciter field time constant in s, validation range: `(eps(), 2)`
- `Kf::Float64`: Rate feedback excitation system stabilizer gain, validation range: `(0, 0.3)`
- `Tf::Float64`: Rate feedback time constant, validation range: `(eps(), 1.5)`
- `Kc::Float64`: Rectifier loading factor proportional to commutating reactance, validation range: `(0, 1)`
- `Kd::Float64`: Demagnetizing factor, function of exciter alternator reactances, validation range: `(0, 1)`
- `Ke::Float64`: Exciter field proportional constant, validation range: `(0, 1)`
- `E_sat::Tuple{Float64, Float64}`: Exciter output voltage for saturation factor: (E1, E2)
- `Se::Tuple{Float64, Float64}`: Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))
- `Vr_lim::MinMax`: Limits for exciter field voltage: `(Vr_min, Vr_max)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `saturation_coeffs::Tuple{Float64, Float64}`: (default: `PowerSystems.get_avr_saturation(E_sat, Se)`) (**Do not modify.**) Coefficients (A,B) of the function: Se(x) = B(x - A)^2/x
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: Lead-lag state,
Vr2: Regulator output state,
Ve: Integrator output state,
Vr3: Feedback output state
- `n_states::Int`: (**Do not modify.**) ESAC1A has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) ESAC1A has 5 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ESAC1A <: AVR
"Regulator input filter time constant in s"
Tr::Float64
"Regulator denominator (lag) time constant in s"
Tb::Float64
"Regulator numerator (lead) time constant in s"
Tc::Float64
"Regulator output gain"
Ka::Float64
"Regulator output time constant in s"
Ta::Float64
"Limits for regulator output `(Va_min, Va_max)`"
Va_lim::MinMax
"Exciter field time constant in s"
Te::Float64
"Rate feedback excitation system stabilizer gain"
Kf::Float64
"Rate feedback time constant"
Tf::Float64
"Rectifier loading factor proportional to commutating reactance"
Kc::Float64
"Demagnetizing factor, function of exciter alternator reactances"
Kd::Float64
"Exciter field proportional constant"
Ke::Float64
"Exciter output voltage for saturation factor: (E1, E2)"
E_sat::Tuple{Float64, Float64}
"Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))"
Se::Tuple{Float64, Float64}
"Limits for exciter field voltage: `(Vr_min, Vr_max)`"
Vr_lim::MinMax
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Coefficients (A,B) of the function: Se(x) = B(x - A)^2/x"
saturation_coeffs::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: Lead-lag state,
Vr2: Regulator output state,
Ve: Integrator output state,
Vr3: Feedback output state"
states::Vector{Symbol}
"(**Do not modify.**) ESAC1A has 5 states"
n_states::Int
"(**Do not modify.**) ESAC1A has 5 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ESAC1A(Tr, Tb, Tc, Ka, Ta, Va_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, Vr_lim, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), )
ESAC1A(Tr, Tb, Tc, Ka, Ta, Va_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, Vr_lim, V_ref, saturation_coeffs, ext, [:Vm, :Vr1, :Vr2, :Ve, :Vr3], 5, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function ESAC1A(; Tr, Tb, Tc, Ka, Ta, Va_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, Vr_lim, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), states=[:Vm, :Vr1, :Vr2, :Ve, :Vr3], n_states=5, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
ESAC1A(Tr, Tb, Tc, Ka, Ta, Va_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, Vr_lim, V_ref, saturation_coeffs, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function ESAC1A(::Nothing)
ESAC1A(;
Tr=0,
Tb=0,
Tc=0,
Ka=0,
Ta=0,
Va_lim=(min=0.0, max=0.0),
Te=0,
Kf=0,
Tf=0,
Kc=0,
Kd=0,
Ke=0,
E_sat=(0.0, 0.0),
Se=(0.0, 0.0),
Vr_lim=(min=0.0, max=0.0),
V_ref=0,
saturation_coeffs=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`ESAC1A`](@ref) `Tr`."""
get_Tr(value::ESAC1A) = value.Tr
"""Get [`ESAC1A`](@ref) `Tb`."""
get_Tb(value::ESAC1A) = value.Tb
"""Get [`ESAC1A`](@ref) `Tc`."""
get_Tc(value::ESAC1A) = value.Tc
"""Get [`ESAC1A`](@ref) `Ka`."""
get_Ka(value::ESAC1A) = value.Ka
"""Get [`ESAC1A`](@ref) `Ta`."""
get_Ta(value::ESAC1A) = value.Ta
"""Get [`ESAC1A`](@ref) `Va_lim`."""
get_Va_lim(value::ESAC1A) = value.Va_lim
"""Get [`ESAC1A`](@ref) `Te`."""
get_Te(value::ESAC1A) = value.Te
"""Get [`ESAC1A`](@ref) `Kf`."""
get_Kf(value::ESAC1A) = value.Kf
"""Get [`ESAC1A`](@ref) `Tf`."""
get_Tf(value::ESAC1A) = value.Tf
"""Get [`ESAC1A`](@ref) `Kc`."""
get_Kc(value::ESAC1A) = value.Kc
"""Get [`ESAC1A`](@ref) `Kd`."""
get_Kd(value::ESAC1A) = value.Kd
"""Get [`ESAC1A`](@ref) `Ke`."""
get_Ke(value::ESAC1A) = value.Ke
"""Get [`ESAC1A`](@ref) `E_sat`."""
get_E_sat(value::ESAC1A) = value.E_sat
"""Get [`ESAC1A`](@ref) `Se`."""
get_Se(value::ESAC1A) = value.Se
"""Get [`ESAC1A`](@ref) `Vr_lim`."""
get_Vr_lim(value::ESAC1A) = value.Vr_lim
"""Get [`ESAC1A`](@ref) `V_ref`."""
get_V_ref(value::ESAC1A) = value.V_ref
"""Get [`ESAC1A`](@ref) `saturation_coeffs`."""
get_saturation_coeffs(value::ESAC1A) = value.saturation_coeffs
"""Get [`ESAC1A`](@ref) `ext`."""
get_ext(value::ESAC1A) = value.ext
"""Get [`ESAC1A`](@ref) `states`."""
get_states(value::ESAC1A) = value.states
"""Get [`ESAC1A`](@ref) `n_states`."""
get_n_states(value::ESAC1A) = value.n_states
"""Get [`ESAC1A`](@ref) `states_types`."""
get_states_types(value::ESAC1A) = value.states_types
"""Get [`ESAC1A`](@ref) `internal`."""
get_internal(value::ESAC1A) = value.internal
"""Set [`ESAC1A`](@ref) `Tr`."""
set_Tr!(value::ESAC1A, val) = value.Tr = val
"""Set [`ESAC1A`](@ref) `Tb`."""
set_Tb!(value::ESAC1A, val) = value.Tb = val
"""Set [`ESAC1A`](@ref) `Tc`."""
set_Tc!(value::ESAC1A, val) = value.Tc = val
"""Set [`ESAC1A`](@ref) `Ka`."""
set_Ka!(value::ESAC1A, val) = value.Ka = val
"""Set [`ESAC1A`](@ref) `Ta`."""
set_Ta!(value::ESAC1A, val) = value.Ta = val
"""Set [`ESAC1A`](@ref) `Va_lim`."""
set_Va_lim!(value::ESAC1A, val) = value.Va_lim = val
"""Set [`ESAC1A`](@ref) `Te`."""
set_Te!(value::ESAC1A, val) = value.Te = val
"""Set [`ESAC1A`](@ref) `Kf`."""
set_Kf!(value::ESAC1A, val) = value.Kf = val
"""Set [`ESAC1A`](@ref) `Tf`."""
set_Tf!(value::ESAC1A, val) = value.Tf = val
"""Set [`ESAC1A`](@ref) `Kc`."""
set_Kc!(value::ESAC1A, val) = value.Kc = val
"""Set [`ESAC1A`](@ref) `Kd`."""
set_Kd!(value::ESAC1A, val) = value.Kd = val
"""Set [`ESAC1A`](@ref) `Ke`."""
set_Ke!(value::ESAC1A, val) = value.Ke = val
"""Set [`ESAC1A`](@ref) `E_sat`."""
set_E_sat!(value::ESAC1A, val) = value.E_sat = val
"""Set [`ESAC1A`](@ref) `Se`."""
set_Se!(value::ESAC1A, val) = value.Se = val
"""Set [`ESAC1A`](@ref) `Vr_lim`."""
set_Vr_lim!(value::ESAC1A, val) = value.Vr_lim = val
"""Set [`ESAC1A`](@ref) `V_ref`."""
set_V_ref!(value::ESAC1A, val) = value.V_ref = val
"""Set [`ESAC1A`](@ref) `saturation_coeffs`."""
set_saturation_coeffs!(value::ESAC1A, val) = value.saturation_coeffs = val
"""Set [`ESAC1A`](@ref) `ext`."""
set_ext!(value::ESAC1A, val) = value.ext = val
"""Set [`ESAC1A`](@ref) `states_types`."""
set_states_types!(value::ESAC1A, val) = value.states_types = val
================================================
FILE: src/models/generated/ESAC6A.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ESAC6A <: AVR
Tr::Float64
Ka::Float64
Ta::Float64
Tk::Float64
Tb::Float64
Tc::Float64
Va_lim::MinMax
Vr_lim::MinMax
Te::Float64
VFE_lim::Float64
Kh::Float64
VH_max::Float64
Th::Float64
Tj::Float64
Kc::Float64
Kd::Float64
Ke::Float64
E_sat::Tuple{Float64, Float64}
Se::Tuple{Float64, Float64}
V_ref::Float64
saturation_coeffs::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Modified AC6A. Used to represent field-controlled alternator-rectifier excitation systems with system-supplied electronic voltage regulators.
Parameters of IEEE Std 421.5 Type AC6A Excitacion System. ESAC6A in PSSE and PSLF
# Arguments
- `Tr::Float64`: Regulator input filter time constant in s, validation range: `(0, 0.5)`
- `Ka::Float64`: Regulator output gain, validation range: `(0, 1000)`
- `Ta::Float64`: Regulator output lag time constant in s, validation range: `(0, 10)`
- `Tk::Float64`: Voltage Regulator lead time constant, validation range: `(0, 10)`
- `Tb::Float64`: Regulator denominator (lag) time constant in s, validation range: `(0, 20)`
- `Tc::Float64`: Regulator numerator (lead) time constant in s, validation range: `(0, 20)`
- `Va_lim::MinMax`: Limits for regulator output `(Va_min, Va_max)`
- `Vr_lim::MinMax`: Limits for exciter field voltage `(Vr_min, Vr_max)`
- `Te::Float64`: Exciter field time constant, validation range: `(eps(), 2)`
- `VFE_lim::Float64`: Exciter field current limiter reference, validation range: `(-5, 20)`
- `Kh::Float64`: Exciter field current regulator feedback gain, validation range: `(0, 100)`
- `VH_max::Float64`: Exciter field current limiter maximum output, validation range: `(0, 100)`
- `Th::Float64`: Exciter field current limiter denominator (lag) time constant, validation range: `(0, 1)`
- `Tj::Float64`: Exciter field current limiter numerator (lead) time constant, validation range: `(0, 1)`
- `Kc::Float64`: Rectifier loading factor proportional to commutating reactance, validation range: `(0, 1)`
- `Kd::Float64`: Demagnetizing factor, function of exciter alternator reactances, validation range: `(0, 2)`
- `Ke::Float64`: Exciter field proportional constant, validation range: `(0, 2)`
- `E_sat::Tuple{Float64, Float64}`: Exciter output voltage for saturation factor: (E1, E2)
- `Se::Tuple{Float64, Float64}`: Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `saturation_coeffs::Tuple{Float64, Float64}`: (default: `PowerSystems.get_avr_saturation(E_sat, Se)`) (**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: Lead-lag state,
Vr2: Regulator output state,
Ve: Integrator output state,
Vr3: Feedback output state
- `n_states::Int`: (**Do not modify.**) ESAC6A has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) ESAC6A has 5 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ESAC6A <: AVR
"Regulator input filter time constant in s"
Tr::Float64
"Regulator output gain"
Ka::Float64
"Regulator output lag time constant in s"
Ta::Float64
"Voltage Regulator lead time constant"
Tk::Float64
"Regulator denominator (lag) time constant in s"
Tb::Float64
"Regulator numerator (lead) time constant in s"
Tc::Float64
"Limits for regulator output `(Va_min, Va_max)`"
Va_lim::MinMax
"Limits for exciter field voltage `(Vr_min, Vr_max)`"
Vr_lim::MinMax
"Exciter field time constant"
Te::Float64
"Exciter field current limiter reference"
VFE_lim::Float64
"Exciter field current regulator feedback gain"
Kh::Float64
"Exciter field current limiter maximum output"
VH_max::Float64
"Exciter field current limiter denominator (lag) time constant"
Th::Float64
"Exciter field current limiter numerator (lead) time constant"
Tj::Float64
"Rectifier loading factor proportional to commutating reactance"
Kc::Float64
"Demagnetizing factor, function of exciter alternator reactances"
Kd::Float64
"Exciter field proportional constant"
Ke::Float64
"Exciter output voltage for saturation factor: (E1, E2)"
E_sat::Tuple{Float64, Float64}
"Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))"
Se::Tuple{Float64, Float64}
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V"
saturation_coeffs::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: Lead-lag state,
Vr2: Regulator output state,
Ve: Integrator output state,
Vr3: Feedback output state"
states::Vector{Symbol}
"(**Do not modify.**) ESAC6A has 5 states"
n_states::Int
"(**Do not modify.**) ESAC6A has 5 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ESAC6A(Tr, Ka, Ta, Tk, Tb, Tc, Va_lim, Vr_lim, Te, VFE_lim, Kh, VH_max, Th, Tj, Kc, Kd, Ke, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), )
ESAC6A(Tr, Ka, Ta, Tk, Tb, Tc, Va_lim, Vr_lim, Te, VFE_lim, Kh, VH_max, Th, Tj, Kc, Kd, Ke, E_sat, Se, V_ref, saturation_coeffs, ext, [:Vm, :Vr1, :Vr2, :Ve, :Vr3], 5, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Hybrid], InfrastructureSystemsInternal(), )
end
function ESAC6A(; Tr, Ka, Ta, Tk, Tb, Tc, Va_lim, Vr_lim, Te, VFE_lim, Kh, VH_max, Th, Tj, Kc, Kd, Ke, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), states=[:Vm, :Vr1, :Vr2, :Ve, :Vr3], n_states=5, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Hybrid], internal=InfrastructureSystemsInternal(), )
ESAC6A(Tr, Ka, Ta, Tk, Tb, Tc, Va_lim, Vr_lim, Te, VFE_lim, Kh, VH_max, Th, Tj, Kc, Kd, Ke, E_sat, Se, V_ref, saturation_coeffs, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function ESAC6A(::Nothing)
ESAC6A(;
Tr=0,
Ka=0,
Ta=0,
Tk=0,
Tb=0,
Tc=0,
Va_lim=(min=0.0, max=0.0),
Vr_lim=(min=0.0, max=0.0),
Te=0,
VFE_lim=0,
Kh=0,
VH_max=0,
Th=0,
Tj=0,
Kc=0,
Kd=0,
Ke=0,
E_sat=(0.0, 0.0),
Se=(0.0, 0.0),
V_ref=0,
saturation_coeffs=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`ESAC6A`](@ref) `Tr`."""
get_Tr(value::ESAC6A) = value.Tr
"""Get [`ESAC6A`](@ref) `Ka`."""
get_Ka(value::ESAC6A) = value.Ka
"""Get [`ESAC6A`](@ref) `Ta`."""
get_Ta(value::ESAC6A) = value.Ta
"""Get [`ESAC6A`](@ref) `Tk`."""
get_Tk(value::ESAC6A) = value.Tk
"""Get [`ESAC6A`](@ref) `Tb`."""
get_Tb(value::ESAC6A) = value.Tb
"""Get [`ESAC6A`](@ref) `Tc`."""
get_Tc(value::ESAC6A) = value.Tc
"""Get [`ESAC6A`](@ref) `Va_lim`."""
get_Va_lim(value::ESAC6A) = value.Va_lim
"""Get [`ESAC6A`](@ref) `Vr_lim`."""
get_Vr_lim(value::ESAC6A) = value.Vr_lim
"""Get [`ESAC6A`](@ref) `Te`."""
get_Te(value::ESAC6A) = value.Te
"""Get [`ESAC6A`](@ref) `VFE_lim`."""
get_VFE_lim(value::ESAC6A) = value.VFE_lim
"""Get [`ESAC6A`](@ref) `Kh`."""
get_Kh(value::ESAC6A) = value.Kh
"""Get [`ESAC6A`](@ref) `VH_max`."""
get_VH_max(value::ESAC6A) = value.VH_max
"""Get [`ESAC6A`](@ref) `Th`."""
get_Th(value::ESAC6A) = value.Th
"""Get [`ESAC6A`](@ref) `Tj`."""
get_Tj(value::ESAC6A) = value.Tj
"""Get [`ESAC6A`](@ref) `Kc`."""
get_Kc(value::ESAC6A) = value.Kc
"""Get [`ESAC6A`](@ref) `Kd`."""
get_Kd(value::ESAC6A) = value.Kd
"""Get [`ESAC6A`](@ref) `Ke`."""
get_Ke(value::ESAC6A) = value.Ke
"""Get [`ESAC6A`](@ref) `E_sat`."""
get_E_sat(value::ESAC6A) = value.E_sat
"""Get [`ESAC6A`](@ref) `Se`."""
get_Se(value::ESAC6A) = value.Se
"""Get [`ESAC6A`](@ref) `V_ref`."""
get_V_ref(value::ESAC6A) = value.V_ref
"""Get [`ESAC6A`](@ref) `saturation_coeffs`."""
get_saturation_coeffs(value::ESAC6A) = value.saturation_coeffs
"""Get [`ESAC6A`](@ref) `ext`."""
get_ext(value::ESAC6A) = value.ext
"""Get [`ESAC6A`](@ref) `states`."""
get_states(value::ESAC6A) = value.states
"""Get [`ESAC6A`](@ref) `n_states`."""
get_n_states(value::ESAC6A) = value.n_states
"""Get [`ESAC6A`](@ref) `states_types`."""
get_states_types(value::ESAC6A) = value.states_types
"""Get [`ESAC6A`](@ref) `internal`."""
get_internal(value::ESAC6A) = value.internal
"""Set [`ESAC6A`](@ref) `Tr`."""
set_Tr!(value::ESAC6A, val) = value.Tr = val
"""Set [`ESAC6A`](@ref) `Ka`."""
set_Ka!(value::ESAC6A, val) = value.Ka = val
"""Set [`ESAC6A`](@ref) `Ta`."""
set_Ta!(value::ESAC6A, val) = value.Ta = val
"""Set [`ESAC6A`](@ref) `Tk`."""
set_Tk!(value::ESAC6A, val) = value.Tk = val
"""Set [`ESAC6A`](@ref) `Tb`."""
set_Tb!(value::ESAC6A, val) = value.Tb = val
"""Set [`ESAC6A`](@ref) `Tc`."""
set_Tc!(value::ESAC6A, val) = value.Tc = val
"""Set [`ESAC6A`](@ref) `Va_lim`."""
set_Va_lim!(value::ESAC6A, val) = value.Va_lim = val
"""Set [`ESAC6A`](@ref) `Vr_lim`."""
set_Vr_lim!(value::ESAC6A, val) = value.Vr_lim = val
"""Set [`ESAC6A`](@ref) `Te`."""
set_Te!(value::ESAC6A, val) = value.Te = val
"""Set [`ESAC6A`](@ref) `VFE_lim`."""
set_VFE_lim!(value::ESAC6A, val) = value.VFE_lim = val
"""Set [`ESAC6A`](@ref) `Kh`."""
set_Kh!(value::ESAC6A, val) = value.Kh = val
"""Set [`ESAC6A`](@ref) `VH_max`."""
set_VH_max!(value::ESAC6A, val) = value.VH_max = val
"""Set [`ESAC6A`](@ref) `Th`."""
set_Th!(value::ESAC6A, val) = value.Th = val
"""Set [`ESAC6A`](@ref) `Tj`."""
set_Tj!(value::ESAC6A, val) = value.Tj = val
"""Set [`ESAC6A`](@ref) `Kc`."""
set_Kc!(value::ESAC6A, val) = value.Kc = val
"""Set [`ESAC6A`](@ref) `Kd`."""
set_Kd!(value::ESAC6A, val) = value.Kd = val
"""Set [`ESAC6A`](@ref) `Ke`."""
set_Ke!(value::ESAC6A, val) = value.Ke = val
"""Set [`ESAC6A`](@ref) `E_sat`."""
set_E_sat!(value::ESAC6A, val) = value.E_sat = val
"""Set [`ESAC6A`](@ref) `Se`."""
set_Se!(value::ESAC6A, val) = value.Se = val
"""Set [`ESAC6A`](@ref) `V_ref`."""
set_V_ref!(value::ESAC6A, val) = value.V_ref = val
"""Set [`ESAC6A`](@ref) `saturation_coeffs`."""
set_saturation_coeffs!(value::ESAC6A, val) = value.saturation_coeffs = val
"""Set [`ESAC6A`](@ref) `ext`."""
set_ext!(value::ESAC6A, val) = value.ext = val
"""Set [`ESAC6A`](@ref) `states_types`."""
set_states_types!(value::ESAC6A, val) = value.states_types = val
================================================
FILE: src/models/generated/ESAC8B.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ESAC8B <: AVR
Tr::Float64
Kp::Float64
Ki::Float64
Kd::Float64
Td::Float64
Ka::Float64
Ta::Float64
Vr_lim::MinMax
Te::Float64
Ke::Float64
E_sat::Tuple{Float64, Float64}
Se::Tuple{Float64, Float64}
V_ref::Float64
saturation_coeffs::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Excitation System AC8B. Used to represent the Basler Digital Excitation Control System (DECS) with PID controller in PSSE.
# Arguments
- `Tr::Float64`: Regulator input filter time constant in s, validation range: `(0, nothing)`
- `Kp::Float64`: Regulator proportional PID gain, validation range: `(0, nothing)`
- `Ki::Float64`: Regulator integral PID gain, validation range: `(0, nothing)`
- `Kd::Float64`: Regulator derivative PID gain, validation range: `(0, nothing)`
- `Td::Float64`: Regulator derivative PID time constant., validation range: `(0, 10)`
- `Ka::Float64`: Regulator output gain, validation range: `(0, 1000)`
- `Ta::Float64`: Regulator output lag time constant in s, validation range: `(0, 10)`
- `Vr_lim::MinMax`: Limits for exciter field voltage `(Vr_min, Vr_max)`
- `Te::Float64`: Exciter field time constant, validation range: `(eps(), 2)`
- `Ke::Float64`: Exciter field proportional constant, validation range: `(0, 2)`
- `E_sat::Tuple{Float64, Float64}`: Exciter output voltage for saturation factor: (E1, E2)
- `Se::Tuple{Float64, Float64}`: Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `saturation_coeffs::Tuple{Float64, Float64}`: (default: `PowerSystems.get_avr_saturation(E_sat, Se)`) (**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
x_i: Internal PI-block state,
x_d: Internal Derivative-block state,
Vr: Voltage regulator state,
Efd: Exciter output state
- `n_states::Int`: (**Do not modify.**) ESAC8B has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) ESAC8B has 5 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ESAC8B <: AVR
"Regulator input filter time constant in s"
Tr::Float64
"Regulator proportional PID gain"
Kp::Float64
"Regulator integral PID gain"
Ki::Float64
"Regulator derivative PID gain"
Kd::Float64
"Regulator derivative PID time constant."
Td::Float64
"Regulator output gain"
Ka::Float64
"Regulator output lag time constant in s"
Ta::Float64
"Limits for exciter field voltage `(Vr_min, Vr_max)`"
Vr_lim::MinMax
"Exciter field time constant"
Te::Float64
"Exciter field proportional constant"
Ke::Float64
"Exciter output voltage for saturation factor: (E1, E2)"
E_sat::Tuple{Float64, Float64}
"Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))"
Se::Tuple{Float64, Float64}
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V"
saturation_coeffs::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
x_i: Internal PI-block state,
x_d: Internal Derivative-block state,
Vr: Voltage regulator state,
Efd: Exciter output state"
states::Vector{Symbol}
"(**Do not modify.**) ESAC8B has 5 states"
n_states::Int
"(**Do not modify.**) ESAC8B has 5 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ESAC8B(Tr, Kp, Ki, Kd, Td, Ka, Ta, Vr_lim, Te, Ke, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), )
ESAC8B(Tr, Kp, Ki, Kd, Td, Ka, Ta, Vr_lim, Te, Ke, E_sat, Se, V_ref, saturation_coeffs, ext, [:Vm, :x_i, :x_d, :Vr, :Efd], 5, [StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential, StateTypes.Hybrid, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function ESAC8B(; Tr, Kp, Ki, Kd, Td, Ka, Ta, Vr_lim, Te, Ke, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), states=[:Vm, :x_i, :x_d, :Vr, :Efd], n_states=5, states_types=[StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential, StateTypes.Hybrid, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
ESAC8B(Tr, Kp, Ki, Kd, Td, Ka, Ta, Vr_lim, Te, Ke, E_sat, Se, V_ref, saturation_coeffs, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function ESAC8B(::Nothing)
ESAC8B(;
Tr=0,
Kp=0,
Ki=0,
Kd=0,
Td=0,
Ka=0,
Ta=0,
Vr_lim=(min=0.0, max=0.0),
Te=0,
Ke=0,
E_sat=(0.0, 0.0),
Se=(0.0, 0.0),
V_ref=0,
saturation_coeffs=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`ESAC8B`](@ref) `Tr`."""
get_Tr(value::ESAC8B) = value.Tr
"""Get [`ESAC8B`](@ref) `Kp`."""
get_Kp(value::ESAC8B) = value.Kp
"""Get [`ESAC8B`](@ref) `Ki`."""
get_Ki(value::ESAC8B) = value.Ki
"""Get [`ESAC8B`](@ref) `Kd`."""
get_Kd(value::ESAC8B) = value.Kd
"""Get [`ESAC8B`](@ref) `Td`."""
get_Td(value::ESAC8B) = value.Td
"""Get [`ESAC8B`](@ref) `Ka`."""
get_Ka(value::ESAC8B) = value.Ka
"""Get [`ESAC8B`](@ref) `Ta`."""
get_Ta(value::ESAC8B) = value.Ta
"""Get [`ESAC8B`](@ref) `Vr_lim`."""
get_Vr_lim(value::ESAC8B) = value.Vr_lim
"""Get [`ESAC8B`](@ref) `Te`."""
get_Te(value::ESAC8B) = value.Te
"""Get [`ESAC8B`](@ref) `Ke`."""
get_Ke(value::ESAC8B) = value.Ke
"""Get [`ESAC8B`](@ref) `E_sat`."""
get_E_sat(value::ESAC8B) = value.E_sat
"""Get [`ESAC8B`](@ref) `Se`."""
get_Se(value::ESAC8B) = value.Se
"""Get [`ESAC8B`](@ref) `V_ref`."""
get_V_ref(value::ESAC8B) = value.V_ref
"""Get [`ESAC8B`](@ref) `saturation_coeffs`."""
get_saturation_coeffs(value::ESAC8B) = value.saturation_coeffs
"""Get [`ESAC8B`](@ref) `ext`."""
get_ext(value::ESAC8B) = value.ext
"""Get [`ESAC8B`](@ref) `states`."""
get_states(value::ESAC8B) = value.states
"""Get [`ESAC8B`](@ref) `n_states`."""
get_n_states(value::ESAC8B) = value.n_states
"""Get [`ESAC8B`](@ref) `states_types`."""
get_states_types(value::ESAC8B) = value.states_types
"""Get [`ESAC8B`](@ref) `internal`."""
get_internal(value::ESAC8B) = value.internal
"""Set [`ESAC8B`](@ref) `Tr`."""
set_Tr!(value::ESAC8B, val) = value.Tr = val
"""Set [`ESAC8B`](@ref) `Kp`."""
set_Kp!(value::ESAC8B, val) = value.Kp = val
"""Set [`ESAC8B`](@ref) `Ki`."""
set_Ki!(value::ESAC8B, val) = value.Ki = val
"""Set [`ESAC8B`](@ref) `Kd`."""
set_Kd!(value::ESAC8B, val) = value.Kd = val
"""Set [`ESAC8B`](@ref) `Td`."""
set_Td!(value::ESAC8B, val) = value.Td = val
"""Set [`ESAC8B`](@ref) `Ka`."""
set_Ka!(value::ESAC8B, val) = value.Ka = val
"""Set [`ESAC8B`](@ref) `Ta`."""
set_Ta!(value::ESAC8B, val) = value.Ta = val
"""Set [`ESAC8B`](@ref) `Vr_lim`."""
set_Vr_lim!(value::ESAC8B, val) = value.Vr_lim = val
"""Set [`ESAC8B`](@ref) `Te`."""
set_Te!(value::ESAC8B, val) = value.Te = val
"""Set [`ESAC8B`](@ref) `Ke`."""
set_Ke!(value::ESAC8B, val) = value.Ke = val
"""Set [`ESAC8B`](@ref) `E_sat`."""
set_E_sat!(value::ESAC8B, val) = value.E_sat = val
"""Set [`ESAC8B`](@ref) `Se`."""
set_Se!(value::ESAC8B, val) = value.Se = val
"""Set [`ESAC8B`](@ref) `V_ref`."""
set_V_ref!(value::ESAC8B, val) = value.V_ref = val
"""Set [`ESAC8B`](@ref) `saturation_coeffs`."""
set_saturation_coeffs!(value::ESAC8B, val) = value.saturation_coeffs = val
"""Set [`ESAC8B`](@ref) `ext`."""
set_ext!(value::ESAC8B, val) = value.ext = val
"""Set [`ESAC8B`](@ref) `states_types`."""
set_states_types!(value::ESAC8B, val) = value.states_types = val
================================================
FILE: src/models/generated/ESDC1A.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ESDC1A <: AVR
Tr::Float64
Ka::Float64
Ta::Float64
Tb::Float64
Tc::Float64
Vr_lim::MinMax
Ke::Float64
Te::Float64
Kf::Float64
Tf::Float64
switch::Int
E_sat::Tuple{Float64, Float64}
Se::Tuple{Float64, Float64}
V_ref::Float64
saturation_coeffs::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Self-excited shunt fields with the voltage regulator operating in a mode commonly termed buck-boost.
Parameters of IEEE Std 421.5 Type DC1A Excitacion System. This model corresponds to ESDC1A in PSSE and PSLF
# Arguments
- `Tr::Float64`: Voltage Measurement Time Constant in s, validation range: `(0, 0.5)`
- `Ka::Float64`: Amplifier Gain, validation range: `(10, 500)`
- `Ta::Float64`: Amplifier Time Constant in s, validation range: `(0, 1)`
- `Tb::Float64`: Regulator input Time Constant in s, validation range: `(0, nothing)`
- `Tc::Float64`: Regulator input Time Constant in s, validation range: `(0, nothing)`
- `Vr_lim::MinMax`: Voltage regulator limits (regulator output) (Vi_min, Vi_max)
- `Ke::Float64`: Exciter constant related to self-excited field, validation range: `(0, nothing)`
- `Te::Float64`: Exciter time constant, integration rate associated with exciter control, validation range: `(eps(), 1)`
- `Kf::Float64`: Excitation control system stabilizer gain, validation range: `(eps(), 0.3)`
- `Tf::Float64`: Excitation control system stabilizer time constant, validation range: `(eps(), nothing)`
- `switch::Int`: Switch, validation range: `(0, 1)`
- `E_sat::Tuple{Float64, Float64}`: Exciter output voltage for saturation factor: (E1, E2)
- `Se::Tuple{Float64, Float64}`: Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `saturation_coeffs::Tuple{Float64, Float64}`: (default: `PowerSystems.get_avr_saturation(E_sat, Se)`) (**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vt: Terminal Voltage,
Vr1: input lead lag,
Vr2: Regulator Output,
Vf: Exciter Output,
Vr3: Rate feedback integrator
- `n_states::Int`: (**Do not modify.**) The ESDC1A has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) ESDC1A has 5 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ESDC1A <: AVR
"Voltage Measurement Time Constant in s"
Tr::Float64
"Amplifier Gain"
Ka::Float64
"Amplifier Time Constant in s"
Ta::Float64
"Regulator input Time Constant in s"
Tb::Float64
"Regulator input Time Constant in s"
Tc::Float64
"Voltage regulator limits (regulator output) (Vi_min, Vi_max)"
Vr_lim::MinMax
"Exciter constant related to self-excited field"
Ke::Float64
"Exciter time constant, integration rate associated with exciter control"
Te::Float64
"Excitation control system stabilizer gain"
Kf::Float64
"Excitation control system stabilizer time constant"
Tf::Float64
"Switch"
switch::Int
"Exciter output voltage for saturation factor: (E1, E2)"
E_sat::Tuple{Float64, Float64}
"Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))"
Se::Tuple{Float64, Float64}
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V"
saturation_coeffs::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vt: Terminal Voltage,
Vr1: input lead lag,
Vr2: Regulator Output,
Vf: Exciter Output,
Vr3: Rate feedback integrator"
states::Vector{Symbol}
"(**Do not modify.**) The ESDC1A has 5 states"
n_states::Int
"(**Do not modify.**) ESDC1A has 5 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ESDC1A(Tr, Ka, Ta, Tb, Tc, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), )
ESDC1A(Tr, Ka, Ta, Tb, Tc, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref, saturation_coeffs, ext, [:Vt, :Vr1, :Vr2, :Vf, :Vr3], 5, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function ESDC1A(; Tr, Ka, Ta, Tb, Tc, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), states=[:Vt, :Vr1, :Vr2, :Vf, :Vr3], n_states=5, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
ESDC1A(Tr, Ka, Ta, Tb, Tc, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref, saturation_coeffs, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function ESDC1A(::Nothing)
ESDC1A(;
Tr=0,
Ka=0,
Ta=0,
Tb=0,
Tc=0,
Vr_lim=(min=0.0, max=0.0),
Ke=0,
Te=0,
Kf=0,
Tf=0,
switch=0,
E_sat=(0.0, 0.0),
Se=(0.0, 0.0),
V_ref=0,
saturation_coeffs=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`ESDC1A`](@ref) `Tr`."""
get_Tr(value::ESDC1A) = value.Tr
"""Get [`ESDC1A`](@ref) `Ka`."""
get_Ka(value::ESDC1A) = value.Ka
"""Get [`ESDC1A`](@ref) `Ta`."""
get_Ta(value::ESDC1A) = value.Ta
"""Get [`ESDC1A`](@ref) `Tb`."""
get_Tb(value::ESDC1A) = value.Tb
"""Get [`ESDC1A`](@ref) `Tc`."""
get_Tc(value::ESDC1A) = value.Tc
"""Get [`ESDC1A`](@ref) `Vr_lim`."""
get_Vr_lim(value::ESDC1A) = value.Vr_lim
"""Get [`ESDC1A`](@ref) `Ke`."""
get_Ke(value::ESDC1A) = value.Ke
"""Get [`ESDC1A`](@ref) `Te`."""
get_Te(value::ESDC1A) = value.Te
"""Get [`ESDC1A`](@ref) `Kf`."""
get_Kf(value::ESDC1A) = value.Kf
"""Get [`ESDC1A`](@ref) `Tf`."""
get_Tf(value::ESDC1A) = value.Tf
"""Get [`ESDC1A`](@ref) `switch`."""
get_switch(value::ESDC1A) = value.switch
"""Get [`ESDC1A`](@ref) `E_sat`."""
get_E_sat(value::ESDC1A) = value.E_sat
"""Get [`ESDC1A`](@ref) `Se`."""
get_Se(value::ESDC1A) = value.Se
"""Get [`ESDC1A`](@ref) `V_ref`."""
get_V_ref(value::ESDC1A) = value.V_ref
"""Get [`ESDC1A`](@ref) `saturation_coeffs`."""
get_saturation_coeffs(value::ESDC1A) = value.saturation_coeffs
"""Get [`ESDC1A`](@ref) `ext`."""
get_ext(value::ESDC1A) = value.ext
"""Get [`ESDC1A`](@ref) `states`."""
get_states(value::ESDC1A) = value.states
"""Get [`ESDC1A`](@ref) `n_states`."""
get_n_states(value::ESDC1A) = value.n_states
"""Get [`ESDC1A`](@ref) `states_types`."""
get_states_types(value::ESDC1A) = value.states_types
"""Get [`ESDC1A`](@ref) `internal`."""
get_internal(value::ESDC1A) = value.internal
"""Set [`ESDC1A`](@ref) `Tr`."""
set_Tr!(value::ESDC1A, val) = value.Tr = val
"""Set [`ESDC1A`](@ref) `Ka`."""
set_Ka!(value::ESDC1A, val) = value.Ka = val
"""Set [`ESDC1A`](@ref) `Ta`."""
set_Ta!(value::ESDC1A, val) = value.Ta = val
"""Set [`ESDC1A`](@ref) `Tb`."""
set_Tb!(value::ESDC1A, val) = value.Tb = val
"""Set [`ESDC1A`](@ref) `Tc`."""
set_Tc!(value::ESDC1A, val) = value.Tc = val
"""Set [`ESDC1A`](@ref) `Vr_lim`."""
set_Vr_lim!(value::ESDC1A, val) = value.Vr_lim = val
"""Set [`ESDC1A`](@ref) `Ke`."""
set_Ke!(value::ESDC1A, val) = value.Ke = val
"""Set [`ESDC1A`](@ref) `Te`."""
set_Te!(value::ESDC1A, val) = value.Te = val
"""Set [`ESDC1A`](@ref) `Kf`."""
set_Kf!(value::ESDC1A, val) = value.Kf = val
"""Set [`ESDC1A`](@ref) `Tf`."""
set_Tf!(value::ESDC1A, val) = value.Tf = val
"""Set [`ESDC1A`](@ref) `switch`."""
set_switch!(value::ESDC1A, val) = value.switch = val
"""Set [`ESDC1A`](@ref) `E_sat`."""
set_E_sat!(value::ESDC1A, val) = value.E_sat = val
"""Set [`ESDC1A`](@ref) `Se`."""
set_Se!(value::ESDC1A, val) = value.Se = val
"""Set [`ESDC1A`](@ref) `V_ref`."""
set_V_ref!(value::ESDC1A, val) = value.V_ref = val
"""Set [`ESDC1A`](@ref) `saturation_coeffs`."""
set_saturation_coeffs!(value::ESDC1A, val) = value.saturation_coeffs = val
"""Set [`ESDC1A`](@ref) `ext`."""
set_ext!(value::ESDC1A, val) = value.ext = val
"""Set [`ESDC1A`](@ref) `states_types`."""
set_states_types!(value::ESDC1A, val) = value.states_types = val
================================================
FILE: src/models/generated/ESDC2A.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ESDC2A <: AVR
Tr::Float64
Ka::Float64
Ta::Float64
Tb::Float64
Tc::Float64
Vr_lim::MinMax
Ke::Float64
Te::Float64
Kf::Float64
Tf::Float64
switch::Int
E_sat::Tuple{Float64, Float64}
Se::Tuple{Float64, Float64}
V_ref::Float64
saturation_coeffs::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Is used to represent field-controlled dc commutator exciters with continuously acting voltage regulators having power supplies derived from the generator or auxiliaries bus.
Parameters of IEEE Std 421.5 Type DC2A Excitacion System. This model corresponds to ESDC2A in PSSE and PSLF
# Arguments
- `Tr::Float64`: Voltage Measurement Time Constant in s, validation range: `(0, 0.5)`
- `Ka::Float64`: Amplifier Gain, validation range: `(10, 500)`
- `Ta::Float64`: Amplifier Time Constant in s, validation range: `(0, 1)`
- `Tb::Float64`: Regulator input Time Constant in s, validation range: `(0, nothing)`
- `Tc::Float64`: Regulator input Time Constant in s, validation range: `(0, nothing)`
- `Vr_lim::MinMax`: Voltage regulator limits (regulator output) (Vi_min, Vi_max)
- `Ke::Float64`: Exciter constant related to self-excited field, validation range: `(-1, 1)`
- `Te::Float64`: Exciter time constant, integration rate associated with exciter control, validation range: `(eps(), 2)`
- `Kf::Float64`: Excitation control system stabilizer gain, validation range: `(0, 0.3)`
- `Tf::Float64`: Excitation control system stabilizer time constant. Appropiate Data: 5.0 <= Tf/Kf <= 15.0, validation range: `(eps(), 1.5)`
- `switch::Int`: Switch, validation range: `(0, 1)`
- `E_sat::Tuple{Float64, Float64}`: Exciter output voltage for saturation factor: (E1, E2)
- `Se::Tuple{Float64, Float64}`: Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `saturation_coeffs::Tuple{Float64, Float64}`: (default: `PowerSystems.get_avr_saturation(E_sat, Se)`) (**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vt: Terminal Voltage,
Vr1: input lead lag,
Vr2: Regulator Output,
Vf: Exciter Output,
Vr3: Rate feedback integrator
- `n_states::Int`: (**Do not modify.**) The ESDC2A has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) ESDC2A has 5 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ESDC2A <: AVR
"Voltage Measurement Time Constant in s"
Tr::Float64
"Amplifier Gain"
Ka::Float64
"Amplifier Time Constant in s"
Ta::Float64
"Regulator input Time Constant in s"
Tb::Float64
"Regulator input Time Constant in s"
Tc::Float64
"Voltage regulator limits (regulator output) (Vi_min, Vi_max)"
Vr_lim::MinMax
"Exciter constant related to self-excited field"
Ke::Float64
"Exciter time constant, integration rate associated with exciter control"
Te::Float64
"Excitation control system stabilizer gain"
Kf::Float64
"Excitation control system stabilizer time constant. Appropiate Data: 5.0 <= Tf/Kf <= 15.0"
Tf::Float64
"Switch"
switch::Int
"Exciter output voltage for saturation factor: (E1, E2)"
E_sat::Tuple{Float64, Float64}
"Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))"
Se::Tuple{Float64, Float64}
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V"
saturation_coeffs::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vt: Terminal Voltage,
Vr1: input lead lag,
Vr2: Regulator Output,
Vf: Exciter Output,
Vr3: Rate feedback integrator"
states::Vector{Symbol}
"(**Do not modify.**) The ESDC2A has 5 states"
n_states::Int
"(**Do not modify.**) ESDC2A has 5 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ESDC2A(Tr, Ka, Ta, Tb, Tc, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), )
ESDC2A(Tr, Ka, Ta, Tb, Tc, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref, saturation_coeffs, ext, [:Vt, :Vr1, :Vr2, :Vf, :Vr3], 5, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function ESDC2A(; Tr, Ka, Ta, Tb, Tc, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), states=[:Vt, :Vr1, :Vr2, :Vf, :Vr3], n_states=5, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
ESDC2A(Tr, Ka, Ta, Tb, Tc, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref, saturation_coeffs, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function ESDC2A(::Nothing)
ESDC2A(;
Tr=0,
Ka=0,
Ta=0,
Tb=0,
Tc=0,
Vr_lim=(min=0.0, max=0.0),
Ke=0,
Te=0,
Kf=0,
Tf=0,
switch=0,
E_sat=(0.0, 0.0),
Se=(0.0, 0.0),
V_ref=0,
saturation_coeffs=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`ESDC2A`](@ref) `Tr`."""
get_Tr(value::ESDC2A) = value.Tr
"""Get [`ESDC2A`](@ref) `Ka`."""
get_Ka(value::ESDC2A) = value.Ka
"""Get [`ESDC2A`](@ref) `Ta`."""
get_Ta(value::ESDC2A) = value.Ta
"""Get [`ESDC2A`](@ref) `Tb`."""
get_Tb(value::ESDC2A) = value.Tb
"""Get [`ESDC2A`](@ref) `Tc`."""
get_Tc(value::ESDC2A) = value.Tc
"""Get [`ESDC2A`](@ref) `Vr_lim`."""
get_Vr_lim(value::ESDC2A) = value.Vr_lim
"""Get [`ESDC2A`](@ref) `Ke`."""
get_Ke(value::ESDC2A) = value.Ke
"""Get [`ESDC2A`](@ref) `Te`."""
get_Te(value::ESDC2A) = value.Te
"""Get [`ESDC2A`](@ref) `Kf`."""
get_Kf(value::ESDC2A) = value.Kf
"""Get [`ESDC2A`](@ref) `Tf`."""
get_Tf(value::ESDC2A) = value.Tf
"""Get [`ESDC2A`](@ref) `switch`."""
get_switch(value::ESDC2A) = value.switch
"""Get [`ESDC2A`](@ref) `E_sat`."""
get_E_sat(value::ESDC2A) = value.E_sat
"""Get [`ESDC2A`](@ref) `Se`."""
get_Se(value::ESDC2A) = value.Se
"""Get [`ESDC2A`](@ref) `V_ref`."""
get_V_ref(value::ESDC2A) = value.V_ref
"""Get [`ESDC2A`](@ref) `saturation_coeffs`."""
get_saturation_coeffs(value::ESDC2A) = value.saturation_coeffs
"""Get [`ESDC2A`](@ref) `ext`."""
get_ext(value::ESDC2A) = value.ext
"""Get [`ESDC2A`](@ref) `states`."""
get_states(value::ESDC2A) = value.states
"""Get [`ESDC2A`](@ref) `n_states`."""
get_n_states(value::ESDC2A) = value.n_states
"""Get [`ESDC2A`](@ref) `states_types`."""
get_states_types(value::ESDC2A) = value.states_types
"""Get [`ESDC2A`](@ref) `internal`."""
get_internal(value::ESDC2A) = value.internal
"""Set [`ESDC2A`](@ref) `Tr`."""
set_Tr!(value::ESDC2A, val) = value.Tr = val
"""Set [`ESDC2A`](@ref) `Ka`."""
set_Ka!(value::ESDC2A, val) = value.Ka = val
"""Set [`ESDC2A`](@ref) `Ta`."""
set_Ta!(value::ESDC2A, val) = value.Ta = val
"""Set [`ESDC2A`](@ref) `Tb`."""
set_Tb!(value::ESDC2A, val) = value.Tb = val
"""Set [`ESDC2A`](@ref) `Tc`."""
set_Tc!(value::ESDC2A, val) = value.Tc = val
"""Set [`ESDC2A`](@ref) `Vr_lim`."""
set_Vr_lim!(value::ESDC2A, val) = value.Vr_lim = val
"""Set [`ESDC2A`](@ref) `Ke`."""
set_Ke!(value::ESDC2A, val) = value.Ke = val
"""Set [`ESDC2A`](@ref) `Te`."""
set_Te!(value::ESDC2A, val) = value.Te = val
"""Set [`ESDC2A`](@ref) `Kf`."""
set_Kf!(value::ESDC2A, val) = value.Kf = val
"""Set [`ESDC2A`](@ref) `Tf`."""
set_Tf!(value::ESDC2A, val) = value.Tf = val
"""Set [`ESDC2A`](@ref) `switch`."""
set_switch!(value::ESDC2A, val) = value.switch = val
"""Set [`ESDC2A`](@ref) `E_sat`."""
set_E_sat!(value::ESDC2A, val) = value.E_sat = val
"""Set [`ESDC2A`](@ref) `Se`."""
set_Se!(value::ESDC2A, val) = value.Se = val
"""Set [`ESDC2A`](@ref) `V_ref`."""
set_V_ref!(value::ESDC2A, val) = value.V_ref = val
"""Set [`ESDC2A`](@ref) `saturation_coeffs`."""
set_saturation_coeffs!(value::ESDC2A, val) = value.saturation_coeffs = val
"""Set [`ESDC2A`](@ref) `ext`."""
set_ext!(value::ESDC2A, val) = value.ext = val
"""Set [`ESDC2A`](@ref) `states_types`."""
set_states_types!(value::ESDC2A, val) = value.states_types = val
================================================
FILE: src/models/generated/ESST1A.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ESST1A <: AVR
UEL_flags::Int
PSS_flags::Int
Tr::Float64
Vi_lim::Tuple{Float64, Float64}
Tc::Float64
Tb::Float64
Tc1::Float64
Tb1::Float64
Ka::Float64
Ta::Float64
Va_lim::MinMax
Vr_lim::MinMax
Kc::Float64
Kf::Float64
Tf::Float64
K_lr::Float64
I_lr::Float64
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
This excitation system supplies power through a transformer from the generator terminals and its regulated by a controlled rectifier (via thyristors).
Parameters of IEEE Std 421.5 Type ST1A Excitacion System. ESST1A in PSSE and PSLF
# Arguments
- `UEL_flags::Int`: Code input for Underexcitization limiter (UEL) entry. Not supported, validation range: `(1, 3)`
- `PSS_flags::Int`: Code input for Power System Stabilizer (PSS) or (VOS) entry, validation range: `(1, 2)`
- `Tr::Float64`: Regulator input filter time constant in s, validation range: `(0, 0.1)`
- `Vi_lim::Tuple{Float64, Float64}`: Voltage error limits (regulator input) (Vi_min, Vi_max)
- `Tc::Float64`: First regulator denominator (lead) time constant in s, validation range: `(0, 10)`
- `Tb::Float64`: First regulator denominator (lag) time constant in s, validation range: `(0, 20)`
- `Tc1::Float64`: Second regulator denominator (lead) time constant in s, validation range: `(0, 10)`
- `Tb1::Float64`: Second regulator denominator (lead) time constant in s, validation range: `(0, 20)`
- `Ka::Float64`: Voltage regulator gain, validation range: `(50, 1000)`
- `Ta::Float64`: Voltage regulator time constant in s, validation range: `(0, 0.5)`
- `Va_lim::MinMax`: Limits for regulator output `(Va_min, Va_max)`
- `Vr_lim::MinMax`: Limits for exciter output `(Vr_min, Vr_max)`
- `Kc::Float64`: Rectifier loading factor proportional to commutating reactance, validation range: `(0, 0.3)`
- `Kf::Float64`: Rate feedback gain, validation range: `(0, 0.3)`
- `Tf::Float64`: Rate feedback time constant in s, validation range: `(eps(), 1.5)`
- `K_lr::Float64`: Exciter output current limiter gain, validation range: `(0, 5)`
- `I_lr::Float64`: Exciter output current limit reference, validation range: `(0, 5)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: First Lead-lag state,
Vr2: Second lead-lag state,
Va: Regulator output state,
Vr3: Feedback output state
- `n_states::Int`: (**Do not modify.**) ST1A has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) ST1A has 5 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ESST1A <: AVR
"Code input for Underexcitization limiter (UEL) entry. Not supported"
UEL_flags::Int
"Code input for Power System Stabilizer (PSS) or (VOS) entry"
PSS_flags::Int
"Regulator input filter time constant in s"
Tr::Float64
"Voltage error limits (regulator input) (Vi_min, Vi_max)"
Vi_lim::Tuple{Float64, Float64}
"First regulator denominator (lead) time constant in s"
Tc::Float64
"First regulator denominator (lag) time constant in s"
Tb::Float64
"Second regulator denominator (lead) time constant in s"
Tc1::Float64
"Second regulator denominator (lead) time constant in s"
Tb1::Float64
"Voltage regulator gain"
Ka::Float64
"Voltage regulator time constant in s"
Ta::Float64
"Limits for regulator output `(Va_min, Va_max)`"
Va_lim::MinMax
"Limits for exciter output `(Vr_min, Vr_max)`"
Vr_lim::MinMax
"Rectifier loading factor proportional to commutating reactance"
Kc::Float64
"Rate feedback gain"
Kf::Float64
"Rate feedback time constant in s"
Tf::Float64
"Exciter output current limiter gain"
K_lr::Float64
"Exciter output current limit reference"
I_lr::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: First Lead-lag state,
Vr2: Second lead-lag state,
Va: Regulator output state,
Vr3: Feedback output state"
states::Vector{Symbol}
"(**Do not modify.**) ST1A has 5 states"
n_states::Int
"(**Do not modify.**) ST1A has 5 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ESST1A(UEL_flags, PSS_flags, Tr, Vi_lim, Tc, Tb, Tc1, Tb1, Ka, Ta, Va_lim, Vr_lim, Kc, Kf, Tf, K_lr, I_lr, V_ref=1.0, ext=Dict{String, Any}(), )
ESST1A(UEL_flags, PSS_flags, Tr, Vi_lim, Tc, Tb, Tc1, Tb1, Ka, Ta, Va_lim, Vr_lim, Kc, Kf, Tf, K_lr, I_lr, V_ref, ext, [:Vm, :Vr1, :Vr2, :Va, :Vr3], 5, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function ESST1A(; UEL_flags, PSS_flags, Tr, Vi_lim, Tc, Tb, Tc1, Tb1, Ka, Ta, Va_lim, Vr_lim, Kc, Kf, Tf, K_lr, I_lr, V_ref=1.0, ext=Dict{String, Any}(), states=[:Vm, :Vr1, :Vr2, :Va, :Vr3], n_states=5, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
ESST1A(UEL_flags, PSS_flags, Tr, Vi_lim, Tc, Tb, Tc1, Tb1, Ka, Ta, Va_lim, Vr_lim, Kc, Kf, Tf, K_lr, I_lr, V_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function ESST1A(::Nothing)
ESST1A(;
UEL_flags=1,
PSS_flags=1,
Tr=0,
Vi_lim=(0.0, 0.0),
Tc=0,
Tb=0,
Tc1=0,
Tb1=0,
Ka=0,
Ta=0,
Va_lim=(min=0.0, max=0.0),
Vr_lim=(min=0.0, max=0.0),
Kc=0,
Kf=0,
Tf=0,
K_lr=0,
I_lr=0,
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ESST1A`](@ref) `UEL_flags`."""
get_UEL_flags(value::ESST1A) = value.UEL_flags
"""Get [`ESST1A`](@ref) `PSS_flags`."""
get_PSS_flags(value::ESST1A) = value.PSS_flags
"""Get [`ESST1A`](@ref) `Tr`."""
get_Tr(value::ESST1A) = value.Tr
"""Get [`ESST1A`](@ref) `Vi_lim`."""
get_Vi_lim(value::ESST1A) = value.Vi_lim
"""Get [`ESST1A`](@ref) `Tc`."""
get_Tc(value::ESST1A) = value.Tc
"""Get [`ESST1A`](@ref) `Tb`."""
get_Tb(value::ESST1A) = value.Tb
"""Get [`ESST1A`](@ref) `Tc1`."""
get_Tc1(value::ESST1A) = value.Tc1
"""Get [`ESST1A`](@ref) `Tb1`."""
get_Tb1(value::ESST1A) = value.Tb1
"""Get [`ESST1A`](@ref) `Ka`."""
get_Ka(value::ESST1A) = value.Ka
"""Get [`ESST1A`](@ref) `Ta`."""
get_Ta(value::ESST1A) = value.Ta
"""Get [`ESST1A`](@ref) `Va_lim`."""
get_Va_lim(value::ESST1A) = value.Va_lim
"""Get [`ESST1A`](@ref) `Vr_lim`."""
get_Vr_lim(value::ESST1A) = value.Vr_lim
"""Get [`ESST1A`](@ref) `Kc`."""
get_Kc(value::ESST1A) = value.Kc
"""Get [`ESST1A`](@ref) `Kf`."""
get_Kf(value::ESST1A) = value.Kf
"""Get [`ESST1A`](@ref) `Tf`."""
get_Tf(value::ESST1A) = value.Tf
"""Get [`ESST1A`](@ref) `K_lr`."""
get_K_lr(value::ESST1A) = value.K_lr
"""Get [`ESST1A`](@ref) `I_lr`."""
get_I_lr(value::ESST1A) = value.I_lr
"""Get [`ESST1A`](@ref) `V_ref`."""
get_V_ref(value::ESST1A) = value.V_ref
"""Get [`ESST1A`](@ref) `ext`."""
get_ext(value::ESST1A) = value.ext
"""Get [`ESST1A`](@ref) `states`."""
get_states(value::ESST1A) = value.states
"""Get [`ESST1A`](@ref) `n_states`."""
get_n_states(value::ESST1A) = value.n_states
"""Get [`ESST1A`](@ref) `states_types`."""
get_states_types(value::ESST1A) = value.states_types
"""Get [`ESST1A`](@ref) `internal`."""
get_internal(value::ESST1A) = value.internal
"""Set [`ESST1A`](@ref) `UEL_flags`."""
set_UEL_flags!(value::ESST1A, val) = value.UEL_flags = val
"""Set [`ESST1A`](@ref) `PSS_flags`."""
set_PSS_flags!(value::ESST1A, val) = value.PSS_flags = val
"""Set [`ESST1A`](@ref) `Tr`."""
set_Tr!(value::ESST1A, val) = value.Tr = val
"""Set [`ESST1A`](@ref) `Vi_lim`."""
set_Vi_lim!(value::ESST1A, val) = value.Vi_lim = val
"""Set [`ESST1A`](@ref) `Tc`."""
set_Tc!(value::ESST1A, val) = value.Tc = val
"""Set [`ESST1A`](@ref) `Tb`."""
set_Tb!(value::ESST1A, val) = value.Tb = val
"""Set [`ESST1A`](@ref) `Tc1`."""
set_Tc1!(value::ESST1A, val) = value.Tc1 = val
"""Set [`ESST1A`](@ref) `Tb1`."""
set_Tb1!(value::ESST1A, val) = value.Tb1 = val
"""Set [`ESST1A`](@ref) `Ka`."""
set_Ka!(value::ESST1A, val) = value.Ka = val
"""Set [`ESST1A`](@ref) `Ta`."""
set_Ta!(value::ESST1A, val) = value.Ta = val
"""Set [`ESST1A`](@ref) `Va_lim`."""
set_Va_lim!(value::ESST1A, val) = value.Va_lim = val
"""Set [`ESST1A`](@ref) `Vr_lim`."""
set_Vr_lim!(value::ESST1A, val) = value.Vr_lim = val
"""Set [`ESST1A`](@ref) `Kc`."""
set_Kc!(value::ESST1A, val) = value.Kc = val
"""Set [`ESST1A`](@ref) `Kf`."""
set_Kf!(value::ESST1A, val) = value.Kf = val
"""Set [`ESST1A`](@ref) `Tf`."""
set_Tf!(value::ESST1A, val) = value.Tf = val
"""Set [`ESST1A`](@ref) `K_lr`."""
set_K_lr!(value::ESST1A, val) = value.K_lr = val
"""Set [`ESST1A`](@ref) `I_lr`."""
set_I_lr!(value::ESST1A, val) = value.I_lr = val
"""Set [`ESST1A`](@ref) `V_ref`."""
set_V_ref!(value::ESST1A, val) = value.V_ref = val
"""Set [`ESST1A`](@ref) `ext`."""
set_ext!(value::ESST1A, val) = value.ext = val
"""Set [`ESST1A`](@ref) `states_types`."""
set_states_types!(value::ESST1A, val) = value.states_types = val
================================================
FILE: src/models/generated/ESST4B.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ESST4B <: AVR
Tr::Float64
K_pr::Float64
K_ir::Float64
Vr_lim::MinMax
Ta::Float64
K_pm::Float64
K_im::Float64
Vm_lim::MinMax
Kg::Float64
Kp::Float64
Ki::Float64
VB_max::Float64
Kc::Float64
Xl::Float64
θp::Float64
V_ref::Float64
θp_rad::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
In these excitation systems, voltage (and also current in compounded systems) is transformed to an appropriate level. Rectifiers, either controlled or non-controlled, provide the necessary direct current for the generator field.
Parameters of IEEE Std 421.5 Type ST4B Excitacion System. ESST4B in PSSE and PSLF
# Arguments
- `Tr::Float64`: Regulator input filter time constant in s, validation range: `(0, 0.5)`
- `K_pr::Float64`: Regulator propotional gain, validation range: `(0, 75)`
- `K_ir::Float64`: Regulator integral gain, validation range: `(0, 75)`
- `Vr_lim::MinMax`: Voltage regulator limits (Vi_min, Vi_max)
- `Ta::Float64`: Voltage regulator time constant in s, validation range: `(0, 1)`
- `K_pm::Float64`: Voltage regulator proportional gain output, validation range: `(0, 1.2)`
- `K_im::Float64`: Voltage regulator integral gain output, validation range: `(0, 18)`
- `Vm_lim::MinMax`: Limits for inner loop output `(Vm_min, Vm_max)`
- `Kg::Float64`: Feedback gain constant of the inner loop field regulator, validation range: `(0, 1.1)`
- `Kp::Float64`: Potential circuit (voltage) gain coefficient, validation range: `(0, 10)`
- `Ki::Float64`: Compound circuit (current) gain coefficient, validation range: `(0, 1.1)`
- `VB_max::Float64`: Maximum available exciter voltage, validation range: `(1, 20)`
- `Kc::Float64`: Rectifier loading factor proportional to commutating reactance, validation range: `(0, 1)`
- `Xl::Float64`: Reactance associated with potential source, validation range: `(0, 0.5)`
- `θp::Float64`: Potential circuit phase angle (degrees), validation range: `(-90, 90)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `θp_rad::Float64`: (default: `θp*π*inv(180)`) (**Do not modify.**) Potential circuit phase angle (radians)
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vt: Sensed Terminal Voltage,
Vr1: Regulator Integrator,
Vr2: Regulator Output,
Vm: Output integrator
- `n_states::Int`: (**Do not modify.**) ST4B has 4 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) ST4B has 4 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ESST4B <: AVR
"Regulator input filter time constant in s"
Tr::Float64
"Regulator propotional gain"
K_pr::Float64
"Regulator integral gain"
K_ir::Float64
"Voltage regulator limits (Vi_min, Vi_max)"
Vr_lim::MinMax
"Voltage regulator time constant in s"
Ta::Float64
"Voltage regulator proportional gain output"
K_pm::Float64
"Voltage regulator integral gain output"
K_im::Float64
"Limits for inner loop output `(Vm_min, Vm_max)`"
Vm_lim::MinMax
"Feedback gain constant of the inner loop field regulator"
Kg::Float64
"Potential circuit (voltage) gain coefficient"
Kp::Float64
"Compound circuit (current) gain coefficient"
Ki::Float64
"Maximum available exciter voltage"
VB_max::Float64
"Rectifier loading factor proportional to commutating reactance"
Kc::Float64
"Reactance associated with potential source"
Xl::Float64
"Potential circuit phase angle (degrees)"
θp::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Potential circuit phase angle (radians)"
θp_rad::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vt: Sensed Terminal Voltage,
Vr1: Regulator Integrator,
Vr2: Regulator Output,
Vm: Output integrator"
states::Vector{Symbol}
"(**Do not modify.**) ST4B has 4 states"
n_states::Int
"(**Do not modify.**) ST4B has 4 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ESST4B(Tr, K_pr, K_ir, Vr_lim, Ta, K_pm, K_im, Vm_lim, Kg, Kp, Ki, VB_max, Kc, Xl, θp, V_ref=1.0, θp_rad=θp*π*inv(180), ext=Dict{String, Any}(), )
ESST4B(Tr, K_pr, K_ir, Vr_lim, Ta, K_pm, K_im, Vm_lim, Kg, Kp, Ki, VB_max, Kc, Xl, θp, V_ref, θp_rad, ext, [:Vt, :Vr1, :Vr2, :Vm], 4, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], InfrastructureSystemsInternal(), )
end
function ESST4B(; Tr, K_pr, K_ir, Vr_lim, Ta, K_pm, K_im, Vm_lim, Kg, Kp, Ki, VB_max, Kc, Xl, θp, V_ref=1.0, θp_rad=θp*π*inv(180), ext=Dict{String, Any}(), states=[:Vt, :Vr1, :Vr2, :Vm], n_states=4, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], internal=InfrastructureSystemsInternal(), )
ESST4B(Tr, K_pr, K_ir, Vr_lim, Ta, K_pm, K_im, Vm_lim, Kg, Kp, Ki, VB_max, Kc, Xl, θp, V_ref, θp_rad, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function ESST4B(::Nothing)
ESST4B(;
Tr=0,
K_pr=0,
K_ir=0,
Vr_lim=(min=0.0, max=0.0),
Ta=0,
K_pm=0,
K_im=0,
Vm_lim=(min=0.0, max=0.0),
Kg=0,
Kp=0,
Ki=0,
VB_max=0,
Kc=0,
Xl=0,
θp=0,
V_ref=0,
θp_rad=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ESST4B`](@ref) `Tr`."""
get_Tr(value::ESST4B) = value.Tr
"""Get [`ESST4B`](@ref) `K_pr`."""
get_K_pr(value::ESST4B) = value.K_pr
"""Get [`ESST4B`](@ref) `K_ir`."""
get_K_ir(value::ESST4B) = value.K_ir
"""Get [`ESST4B`](@ref) `Vr_lim`."""
get_Vr_lim(value::ESST4B) = value.Vr_lim
"""Get [`ESST4B`](@ref) `Ta`."""
get_Ta(value::ESST4B) = value.Ta
"""Get [`ESST4B`](@ref) `K_pm`."""
get_K_pm(value::ESST4B) = value.K_pm
"""Get [`ESST4B`](@ref) `K_im`."""
get_K_im(value::ESST4B) = value.K_im
"""Get [`ESST4B`](@ref) `Vm_lim`."""
get_Vm_lim(value::ESST4B) = value.Vm_lim
"""Get [`ESST4B`](@ref) `Kg`."""
get_Kg(value::ESST4B) = value.Kg
"""Get [`ESST4B`](@ref) `Kp`."""
get_Kp(value::ESST4B) = value.Kp
"""Get [`ESST4B`](@ref) `Ki`."""
get_Ki(value::ESST4B) = value.Ki
"""Get [`ESST4B`](@ref) `VB_max`."""
get_VB_max(value::ESST4B) = value.VB_max
"""Get [`ESST4B`](@ref) `Kc`."""
get_Kc(value::ESST4B) = value.Kc
"""Get [`ESST4B`](@ref) `Xl`."""
get_Xl(value::ESST4B) = value.Xl
"""Get [`ESST4B`](@ref) `θp`."""
get_θp(value::ESST4B) = value.θp
"""Get [`ESST4B`](@ref) `V_ref`."""
get_V_ref(value::ESST4B) = value.V_ref
"""Get [`ESST4B`](@ref) `θp_rad`."""
get_θp_rad(value::ESST4B) = value.θp_rad
"""Get [`ESST4B`](@ref) `ext`."""
get_ext(value::ESST4B) = value.ext
"""Get [`ESST4B`](@ref) `states`."""
get_states(value::ESST4B) = value.states
"""Get [`ESST4B`](@ref) `n_states`."""
get_n_states(value::ESST4B) = value.n_states
"""Get [`ESST4B`](@ref) `states_types`."""
get_states_types(value::ESST4B) = value.states_types
"""Get [`ESST4B`](@ref) `internal`."""
get_internal(value::ESST4B) = value.internal
"""Set [`ESST4B`](@ref) `Tr`."""
set_Tr!(value::ESST4B, val) = value.Tr = val
"""Set [`ESST4B`](@ref) `K_pr`."""
set_K_pr!(value::ESST4B, val) = value.K_pr = val
"""Set [`ESST4B`](@ref) `K_ir`."""
set_K_ir!(value::ESST4B, val) = value.K_ir = val
"""Set [`ESST4B`](@ref) `Vr_lim`."""
set_Vr_lim!(value::ESST4B, val) = value.Vr_lim = val
"""Set [`ESST4B`](@ref) `Ta`."""
set_Ta!(value::ESST4B, val) = value.Ta = val
"""Set [`ESST4B`](@ref) `K_pm`."""
set_K_pm!(value::ESST4B, val) = value.K_pm = val
"""Set [`ESST4B`](@ref) `K_im`."""
set_K_im!(value::ESST4B, val) = value.K_im = val
"""Set [`ESST4B`](@ref) `Vm_lim`."""
set_Vm_lim!(value::ESST4B, val) = value.Vm_lim = val
"""Set [`ESST4B`](@ref) `Kg`."""
set_Kg!(value::ESST4B, val) = value.Kg = val
"""Set [`ESST4B`](@ref) `Kp`."""
set_Kp!(value::ESST4B, val) = value.Kp = val
"""Set [`ESST4B`](@ref) `Ki`."""
set_Ki!(value::ESST4B, val) = value.Ki = val
"""Set [`ESST4B`](@ref) `VB_max`."""
set_VB_max!(value::ESST4B, val) = value.VB_max = val
"""Set [`ESST4B`](@ref) `Kc`."""
set_Kc!(value::ESST4B, val) = value.Kc = val
"""Set [`ESST4B`](@ref) `Xl`."""
set_Xl!(value::ESST4B, val) = value.Xl = val
"""Set [`ESST4B`](@ref) `θp`."""
set_θp!(value::ESST4B, val) = value.θp = val
"""Set [`ESST4B`](@ref) `V_ref`."""
set_V_ref!(value::ESST4B, val) = value.V_ref = val
"""Set [`ESST4B`](@ref) `θp_rad`."""
set_θp_rad!(value::ESST4B, val) = value.θp_rad = val
"""Set [`ESST4B`](@ref) `ext`."""
set_ext!(value::ESST4B, val) = value.ext = val
"""Set [`ESST4B`](@ref) `states_types`."""
set_states_types!(value::ESST4B, val) = value.states_types = val
================================================
FILE: src/models/generated/EX4VSA.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct EX4VSA <: AVR
Iflim::Float64
d::Float64
f::Float64
Spar::Float64
K1::Float64
K2::Float64
Oel_lim::MinMax
G::Float64
Ta::Float64
Tb::Float64
Te::Float64
E_lim::MinMax
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
IEEE Excitation System for Voltage Security Assesment
# Arguments
- `Iflim::Float64`: OEL Field current limit, validation range: `(0, nothing)`
- `d::Float64`: OEL parameter d, validation range: `(0, nothing)`
- `f::Float64`: OEL parameter f, validation range: `(0, nothing)`
- `Spar::Float64`: OEL parameter Spar, validation range: `(0, nothing)`
- `K1::Float64`: OEL delay time constant, validation range: `(0, nothing)`
- `K2::Float64`: OEL parameter K2, validation range: `(0, nothing)`
- `Oel_lim::MinMax`: Oel integrator limits (Oel_min, Oel_max)
- `G::Float64`: AVR Exciter Gain, validation range: `(0, nothing)`
- `Ta::Float64`: Numerator lead-lag (lag) time constant in s, validation range: `(0, nothing)`
- `Tb::Float64`: Denominator lead-lag (lag) time constant in s, validation range: `(0, nothing)`
- `Te::Float64`: Exciter Time Constant in s, validation range: `(0, nothing)`
- `E_lim::MinMax`: Voltage regulator limits (regulator output) (E_min, E_max)
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vll: Lead-lag internal state,
Vex: Exciter Output,
oel: OEL integrator state
- `n_states::Int`: (**Do not modify.**) The EX4VSA has 3 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct EX4VSA <: AVR
"OEL Field current limit"
Iflim::Float64
"OEL parameter d"
d::Float64
"OEL parameter f"
f::Float64
"OEL parameter Spar"
Spar::Float64
"OEL delay time constant"
K1::Float64
"OEL parameter K2"
K2::Float64
"Oel integrator limits (Oel_min, Oel_max)"
Oel_lim::MinMax
"AVR Exciter Gain"
G::Float64
"Numerator lead-lag (lag) time constant in s"
Ta::Float64
"Denominator lead-lag (lag) time constant in s"
Tb::Float64
"Exciter Time Constant in s"
Te::Float64
"Voltage regulator limits (regulator output) (E_min, E_max)"
E_lim::MinMax
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vll: Lead-lag internal state,
Vex: Exciter Output,
oel: OEL integrator state"
states::Vector{Symbol}
"(**Do not modify.**) The EX4VSA has 3 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function EX4VSA(Iflim, d, f, Spar, K1, K2, Oel_lim, G, Ta, Tb, Te, E_lim, V_ref=1.0, ext=Dict{String, Any}(), )
EX4VSA(Iflim, d, f, Spar, K1, K2, Oel_lim, G, Ta, Tb, Te, E_lim, V_ref, ext, [:Vll, :Vex, :oel], 3, InfrastructureSystemsInternal(), )
end
function EX4VSA(; Iflim, d, f, Spar, K1, K2, Oel_lim, G, Ta, Tb, Te, E_lim, V_ref=1.0, ext=Dict{String, Any}(), states=[:Vll, :Vex, :oel], n_states=3, internal=InfrastructureSystemsInternal(), )
EX4VSA(Iflim, d, f, Spar, K1, K2, Oel_lim, G, Ta, Tb, Te, E_lim, V_ref, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function EX4VSA(::Nothing)
EX4VSA(;
Iflim=0,
d=0,
f=0,
Spar=0,
K1=0,
K2=0,
Oel_lim=(min=0.0, max=0.0),
G=0,
Ta=0,
Tb=0,
Te=0,
E_lim=(min=0.0, max=0.0),
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`EX4VSA`](@ref) `Iflim`."""
get_Iflim(value::EX4VSA) = value.Iflim
"""Get [`EX4VSA`](@ref) `d`."""
get_d(value::EX4VSA) = value.d
"""Get [`EX4VSA`](@ref) `f`."""
get_f(value::EX4VSA) = value.f
"""Get [`EX4VSA`](@ref) `Spar`."""
get_Spar(value::EX4VSA) = value.Spar
"""Get [`EX4VSA`](@ref) `K1`."""
get_K1(value::EX4VSA) = value.K1
"""Get [`EX4VSA`](@ref) `K2`."""
get_K2(value::EX4VSA) = value.K2
"""Get [`EX4VSA`](@ref) `Oel_lim`."""
get_Oel_lim(value::EX4VSA) = value.Oel_lim
"""Get [`EX4VSA`](@ref) `G`."""
get_G(value::EX4VSA) = value.G
"""Get [`EX4VSA`](@ref) `Ta`."""
get_Ta(value::EX4VSA) = value.Ta
"""Get [`EX4VSA`](@ref) `Tb`."""
get_Tb(value::EX4VSA) = value.Tb
"""Get [`EX4VSA`](@ref) `Te`."""
get_Te(value::EX4VSA) = value.Te
"""Get [`EX4VSA`](@ref) `E_lim`."""
get_E_lim(value::EX4VSA) = value.E_lim
"""Get [`EX4VSA`](@ref) `V_ref`."""
get_V_ref(value::EX4VSA) = value.V_ref
"""Get [`EX4VSA`](@ref) `ext`."""
get_ext(value::EX4VSA) = value.ext
"""Get [`EX4VSA`](@ref) `states`."""
get_states(value::EX4VSA) = value.states
"""Get [`EX4VSA`](@ref) `n_states`."""
get_n_states(value::EX4VSA) = value.n_states
"""Get [`EX4VSA`](@ref) `internal`."""
get_internal(value::EX4VSA) = value.internal
"""Set [`EX4VSA`](@ref) `Iflim`."""
set_Iflim!(value::EX4VSA, val) = value.Iflim = val
"""Set [`EX4VSA`](@ref) `d`."""
set_d!(value::EX4VSA, val) = value.d = val
"""Set [`EX4VSA`](@ref) `f`."""
set_f!(value::EX4VSA, val) = value.f = val
"""Set [`EX4VSA`](@ref) `Spar`."""
set_Spar!(value::EX4VSA, val) = value.Spar = val
"""Set [`EX4VSA`](@ref) `K1`."""
set_K1!(value::EX4VSA, val) = value.K1 = val
"""Set [`EX4VSA`](@ref) `K2`."""
set_K2!(value::EX4VSA, val) = value.K2 = val
"""Set [`EX4VSA`](@ref) `Oel_lim`."""
set_Oel_lim!(value::EX4VSA, val) = value.Oel_lim = val
"""Set [`EX4VSA`](@ref) `G`."""
set_G!(value::EX4VSA, val) = value.G = val
"""Set [`EX4VSA`](@ref) `Ta`."""
set_Ta!(value::EX4VSA, val) = value.Ta = val
"""Set [`EX4VSA`](@ref) `Tb`."""
set_Tb!(value::EX4VSA, val) = value.Tb = val
"""Set [`EX4VSA`](@ref) `Te`."""
set_Te!(value::EX4VSA, val) = value.Te = val
"""Set [`EX4VSA`](@ref) `E_lim`."""
set_E_lim!(value::EX4VSA, val) = value.E_lim = val
"""Set [`EX4VSA`](@ref) `V_ref`."""
set_V_ref!(value::EX4VSA, val) = value.V_ref = val
"""Set [`EX4VSA`](@ref) `ext`."""
set_ext!(value::EX4VSA, val) = value.ext = val
================================================
FILE: src/models/generated/EXAC1.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct EXAC1 <: AVR
Tr::Float64
Tb::Float64
Tc::Float64
Ka::Float64
Ta::Float64
Vr_lim::MinMax
Te::Float64
Kf::Float64
Tf::Float64
Kc::Float64
Kd::Float64
Ke::Float64
E_sat::Tuple{Float64, Float64}
Se::Tuple{Float64, Float64}
V_ref::Float64
saturation_coeffs::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Modified ESAC1A. This excitation systems consists of an alternator main exciter feeding its output via non-controlled rectifiers.
The exciter does not employ self-excitation, and the voltage regulator power is taken from a source that is not affected by external transients.
Parameters of IEEE Std 421.5 Type AC1A. EXAC1 in PSSE and PSLF
# Arguments
- `Tr::Float64`: Regulator input filter time constant in s, validation range: `(0, 0.5)`
- `Tb::Float64`: Regulator denominator (lag) time constant in s, validation range: `(0, 20)`
- `Tc::Float64`: Regulator numerator (lead) time constant in s, validation range: `(0, 20)`
- `Ka::Float64`: Regulator output gain, validation range: `(0, 1000)`
- `Ta::Float64`: Regulator output time constant in s, validation range: `(0, 10)`
- `Vr_lim::MinMax`: Limits for regulator output `(Vr_min, Vr_max)`
- `Te::Float64`: Exciter field time constant in s, validation range: `(eps(), 2)`
- `Kf::Float64`: Rate feedback excitation system stabilizer gain, validation range: `(0, 0.3)`
- `Tf::Float64`: Rate feedback time constant, validation range: `(eps(), 1.5)`
- `Kc::Float64`: Rectifier loading factor proportional to commutating reactance, validation range: `(0, 1)`
- `Kd::Float64`: Demagnetizing factor, function of exciter alternator reactances, validation range: `(0, 1)`
- `Ke::Float64`: Exciter field proportional constant, validation range: `(0, 1)`
- `E_sat::Tuple{Float64, Float64}`: Exciter output voltage for saturation factor: (E1, E2)
- `Se::Tuple{Float64, Float64}`: Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `saturation_coeffs::Tuple{Float64, Float64}`: (default: `PowerSystems.get_avr_saturation(E_sat, Se)`) (**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: Lead-lag state,
Vr2: Regulator output state,
Ve: Integrator output state,
Vr3: Feedback output state
- `n_states::Int`: (**Do not modify.**) EXAC1 has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) EXAC1 has 5 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct EXAC1 <: AVR
"Regulator input filter time constant in s"
Tr::Float64
"Regulator denominator (lag) time constant in s"
Tb::Float64
"Regulator numerator (lead) time constant in s"
Tc::Float64
"Regulator output gain"
Ka::Float64
"Regulator output time constant in s"
Ta::Float64
"Limits for regulator output `(Vr_min, Vr_max)`"
Vr_lim::MinMax
"Exciter field time constant in s"
Te::Float64
"Rate feedback excitation system stabilizer gain"
Kf::Float64
"Rate feedback time constant"
Tf::Float64
"Rectifier loading factor proportional to commutating reactance"
Kc::Float64
"Demagnetizing factor, function of exciter alternator reactances"
Kd::Float64
"Exciter field proportional constant"
Ke::Float64
"Exciter output voltage for saturation factor: (E1, E2)"
E_sat::Tuple{Float64, Float64}
"Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))"
Se::Tuple{Float64, Float64}
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V"
saturation_coeffs::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: Lead-lag state,
Vr2: Regulator output state,
Ve: Integrator output state,
Vr3: Feedback output state"
states::Vector{Symbol}
"(**Do not modify.**) EXAC1 has 5 states"
n_states::Int
"(**Do not modify.**) EXAC1 has 5 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function EXAC1(Tr, Tb, Tc, Ka, Ta, Vr_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), )
EXAC1(Tr, Tb, Tc, Ka, Ta, Vr_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, V_ref, saturation_coeffs, ext, [:Vm, :Vr1, :Vr2, :Ve, :Vr3], 5, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function EXAC1(; Tr, Tb, Tc, Ka, Ta, Vr_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), states=[:Vm, :Vr1, :Vr2, :Ve, :Vr3], n_states=5, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
EXAC1(Tr, Tb, Tc, Ka, Ta, Vr_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, V_ref, saturation_coeffs, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function EXAC1(::Nothing)
EXAC1(;
Tr=0,
Tb=0,
Tc=0,
Ka=0,
Ta=0,
Vr_lim=(min=0.0, max=0.0),
Te=0,
Kf=0,
Tf=0,
Kc=0,
Kd=0,
Ke=0,
E_sat=(0.0, 0.0),
Se=(0.0, 0.0),
V_ref=0,
saturation_coeffs=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`EXAC1`](@ref) `Tr`."""
get_Tr(value::EXAC1) = value.Tr
"""Get [`EXAC1`](@ref) `Tb`."""
get_Tb(value::EXAC1) = value.Tb
"""Get [`EXAC1`](@ref) `Tc`."""
get_Tc(value::EXAC1) = value.Tc
"""Get [`EXAC1`](@ref) `Ka`."""
get_Ka(value::EXAC1) = value.Ka
"""Get [`EXAC1`](@ref) `Ta`."""
get_Ta(value::EXAC1) = value.Ta
"""Get [`EXAC1`](@ref) `Vr_lim`."""
get_Vr_lim(value::EXAC1) = value.Vr_lim
"""Get [`EXAC1`](@ref) `Te`."""
get_Te(value::EXAC1) = value.Te
"""Get [`EXAC1`](@ref) `Kf`."""
get_Kf(value::EXAC1) = value.Kf
"""Get [`EXAC1`](@ref) `Tf`."""
get_Tf(value::EXAC1) = value.Tf
"""Get [`EXAC1`](@ref) `Kc`."""
get_Kc(value::EXAC1) = value.Kc
"""Get [`EXAC1`](@ref) `Kd`."""
get_Kd(value::EXAC1) = value.Kd
"""Get [`EXAC1`](@ref) `Ke`."""
get_Ke(value::EXAC1) = value.Ke
"""Get [`EXAC1`](@ref) `E_sat`."""
get_E_sat(value::EXAC1) = value.E_sat
"""Get [`EXAC1`](@ref) `Se`."""
get_Se(value::EXAC1) = value.Se
"""Get [`EXAC1`](@ref) `V_ref`."""
get_V_ref(value::EXAC1) = value.V_ref
"""Get [`EXAC1`](@ref) `saturation_coeffs`."""
get_saturation_coeffs(value::EXAC1) = value.saturation_coeffs
"""Get [`EXAC1`](@ref) `ext`."""
get_ext(value::EXAC1) = value.ext
"""Get [`EXAC1`](@ref) `states`."""
get_states(value::EXAC1) = value.states
"""Get [`EXAC1`](@ref) `n_states`."""
get_n_states(value::EXAC1) = value.n_states
"""Get [`EXAC1`](@ref) `states_types`."""
get_states_types(value::EXAC1) = value.states_types
"""Get [`EXAC1`](@ref) `internal`."""
get_internal(value::EXAC1) = value.internal
"""Set [`EXAC1`](@ref) `Tr`."""
set_Tr!(value::EXAC1, val) = value.Tr = val
"""Set [`EXAC1`](@ref) `Tb`."""
set_Tb!(value::EXAC1, val) = value.Tb = val
"""Set [`EXAC1`](@ref) `Tc`."""
set_Tc!(value::EXAC1, val) = value.Tc = val
"""Set [`EXAC1`](@ref) `Ka`."""
set_Ka!(value::EXAC1, val) = value.Ka = val
"""Set [`EXAC1`](@ref) `Ta`."""
set_Ta!(value::EXAC1, val) = value.Ta = val
"""Set [`EXAC1`](@ref) `Vr_lim`."""
set_Vr_lim!(value::EXAC1, val) = value.Vr_lim = val
"""Set [`EXAC1`](@ref) `Te`."""
set_Te!(value::EXAC1, val) = value.Te = val
"""Set [`EXAC1`](@ref) `Kf`."""
set_Kf!(value::EXAC1, val) = value.Kf = val
"""Set [`EXAC1`](@ref) `Tf`."""
set_Tf!(value::EXAC1, val) = value.Tf = val
"""Set [`EXAC1`](@ref) `Kc`."""
set_Kc!(value::EXAC1, val) = value.Kc = val
"""Set [`EXAC1`](@ref) `Kd`."""
set_Kd!(value::EXAC1, val) = value.Kd = val
"""Set [`EXAC1`](@ref) `Ke`."""
set_Ke!(value::EXAC1, val) = value.Ke = val
"""Set [`EXAC1`](@ref) `E_sat`."""
set_E_sat!(value::EXAC1, val) = value.E_sat = val
"""Set [`EXAC1`](@ref) `Se`."""
set_Se!(value::EXAC1, val) = value.Se = val
"""Set [`EXAC1`](@ref) `V_ref`."""
set_V_ref!(value::EXAC1, val) = value.V_ref = val
"""Set [`EXAC1`](@ref) `saturation_coeffs`."""
set_saturation_coeffs!(value::EXAC1, val) = value.saturation_coeffs = val
"""Set [`EXAC1`](@ref) `ext`."""
set_ext!(value::EXAC1, val) = value.ext = val
"""Set [`EXAC1`](@ref) `states_types`."""
set_states_types!(value::EXAC1, val) = value.states_types = val
================================================
FILE: src/models/generated/EXAC1A.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct EXAC1A <: AVR
Tr::Float64
Tb::Float64
Tc::Float64
Ka::Float64
Ta::Float64
Va_lim::MinMax
Te::Float64
Kf::Float64
Tf::Float64
Kc::Float64
Kd::Float64
Ke::Float64
E_sat::Tuple{Float64, Float64}
Se::Tuple{Float64, Float64}
Vr_lim::MinMax
V_ref::Float64
saturation_coeffs::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Modified ESAC1A. This excitation systems consists of an alternator main exciter feeding its output via non-controlled rectifiers.
The exciter does not employ self-excitation, and the voltage regulator power is taken from a source that is not affected by external transients.
Parameters of IEEE Std 421.5 Type AC1A Excitacion System. EXAC1A in PSSE and PSLF
# Arguments
- `Tr::Float64`: Regulator input filter time constant in s, validation range: `(0, 0.5)`
- `Tb::Float64`: Regulator denominator (lag) time constant in s, validation range: `(0, 20)`
- `Tc::Float64`: Regulator numerator (lead) time constant in s, validation range: `(0, 20)`
- `Ka::Float64`: Regulator output gain, validation range: `(0, 1000)`
- `Ta::Float64`: Regulator output time constant in s, validation range: `(0, 10)`
- `Va_lim::MinMax`: Limits for regulator output `(Va_min, Va_max)`
- `Te::Float64`: Exciter field time constant in s, validation range: `(eps(), 2)`
- `Kf::Float64`: Rate feedback excitation system stabilizer gain, validation range: `(0, 0.3)`
- `Tf::Float64`: Rate feedback time constant, validation range: `(eps(), 1.5)`
- `Kc::Float64`: Rectifier loading factor proportional to commutating reactance, validation range: `(0, 1)`
- `Kd::Float64`: Demagnetizing factor, function of exciter alternator reactances, validation range: `(0, 1)`
- `Ke::Float64`: Exciter field proportional constant, validation range: `(0, 1)`
- `E_sat::Tuple{Float64, Float64}`: Exciter output voltage for saturation factor: (E1, E2)
- `Se::Tuple{Float64, Float64}`: Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))
- `Vr_lim::MinMax`: Limits for exciter field voltage: `(Vr_min, Vr_max)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `saturation_coeffs::Tuple{Float64, Float64}`: (default: `PowerSystems.get_avr_saturation(E_sat, Se)`) (**Do not modify.**) Coefficients (A,B) of the function: Se(x) = B(x - A)^2/x
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: Lead-lag state,
Vr2: Regulator output state,
Ve: Integrator output state,
Vr3: Feedback output state
- `n_states::Int`: (**Do not modify.**) EXAC1A has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) EXAC1A has 5 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct EXAC1A <: AVR
"Regulator input filter time constant in s"
Tr::Float64
"Regulator denominator (lag) time constant in s"
Tb::Float64
"Regulator numerator (lead) time constant in s"
Tc::Float64
"Regulator output gain"
Ka::Float64
"Regulator output time constant in s"
Ta::Float64
"Limits for regulator output `(Va_min, Va_max)`"
Va_lim::MinMax
"Exciter field time constant in s"
Te::Float64
"Rate feedback excitation system stabilizer gain"
Kf::Float64
"Rate feedback time constant"
Tf::Float64
"Rectifier loading factor proportional to commutating reactance"
Kc::Float64
"Demagnetizing factor, function of exciter alternator reactances"
Kd::Float64
"Exciter field proportional constant"
Ke::Float64
"Exciter output voltage for saturation factor: (E1, E2)"
E_sat::Tuple{Float64, Float64}
"Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))"
Se::Tuple{Float64, Float64}
"Limits for exciter field voltage: `(Vr_min, Vr_max)`"
Vr_lim::MinMax
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Coefficients (A,B) of the function: Se(x) = B(x - A)^2/x"
saturation_coeffs::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: Lead-lag state,
Vr2: Regulator output state,
Ve: Integrator output state,
Vr3: Feedback output state"
states::Vector{Symbol}
"(**Do not modify.**) EXAC1A has 5 states"
n_states::Int
"(**Do not modify.**) EXAC1A has 5 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function EXAC1A(Tr, Tb, Tc, Ka, Ta, Va_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, Vr_lim, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), )
EXAC1A(Tr, Tb, Tc, Ka, Ta, Va_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, Vr_lim, V_ref, saturation_coeffs, ext, [:Vm, :Vr1, :Vr2, :Ve, :Vr3], 5, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function EXAC1A(; Tr, Tb, Tc, Ka, Ta, Va_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, Vr_lim, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), states=[:Vm, :Vr1, :Vr2, :Ve, :Vr3], n_states=5, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
EXAC1A(Tr, Tb, Tc, Ka, Ta, Va_lim, Te, Kf, Tf, Kc, Kd, Ke, E_sat, Se, Vr_lim, V_ref, saturation_coeffs, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function EXAC1A(::Nothing)
EXAC1A(;
Tr=0,
Tb=0,
Tc=0,
Ka=0,
Ta=0,
Va_lim=(min=0.0, max=0.0),
Te=0,
Kf=0,
Tf=0,
Kc=0,
Kd=0,
Ke=0,
E_sat=(0.0, 0.0),
Se=(0.0, 0.0),
Vr_lim=(min=0.0, max=0.0),
V_ref=0,
saturation_coeffs=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`EXAC1A`](@ref) `Tr`."""
get_Tr(value::EXAC1A) = value.Tr
"""Get [`EXAC1A`](@ref) `Tb`."""
get_Tb(value::EXAC1A) = value.Tb
"""Get [`EXAC1A`](@ref) `Tc`."""
get_Tc(value::EXAC1A) = value.Tc
"""Get [`EXAC1A`](@ref) `Ka`."""
get_Ka(value::EXAC1A) = value.Ka
"""Get [`EXAC1A`](@ref) `Ta`."""
get_Ta(value::EXAC1A) = value.Ta
"""Get [`EXAC1A`](@ref) `Va_lim`."""
get_Va_lim(value::EXAC1A) = value.Va_lim
"""Get [`EXAC1A`](@ref) `Te`."""
get_Te(value::EXAC1A) = value.Te
"""Get [`EXAC1A`](@ref) `Kf`."""
get_Kf(value::EXAC1A) = value.Kf
"""Get [`EXAC1A`](@ref) `Tf`."""
get_Tf(value::EXAC1A) = value.Tf
"""Get [`EXAC1A`](@ref) `Kc`."""
get_Kc(value::EXAC1A) = value.Kc
"""Get [`EXAC1A`](@ref) `Kd`."""
get_Kd(value::EXAC1A) = value.Kd
"""Get [`EXAC1A`](@ref) `Ke`."""
get_Ke(value::EXAC1A) = value.Ke
"""Get [`EXAC1A`](@ref) `E_sat`."""
get_E_sat(value::EXAC1A) = value.E_sat
"""Get [`EXAC1A`](@ref) `Se`."""
get_Se(value::EXAC1A) = value.Se
"""Get [`EXAC1A`](@ref) `Vr_lim`."""
get_Vr_lim(value::EXAC1A) = value.Vr_lim
"""Get [`EXAC1A`](@ref) `V_ref`."""
get_V_ref(value::EXAC1A) = value.V_ref
"""Get [`EXAC1A`](@ref) `saturation_coeffs`."""
get_saturation_coeffs(value::EXAC1A) = value.saturation_coeffs
"""Get [`EXAC1A`](@ref) `ext`."""
get_ext(value::EXAC1A) = value.ext
"""Get [`EXAC1A`](@ref) `states`."""
get_states(value::EXAC1A) = value.states
"""Get [`EXAC1A`](@ref) `n_states`."""
get_n_states(value::EXAC1A) = value.n_states
"""Get [`EXAC1A`](@ref) `states_types`."""
get_states_types(value::EXAC1A) = value.states_types
"""Get [`EXAC1A`](@ref) `internal`."""
get_internal(value::EXAC1A) = value.internal
"""Set [`EXAC1A`](@ref) `Tr`."""
set_Tr!(value::EXAC1A, val) = value.Tr = val
"""Set [`EXAC1A`](@ref) `Tb`."""
set_Tb!(value::EXAC1A, val) = value.Tb = val
"""Set [`EXAC1A`](@ref) `Tc`."""
set_Tc!(value::EXAC1A, val) = value.Tc = val
"""Set [`EXAC1A`](@ref) `Ka`."""
set_Ka!(value::EXAC1A, val) = value.Ka = val
"""Set [`EXAC1A`](@ref) `Ta`."""
set_Ta!(value::EXAC1A, val) = value.Ta = val
"""Set [`EXAC1A`](@ref) `Va_lim`."""
set_Va_lim!(value::EXAC1A, val) = value.Va_lim = val
"""Set [`EXAC1A`](@ref) `Te`."""
set_Te!(value::EXAC1A, val) = value.Te = val
"""Set [`EXAC1A`](@ref) `Kf`."""
set_Kf!(value::EXAC1A, val) = value.Kf = val
"""Set [`EXAC1A`](@ref) `Tf`."""
set_Tf!(value::EXAC1A, val) = value.Tf = val
"""Set [`EXAC1A`](@ref) `Kc`."""
set_Kc!(value::EXAC1A, val) = value.Kc = val
"""Set [`EXAC1A`](@ref) `Kd`."""
set_Kd!(value::EXAC1A, val) = value.Kd = val
"""Set [`EXAC1A`](@ref) `Ke`."""
set_Ke!(value::EXAC1A, val) = value.Ke = val
"""Set [`EXAC1A`](@ref) `E_sat`."""
set_E_sat!(value::EXAC1A, val) = value.E_sat = val
"""Set [`EXAC1A`](@ref) `Se`."""
set_Se!(value::EXAC1A, val) = value.Se = val
"""Set [`EXAC1A`](@ref) `Vr_lim`."""
set_Vr_lim!(value::EXAC1A, val) = value.Vr_lim = val
"""Set [`EXAC1A`](@ref) `V_ref`."""
set_V_ref!(value::EXAC1A, val) = value.V_ref = val
"""Set [`EXAC1A`](@ref) `saturation_coeffs`."""
set_saturation_coeffs!(value::EXAC1A, val) = value.saturation_coeffs = val
"""Set [`EXAC1A`](@ref) `ext`."""
set_ext!(value::EXAC1A, val) = value.ext = val
"""Set [`EXAC1A`](@ref) `states_types`."""
set_states_types!(value::EXAC1A, val) = value.states_types = val
================================================
FILE: src/models/generated/EXAC2.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct EXAC2 <: AVR
Tr::Float64
Tb::Float64
Tc::Float64
Ka::Float64
Ta::Float64
Va_lim::MinMax
Kb::Float64
Vr_lim::MinMax
Te::Float64
Kl::Float64
Kh::Float64
Kf::Float64
Tf::Float64
Kc::Float64
Kd::Float64
Ke::Float64
V_lr::Float64
E_sat::Tuple{Float64, Float64}
Se::Tuple{Float64, Float64}
V_ref::Float64
saturation_coeffs::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Modified AC2. This excitation systems consists of an alternator main exciter feeding its output via non-controlled rectifiers.
The exciter does not employ self-excitation, and the voltage regulator power is taken from a source that is not affected by external transients.
Parameters of IEEE Std 421.5 Type AC2A Excitacion System. The alternator main exciter is used, feeding its output via non-controlled rectifiers. The Type AC2C model is similar to that of Type AC1C except for the inclusion of exciter time constant compensation and exciter field current limiting elements. EXAC2 in PSSE and PSLF
# Arguments
- `Tr::Float64`: Regulator input filter time constant in s, validation range: `(0, 0.5)`
- `Tb::Float64`: Regulator denominator (lag) time constant in s, validation range: `(0, 20)`
- `Tc::Float64`: Regulator numerator (lead) time constant in s, validation range: `(0, 20)`
- `Ka::Float64`: Regulator output gain, validation range: `(0, 1000)`
- `Ta::Float64`: Regulator output time constant in s, validation range: `(0, 10)`
- `Va_lim::MinMax`: Limits for regulator output `(Va_min, Va_max)`
- `Kb::Float64`: Second Stage regulator gain, validation range: `(eps(), 500)`
- `Vr_lim::MinMax`: Limits for exciter field voltage `(Vr_min, Vr_max)`
- `Te::Float64`: Exciter field time constant, validation range: `(eps(), 2)`
- `Kl::Float64`: Exciter field current limiter gain, validation range: `(0, 1.1)`
- `Kh::Float64`: Exciter field current regulator feedback gain, validation range: `(0, 1.1)`
- `Kf::Float64`: Rate feedback excitation system stabilizer gain, validation range: `(0, 0.3)`
- `Tf::Float64`: Rate feedback time constant, validation range: `(eps(), nothing)`
- `Kc::Float64`: Rectifier loading factor proportional to commutating reactance, validation range: `(0, 1)`
- `Kd::Float64`: Demagnetizing factor, function of exciter alternator reactances, validation range: `(0, 1)`
- `Ke::Float64`: Exciter field proportional constant, validation range: `(0, 1)`
- `V_lr::Float64`: Maximum exciter field current, validation range: `(0, nothing)`
- `E_sat::Tuple{Float64, Float64}`: Exciter output voltage for saturation factor: (E1, E2)
- `Se::Tuple{Float64, Float64}`: Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `saturation_coeffs::Tuple{Float64, Float64}`: (default: `PowerSystems.get_avr_saturation(E_sat, Se)`) (**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: Lead-lag state,
Vr2: Regulator output state,
Ve: Integrator output state,
Vr3: Feedback output state
- `n_states::Int`: (**Do not modify.**) EXAC2 has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) EXAC2 has 5 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct EXAC2 <: AVR
"Regulator input filter time constant in s"
Tr::Float64
"Regulator denominator (lag) time constant in s"
Tb::Float64
"Regulator numerator (lead) time constant in s"
Tc::Float64
"Regulator output gain"
Ka::Float64
"Regulator output time constant in s"
Ta::Float64
"Limits for regulator output `(Va_min, Va_max)`"
Va_lim::MinMax
"Second Stage regulator gain"
Kb::Float64
"Limits for exciter field voltage `(Vr_min, Vr_max)`"
Vr_lim::MinMax
"Exciter field time constant"
Te::Float64
"Exciter field current limiter gain"
Kl::Float64
"Exciter field current regulator feedback gain"
Kh::Float64
"Rate feedback excitation system stabilizer gain"
Kf::Float64
"Rate feedback time constant"
Tf::Float64
"Rectifier loading factor proportional to commutating reactance"
Kc::Float64
"Demagnetizing factor, function of exciter alternator reactances"
Kd::Float64
"Exciter field proportional constant"
Ke::Float64
"Maximum exciter field current"
V_lr::Float64
"Exciter output voltage for saturation factor: (E1, E2)"
E_sat::Tuple{Float64, Float64}
"Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))"
Se::Tuple{Float64, Float64}
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V"
saturation_coeffs::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: Lead-lag state,
Vr2: Regulator output state,
Ve: Integrator output state,
Vr3: Feedback output state"
states::Vector{Symbol}
"(**Do not modify.**) EXAC2 has 5 states"
n_states::Int
"(**Do not modify.**) EXAC2 has 5 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function EXAC2(Tr, Tb, Tc, Ka, Ta, Va_lim, Kb, Vr_lim, Te, Kl, Kh, Kf, Tf, Kc, Kd, Ke, V_lr, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), )
EXAC2(Tr, Tb, Tc, Ka, Ta, Va_lim, Kb, Vr_lim, Te, Kl, Kh, Kf, Tf, Kc, Kd, Ke, V_lr, E_sat, Se, V_ref, saturation_coeffs, ext, [:Vm, :Vr1, :Vr2, :Ve, :Vr3], 5, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function EXAC2(; Tr, Tb, Tc, Ka, Ta, Va_lim, Kb, Vr_lim, Te, Kl, Kh, Kf, Tf, Kc, Kd, Ke, V_lr, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), states=[:Vm, :Vr1, :Vr2, :Ve, :Vr3], n_states=5, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
EXAC2(Tr, Tb, Tc, Ka, Ta, Va_lim, Kb, Vr_lim, Te, Kl, Kh, Kf, Tf, Kc, Kd, Ke, V_lr, E_sat, Se, V_ref, saturation_coeffs, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function EXAC2(::Nothing)
EXAC2(;
Tr=0,
Tb=0,
Tc=0,
Ka=0,
Ta=0,
Va_lim=(min=0.0, max=0.0),
Kb=0,
Vr_lim=(min=0.0, max=0.0),
Te=0,
Kl=0,
Kh=0,
Kf=0,
Tf=0,
Kc=0,
Kd=0,
Ke=0,
V_lr=0,
E_sat=(0.0, 0.0),
Se=(0.0, 0.0),
V_ref=0,
saturation_coeffs=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`EXAC2`](@ref) `Tr`."""
get_Tr(value::EXAC2) = value.Tr
"""Get [`EXAC2`](@ref) `Tb`."""
get_Tb(value::EXAC2) = value.Tb
"""Get [`EXAC2`](@ref) `Tc`."""
get_Tc(value::EXAC2) = value.Tc
"""Get [`EXAC2`](@ref) `Ka`."""
get_Ka(value::EXAC2) = value.Ka
"""Get [`EXAC2`](@ref) `Ta`."""
get_Ta(value::EXAC2) = value.Ta
"""Get [`EXAC2`](@ref) `Va_lim`."""
get_Va_lim(value::EXAC2) = value.Va_lim
"""Get [`EXAC2`](@ref) `Kb`."""
get_Kb(value::EXAC2) = value.Kb
"""Get [`EXAC2`](@ref) `Vr_lim`."""
get_Vr_lim(value::EXAC2) = value.Vr_lim
"""Get [`EXAC2`](@ref) `Te`."""
get_Te(value::EXAC2) = value.Te
"""Get [`EXAC2`](@ref) `Kl`."""
get_Kl(value::EXAC2) = value.Kl
"""Get [`EXAC2`](@ref) `Kh`."""
get_Kh(value::EXAC2) = value.Kh
"""Get [`EXAC2`](@ref) `Kf`."""
get_Kf(value::EXAC2) = value.Kf
"""Get [`EXAC2`](@ref) `Tf`."""
get_Tf(value::EXAC2) = value.Tf
"""Get [`EXAC2`](@ref) `Kc`."""
get_Kc(value::EXAC2) = value.Kc
"""Get [`EXAC2`](@ref) `Kd`."""
get_Kd(value::EXAC2) = value.Kd
"""Get [`EXAC2`](@ref) `Ke`."""
get_Ke(value::EXAC2) = value.Ke
"""Get [`EXAC2`](@ref) `V_lr`."""
get_V_lr(value::EXAC2) = value.V_lr
"""Get [`EXAC2`](@ref) `E_sat`."""
get_E_sat(value::EXAC2) = value.E_sat
"""Get [`EXAC2`](@ref) `Se`."""
get_Se(value::EXAC2) = value.Se
"""Get [`EXAC2`](@ref) `V_ref`."""
get_V_ref(value::EXAC2) = value.V_ref
"""Get [`EXAC2`](@ref) `saturation_coeffs`."""
get_saturation_coeffs(value::EXAC2) = value.saturation_coeffs
"""Get [`EXAC2`](@ref) `ext`."""
get_ext(value::EXAC2) = value.ext
"""Get [`EXAC2`](@ref) `states`."""
get_states(value::EXAC2) = value.states
"""Get [`EXAC2`](@ref) `n_states`."""
get_n_states(value::EXAC2) = value.n_states
"""Get [`EXAC2`](@ref) `states_types`."""
get_states_types(value::EXAC2) = value.states_types
"""Get [`EXAC2`](@ref) `internal`."""
get_internal(value::EXAC2) = value.internal
"""Set [`EXAC2`](@ref) `Tr`."""
set_Tr!(value::EXAC2, val) = value.Tr = val
"""Set [`EXAC2`](@ref) `Tb`."""
set_Tb!(value::EXAC2, val) = value.Tb = val
"""Set [`EXAC2`](@ref) `Tc`."""
set_Tc!(value::EXAC2, val) = value.Tc = val
"""Set [`EXAC2`](@ref) `Ka`."""
set_Ka!(value::EXAC2, val) = value.Ka = val
"""Set [`EXAC2`](@ref) `Ta`."""
set_Ta!(value::EXAC2, val) = value.Ta = val
"""Set [`EXAC2`](@ref) `Va_lim`."""
set_Va_lim!(value::EXAC2, val) = value.Va_lim = val
"""Set [`EXAC2`](@ref) `Kb`."""
set_Kb!(value::EXAC2, val) = value.Kb = val
"""Set [`EXAC2`](@ref) `Vr_lim`."""
set_Vr_lim!(value::EXAC2, val) = value.Vr_lim = val
"""Set [`EXAC2`](@ref) `Te`."""
set_Te!(value::EXAC2, val) = value.Te = val
"""Set [`EXAC2`](@ref) `Kl`."""
set_Kl!(value::EXAC2, val) = value.Kl = val
"""Set [`EXAC2`](@ref) `Kh`."""
set_Kh!(value::EXAC2, val) = value.Kh = val
"""Set [`EXAC2`](@ref) `Kf`."""
set_Kf!(value::EXAC2, val) = value.Kf = val
"""Set [`EXAC2`](@ref) `Tf`."""
set_Tf!(value::EXAC2, val) = value.Tf = val
"""Set [`EXAC2`](@ref) `Kc`."""
set_Kc!(value::EXAC2, val) = value.Kc = val
"""Set [`EXAC2`](@ref) `Kd`."""
set_Kd!(value::EXAC2, val) = value.Kd = val
"""Set [`EXAC2`](@ref) `Ke`."""
set_Ke!(value::EXAC2, val) = value.Ke = val
"""Set [`EXAC2`](@ref) `V_lr`."""
set_V_lr!(value::EXAC2, val) = value.V_lr = val
"""Set [`EXAC2`](@ref) `E_sat`."""
set_E_sat!(value::EXAC2, val) = value.E_sat = val
"""Set [`EXAC2`](@ref) `Se`."""
set_Se!(value::EXAC2, val) = value.Se = val
"""Set [`EXAC2`](@ref) `V_ref`."""
set_V_ref!(value::EXAC2, val) = value.V_ref = val
"""Set [`EXAC2`](@ref) `saturation_coeffs`."""
set_saturation_coeffs!(value::EXAC2, val) = value.saturation_coeffs = val
"""Set [`EXAC2`](@ref) `ext`."""
set_ext!(value::EXAC2, val) = value.ext = val
"""Set [`EXAC2`](@ref) `states_types`."""
set_states_types!(value::EXAC2, val) = value.states_types = val
================================================
FILE: src/models/generated/EXPIC1.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct EXPIC1 <: AVR
Tr::Float64
Ka::Float64
Ta::Float64
Va_lim::MinMax
Ta_2::Float64
Ta_3::Float64
Ta_4::Float64
Vr_lim::MinMax
Kf::Float64
Tf_1::Float64
Tf_2::Float64
Efd_lim::MinMax
Ke::Float64
Te::Float64
E_sat::Tuple{Float64, Float64}
Se::Tuple{Float64, Float64}
Kp::Float64
Ki::Float64
Kc::Float64
V_ref::Float64
saturation_coeffs::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Generic Proportional/Integral Excitation System
# Arguments
- `Tr::Float64`: Regulator input filter time constant in s, validation range: `(0, 0.5)`
- `Ka::Float64`: Voltage regulator gain, validation range: `(1, 500)`
- `Ta::Float64`: Voltage regulator time constant in s, validation range: `(0, 10)`
- `Va_lim::MinMax`: Limits for pi controler `(Vr_min, Vr_max)`
- `Ta_2::Float64`: Voltage regulator time constant in s, validation range: `(0, nothing)`
- `Ta_3::Float64`: Voltage regulator time constant in s, validation range: `(0, nothing)`
- `Ta_4::Float64`: Voltage regulator time constant in s, validation range: `(0, nothing)`
- `Vr_lim::MinMax`: Voltage regulator limits (regulator output) (Vi_min, Vi_max)
- `Kf::Float64`: Rate feedback gain, validation range: `(0, 0.3)`
- `Tf_1::Float64`: Rate Feedback time constant in s, validation range: `(eps(), 15)`
- `Tf_2::Float64`: Rate Feedback time constant in s, validation range: `(0, 5)`
- `Efd_lim::MinMax`: Field Voltage regulator limits (regulator output) (Efd_min, Efd_max)
- `Ke::Float64`: Exciter constant, validation range: `(0, 1)`
- `Te::Float64`: Exciter time constant, validation range: `(0, 2)`
- `E_sat::Tuple{Float64, Float64}`: Exciter output voltage for saturation factor: (E1, E2)
- `Se::Tuple{Float64, Float64}`: Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))
- `Kp::Float64`: Potential source gain, validation range: `(0, 5)`
- `Ki::Float64`: current source gain, validation range: `(0, 1.1)`
- `Kc::Float64`: Exciter regulation factor, validation range: `(0, 2)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `saturation_coeffs::Tuple{Float64, Float64}`: (default: `PowerSystems.get_avr_saturation(E_sat, Se)`) (**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: First Lead-lag state,
Vr2: Second regulator lead-lag state,
Vr2: Third regulator lead-lag state
Vf: Exciter output
Vr3: First feedback integrator,
Vr4: second feedback integrator
- `n_states::Int`: (**Do not modify.**) EXPIC1 has 6 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) EXPIC has 6 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct EXPIC1 <: AVR
"Regulator input filter time constant in s"
Tr::Float64
"Voltage regulator gain"
Ka::Float64
"Voltage regulator time constant in s"
Ta::Float64
"Limits for pi controler `(Vr_min, Vr_max)`"
Va_lim::MinMax
"Voltage regulator time constant in s"
Ta_2::Float64
"Voltage regulator time constant in s"
Ta_3::Float64
"Voltage regulator time constant in s"
Ta_4::Float64
"Voltage regulator limits (regulator output) (Vi_min, Vi_max)"
Vr_lim::MinMax
"Rate feedback gain"
Kf::Float64
"Rate Feedback time constant in s"
Tf_1::Float64
"Rate Feedback time constant in s"
Tf_2::Float64
"Field Voltage regulator limits (regulator output) (Efd_min, Efd_max)"
Efd_lim::MinMax
"Exciter constant"
Ke::Float64
"Exciter time constant"
Te::Float64
"Exciter output voltage for saturation factor: (E1, E2)"
E_sat::Tuple{Float64, Float64}
"Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))"
Se::Tuple{Float64, Float64}
"Potential source gain"
Kp::Float64
"current source gain"
Ki::Float64
"Exciter regulation factor"
Kc::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V"
saturation_coeffs::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
Vr1: First Lead-lag state,
Vr2: Second regulator lead-lag state,
Vr2: Third regulator lead-lag state
Vf: Exciter output
Vr3: First feedback integrator,
Vr4: second feedback integrator"
states::Vector{Symbol}
"(**Do not modify.**) EXPIC1 has 6 states"
n_states::Int
"(**Do not modify.**) EXPIC has 6 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function EXPIC1(Tr, Ka, Ta, Va_lim, Ta_2, Ta_3, Ta_4, Vr_lim, Kf, Tf_1, Tf_2, Efd_lim, Ke, Te, E_sat, Se, Kp, Ki, Kc, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), )
EXPIC1(Tr, Ka, Ta, Va_lim, Ta_2, Ta_3, Ta_4, Vr_lim, Kf, Tf_1, Tf_2, Efd_lim, Ke, Te, E_sat, Se, Kp, Ki, Kc, V_ref, saturation_coeffs, ext, [:Vm, :Vr1, :Vr2, :Vf, :Vr3, :Vr4], 6, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Hybrid], InfrastructureSystemsInternal(), )
end
function EXPIC1(; Tr, Ka, Ta, Va_lim, Ta_2, Ta_3, Ta_4, Vr_lim, Kf, Tf_1, Tf_2, Efd_lim, Ke, Te, E_sat, Se, Kp, Ki, Kc, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), states=[:Vm, :Vr1, :Vr2, :Vf, :Vr3, :Vr4], n_states=6, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Hybrid], internal=InfrastructureSystemsInternal(), )
EXPIC1(Tr, Ka, Ta, Va_lim, Ta_2, Ta_3, Ta_4, Vr_lim, Kf, Tf_1, Tf_2, Efd_lim, Ke, Te, E_sat, Se, Kp, Ki, Kc, V_ref, saturation_coeffs, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function EXPIC1(::Nothing)
EXPIC1(;
Tr=0,
Ka=0,
Ta=0,
Va_lim=(min=0.0, max=0.0),
Ta_2=0,
Ta_3=0,
Ta_4=0,
Vr_lim=(min=0.0, max=0.0),
Kf=0,
Tf_1=0,
Tf_2=0,
Efd_lim=(min=0.0, max=0.0),
Ke=0,
Te=0,
E_sat=(0.0, 0.0),
Se=(0.0, 0.0),
Kp=0,
Ki=0,
Kc=0,
V_ref=0,
saturation_coeffs=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`EXPIC1`](@ref) `Tr`."""
get_Tr(value::EXPIC1) = value.Tr
"""Get [`EXPIC1`](@ref) `Ka`."""
get_Ka(value::EXPIC1) = value.Ka
"""Get [`EXPIC1`](@ref) `Ta`."""
get_Ta(value::EXPIC1) = value.Ta
"""Get [`EXPIC1`](@ref) `Va_lim`."""
get_Va_lim(value::EXPIC1) = value.Va_lim
"""Get [`EXPIC1`](@ref) `Ta_2`."""
get_Ta_2(value::EXPIC1) = value.Ta_2
"""Get [`EXPIC1`](@ref) `Ta_3`."""
get_Ta_3(value::EXPIC1) = value.Ta_3
"""Get [`EXPIC1`](@ref) `Ta_4`."""
get_Ta_4(value::EXPIC1) = value.Ta_4
"""Get [`EXPIC1`](@ref) `Vr_lim`."""
get_Vr_lim(value::EXPIC1) = value.Vr_lim
"""Get [`EXPIC1`](@ref) `Kf`."""
get_Kf(value::EXPIC1) = value.Kf
"""Get [`EXPIC1`](@ref) `Tf_1`."""
get_Tf_1(value::EXPIC1) = value.Tf_1
"""Get [`EXPIC1`](@ref) `Tf_2`."""
get_Tf_2(value::EXPIC1) = value.Tf_2
"""Get [`EXPIC1`](@ref) `Efd_lim`."""
get_Efd_lim(value::EXPIC1) = value.Efd_lim
"""Get [`EXPIC1`](@ref) `Ke`."""
get_Ke(value::EXPIC1) = value.Ke
"""Get [`EXPIC1`](@ref) `Te`."""
get_Te(value::EXPIC1) = value.Te
"""Get [`EXPIC1`](@ref) `E_sat`."""
get_E_sat(value::EXPIC1) = value.E_sat
"""Get [`EXPIC1`](@ref) `Se`."""
get_Se(value::EXPIC1) = value.Se
"""Get [`EXPIC1`](@ref) `Kp`."""
get_Kp(value::EXPIC1) = value.Kp
"""Get [`EXPIC1`](@ref) `Ki`."""
get_Ki(value::EXPIC1) = value.Ki
"""Get [`EXPIC1`](@ref) `Kc`."""
get_Kc(value::EXPIC1) = value.Kc
"""Get [`EXPIC1`](@ref) `V_ref`."""
get_V_ref(value::EXPIC1) = value.V_ref
"""Get [`EXPIC1`](@ref) `saturation_coeffs`."""
get_saturation_coeffs(value::EXPIC1) = value.saturation_coeffs
"""Get [`EXPIC1`](@ref) `ext`."""
get_ext(value::EXPIC1) = value.ext
"""Get [`EXPIC1`](@ref) `states`."""
get_states(value::EXPIC1) = value.states
"""Get [`EXPIC1`](@ref) `n_states`."""
get_n_states(value::EXPIC1) = value.n_states
"""Get [`EXPIC1`](@ref) `states_types`."""
get_states_types(value::EXPIC1) = value.states_types
"""Get [`EXPIC1`](@ref) `internal`."""
get_internal(value::EXPIC1) = value.internal
"""Set [`EXPIC1`](@ref) `Tr`."""
set_Tr!(value::EXPIC1, val) = value.Tr = val
"""Set [`EXPIC1`](@ref) `Ka`."""
set_Ka!(value::EXPIC1, val) = value.Ka = val
"""Set [`EXPIC1`](@ref) `Ta`."""
set_Ta!(value::EXPIC1, val) = value.Ta = val
"""Set [`EXPIC1`](@ref) `Va_lim`."""
set_Va_lim!(value::EXPIC1, val) = value.Va_lim = val
"""Set [`EXPIC1`](@ref) `Ta_2`."""
set_Ta_2!(value::EXPIC1, val) = value.Ta_2 = val
"""Set [`EXPIC1`](@ref) `Ta_3`."""
set_Ta_3!(value::EXPIC1, val) = value.Ta_3 = val
"""Set [`EXPIC1`](@ref) `Ta_4`."""
set_Ta_4!(value::EXPIC1, val) = value.Ta_4 = val
"""Set [`EXPIC1`](@ref) `Vr_lim`."""
set_Vr_lim!(value::EXPIC1, val) = value.Vr_lim = val
"""Set [`EXPIC1`](@ref) `Kf`."""
set_Kf!(value::EXPIC1, val) = value.Kf = val
"""Set [`EXPIC1`](@ref) `Tf_1`."""
set_Tf_1!(value::EXPIC1, val) = value.Tf_1 = val
"""Set [`EXPIC1`](@ref) `Tf_2`."""
set_Tf_2!(value::EXPIC1, val) = value.Tf_2 = val
"""Set [`EXPIC1`](@ref) `Efd_lim`."""
set_Efd_lim!(value::EXPIC1, val) = value.Efd_lim = val
"""Set [`EXPIC1`](@ref) `Ke`."""
set_Ke!(value::EXPIC1, val) = value.Ke = val
"""Set [`EXPIC1`](@ref) `Te`."""
set_Te!(value::EXPIC1, val) = value.Te = val
"""Set [`EXPIC1`](@ref) `E_sat`."""
set_E_sat!(value::EXPIC1, val) = value.E_sat = val
"""Set [`EXPIC1`](@ref) `Se`."""
set_Se!(value::EXPIC1, val) = value.Se = val
"""Set [`EXPIC1`](@ref) `Kp`."""
set_Kp!(value::EXPIC1, val) = value.Kp = val
"""Set [`EXPIC1`](@ref) `Ki`."""
set_Ki!(value::EXPIC1, val) = value.Ki = val
"""Set [`EXPIC1`](@ref) `Kc`."""
set_Kc!(value::EXPIC1, val) = value.Kc = val
"""Set [`EXPIC1`](@ref) `V_ref`."""
set_V_ref!(value::EXPIC1, val) = value.V_ref = val
"""Set [`EXPIC1`](@ref) `saturation_coeffs`."""
set_saturation_coeffs!(value::EXPIC1, val) = value.saturation_coeffs = val
"""Set [`EXPIC1`](@ref) `ext`."""
set_ext!(value::EXPIC1, val) = value.ext = val
"""Set [`EXPIC1`](@ref) `states_types`."""
set_states_types!(value::EXPIC1, val) = value.states_types = val
================================================
FILE: src/models/generated/EXST1.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct EXST1 <: AVR
Tr::Float64
Vi_lim::MinMax
Tc::Float64
Tb::Float64
Ka::Float64
Ta::Float64
Vr_lim::MinMax
Kc::Float64
Kf::Float64
Tf::Float64
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
IEEE Type ST1 Excitation System (PTI version)
# Arguments
- `Tr::Float64`: Voltage Measurement Time Constant in s, validation range: `(0, nothing)`
- `Vi_lim::MinMax`: Voltage input limits (Vi_min, Vi_max)
- `Tc::Float64`: Numerator lead-lag (lead) time constant in s, validation range: `(0, nothing)`
- `Tb::Float64`: Denominator lead-lag (lag) time constant in s, validation range: `(0, nothing)`
- `Ka::Float64`: Amplifier Gain, validation range: `(0, nothing)`
- `Ta::Float64`: Amplifier Time Constant in s, validation range: `(0, nothing)`
- `Vr_lim::MinMax`: Voltage regulator limits (regulator output) (Vr_min, Vr_max)
- `Kc::Float64`: Current field constant limiter multiplier, validation range: `(0, nothing)`
- `Kf::Float64`: Excitation control system stabilizer gain, validation range: `(eps(), 0.3)`
- `Tf::Float64`: Excitation control system stabilizer time constant, validation range: `(eps(), nothing)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed Terminal Voltage,
Vrll: Lead-Lag state,
Vr: Regulator Output,
Vfb: Feedback state
- `n_states::Int`: (**Do not modify.**) The EXST1 has 4 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct EXST1 <: AVR
"Voltage Measurement Time Constant in s"
Tr::Float64
"Voltage input limits (Vi_min, Vi_max)"
Vi_lim::MinMax
"Numerator lead-lag (lead) time constant in s"
Tc::Float64
"Denominator lead-lag (lag) time constant in s"
Tb::Float64
"Amplifier Gain"
Ka::Float64
"Amplifier Time Constant in s"
Ta::Float64
"Voltage regulator limits (regulator output) (Vr_min, Vr_max)"
Vr_lim::MinMax
"Current field constant limiter multiplier"
Kc::Float64
"Excitation control system stabilizer gain"
Kf::Float64
"Excitation control system stabilizer time constant"
Tf::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed Terminal Voltage,
Vrll: Lead-Lag state,
Vr: Regulator Output,
Vfb: Feedback state"
states::Vector{Symbol}
"(**Do not modify.**) The EXST1 has 4 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function EXST1(Tr, Vi_lim, Tc, Tb, Ka, Ta, Vr_lim, Kc, Kf, Tf, V_ref=1.0, ext=Dict{String, Any}(), )
EXST1(Tr, Vi_lim, Tc, Tb, Ka, Ta, Vr_lim, Kc, Kf, Tf, V_ref, ext, [:Vm, :Vrll, :Vr, :Vfb], 4, InfrastructureSystemsInternal(), )
end
function EXST1(; Tr, Vi_lim, Tc, Tb, Ka, Ta, Vr_lim, Kc, Kf, Tf, V_ref=1.0, ext=Dict{String, Any}(), states=[:Vm, :Vrll, :Vr, :Vfb], n_states=4, internal=InfrastructureSystemsInternal(), )
EXST1(Tr, Vi_lim, Tc, Tb, Ka, Ta, Vr_lim, Kc, Kf, Tf, V_ref, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function EXST1(::Nothing)
EXST1(;
Tr=0,
Vi_lim=(min=0.0, max=0.0),
Tc=0,
Tb=0,
Ka=0,
Ta=0,
Vr_lim=(min=0.0, max=0.0),
Kc=0,
Kf=0,
Tf=0,
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`EXST1`](@ref) `Tr`."""
get_Tr(value::EXST1) = value.Tr
"""Get [`EXST1`](@ref) `Vi_lim`."""
get_Vi_lim(value::EXST1) = value.Vi_lim
"""Get [`EXST1`](@ref) `Tc`."""
get_Tc(value::EXST1) = value.Tc
"""Get [`EXST1`](@ref) `Tb`."""
get_Tb(value::EXST1) = value.Tb
"""Get [`EXST1`](@ref) `Ka`."""
get_Ka(value::EXST1) = value.Ka
"""Get [`EXST1`](@ref) `Ta`."""
get_Ta(value::EXST1) = value.Ta
"""Get [`EXST1`](@ref) `Vr_lim`."""
get_Vr_lim(value::EXST1) = value.Vr_lim
"""Get [`EXST1`](@ref) `Kc`."""
get_Kc(value::EXST1) = value.Kc
"""Get [`EXST1`](@ref) `Kf`."""
get_Kf(value::EXST1) = value.Kf
"""Get [`EXST1`](@ref) `Tf`."""
get_Tf(value::EXST1) = value.Tf
"""Get [`EXST1`](@ref) `V_ref`."""
get_V_ref(value::EXST1) = value.V_ref
"""Get [`EXST1`](@ref) `ext`."""
get_ext(value::EXST1) = value.ext
"""Get [`EXST1`](@ref) `states`."""
get_states(value::EXST1) = value.states
"""Get [`EXST1`](@ref) `n_states`."""
get_n_states(value::EXST1) = value.n_states
"""Get [`EXST1`](@ref) `internal`."""
get_internal(value::EXST1) = value.internal
"""Set [`EXST1`](@ref) `Tr`."""
set_Tr!(value::EXST1, val) = value.Tr = val
"""Set [`EXST1`](@ref) `Vi_lim`."""
set_Vi_lim!(value::EXST1, val) = value.Vi_lim = val
"""Set [`EXST1`](@ref) `Tc`."""
set_Tc!(value::EXST1, val) = value.Tc = val
"""Set [`EXST1`](@ref) `Tb`."""
set_Tb!(value::EXST1, val) = value.Tb = val
"""Set [`EXST1`](@ref) `Ka`."""
set_Ka!(value::EXST1, val) = value.Ka = val
"""Set [`EXST1`](@ref) `Ta`."""
set_Ta!(value::EXST1, val) = value.Ta = val
"""Set [`EXST1`](@ref) `Vr_lim`."""
set_Vr_lim!(value::EXST1, val) = value.Vr_lim = val
"""Set [`EXST1`](@ref) `Kc`."""
set_Kc!(value::EXST1, val) = value.Kc = val
"""Set [`EXST1`](@ref) `Kf`."""
set_Kf!(value::EXST1, val) = value.Kf = val
"""Set [`EXST1`](@ref) `Tf`."""
set_Tf!(value::EXST1, val) = value.Tf = val
"""Set [`EXST1`](@ref) `V_ref`."""
set_V_ref!(value::EXST1, val) = value.V_ref = val
"""Set [`EXST1`](@ref) `ext`."""
set_ext!(value::EXST1, val) = value.ext = val
================================================
FILE: src/models/generated/EnergyReservoirStorage.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct EnergyReservoirStorage <: Storage
name::String
available::Bool
bus::ACBus
prime_mover_type::PrimeMovers
storage_technology_type::StorageTech
storage_capacity::Float64
storage_level_limits::MinMax
initial_storage_capacity_level::Float64
rating::Float64
active_power::Float64
input_active_power_limits::MinMax
output_active_power_limits::MinMax
efficiency::NamedTuple{(:in, :out), Tuple{Float64, Float64}}
reactive_power::Float64
reactive_power_limits::Union{Nothing, MinMax}
base_power::Float64
operation_cost::Union{StorageCost, MarketBidCost}
conversion_factor::Float64
storage_target::Float64
cycle_limits::Int
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
An energy storage device, modeled as a generic energy reservoir.
This is suitable for modeling storage charging and discharging with average efficiency losses, ignoring the physical dynamics of the storage unit. A variety of energy storage types and chemistries can be modeled with this approach. For pumped hydro storage, alternatively see [`HydroPumpTurbine`](@ref) and [`HydroReservoir`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `prime_mover_type::PrimeMovers`: Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)
- `storage_technology_type::StorageTech`: Storage Technology Complementary to EIA 923. Options are listed [here](@ref storagetech_list)
- `storage_capacity::Float64`: Maximum storage capacity (can be in units of, e.g., MWh for batteries or liters for hydrogen). When in MWh, this value divided by base_power (MVA) gives an approximate duration in hours, assuming unity power factor. For understanding this relationship, see [per unitization](@ref per_unit), validation range: `(0, nothing)`
- `storage_level_limits::MinMax`: Minimum and maximum allowable storage levels [0, 1], which can be used to model derates or other restrictions, such as state-of-charge restrictions on battery cycling, validation range: `(0, 1)`
- `initial_storage_capacity_level::Float64`: Initial storage capacity level as a ratio [0, 1.0] of `storage_capacity`, validation range: `(0, 1)`
- `rating::Float64`: Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power
- `active_power::Float64`: Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used
- `input_active_power_limits::MinMax`: Minimum and maximum limits on the input active power (i.e., charging), validation range: `(0, nothing)`
- `output_active_power_limits::MinMax`: Minimum and maximum limits on the output active power (i.e., discharging), validation range: `(0, nothing)`
- `efficiency::NamedTuple{(:in, :out), Tuple{Float64, Float64}}`: Average efficiency [0, 1] `in` (charging/filling) and `out` (discharging/consuming) of the storage system, validation range: `(0, 1)`
- `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR), validation range: `reactive_power_limits`
- `reactive_power_limits::Union{Nothing, MinMax}`: Minimum and maximum reactive power limits. Set to `Nothing` if not applicable
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `operation_cost::Union{StorageCost, MarketBidCost}`: (default: `StorageCost(nothing)`) [`OperationalCost`](@ref) of storage
- `conversion_factor::Float64`: (default: `1.0`) Conversion factor of `storage_capacity` to MWh, if different than 1.0. For example, X MWh/liter hydrogen
- `storage_target::Float64`: (default: `0.0`) Storage target at the end of simulation as ratio of storage capacity
- `cycle_limits::Int`: (default: `1e4`) Storage Maximum number of cycles per year
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct EnergyReservoirStorage <: Storage
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)"
prime_mover_type::PrimeMovers
"Storage Technology Complementary to EIA 923. Options are listed [here](@ref storagetech_list)"
storage_technology_type::StorageTech
"Maximum storage capacity (can be in units of, e.g., MWh for batteries or liters for hydrogen). When in MWh, this value divided by base_power (MVA) gives an approximate duration in hours, assuming unity power factor. For understanding this relationship, see [per unitization](@ref per_unit)"
storage_capacity::Float64
"Minimum and maximum allowable storage levels [0, 1], which can be used to model derates or other restrictions, such as state-of-charge restrictions on battery cycling"
storage_level_limits::MinMax
"Initial storage capacity level as a ratio [0, 1.0] of `storage_capacity`"
initial_storage_capacity_level::Float64
"Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power"
rating::Float64
"Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used"
active_power::Float64
"Minimum and maximum limits on the input active power (i.e., charging)"
input_active_power_limits::MinMax
"Minimum and maximum limits on the output active power (i.e., discharging)"
output_active_power_limits::MinMax
"Average efficiency [0, 1] `in` (charging/filling) and `out` (discharging/consuming) of the storage system"
efficiency::NamedTuple{(:in, :out), Tuple{Float64, Float64}}
"Initial reactive power set point of the unit (MVAR)"
reactive_power::Float64
"Minimum and maximum reactive power limits. Set to `Nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"[`OperationalCost`](@ref) of storage"
operation_cost::Union{StorageCost, MarketBidCost}
"Conversion factor of `storage_capacity` to MWh, if different than 1.0. For example, X MWh/liter hydrogen"
conversion_factor::Float64
"Storage target at the end of simulation as ratio of storage capacity"
storage_target::Float64
"Storage Maximum number of cycles per year"
cycle_limits::Int
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function EnergyReservoirStorage(name, available, bus, prime_mover_type, storage_technology_type, storage_capacity, storage_level_limits, initial_storage_capacity_level, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, operation_cost=StorageCost(nothing), conversion_factor=1.0, storage_target=0.0, cycle_limits=1e4, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
EnergyReservoirStorage(name, available, bus, prime_mover_type, storage_technology_type, storage_capacity, storage_level_limits, initial_storage_capacity_level, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, operation_cost, conversion_factor, storage_target, cycle_limits, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function EnergyReservoirStorage(; name, available, bus, prime_mover_type, storage_technology_type, storage_capacity, storage_level_limits, initial_storage_capacity_level, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, operation_cost=StorageCost(nothing), conversion_factor=1.0, storage_target=0.0, cycle_limits=1e4, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
EnergyReservoirStorage(name, available, bus, prime_mover_type, storage_technology_type, storage_capacity, storage_level_limits, initial_storage_capacity_level, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, operation_cost, conversion_factor, storage_target, cycle_limits, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function EnergyReservoirStorage(::Nothing)
EnergyReservoirStorage(;
name="init",
available=false,
bus=ACBus(nothing),
prime_mover_type=PrimeMovers.BA,
storage_technology_type=StorageTech.OTHER_CHEM,
storage_capacity=0.0,
storage_level_limits=(min=0.0, max=0.0),
initial_storage_capacity_level=0.0,
rating=0.0,
active_power=0.0,
input_active_power_limits=(min=0.0, max=0.0),
output_active_power_limits=(min=0.0, max=0.0),
efficiency=(in=0.0, out=0.0),
reactive_power=0.0,
reactive_power_limits=(min=0.0, max=0.0),
base_power=100.0,
operation_cost=StorageCost(nothing),
conversion_factor=0.0,
storage_target=0.0,
cycle_limits=0,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`EnergyReservoirStorage`](@ref) `name`."""
get_name(value::EnergyReservoirStorage) = value.name
"""Get [`EnergyReservoirStorage`](@ref) `available`."""
get_available(value::EnergyReservoirStorage) = value.available
"""Get [`EnergyReservoirStorage`](@ref) `bus`."""
get_bus(value::EnergyReservoirStorage) = value.bus
"""Get [`EnergyReservoirStorage`](@ref) `prime_mover_type`."""
get_prime_mover_type(value::EnergyReservoirStorage) = value.prime_mover_type
"""Get [`EnergyReservoirStorage`](@ref) `storage_technology_type`."""
get_storage_technology_type(value::EnergyReservoirStorage) = value.storage_technology_type
"""Get [`EnergyReservoirStorage`](@ref) `storage_capacity`."""
get_storage_capacity(value::EnergyReservoirStorage) = get_value(value, Val(:storage_capacity), Val(:mva))
"""Get [`EnergyReservoirStorage`](@ref) `storage_level_limits`."""
get_storage_level_limits(value::EnergyReservoirStorage) = value.storage_level_limits
"""Get [`EnergyReservoirStorage`](@ref) `initial_storage_capacity_level`."""
get_initial_storage_capacity_level(value::EnergyReservoirStorage) = value.initial_storage_capacity_level
"""Get [`EnergyReservoirStorage`](@ref) `rating`."""
get_rating(value::EnergyReservoirStorage) = get_value(value, Val(:rating), Val(:mva))
"""Get [`EnergyReservoirStorage`](@ref) `active_power`."""
get_active_power(value::EnergyReservoirStorage) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`EnergyReservoirStorage`](@ref) `input_active_power_limits`."""
get_input_active_power_limits(value::EnergyReservoirStorage) = get_value(value, Val(:input_active_power_limits), Val(:mva))
"""Get [`EnergyReservoirStorage`](@ref) `output_active_power_limits`."""
get_output_active_power_limits(value::EnergyReservoirStorage) = get_value(value, Val(:output_active_power_limits), Val(:mva))
"""Get [`EnergyReservoirStorage`](@ref) `efficiency`."""
get_efficiency(value::EnergyReservoirStorage) = value.efficiency
"""Get [`EnergyReservoirStorage`](@ref) `reactive_power`."""
get_reactive_power(value::EnergyReservoirStorage) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`EnergyReservoirStorage`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::EnergyReservoirStorage) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`EnergyReservoirStorage`](@ref) `base_power`."""
get_base_power(value::EnergyReservoirStorage) = value.base_power
"""Get [`EnergyReservoirStorage`](@ref) `operation_cost`."""
get_operation_cost(value::EnergyReservoirStorage) = value.operation_cost
"""Get [`EnergyReservoirStorage`](@ref) `conversion_factor`."""
get_conversion_factor(value::EnergyReservoirStorage) = value.conversion_factor
"""Get [`EnergyReservoirStorage`](@ref) `storage_target`."""
get_storage_target(value::EnergyReservoirStorage) = value.storage_target
"""Get [`EnergyReservoirStorage`](@ref) `cycle_limits`."""
get_cycle_limits(value::EnergyReservoirStorage) = value.cycle_limits
"""Get [`EnergyReservoirStorage`](@ref) `services`."""
get_services(value::EnergyReservoirStorage) = value.services
"""Get [`EnergyReservoirStorage`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::EnergyReservoirStorage) = value.dynamic_injector
"""Get [`EnergyReservoirStorage`](@ref) `ext`."""
get_ext(value::EnergyReservoirStorage) = value.ext
"""Get [`EnergyReservoirStorage`](@ref) `internal`."""
get_internal(value::EnergyReservoirStorage) = value.internal
"""Set [`EnergyReservoirStorage`](@ref) `available`."""
set_available!(value::EnergyReservoirStorage, val) = value.available = val
"""Set [`EnergyReservoirStorage`](@ref) `bus`."""
set_bus!(value::EnergyReservoirStorage, val) = value.bus = val
"""Set [`EnergyReservoirStorage`](@ref) `prime_mover_type`."""
set_prime_mover_type!(value::EnergyReservoirStorage, val) = value.prime_mover_type = val
"""Set [`EnergyReservoirStorage`](@ref) `storage_technology_type`."""
set_storage_technology_type!(value::EnergyReservoirStorage, val) = value.storage_technology_type = val
"""Set [`EnergyReservoirStorage`](@ref) `storage_capacity`."""
set_storage_capacity!(value::EnergyReservoirStorage, val) = value.storage_capacity = set_value(value, Val(:storage_capacity), val, Val(:mva))
"""Set [`EnergyReservoirStorage`](@ref) `storage_level_limits`."""
set_storage_level_limits!(value::EnergyReservoirStorage, val) = value.storage_level_limits = val
"""Set [`EnergyReservoirStorage`](@ref) `initial_storage_capacity_level`."""
set_initial_storage_capacity_level!(value::EnergyReservoirStorage, val) = value.initial_storage_capacity_level = val
"""Set [`EnergyReservoirStorage`](@ref) `rating`."""
set_rating!(value::EnergyReservoirStorage, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`EnergyReservoirStorage`](@ref) `active_power`."""
set_active_power!(value::EnergyReservoirStorage, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`EnergyReservoirStorage`](@ref) `input_active_power_limits`."""
set_input_active_power_limits!(value::EnergyReservoirStorage, val) = value.input_active_power_limits = set_value(value, Val(:input_active_power_limits), val, Val(:mva))
"""Set [`EnergyReservoirStorage`](@ref) `output_active_power_limits`."""
set_output_active_power_limits!(value::EnergyReservoirStorage, val) = value.output_active_power_limits = set_value(value, Val(:output_active_power_limits), val, Val(:mva))
"""Set [`EnergyReservoirStorage`](@ref) `efficiency`."""
set_efficiency!(value::EnergyReservoirStorage, val) = value.efficiency = val
"""Set [`EnergyReservoirStorage`](@ref) `reactive_power`."""
set_reactive_power!(value::EnergyReservoirStorage, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`EnergyReservoirStorage`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::EnergyReservoirStorage, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`EnergyReservoirStorage`](@ref) `base_power`."""
set_base_power!(value::EnergyReservoirStorage, val) = value.base_power = val
"""Set [`EnergyReservoirStorage`](@ref) `operation_cost`."""
set_operation_cost!(value::EnergyReservoirStorage, val) = value.operation_cost = val
"""Set [`EnergyReservoirStorage`](@ref) `conversion_factor`."""
set_conversion_factor!(value::EnergyReservoirStorage, val) = value.conversion_factor = val
"""Set [`EnergyReservoirStorage`](@ref) `storage_target`."""
set_storage_target!(value::EnergyReservoirStorage, val) = value.storage_target = val
"""Set [`EnergyReservoirStorage`](@ref) `cycle_limits`."""
set_cycle_limits!(value::EnergyReservoirStorage, val) = value.cycle_limits = val
"""Set [`EnergyReservoirStorage`](@ref) `services`."""
set_services!(value::EnergyReservoirStorage, val) = value.services = val
"""Set [`EnergyReservoirStorage`](@ref) `ext`."""
set_ext!(value::EnergyReservoirStorage, val) = value.ext = val
================================================
FILE: src/models/generated/ExponentialLoad.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ExponentialLoad <: StaticLoad
name::String
available::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
α::Float64
β::Float64
base_power::Float64
max_active_power::Float64
max_reactive_power::Float64
conformity::LoadConformity
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A voltage-dependent [ZIP load](@ref Z), most commonly used for dynamics modeling.
An `ExponentialLoad` models active power as P = P0 * V^α and reactive power as Q = Q0 * V^β, where the exponents α and β select govern the voltage dependency. For an alternative three-part formulation of the ZIP model, see [`StandardLoad`](@ref). For a simpler load model with no voltage dependency, see [`PowerLoad`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Active power coefficient, P0 (MW)
- `reactive_power::Float64`: Reactive power coefficient, Q0 (MVAR)
- `α::Float64`: Exponent relating voltage dependency for active power. 0 = constant power only, 1 = constant current only, and 2 = constant impedance only, validation range: `(0, nothing)`
- `β::Float64`: Exponent relating voltage dependency for reactive power. 0 = constant power only, 1 = constant current only, and 2 = constant impedance only, validation range: `(0, nothing)`
- `base_power::Float64`: Base power (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `max_active_power::Float64`: Maximum active power (MW) that this load can demand
- `max_reactive_power::Float64`: Maximum reactive power (MVAR) that this load can demand
- `conformity::LoadConformity`: (default: `LoadConformity.UNDEFINED`) Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list).
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ExponentialLoad <: StaticLoad
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Active power coefficient, P0 (MW)"
active_power::Float64
"Reactive power coefficient, Q0 (MVAR)"
reactive_power::Float64
"Exponent relating voltage dependency for active power. 0 = constant power only, 1 = constant current only, and 2 = constant impedance only"
α::Float64
"Exponent relating voltage dependency for reactive power. 0 = constant power only, 1 = constant current only, and 2 = constant impedance only"
β::Float64
"Base power (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Maximum active power (MW) that this load can demand"
max_active_power::Float64
"Maximum reactive power (MVAR) that this load can demand"
max_reactive_power::Float64
"Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list)."
conformity::LoadConformity
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ExponentialLoad(name, available, bus, active_power, reactive_power, α, β, base_power, max_active_power, max_reactive_power, conformity=LoadConformity.UNDEFINED, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
ExponentialLoad(name, available, bus, active_power, reactive_power, α, β, base_power, max_active_power, max_reactive_power, conformity, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function ExponentialLoad(; name, available, bus, active_power, reactive_power, α, β, base_power, max_active_power, max_reactive_power, conformity=LoadConformity.UNDEFINED, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
ExponentialLoad(name, available, bus, active_power, reactive_power, α, β, base_power, max_active_power, max_reactive_power, conformity, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function ExponentialLoad(::Nothing)
ExponentialLoad(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
α=0.0,
β=0.0,
base_power=100.0,
max_active_power=0.0,
max_reactive_power=0.0,
conformity=LoadConformity.UNDEFINED,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`ExponentialLoad`](@ref) `name`."""
get_name(value::ExponentialLoad) = value.name
"""Get [`ExponentialLoad`](@ref) `available`."""
get_available(value::ExponentialLoad) = value.available
"""Get [`ExponentialLoad`](@ref) `bus`."""
get_bus(value::ExponentialLoad) = value.bus
"""Get [`ExponentialLoad`](@ref) `active_power`."""
get_active_power(value::ExponentialLoad) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`ExponentialLoad`](@ref) `reactive_power`."""
get_reactive_power(value::ExponentialLoad) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`ExponentialLoad`](@ref) `α`."""
get_α(value::ExponentialLoad) = value.α
"""Get [`ExponentialLoad`](@ref) `β`."""
get_β(value::ExponentialLoad) = value.β
"""Get [`ExponentialLoad`](@ref) `base_power`."""
get_base_power(value::ExponentialLoad) = value.base_power
"""Get [`ExponentialLoad`](@ref) `max_active_power`."""
get_max_active_power(value::ExponentialLoad) = get_value(value, Val(:max_active_power), Val(:mva))
"""Get [`ExponentialLoad`](@ref) `max_reactive_power`."""
get_max_reactive_power(value::ExponentialLoad) = get_value(value, Val(:max_reactive_power), Val(:mva))
"""Get [`ExponentialLoad`](@ref) `conformity`."""
get_conformity(value::ExponentialLoad) = value.conformity
"""Get [`ExponentialLoad`](@ref) `services`."""
get_services(value::ExponentialLoad) = value.services
"""Get [`ExponentialLoad`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::ExponentialLoad) = value.dynamic_injector
"""Get [`ExponentialLoad`](@ref) `ext`."""
get_ext(value::ExponentialLoad) = value.ext
"""Get [`ExponentialLoad`](@ref) `internal`."""
get_internal(value::ExponentialLoad) = value.internal
"""Set [`ExponentialLoad`](@ref) `available`."""
set_available!(value::ExponentialLoad, val) = value.available = val
"""Set [`ExponentialLoad`](@ref) `bus`."""
set_bus!(value::ExponentialLoad, val) = value.bus = val
"""Set [`ExponentialLoad`](@ref) `active_power`."""
set_active_power!(value::ExponentialLoad, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`ExponentialLoad`](@ref) `reactive_power`."""
set_reactive_power!(value::ExponentialLoad, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`ExponentialLoad`](@ref) `α`."""
set_α!(value::ExponentialLoad, val) = value.α = val
"""Set [`ExponentialLoad`](@ref) `β`."""
set_β!(value::ExponentialLoad, val) = value.β = val
"""Set [`ExponentialLoad`](@ref) `base_power`."""
set_base_power!(value::ExponentialLoad, val) = value.base_power = val
"""Set [`ExponentialLoad`](@ref) `max_active_power`."""
set_max_active_power!(value::ExponentialLoad, val) = value.max_active_power = set_value(value, Val(:max_active_power), val, Val(:mva))
"""Set [`ExponentialLoad`](@ref) `max_reactive_power`."""
set_max_reactive_power!(value::ExponentialLoad, val) = value.max_reactive_power = set_value(value, Val(:max_reactive_power), val, Val(:mva))
"""Set [`ExponentialLoad`](@ref) `conformity`."""
set_conformity!(value::ExponentialLoad, val) = value.conformity = val
"""Set [`ExponentialLoad`](@ref) `services`."""
set_services!(value::ExponentialLoad, val) = value.services = val
"""Set [`ExponentialLoad`](@ref) `ext`."""
set_ext!(value::ExponentialLoad, val) = value.ext = val
================================================
FILE: src/models/generated/FACTSControlDevice.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct FACTSControlDevice <: StaticInjection
name::String
available::Bool
bus::ACBus
control_mode::Union{Nothing, FACTSOperationModes}
voltage_setpoint::Float64
max_shunt_current::Float64
reactive_power_required::Float64
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
Facts control devices.
Most often used in AC power flow studies as a control of voltage and, active and reactive power.
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Sending end bus number
- `control_mode::Union{Nothing, FACTSOperationModes}`: Control mode. Used to describe the behavior of the control device. [Options are listed here.](@ref factsmodes_list)
- `voltage_setpoint::Float64`: Voltage setpoint at the sending end bus, it has to be a [`PV`](@ref acbustypes_list) bus, in p.u. ([`SYSTEM_BASE`](@ref per_unit)).
- `max_shunt_current::Float64`: Maximum shunt current at the sending end bus; entered in MVA at unity voltage.
- `reactive_power_required::Float64`: Total MVAr required to hold voltage at sending bus, in %.
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) Corresponding dynamic injection model for FACTS control device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct FACTSControlDevice <: StaticInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Sending end bus number"
bus::ACBus
"Control mode. Used to describe the behavior of the control device. [Options are listed here.](@ref factsmodes_list)"
control_mode::Union{Nothing, FACTSOperationModes}
"Voltage setpoint at the sending end bus, it has to be a [`PV`](@ref acbustypes_list) bus, in p.u. ([`SYSTEM_BASE`](@ref per_unit))."
voltage_setpoint::Float64
"Maximum shunt current at the sending end bus; entered in MVA at unity voltage."
max_shunt_current::Float64
"Total MVAr required to hold voltage at sending bus, in %."
reactive_power_required::Float64
"Services that this device contributes to"
services::Vector{Service}
"Corresponding dynamic injection model for FACTS control device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function FACTSControlDevice(name, available, bus, control_mode, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
FACTSControlDevice(name, available, bus, control_mode, services, dynamic_injector, ext, 1.0, 9999.0, 100.0, InfrastructureSystemsInternal(), )
end
function FACTSControlDevice(; name, available, bus, control_mode, voltage_setpoint=1.0, max_shunt_current=9999.0, reactive_power_required=100.0, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
FACTSControlDevice(name, available, bus, control_mode, voltage_setpoint, max_shunt_current, reactive_power_required, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function FACTSControlDevice(::Nothing)
FACTSControlDevice(;
name="init",
available=false,
bus=ACBus(nothing),
control_mode=nothing,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`FACTSControlDevice`](@ref) `name`."""
get_name(value::FACTSControlDevice) = value.name
"""Get [`FACTSControlDevice`](@ref) `available`."""
get_available(value::FACTSControlDevice) = value.available
"""Get [`FACTSControlDevice`](@ref) `bus`."""
get_bus(value::FACTSControlDevice) = value.bus
"""Get [`FACTSControlDevice`](@ref) `control_mode`."""
get_control_mode(value::FACTSControlDevice) = value.control_mode
"""Get [`FACTSControlDevice`](@ref) `voltage_setpoint`."""
get_voltage_setpoint(value::FACTSControlDevice) = value.voltage_setpoint
"""Get [`FACTSControlDevice`](@ref) `max_shunt_current`."""
get_max_shunt_current(value::FACTSControlDevice) = value.max_shunt_current
"""Get [`FACTSControlDevice`](@ref) `reactive_power_required`."""
get_reactive_power_required(value::FACTSControlDevice) = value.reactive_power_required
"""Get [`FACTSControlDevice`](@ref) `services`."""
get_services(value::FACTSControlDevice) = value.services
"""Get [`FACTSControlDevice`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::FACTSControlDevice) = value.dynamic_injector
"""Get [`FACTSControlDevice`](@ref) `ext`."""
get_ext(value::FACTSControlDevice) = value.ext
"""Get [`FACTSControlDevice`](@ref) `internal`."""
get_internal(value::FACTSControlDevice) = value.internal
"""Set [`FACTSControlDevice`](@ref) `available`."""
set_available!(value::FACTSControlDevice, val) = value.available = val
"""Set [`FACTSControlDevice`](@ref) `bus`."""
set_bus!(value::FACTSControlDevice, val) = value.bus = val
"""Set [`FACTSControlDevice`](@ref) `control_mode`."""
set_control_mode!(value::FACTSControlDevice, val) = value.control_mode = val
"""Set [`FACTSControlDevice`](@ref) `voltage_setpoint`."""
set_voltage_setpoint!(value::FACTSControlDevice, val) = value.voltage_setpoint = val
"""Set [`FACTSControlDevice`](@ref) `max_shunt_current`."""
set_max_shunt_current!(value::FACTSControlDevice, val) = value.max_shunt_current = val
"""Set [`FACTSControlDevice`](@ref) `reactive_power_required`."""
set_reactive_power_required!(value::FACTSControlDevice, val) = value.reactive_power_required = val
"""Set [`FACTSControlDevice`](@ref) `services`."""
set_services!(value::FACTSControlDevice, val) = value.services = val
"""Set [`FACTSControlDevice`](@ref) `ext`."""
set_ext!(value::FACTSControlDevice, val) = value.ext = val
================================================
FILE: src/models/generated/FiveMassShaft.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct FiveMassShaft <: Shaft
H::Float64
H_hp::Float64
H_ip::Float64
H_lp::Float64
H_ex::Float64
D::Float64
D_hp::Float64
D_ip::Float64
D_lp::Float64
D_ex::Float64
D_12::Float64
D_23::Float64
D_34::Float64
D_45::Float64
K_hp::Float64
K_ip::Float64
K_lp::Float64
K_ex::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 5 mass-spring shaft model.
It contains a High-Pressure (HP) steam turbine, Intermediate-Pressure (IP)
steam turbine, Low-Pressure (LP) steam turbine, the Rotor and an Exciter (EX) mover
# Arguments
- `H::Float64`: Rotor inertia constant in MWs/MVA, validation range: `(0, nothing)`
- `H_hp::Float64`: High pressure turbine inertia constant in MWs/MVA, validation range: `(0, nothing)`
- `H_ip::Float64`: Intermediate pressure turbine inertia constant in MWs/MVA, validation range: `(0, nothing)`
- `H_lp::Float64`: Low pressure turbine inertia constant in MWs/MVA, validation range: `(0, nothing)`
- `H_ex::Float64`: Exciter inertia constant in MWs/MVA, validation range: `(0, nothing)`
- `D::Float64`: Rotor natural damping in pu, validation range: `(0, nothing)`
- `D_hp::Float64`: High pressure turbine natural damping in pu, validation range: `(0, nothing)`
- `D_ip::Float64`: Intermediate pressure turbine natural damping in pu, validation range: `(0, nothing)`
- `D_lp::Float64`: Low pressure turbine natural damping in pu, validation range: `(0, nothing)`
- `D_ex::Float64`: Exciter natural damping in pu, validation range: `(0, nothing)`
- `D_12::Float64`: High-Intermediate pressure turbine damping, validation range: `(0, nothing)`
- `D_23::Float64`: Intermediate-Low pressure turbine damping, validation range: `(0, nothing)`
- `D_34::Float64`: Low pressure turbine-Rotor damping, validation range: `(0, nothing)`
- `D_45::Float64`: Rotor-Exciter damping, validation range: `(0, nothing)`
- `K_hp::Float64`: High pressure turbine angle coefficient, validation range: `(0, nothing)`
- `K_ip::Float64`: Intermediate pressure turbine angle coefficient, validation range: `(0, nothing)`
- `K_lp::Float64`: Low pressure turbine angle coefficient, validation range: `(0, nothing)`
- `K_ex::Float64`: Exciter angle coefficient, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
δ: rotor angle,
ω: rotor speed,
δ_hp: rotor angle of high pressure turbine,
ω_hp: rotor speed of high pressure turbine,
δ_ip: rotor angle of intermediate pressure turbine,
ω_ip: rotor speed of intermediate pressure turbine,
δ_lp: rotor angle of low pressure turbine,
ω_lp: rotor speed of low pressure turbine,
δ_ex: rotor angle of exciter,
ω_lp: rotor speed of exciter
- `n_states::Int`: (**Do not modify.**) FiveMassShaft has 10 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct FiveMassShaft <: Shaft
"Rotor inertia constant in MWs/MVA"
H::Float64
"High pressure turbine inertia constant in MWs/MVA"
H_hp::Float64
"Intermediate pressure turbine inertia constant in MWs/MVA"
H_ip::Float64
"Low pressure turbine inertia constant in MWs/MVA"
H_lp::Float64
" Exciter inertia constant in MWs/MVA"
H_ex::Float64
"Rotor natural damping in pu"
D::Float64
"High pressure turbine natural damping in pu"
D_hp::Float64
"Intermediate pressure turbine natural damping in pu"
D_ip::Float64
"Low pressure turbine natural damping in pu"
D_lp::Float64
"Exciter natural damping in pu"
D_ex::Float64
"High-Intermediate pressure turbine damping"
D_12::Float64
"Intermediate-Low pressure turbine damping"
D_23::Float64
"Low pressure turbine-Rotor damping"
D_34::Float64
"Rotor-Exciter damping"
D_45::Float64
"High pressure turbine angle coefficient"
K_hp::Float64
"Intermediate pressure turbine angle coefficient"
K_ip::Float64
"Low pressure turbine angle coefficient"
K_lp::Float64
"Exciter angle coefficient"
K_ex::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
δ: rotor angle,
ω: rotor speed,
δ_hp: rotor angle of high pressure turbine,
ω_hp: rotor speed of high pressure turbine,
δ_ip: rotor angle of intermediate pressure turbine,
ω_ip: rotor speed of intermediate pressure turbine,
δ_lp: rotor angle of low pressure turbine,
ω_lp: rotor speed of low pressure turbine,
δ_ex: rotor angle of exciter,
ω_lp: rotor speed of exciter"
states::Vector{Symbol}
"(**Do not modify.**) FiveMassShaft has 10 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function FiveMassShaft(H, H_hp, H_ip, H_lp, H_ex, D, D_hp, D_ip, D_lp, D_ex, D_12, D_23, D_34, D_45, K_hp, K_ip, K_lp, K_ex, ext=Dict{String, Any}(), )
FiveMassShaft(H, H_hp, H_ip, H_lp, H_ex, D, D_hp, D_ip, D_lp, D_ex, D_12, D_23, D_34, D_45, K_hp, K_ip, K_lp, K_ex, ext, [:δ, :ω, :δ_hp, :ω_hp, :δ_ip, :ω_ip, :δ_lp, :ω_lp, :δ_ex, :ω_ex], 10, InfrastructureSystemsInternal(), )
end
function FiveMassShaft(; H, H_hp, H_ip, H_lp, H_ex, D, D_hp, D_ip, D_lp, D_ex, D_12, D_23, D_34, D_45, K_hp, K_ip, K_lp, K_ex, ext=Dict{String, Any}(), states=[:δ, :ω, :δ_hp, :ω_hp, :δ_ip, :ω_ip, :δ_lp, :ω_lp, :δ_ex, :ω_ex], n_states=10, internal=InfrastructureSystemsInternal(), )
FiveMassShaft(H, H_hp, H_ip, H_lp, H_ex, D, D_hp, D_ip, D_lp, D_ex, D_12, D_23, D_34, D_45, K_hp, K_ip, K_lp, K_ex, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function FiveMassShaft(::Nothing)
FiveMassShaft(;
H=0,
H_hp=0,
H_ip=0,
H_lp=0,
H_ex=0,
D=0,
D_hp=0,
D_ip=0,
D_lp=0,
D_ex=0,
D_12=0,
D_23=0,
D_34=0,
D_45=0,
K_hp=0,
K_ip=0,
K_lp=0,
K_ex=0,
ext=Dict{String, Any}(),
)
end
"""Get [`FiveMassShaft`](@ref) `H`."""
get_H(value::FiveMassShaft) = value.H
"""Get [`FiveMassShaft`](@ref) `H_hp`."""
get_H_hp(value::FiveMassShaft) = value.H_hp
"""Get [`FiveMassShaft`](@ref) `H_ip`."""
get_H_ip(value::FiveMassShaft) = value.H_ip
"""Get [`FiveMassShaft`](@ref) `H_lp`."""
get_H_lp(value::FiveMassShaft) = value.H_lp
"""Get [`FiveMassShaft`](@ref) `H_ex`."""
get_H_ex(value::FiveMassShaft) = value.H_ex
"""Get [`FiveMassShaft`](@ref) `D`."""
get_D(value::FiveMassShaft) = value.D
"""Get [`FiveMassShaft`](@ref) `D_hp`."""
get_D_hp(value::FiveMassShaft) = value.D_hp
"""Get [`FiveMassShaft`](@ref) `D_ip`."""
get_D_ip(value::FiveMassShaft) = value.D_ip
"""Get [`FiveMassShaft`](@ref) `D_lp`."""
get_D_lp(value::FiveMassShaft) = value.D_lp
"""Get [`FiveMassShaft`](@ref) `D_ex`."""
get_D_ex(value::FiveMassShaft) = value.D_ex
"""Get [`FiveMassShaft`](@ref) `D_12`."""
get_D_12(value::FiveMassShaft) = value.D_12
"""Get [`FiveMassShaft`](@ref) `D_23`."""
get_D_23(value::FiveMassShaft) = value.D_23
"""Get [`FiveMassShaft`](@ref) `D_34`."""
get_D_34(value::FiveMassShaft) = value.D_34
"""Get [`FiveMassShaft`](@ref) `D_45`."""
get_D_45(value::FiveMassShaft) = value.D_45
"""Get [`FiveMassShaft`](@ref) `K_hp`."""
get_K_hp(value::FiveMassShaft) = value.K_hp
"""Get [`FiveMassShaft`](@ref) `K_ip`."""
get_K_ip(value::FiveMassShaft) = value.K_ip
"""Get [`FiveMassShaft`](@ref) `K_lp`."""
get_K_lp(value::FiveMassShaft) = value.K_lp
"""Get [`FiveMassShaft`](@ref) `K_ex`."""
get_K_ex(value::FiveMassShaft) = value.K_ex
"""Get [`FiveMassShaft`](@ref) `ext`."""
get_ext(value::FiveMassShaft) = value.ext
"""Get [`FiveMassShaft`](@ref) `states`."""
get_states(value::FiveMassShaft) = value.states
"""Get [`FiveMassShaft`](@ref) `n_states`."""
get_n_states(value::FiveMassShaft) = value.n_states
"""Get [`FiveMassShaft`](@ref) `internal`."""
get_internal(value::FiveMassShaft) = value.internal
"""Set [`FiveMassShaft`](@ref) `H`."""
set_H!(value::FiveMassShaft, val) = value.H = val
"""Set [`FiveMassShaft`](@ref) `H_hp`."""
set_H_hp!(value::FiveMassShaft, val) = value.H_hp = val
"""Set [`FiveMassShaft`](@ref) `H_ip`."""
set_H_ip!(value::FiveMassShaft, val) = value.H_ip = val
"""Set [`FiveMassShaft`](@ref) `H_lp`."""
set_H_lp!(value::FiveMassShaft, val) = value.H_lp = val
"""Set [`FiveMassShaft`](@ref) `H_ex`."""
set_H_ex!(value::FiveMassShaft, val) = value.H_ex = val
"""Set [`FiveMassShaft`](@ref) `D`."""
set_D!(value::FiveMassShaft, val) = value.D = val
"""Set [`FiveMassShaft`](@ref) `D_hp`."""
set_D_hp!(value::FiveMassShaft, val) = value.D_hp = val
"""Set [`FiveMassShaft`](@ref) `D_ip`."""
set_D_ip!(value::FiveMassShaft, val) = value.D_ip = val
"""Set [`FiveMassShaft`](@ref) `D_lp`."""
set_D_lp!(value::FiveMassShaft, val) = value.D_lp = val
"""Set [`FiveMassShaft`](@ref) `D_ex`."""
set_D_ex!(value::FiveMassShaft, val) = value.D_ex = val
"""Set [`FiveMassShaft`](@ref) `D_12`."""
set_D_12!(value::FiveMassShaft, val) = value.D_12 = val
"""Set [`FiveMassShaft`](@ref) `D_23`."""
set_D_23!(value::FiveMassShaft, val) = value.D_23 = val
"""Set [`FiveMassShaft`](@ref) `D_34`."""
set_D_34!(value::FiveMassShaft, val) = value.D_34 = val
"""Set [`FiveMassShaft`](@ref) `D_45`."""
set_D_45!(value::FiveMassShaft, val) = value.D_45 = val
"""Set [`FiveMassShaft`](@ref) `K_hp`."""
set_K_hp!(value::FiveMassShaft, val) = value.K_hp = val
"""Set [`FiveMassShaft`](@ref) `K_ip`."""
set_K_ip!(value::FiveMassShaft, val) = value.K_ip = val
"""Set [`FiveMassShaft`](@ref) `K_lp`."""
set_K_lp!(value::FiveMassShaft, val) = value.K_lp = val
"""Set [`FiveMassShaft`](@ref) `K_ex`."""
set_K_ex!(value::FiveMassShaft, val) = value.K_ex = val
"""Set [`FiveMassShaft`](@ref) `ext`."""
set_ext!(value::FiveMassShaft, val) = value.ext = val
================================================
FILE: src/models/generated/FixedAdmittance.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct FixedAdmittance <: ElectricLoad
name::String
available::Bool
bus::ACBus
Y::Complex{Float64}
dynamic_injector::Union{Nothing, DynamicInjection}
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A fixed admittance.
Most often used in dynamics or AC power flow studies as a source of reactive power
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `Y::Complex{Float64}`: Fixed admittance in p.u. ([`SYSTEM_BASE`](@ref per_unit))
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection model for admittance
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct FixedAdmittance <: ElectricLoad
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Fixed admittance in p.u. ([`SYSTEM_BASE`](@ref per_unit))"
Y::Complex{Float64}
"corresponding dynamic injection model for admittance"
dynamic_injector::Union{Nothing, DynamicInjection}
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function FixedAdmittance(name, available, bus, Y, dynamic_injector=nothing, services=Device[], ext=Dict{String, Any}(), )
FixedAdmittance(name, available, bus, Y, dynamic_injector, services, ext, InfrastructureSystemsInternal(), )
end
function FixedAdmittance(; name, available, bus, Y, dynamic_injector=nothing, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
FixedAdmittance(name, available, bus, Y, dynamic_injector, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function FixedAdmittance(::Nothing)
FixedAdmittance(;
name="init",
available=false,
bus=ACBus(nothing),
Y=0.0,
dynamic_injector=nothing,
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`FixedAdmittance`](@ref) `name`."""
get_name(value::FixedAdmittance) = value.name
"""Get [`FixedAdmittance`](@ref) `available`."""
get_available(value::FixedAdmittance) = value.available
"""Get [`FixedAdmittance`](@ref) `bus`."""
get_bus(value::FixedAdmittance) = value.bus
"""Get [`FixedAdmittance`](@ref) `Y`."""
get_Y(value::FixedAdmittance) = value.Y
"""Get [`FixedAdmittance`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::FixedAdmittance) = value.dynamic_injector
"""Get [`FixedAdmittance`](@ref) `services`."""
get_services(value::FixedAdmittance) = value.services
"""Get [`FixedAdmittance`](@ref) `ext`."""
get_ext(value::FixedAdmittance) = value.ext
"""Get [`FixedAdmittance`](@ref) `internal`."""
get_internal(value::FixedAdmittance) = value.internal
"""Set [`FixedAdmittance`](@ref) `available`."""
set_available!(value::FixedAdmittance, val) = value.available = val
"""Set [`FixedAdmittance`](@ref) `bus`."""
set_bus!(value::FixedAdmittance, val) = value.bus = val
"""Set [`FixedAdmittance`](@ref) `Y`."""
set_Y!(value::FixedAdmittance, val) = value.Y = val
"""Set [`FixedAdmittance`](@ref) `services`."""
set_services!(value::FixedAdmittance, val) = value.services = val
"""Set [`FixedAdmittance`](@ref) `ext`."""
set_ext!(value::FixedAdmittance, val) = value.ext = val
================================================
FILE: src/models/generated/FixedDCSource.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct FixedDCSource <: DCSource
voltage::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of a Fixed DC Source that returns a fixed DC voltage
# Arguments
- `voltage::Float64`: Voltage (V), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) FixedDCSource has no [states](@ref S)
- `n_states::Int`: (**Do not modify.**) FixedDCSource has no states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct FixedDCSource <: DCSource
"Voltage (V)"
voltage::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) FixedDCSource has no [states](@ref S)"
states::Vector{Symbol}
"(**Do not modify.**) FixedDCSource has no states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function FixedDCSource(voltage, ext=Dict{String, Any}(), )
FixedDCSource(voltage, ext, Vector{Symbol}(), 0, InfrastructureSystemsInternal(), )
end
function FixedDCSource(; voltage, ext=Dict{String, Any}(), states=Vector{Symbol}(), n_states=0, internal=InfrastructureSystemsInternal(), )
FixedDCSource(voltage, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function FixedDCSource(::Nothing)
FixedDCSource(;
voltage=0,
ext=Dict{String, Any}(),
)
end
"""Get [`FixedDCSource`](@ref) `voltage`."""
get_voltage(value::FixedDCSource) = value.voltage
"""Get [`FixedDCSource`](@ref) `ext`."""
get_ext(value::FixedDCSource) = value.ext
"""Get [`FixedDCSource`](@ref) `states`."""
get_states(value::FixedDCSource) = value.states
"""Get [`FixedDCSource`](@ref) `n_states`."""
get_n_states(value::FixedDCSource) = value.n_states
"""Get [`FixedDCSource`](@ref) `internal`."""
get_internal(value::FixedDCSource) = value.internal
"""Set [`FixedDCSource`](@ref) `voltage`."""
set_voltage!(value::FixedDCSource, val) = value.voltage = val
"""Set [`FixedDCSource`](@ref) `ext`."""
set_ext!(value::FixedDCSource, val) = value.ext = val
================================================
FILE: src/models/generated/FixedFrequency.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct FixedFrequency <: FrequencyEstimator
frequency::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a Fixed Frequency Estimator (i.e. no PLL)
# Arguments
- `frequency::Float64`: (default: `1.0`) Reference Frequency (pu)
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) FixedFrequency has no [states](@ref S)
- `n_states::Int`: (**Do not modify.**) FixedFrequency has no states
"""
mutable struct FixedFrequency <: FrequencyEstimator
"Reference Frequency (pu)"
frequency::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) FixedFrequency has no [states](@ref S)"
states::Vector{Symbol}
"(**Do not modify.**) FixedFrequency has no states"
n_states::Int
end
function FixedFrequency(; frequency=1.0, ext=Dict{String, Any}(), states=Vector{Symbol}(), n_states=0, )
FixedFrequency(frequency, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function FixedFrequency(::Nothing)
FixedFrequency(;
frequency=0,
ext=Dict{String, Any}(),
)
end
"""Get [`FixedFrequency`](@ref) `frequency`."""
get_frequency(value::FixedFrequency) = value.frequency
"""Get [`FixedFrequency`](@ref) `ext`."""
get_ext(value::FixedFrequency) = value.ext
"""Get [`FixedFrequency`](@ref) `states`."""
get_states(value::FixedFrequency) = value.states
"""Get [`FixedFrequency`](@ref) `n_states`."""
get_n_states(value::FixedFrequency) = value.n_states
"""Set [`FixedFrequency`](@ref) `frequency`."""
set_frequency!(value::FixedFrequency, val) = value.frequency = val
"""Set [`FixedFrequency`](@ref) `ext`."""
set_ext!(value::FixedFrequency, val) = value.ext = val
================================================
FILE: src/models/generated/FullMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct FullMachine <: Machine
R::Float64
R_f::Float64
R_1d::Float64
R_1q::Float64
L_d::Float64
L_q::Float64
L_ad::Float64
L_aq::Float64
L_f1d::Float64
L_ff::Float64
L_1d::Float64
L_1q::Float64
ext::Dict{String, Any}
inv_d_fluxlink::Array{Float64,2}
inv_q_fluxlink::Array{Float64,2}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameter of a full order flux stator-rotor model without zero sequence flux in the stator.
The derivative of stator fluxes (ψd and ψq) is NOT neglected. Only one q-axis damping circuit is considered. All parameters are in machine per unit.
Refer to Chapter 3 of [Power System Stability and Control by P. Kundur](https://www.accessengineeringlibrary.com/content/book/9781260473544) or Chapter 11 of [Power System Dynamics: Stability and Control, by J. Machowski, J. Bialek and J. Bumby](https://www.wiley.com/en-us/Power+System+Dynamics%3A+Stability+and+Control%2C+3rd+Edition-p-9781119526360), for more details.
Note that the models are somewhat different (but equivalent) due to the different Park Transformation used in both books
# Arguments
- `R::Float64`: Resistance after EMF in machine per unit, validation range: `(0, nothing)`
- `R_f::Float64`: Field rotor winding resistance in per unit, validation range: `(0, nothing)`
- `R_1d::Float64`: Damping rotor winding resistance on d-axis in per unit. This value is denoted as RD in Machowski, validation range: `(0, nothing)`
- `R_1q::Float64`: Damping rotor winding resistance on q-axis in per unit. This value is denoted as RQ in Machowski, validation range: `(0, nothing)`
- `L_d::Float64`: Inductance of fictitious damping that represent the effect of the three-phase stator winding in the d-axis of the rotor, in per unit. This value is denoted as L_ad + L_l in Kundur (and Ld in Machowski), validation range: `(0, nothing)`
- `L_q::Float64`: Inductance of fictitious damping that represent the effect of the three-phase stator winding in the q-axis of the rotor, in per unit. This value is denoted as L_aq + L_l in Kundur, validation range: `(0, nothing)`
- `L_ad::Float64`: Mutual inductance between stator winding and rotor field (and damping) winding inductance on d-axis, in per unit, validation range: `(0, nothing)`
- `L_aq::Float64`: Mutual inductance between stator winding and rotor damping winding inductance on q-axis, in per unit, validation range: `(0, nothing)`
- `L_f1d::Float64`: Mutual inductance between rotor field winding and rotor damping winding inductance on d-axis, in per unit, validation range: `(0, nothing)`
- `L_ff::Float64`: Field rotor winding inductance, in per unit, validation range: `(0, nothing)`
- `L_1d::Float64`: Inductance of the d-axis rotor damping circuit, in per unit, validation range: `(0, nothing)`
- `L_1q::Float64`: Inductance of the q-axis rotor damping circuit, in per unit, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `inv_d_fluxlink::Array{Float64,2}`: (**Do not modify.**) Equations 3.127, 3.130, 3.131 From Kundur
- `inv_q_fluxlink::Array{Float64,2}`: (**Do not modify.**) Equations 3.128, 3.132 From Kundur
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
ψd: d-axis stator flux,
ψq: q-axis stator flux,
ψf: field rotor flux,
ψ1d: d-axis rotor damping flux,
ψ1q: q-axis rotor damping flux
- `n_states::Int`: (**Do not modify.**) FullMachine has 5 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct FullMachine <: Machine
"Resistance after EMF in machine per unit"
R::Float64
"Field rotor winding resistance in per unit"
R_f::Float64
" Damping rotor winding resistance on d-axis in per unit. This value is denoted as RD in Machowski"
R_1d::Float64
"Damping rotor winding resistance on q-axis in per unit. This value is denoted as RQ in Machowski"
R_1q::Float64
"Inductance of fictitious damping that represent the effect of the three-phase stator winding in the d-axis of the rotor, in per unit. This value is denoted as L_ad + L_l in Kundur (and Ld in Machowski)"
L_d::Float64
"Inductance of fictitious damping that represent the effect of the three-phase stator winding in the q-axis of the rotor, in per unit. This value is denoted as L_aq + L_l in Kundur"
L_q::Float64
"Mutual inductance between stator winding and rotor field (and damping) winding inductance on d-axis, in per unit"
L_ad::Float64
"Mutual inductance between stator winding and rotor damping winding inductance on q-axis, in per unit"
L_aq::Float64
"Mutual inductance between rotor field winding and rotor damping winding inductance on d-axis, in per unit"
L_f1d::Float64
"Field rotor winding inductance, in per unit"
L_ff::Float64
"Inductance of the d-axis rotor damping circuit, in per unit"
L_1d::Float64
"Inductance of the q-axis rotor damping circuit, in per unit"
L_1q::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) Equations 3.127, 3.130, 3.131 From Kundur"
inv_d_fluxlink::Array{Float64,2}
"(**Do not modify.**) Equations 3.128, 3.132 From Kundur"
inv_q_fluxlink::Array{Float64,2}
"(**Do not modify.**) The [states](@ref S) are:
ψd: d-axis stator flux,
ψq: q-axis stator flux,
ψf: field rotor flux,
ψ1d: d-axis rotor damping flux,
ψ1q: q-axis rotor damping flux"
states::Vector{Symbol}
"(**Do not modify.**) FullMachine has 5 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function FullMachine(R, R_f, R_1d, R_1q, L_d, L_q, L_ad, L_aq, L_f1d, L_ff, L_1d, L_1q, ext=Dict{String, Any}(), )
FullMachine(R, R_f, R_1d, R_1q, L_d, L_q, L_ad, L_aq, L_f1d, L_ff, L_1d, L_1q, ext, inv([[-L_d L_ad L_ad]; [-L_ad L_ff L_f1d]; [-L_ad L_f1d L_1d]]), inv([[-L_q L_aq]; [-L_aq L_1q]]), [:ψd, :ψq, :ψf, :ψ1d, :ψ1q], 5, InfrastructureSystemsInternal(), )
end
function FullMachine(; R, R_f, R_1d, R_1q, L_d, L_q, L_ad, L_aq, L_f1d, L_ff, L_1d, L_1q, ext=Dict{String, Any}(), inv_d_fluxlink=inv([[-L_d L_ad L_ad]; [-L_ad L_ff L_f1d]; [-L_ad L_f1d L_1d]]), inv_q_fluxlink=inv([[-L_q L_aq]; [-L_aq L_1q]]), states=[:ψd, :ψq, :ψf, :ψ1d, :ψ1q], n_states=5, internal=InfrastructureSystemsInternal(), )
FullMachine(R, R_f, R_1d, R_1q, L_d, L_q, L_ad, L_aq, L_f1d, L_ff, L_1d, L_1q, ext, inv_d_fluxlink, inv_q_fluxlink, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function FullMachine(::Nothing)
FullMachine(;
R=0,
R_f=0,
R_1d=0,
R_1q=0,
L_d=1,
L_q=1,
L_ad=2,
L_aq=2,
L_f1d=1,
L_ff=2,
L_1d=1,
L_1q=1,
ext=Dict{String, Any}(),
)
end
"""Get [`FullMachine`](@ref) `R`."""
get_R(value::FullMachine) = value.R
"""Get [`FullMachine`](@ref) `R_f`."""
get_R_f(value::FullMachine) = value.R_f
"""Get [`FullMachine`](@ref) `R_1d`."""
get_R_1d(value::FullMachine) = value.R_1d
"""Get [`FullMachine`](@ref) `R_1q`."""
get_R_1q(value::FullMachine) = value.R_1q
"""Get [`FullMachine`](@ref) `L_d`."""
get_L_d(value::FullMachine) = value.L_d
"""Get [`FullMachine`](@ref) `L_q`."""
get_L_q(value::FullMachine) = value.L_q
"""Get [`FullMachine`](@ref) `L_ad`."""
get_L_ad(value::FullMachine) = value.L_ad
"""Get [`FullMachine`](@ref) `L_aq`."""
get_L_aq(value::FullMachine) = value.L_aq
"""Get [`FullMachine`](@ref) `L_f1d`."""
get_L_f1d(value::FullMachine) = value.L_f1d
"""Get [`FullMachine`](@ref) `L_ff`."""
get_L_ff(value::FullMachine) = value.L_ff
"""Get [`FullMachine`](@ref) `L_1d`."""
get_L_1d(value::FullMachine) = value.L_1d
"""Get [`FullMachine`](@ref) `L_1q`."""
get_L_1q(value::FullMachine) = value.L_1q
"""Get [`FullMachine`](@ref) `ext`."""
get_ext(value::FullMachine) = value.ext
"""Get [`FullMachine`](@ref) `inv_d_fluxlink`."""
get_inv_d_fluxlink(value::FullMachine) = value.inv_d_fluxlink
"""Get [`FullMachine`](@ref) `inv_q_fluxlink`."""
get_inv_q_fluxlink(value::FullMachine) = value.inv_q_fluxlink
"""Get [`FullMachine`](@ref) `states`."""
get_states(value::FullMachine) = value.states
"""Get [`FullMachine`](@ref) `n_states`."""
get_n_states(value::FullMachine) = value.n_states
"""Get [`FullMachine`](@ref) `internal`."""
get_internal(value::FullMachine) = value.internal
"""Set [`FullMachine`](@ref) `R`."""
set_R!(value::FullMachine, val) = value.R = val
"""Set [`FullMachine`](@ref) `R_f`."""
set_R_f!(value::FullMachine, val) = value.R_f = val
"""Set [`FullMachine`](@ref) `R_1d`."""
set_R_1d!(value::FullMachine, val) = value.R_1d = val
"""Set [`FullMachine`](@ref) `R_1q`."""
set_R_1q!(value::FullMachine, val) = value.R_1q = val
"""Set [`FullMachine`](@ref) `L_d`."""
set_L_d!(value::FullMachine, val) = value.L_d = val
"""Set [`FullMachine`](@ref) `L_q`."""
set_L_q!(value::FullMachine, val) = value.L_q = val
"""Set [`FullMachine`](@ref) `L_ad`."""
set_L_ad!(value::FullMachine, val) = value.L_ad = val
"""Set [`FullMachine`](@ref) `L_aq`."""
set_L_aq!(value::FullMachine, val) = value.L_aq = val
"""Set [`FullMachine`](@ref) `L_f1d`."""
set_L_f1d!(value::FullMachine, val) = value.L_f1d = val
"""Set [`FullMachine`](@ref) `L_ff`."""
set_L_ff!(value::FullMachine, val) = value.L_ff = val
"""Set [`FullMachine`](@ref) `L_1d`."""
set_L_1d!(value::FullMachine, val) = value.L_1d = val
"""Set [`FullMachine`](@ref) `L_1q`."""
set_L_1q!(value::FullMachine, val) = value.L_1q = val
"""Set [`FullMachine`](@ref) `ext`."""
set_ext!(value::FullMachine, val) = value.ext = val
"""Set [`FullMachine`](@ref) `inv_d_fluxlink`."""
set_inv_d_fluxlink!(value::FullMachine, val) = value.inv_d_fluxlink = val
"""Set [`FullMachine`](@ref) `inv_q_fluxlink`."""
set_inv_q_fluxlink!(value::FullMachine, val) = value.inv_q_fluxlink = val
================================================
FILE: src/models/generated/GasTG.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct GasTG <: TurbineGov
R::Float64
T1::Float64
T2::Float64
T3::Float64
AT::Float64
Kt::Float64
V_lim::Tuple{Float64, Float64}
D_turb::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Parameters of Gas Turbine-Governor. GAST in PSSE and GAST_PTI in PowerWorld
# Arguments
- `R::Float64`: Speed droop parameter, validation range: `(eps(), 0.1)`
- `T1::Float64`: Governor time constant in s, validation range: `(eps(), 0.5)`
- `T2::Float64`: Combustion chamber time constant, validation range: `(eps(), 0.5)`
- `T3::Float64`: Load limit time constant (exhaust gas measurement time), validation range: `(eps(), 5)`
- `AT::Float64`: Ambient temperature load limit, validation range: `(0, 1)`
- `Kt::Float64`: Load limit feedback gain, validation range: `(0, 5)`
- `V_lim::Tuple{Float64, Float64}`: Operational control limits on fuel valve opening (V_min, V_max)
- `D_turb::Float64`: Speed damping coefficient of gas turbine rotor, validation range: `(0, 0.5)`
- `P_ref::Float64`: (default: `1.0`) Reference Load Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the GAST model are:
x_g1: Fuel valve opening,
x_g2: Fuel flow,
x_g3: Exhaust temperature load
- `n_states::Int`: (**Do not modify.**) GasTG has 3 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) GAST has 3 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct GasTG <: TurbineGov
"Speed droop parameter"
R::Float64
"Governor time constant in s"
T1::Float64
"Combustion chamber time constant"
T2::Float64
"Load limit time constant (exhaust gas measurement time)"
T3::Float64
"Ambient temperature load limit"
AT::Float64
"Load limit feedback gain"
Kt::Float64
"Operational control limits on fuel valve opening (V_min, V_max)"
V_lim::Tuple{Float64, Float64}
"Speed damping coefficient of gas turbine rotor"
D_turb::Float64
"Reference Load Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the GAST model are:
x_g1: Fuel valve opening,
x_g2: Fuel flow,
x_g3: Exhaust temperature load"
states::Vector{Symbol}
"(**Do not modify.**) GasTG has 3 states"
n_states::Int
"(**Do not modify.**) GAST has 3 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function GasTG(R, T1, T2, T3, AT, Kt, V_lim, D_turb, P_ref=1.0, ext=Dict{String, Any}(), )
GasTG(R, T1, T2, T3, AT, Kt, V_lim, D_turb, P_ref, ext, [:x_g1, :x_g2, :x_g3], 3, [StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function GasTG(; R, T1, T2, T3, AT, Kt, V_lim, D_turb, P_ref=1.0, ext=Dict{String, Any}(), states=[:x_g1, :x_g2, :x_g3], n_states=3, states_types=[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
GasTG(R, T1, T2, T3, AT, Kt, V_lim, D_turb, P_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function GasTG(::Nothing)
GasTG(;
R=0,
T1=0,
T2=0,
T3=0,
AT=0,
Kt=0,
V_lim=(0.0, 0.0),
D_turb=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`GasTG`](@ref) `R`."""
get_R(value::GasTG) = value.R
"""Get [`GasTG`](@ref) `T1`."""
get_T1(value::GasTG) = value.T1
"""Get [`GasTG`](@ref) `T2`."""
get_T2(value::GasTG) = value.T2
"""Get [`GasTG`](@ref) `T3`."""
get_T3(value::GasTG) = value.T3
"""Get [`GasTG`](@ref) `AT`."""
get_AT(value::GasTG) = value.AT
"""Get [`GasTG`](@ref) `Kt`."""
get_Kt(value::GasTG) = value.Kt
"""Get [`GasTG`](@ref) `V_lim`."""
get_V_lim(value::GasTG) = value.V_lim
"""Get [`GasTG`](@ref) `D_turb`."""
get_D_turb(value::GasTG) = value.D_turb
"""Get [`GasTG`](@ref) `P_ref`."""
get_P_ref(value::GasTG) = value.P_ref
"""Get [`GasTG`](@ref) `ext`."""
get_ext(value::GasTG) = value.ext
"""Get [`GasTG`](@ref) `states`."""
get_states(value::GasTG) = value.states
"""Get [`GasTG`](@ref) `n_states`."""
get_n_states(value::GasTG) = value.n_states
"""Get [`GasTG`](@ref) `states_types`."""
get_states_types(value::GasTG) = value.states_types
"""Get [`GasTG`](@ref) `internal`."""
get_internal(value::GasTG) = value.internal
"""Set [`GasTG`](@ref) `R`."""
set_R!(value::GasTG, val) = value.R = val
"""Set [`GasTG`](@ref) `T1`."""
set_T1!(value::GasTG, val) = value.T1 = val
"""Set [`GasTG`](@ref) `T2`."""
set_T2!(value::GasTG, val) = value.T2 = val
"""Set [`GasTG`](@ref) `T3`."""
set_T3!(value::GasTG, val) = value.T3 = val
"""Set [`GasTG`](@ref) `AT`."""
set_AT!(value::GasTG, val) = value.AT = val
"""Set [`GasTG`](@ref) `Kt`."""
set_Kt!(value::GasTG, val) = value.Kt = val
"""Set [`GasTG`](@ref) `V_lim`."""
set_V_lim!(value::GasTG, val) = value.V_lim = val
"""Set [`GasTG`](@ref) `D_turb`."""
set_D_turb!(value::GasTG, val) = value.D_turb = val
"""Set [`GasTG`](@ref) `P_ref`."""
set_P_ref!(value::GasTG, val) = value.P_ref = val
"""Set [`GasTG`](@ref) `ext`."""
set_ext!(value::GasTG, val) = value.ext = val
"""Set [`GasTG`](@ref) `states_types`."""
set_states_types!(value::GasTG, val) = value.states_types = val
================================================
FILE: src/models/generated/GeneralGovModel.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct GeneralGovModel <: TurbineGov
Rselect::Int
fuel_flag::Int
R::Float64
Tpelec::Float64
speed_error_signal::MinMax
Kp_gov::Float64
Ki_gov::Float64
Kd_gov::Float64
Td_gov::Float64
valve_position_limits::MinMax
T_act::Float64
K_turb::Float64
Wf_nl::Float64
Tb::Float64
Tc::Float64
T_eng::Float64
Tf_load::Float64
Kp_load::Float64
Ki_load::Float64
Ld_ref::Float64
Dm::Float64
R_open::Float64
R_close::Float64
Ki_mw::Float64
A_set::Float64
Ka::Float64
Ta::Float64
T_rate::Float64
db::Float64
Tsa::Float64
Tsb::Float64
R_lim::UpDown
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
GE General Governor/Turbine Model. The GeneralGovModel (GGOV1) model is a general purpose governor model used for a variety of prime movers controlled by proportional-integral-derivative (PID) governors including gas turbines
# Arguments
- `Rselect::Int`: Feedback signal for governor droop, validation range: `(-2, 1)`
- `fuel_flag::Int`: Flag Switch for fuel source characteristic, validation range: `(0, 1)`
- `R::Float64`: Speed droop parameter, validation range: `(eps(), nothing)`
- `Tpelec::Float64`: Electrical power transducer time constant, seconds, validation range: `(eps(), nothing)`
- `speed_error_signal::MinMax`: Speed error signal limits
- `Kp_gov::Float64`: Governor proportional gain, validation range: `(0, nothing)`
- `Ki_gov::Float64`: Governor integral gain, validation range: `(0, nothing)`
- `Kd_gov::Float64`: Governor derivative gain, validation range: `(0, nothing)`
- `Td_gov::Float64`: Governor derivative time constant, validation range: `(0, nothing)`
- `valve_position_limits::MinMax`: Valve position limits
- `T_act::Float64`: Actuator time constant, validation range: `(0, nothing)`
- `K_turb::Float64`: Turbine gain, validation range: `(0, nothing)`
- `Wf_nl::Float64`: No load fuel flow, pu, validation range: `(0, nothing)`
- `Tb::Float64`: Turbine lag time constant, sec, validation range: `(0, nothing)`
- `Tc::Float64`: Turbine lead time constant, sec, validation range: `(0, nothing)`
- `T_eng::Float64`: Transport lag time constant for diesel engine, sec, validation range: `(0, nothing)`
- `Tf_load::Float64`: Load limiter time constant, validation range: `(0, nothing)`
- `Kp_load::Float64`: Load limiter proportional gain for PI controller, validation range: `(0, nothing)`
- `Ki_load::Float64`: Load integral gain for PI controller, validation range: `(0, nothing)`
- `Ld_ref::Float64`: Load limiter integral gain for PI controller, validation range: `(0, nothing)`
- `Dm::Float64`: Mechanical damping coefficient, pu, validation range: `(0, nothing)`
- `R_open::Float64`: Maximum valve opening rate, pu/sec, validation range: `(0, nothing)`
- `R_close::Float64`: Maximum valve closing rate, pu/sec, validation range: `(0, nothing)`
- `Ki_mw::Float64`: Power controller (reset) gain, validation range: `(0, nothing)`
- `A_set::Float64`: Acceleration limiter setpoint, pu/sec, validation range: `(0, nothing)`
- `Ka::Float64`: Acceleration limiter gain, validation range: `(0, nothing)`
- `Ta::Float64`: Acceleration limiter time constant , validation range: `(eps(), nothing)`
- `T_rate::Float64`: Turbine rating, validation range: `(0, nothing)`
- `db::Float64`: Speed governor deadband, validation range: `(0, nothing)`
- `Tsa::Float64`: Temperature detection lead time constant, validation range: `(0, nothing)`
- `Tsb::Float64`: Temperature detection lag time constant, validation range: `(0, nothing)`
- `R_lim::UpDown`: Maximum rate of load increase
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the GGOV1 model are:
Pe: Machine Electrical Power Measurement,
x_g1: Governor differential control,
x_g2: Governor integral control,
x_g3: Turbine actuator,
x_g4: Turbine Lead-Lag,
x_g5: Turbine load limiter measurement,
x_g6: Turbine Load Limiter Integral Control,
x_g7: Supervisory Load Control,
x_g8: Acceleration Control,
x_g9 Temperature Detection Lead - Lag:
- `n_states::Int`: (**Do not modify.**) GeneralGovModel has 10 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) GGOV1 has 10 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct GeneralGovModel <: TurbineGov
"Feedback signal for governor droop"
Rselect::Int
"Flag Switch for fuel source characteristic"
fuel_flag::Int
"Speed droop parameter"
R::Float64
"Electrical power transducer time constant, seconds"
Tpelec::Float64
"Speed error signal limits"
speed_error_signal::MinMax
"Governor proportional gain"
Kp_gov::Float64
"Governor integral gain"
Ki_gov::Float64
"Governor derivative gain"
Kd_gov::Float64
"Governor derivative time constant"
Td_gov::Float64
"Valve position limits"
valve_position_limits::MinMax
"Actuator time constant"
T_act::Float64
"Turbine gain"
K_turb::Float64
"No load fuel flow, pu"
Wf_nl::Float64
"Turbine lag time constant, sec"
Tb::Float64
"Turbine lead time constant, sec"
Tc::Float64
"Transport lag time constant for diesel engine, sec"
T_eng::Float64
"Load limiter time constant"
Tf_load::Float64
"Load limiter proportional gain for PI controller"
Kp_load::Float64
"Load integral gain for PI controller"
Ki_load::Float64
"Load limiter integral gain for PI controller"
Ld_ref::Float64
"Mechanical damping coefficient, pu"
Dm::Float64
"Maximum valve opening rate, pu/sec"
R_open::Float64
"Maximum valve closing rate, pu/sec"
R_close::Float64
"Power controller (reset) gain"
Ki_mw::Float64
"Acceleration limiter setpoint, pu/sec"
A_set::Float64
"Acceleration limiter gain"
Ka::Float64
"Acceleration limiter time constant "
Ta::Float64
"Turbine rating"
T_rate::Float64
"Speed governor deadband"
db::Float64
"Temperature detection lead time constant"
Tsa::Float64
"Temperature detection lag time constant"
Tsb::Float64
"Maximum rate of load increase"
R_lim::UpDown
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the GGOV1 model are:
Pe: Machine Electrical Power Measurement,
x_g1: Governor differential control,
x_g2: Governor integral control,
x_g3: Turbine actuator,
x_g4: Turbine Lead-Lag,
x_g5: Turbine load limiter measurement,
x_g6: Turbine Load Limiter Integral Control,
x_g7: Supervisory Load Control,
x_g8: Acceleration Control,
x_g9 Temperature Detection Lead - Lag:"
states::Vector{Symbol}
"(**Do not modify.**) GeneralGovModel has 10 states"
n_states::Int
"(**Do not modify.**) GGOV1 has 10 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function GeneralGovModel(Rselect, fuel_flag, R, Tpelec, speed_error_signal, Kp_gov, Ki_gov, Kd_gov, Td_gov, valve_position_limits, T_act, K_turb, Wf_nl, Tb, Tc, T_eng, Tf_load, Kp_load, Ki_load, Ld_ref, Dm, R_open, R_close, Ki_mw, A_set, Ka, Ta, T_rate, db, Tsa, Tsb, R_lim, P_ref=1.0, ext=Dict{String, Any}(), )
GeneralGovModel(Rselect, fuel_flag, R, Tpelec, speed_error_signal, Kp_gov, Ki_gov, Kd_gov, Td_gov, valve_position_limits, T_act, K_turb, Wf_nl, Tb, Tc, T_eng, Tf_load, Kp_load, Ki_load, Ld_ref, Dm, R_open, R_close, Ki_mw, A_set, Ka, Ta, T_rate, db, Tsa, Tsb, R_lim, P_ref, ext, [:Pe, :x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6, :x_g7, :x_g8, :x_g9], 10, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Hybrid], InfrastructureSystemsInternal(), )
end
function GeneralGovModel(; Rselect, fuel_flag, R, Tpelec, speed_error_signal, Kp_gov, Ki_gov, Kd_gov, Td_gov, valve_position_limits, T_act, K_turb, Wf_nl, Tb, Tc, T_eng, Tf_load, Kp_load, Ki_load, Ld_ref, Dm, R_open, R_close, Ki_mw, A_set, Ka, Ta, T_rate, db, Tsa, Tsb, R_lim, P_ref=1.0, ext=Dict{String, Any}(), states=[:Pe, :x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6, :x_g7, :x_g8, :x_g9], n_states=10, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Hybrid], internal=InfrastructureSystemsInternal(), )
GeneralGovModel(Rselect, fuel_flag, R, Tpelec, speed_error_signal, Kp_gov, Ki_gov, Kd_gov, Td_gov, valve_position_limits, T_act, K_turb, Wf_nl, Tb, Tc, T_eng, Tf_load, Kp_load, Ki_load, Ld_ref, Dm, R_open, R_close, Ki_mw, A_set, Ka, Ta, T_rate, db, Tsa, Tsb, R_lim, P_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function GeneralGovModel(::Nothing)
GeneralGovModel(;
Rselect=1,
fuel_flag=0,
R=0,
Tpelec=0,
speed_error_signal=(min=0.0, max=0.0),
Kp_gov=0,
Ki_gov=0,
Kd_gov=0,
Td_gov=0,
valve_position_limits=(min=0.0, max=0.0),
T_act=0,
K_turb=0,
Wf_nl=0,
Tb=0,
Tc=0,
T_eng=0,
Tf_load=0,
Kp_load=0,
Ki_load=0,
Ld_ref=0,
Dm=0,
R_open=0,
R_close=0,
Ki_mw=0,
A_set=0,
Ka=0,
Ta=0,
T_rate=0,
db=0,
Tsa=0,
Tsb=0,
R_lim=(up = 0.0, down = 0.0),
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`GeneralGovModel`](@ref) `Rselect`."""
get_Rselect(value::GeneralGovModel) = value.Rselect
"""Get [`GeneralGovModel`](@ref) `fuel_flag`."""
get_fuel_flag(value::GeneralGovModel) = value.fuel_flag
"""Get [`GeneralGovModel`](@ref) `R`."""
get_R(value::GeneralGovModel) = value.R
"""Get [`GeneralGovModel`](@ref) `Tpelec`."""
get_Tpelec(value::GeneralGovModel) = value.Tpelec
"""Get [`GeneralGovModel`](@ref) `speed_error_signal`."""
get_speed_error_signal(value::GeneralGovModel) = value.speed_error_signal
"""Get [`GeneralGovModel`](@ref) `Kp_gov`."""
get_Kp_gov(value::GeneralGovModel) = value.Kp_gov
"""Get [`GeneralGovModel`](@ref) `Ki_gov`."""
get_Ki_gov(value::GeneralGovModel) = value.Ki_gov
"""Get [`GeneralGovModel`](@ref) `Kd_gov`."""
get_Kd_gov(value::GeneralGovModel) = value.Kd_gov
"""Get [`GeneralGovModel`](@ref) `Td_gov`."""
get_Td_gov(value::GeneralGovModel) = value.Td_gov
"""Get [`GeneralGovModel`](@ref) `valve_position_limits`."""
get_valve_position_limits(value::GeneralGovModel) = value.valve_position_limits
"""Get [`GeneralGovModel`](@ref) `T_act`."""
get_T_act(value::GeneralGovModel) = value.T_act
"""Get [`GeneralGovModel`](@ref) `K_turb`."""
get_K_turb(value::GeneralGovModel) = value.K_turb
"""Get [`GeneralGovModel`](@ref) `Wf_nl`."""
get_Wf_nl(value::GeneralGovModel) = value.Wf_nl
"""Get [`GeneralGovModel`](@ref) `Tb`."""
get_Tb(value::GeneralGovModel) = value.Tb
"""Get [`GeneralGovModel`](@ref) `Tc`."""
get_Tc(value::GeneralGovModel) = value.Tc
"""Get [`GeneralGovModel`](@ref) `T_eng`."""
get_T_eng(value::GeneralGovModel) = value.T_eng
"""Get [`GeneralGovModel`](@ref) `Tf_load`."""
get_Tf_load(value::GeneralGovModel) = value.Tf_load
"""Get [`GeneralGovModel`](@ref) `Kp_load`."""
get_Kp_load(value::GeneralGovModel) = value.Kp_load
"""Get [`GeneralGovModel`](@ref) `Ki_load`."""
get_Ki_load(value::GeneralGovModel) = value.Ki_load
"""Get [`GeneralGovModel`](@ref) `Ld_ref`."""
get_Ld_ref(value::GeneralGovModel) = value.Ld_ref
"""Get [`GeneralGovModel`](@ref) `Dm`."""
get_Dm(value::GeneralGovModel) = value.Dm
"""Get [`GeneralGovModel`](@ref) `R_open`."""
get_R_open(value::GeneralGovModel) = value.R_open
"""Get [`GeneralGovModel`](@ref) `R_close`."""
get_R_close(value::GeneralGovModel) = value.R_close
"""Get [`GeneralGovModel`](@ref) `Ki_mw`."""
get_Ki_mw(value::GeneralGovModel) = value.Ki_mw
"""Get [`GeneralGovModel`](@ref) `A_set`."""
get_A_set(value::GeneralGovModel) = value.A_set
"""Get [`GeneralGovModel`](@ref) `Ka`."""
get_Ka(value::GeneralGovModel) = value.Ka
"""Get [`GeneralGovModel`](@ref) `Ta`."""
get_Ta(value::GeneralGovModel) = value.Ta
"""Get [`GeneralGovModel`](@ref) `T_rate`."""
get_T_rate(value::GeneralGovModel) = value.T_rate
"""Get [`GeneralGovModel`](@ref) `db`."""
get_db(value::GeneralGovModel) = value.db
"""Get [`GeneralGovModel`](@ref) `Tsa`."""
get_Tsa(value::GeneralGovModel) = value.Tsa
"""Get [`GeneralGovModel`](@ref) `Tsb`."""
get_Tsb(value::GeneralGovModel) = value.Tsb
"""Get [`GeneralGovModel`](@ref) `R_lim`."""
get_R_lim(value::GeneralGovModel) = value.R_lim
"""Get [`GeneralGovModel`](@ref) `P_ref`."""
get_P_ref(value::GeneralGovModel) = value.P_ref
"""Get [`GeneralGovModel`](@ref) `ext`."""
get_ext(value::GeneralGovModel) = value.ext
"""Get [`GeneralGovModel`](@ref) `states`."""
get_states(value::GeneralGovModel) = value.states
"""Get [`GeneralGovModel`](@ref) `n_states`."""
get_n_states(value::GeneralGovModel) = value.n_states
"""Get [`GeneralGovModel`](@ref) `states_types`."""
get_states_types(value::GeneralGovModel) = value.states_types
"""Get [`GeneralGovModel`](@ref) `internal`."""
get_internal(value::GeneralGovModel) = value.internal
"""Set [`GeneralGovModel`](@ref) `Rselect`."""
set_Rselect!(value::GeneralGovModel, val) = value.Rselect = val
"""Set [`GeneralGovModel`](@ref) `fuel_flag`."""
set_fuel_flag!(value::GeneralGovModel, val) = value.fuel_flag = val
"""Set [`GeneralGovModel`](@ref) `R`."""
set_R!(value::GeneralGovModel, val) = value.R = val
"""Set [`GeneralGovModel`](@ref) `Tpelec`."""
set_Tpelec!(value::GeneralGovModel, val) = value.Tpelec = val
"""Set [`GeneralGovModel`](@ref) `speed_error_signal`."""
set_speed_error_signal!(value::GeneralGovModel, val) = value.speed_error_signal = val
"""Set [`GeneralGovModel`](@ref) `Kp_gov`."""
set_Kp_gov!(value::GeneralGovModel, val) = value.Kp_gov = val
"""Set [`GeneralGovModel`](@ref) `Ki_gov`."""
set_Ki_gov!(value::GeneralGovModel, val) = value.Ki_gov = val
"""Set [`GeneralGovModel`](@ref) `Kd_gov`."""
set_Kd_gov!(value::GeneralGovModel, val) = value.Kd_gov = val
"""Set [`GeneralGovModel`](@ref) `Td_gov`."""
set_Td_gov!(value::GeneralGovModel, val) = value.Td_gov = val
"""Set [`GeneralGovModel`](@ref) `valve_position_limits`."""
set_valve_position_limits!(value::GeneralGovModel, val) = value.valve_position_limits = val
"""Set [`GeneralGovModel`](@ref) `T_act`."""
set_T_act!(value::GeneralGovModel, val) = value.T_act = val
"""Set [`GeneralGovModel`](@ref) `K_turb`."""
set_K_turb!(value::GeneralGovModel, val) = value.K_turb = val
"""Set [`GeneralGovModel`](@ref) `Wf_nl`."""
set_Wf_nl!(value::GeneralGovModel, val) = value.Wf_nl = val
"""Set [`GeneralGovModel`](@ref) `Tb`."""
set_Tb!(value::GeneralGovModel, val) = value.Tb = val
"""Set [`GeneralGovModel`](@ref) `Tc`."""
set_Tc!(value::GeneralGovModel, val) = value.Tc = val
"""Set [`GeneralGovModel`](@ref) `T_eng`."""
set_T_eng!(value::GeneralGovModel, val) = value.T_eng = val
"""Set [`GeneralGovModel`](@ref) `Tf_load`."""
set_Tf_load!(value::GeneralGovModel, val) = value.Tf_load = val
"""Set [`GeneralGovModel`](@ref) `Kp_load`."""
set_Kp_load!(value::GeneralGovModel, val) = value.Kp_load = val
"""Set [`GeneralGovModel`](@ref) `Ki_load`."""
set_Ki_load!(value::GeneralGovModel, val) = value.Ki_load = val
"""Set [`GeneralGovModel`](@ref) `Ld_ref`."""
set_Ld_ref!(value::GeneralGovModel, val) = value.Ld_ref = val
"""Set [`GeneralGovModel`](@ref) `Dm`."""
set_Dm!(value::GeneralGovModel, val) = value.Dm = val
"""Set [`GeneralGovModel`](@ref) `R_open`."""
set_R_open!(value::GeneralGovModel, val) = value.R_open = val
"""Set [`GeneralGovModel`](@ref) `R_close`."""
set_R_close!(value::GeneralGovModel, val) = value.R_close = val
"""Set [`GeneralGovModel`](@ref) `Ki_mw`."""
set_Ki_mw!(value::GeneralGovModel, val) = value.Ki_mw = val
"""Set [`GeneralGovModel`](@ref) `A_set`."""
set_A_set!(value::GeneralGovModel, val) = value.A_set = val
"""Set [`GeneralGovModel`](@ref) `Ka`."""
set_Ka!(value::GeneralGovModel, val) = value.Ka = val
"""Set [`GeneralGovModel`](@ref) `Ta`."""
set_Ta!(value::GeneralGovModel, val) = value.Ta = val
"""Set [`GeneralGovModel`](@ref) `T_rate`."""
set_T_rate!(value::GeneralGovModel, val) = value.T_rate = val
"""Set [`GeneralGovModel`](@ref) `db`."""
set_db!(value::GeneralGovModel, val) = value.db = val
"""Set [`GeneralGovModel`](@ref) `Tsa`."""
set_Tsa!(value::GeneralGovModel, val) = value.Tsa = val
"""Set [`GeneralGovModel`](@ref) `Tsb`."""
set_Tsb!(value::GeneralGovModel, val) = value.Tsb = val
"""Set [`GeneralGovModel`](@ref) `R_lim`."""
set_R_lim!(value::GeneralGovModel, val) = value.R_lim = val
"""Set [`GeneralGovModel`](@ref) `P_ref`."""
set_P_ref!(value::GeneralGovModel, val) = value.P_ref = val
"""Set [`GeneralGovModel`](@ref) `ext`."""
set_ext!(value::GeneralGovModel, val) = value.ext = val
"""Set [`GeneralGovModel`](@ref) `states_types`."""
set_states_types!(value::GeneralGovModel, val) = value.states_types = val
================================================
FILE: src/models/generated/GenericArcImpedance.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct GenericArcImpedance <: ACTransmission
name::String
available::Bool
active_power_flow::Float64
reactive_power_flow::Float64
max_flow::Float64
arc::Arc
r::Float64
x::Float64
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A virtual impedance between two buses that does not correspond to a physical component. This can be used to model the effects of network reductions (e.g. Ward reduction).
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow::Float64`: Initial condition of active power flow on the line (MW)
- `reactive_power_flow::Float64`: Initial condition of reactive power flow on the line (MVAR)
- `max_flow::Float64`: Maximum allowable flow on the generic impedance. When defining a GenericArcImpedance before it is attached to a `System`, `max_flow` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to
- `arc::Arc`: An [`Arc`](@ref) defining this line `from` a bus `to` another bus
- `r::Float64`: Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))
- `x::Float64`: Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct GenericArcImpedance <: ACTransmission
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial condition of active power flow on the line (MW)"
active_power_flow::Float64
"Initial condition of reactive power flow on the line (MVAR)"
reactive_power_flow::Float64
"Maximum allowable flow on the generic impedance. When defining a GenericArcImpedance before it is attached to a `System`, `max_flow` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to"
max_flow::Float64
"An [`Arc`](@ref) defining this line `from` a bus `to` another bus"
arc::Arc
"Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))"
r::Float64
"Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))"
x::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function GenericArcImpedance(name, available, active_power_flow, reactive_power_flow, max_flow, arc, r, x, ext=Dict{String, Any}(), )
GenericArcImpedance(name, available, active_power_flow, reactive_power_flow, max_flow, arc, r, x, ext, InfrastructureSystemsInternal(), )
end
function GenericArcImpedance(; name, available, active_power_flow, reactive_power_flow, max_flow, arc, r, x, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
GenericArcImpedance(name, available, active_power_flow, reactive_power_flow, max_flow, arc, r, x, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function GenericArcImpedance(::Nothing)
GenericArcImpedance(;
name="init",
available=false,
active_power_flow=0.0,
reactive_power_flow=0.0,
max_flow=0.0,
arc=Arc(ACBus(nothing), ACBus(nothing)),
r=0.0,
x=0.0,
ext=Dict{String, Any}(),
)
end
"""Get [`GenericArcImpedance`](@ref) `name`."""
get_name(value::GenericArcImpedance) = value.name
"""Get [`GenericArcImpedance`](@ref) `available`."""
get_available(value::GenericArcImpedance) = value.available
"""Get [`GenericArcImpedance`](@ref) `active_power_flow`."""
get_active_power_flow(value::GenericArcImpedance) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`GenericArcImpedance`](@ref) `reactive_power_flow`."""
get_reactive_power_flow(value::GenericArcImpedance) = get_value(value, Val(:reactive_power_flow), Val(:mva))
"""Get [`GenericArcImpedance`](@ref) `max_flow`."""
get_max_flow(value::GenericArcImpedance) = get_value(value, Val(:max_flow), Val(:mva))
"""Get [`GenericArcImpedance`](@ref) `arc`."""
get_arc(value::GenericArcImpedance) = value.arc
"""Get [`GenericArcImpedance`](@ref) `r`."""
get_r(value::GenericArcImpedance) = get_value(value, Val(:r), Val(:ohm))
"""Get [`GenericArcImpedance`](@ref) `x`."""
get_x(value::GenericArcImpedance) = get_value(value, Val(:x), Val(:ohm))
"""Get [`GenericArcImpedance`](@ref) `ext`."""
get_ext(value::GenericArcImpedance) = value.ext
"""Get [`GenericArcImpedance`](@ref) `internal`."""
get_internal(value::GenericArcImpedance) = value.internal
"""Set [`GenericArcImpedance`](@ref) `available`."""
set_available!(value::GenericArcImpedance, val) = value.available = val
"""Set [`GenericArcImpedance`](@ref) `active_power_flow`."""
set_active_power_flow!(value::GenericArcImpedance, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`GenericArcImpedance`](@ref) `reactive_power_flow`."""
set_reactive_power_flow!(value::GenericArcImpedance, val) = value.reactive_power_flow = set_value(value, Val(:reactive_power_flow), val, Val(:mva))
"""Set [`GenericArcImpedance`](@ref) `max_flow`."""
set_max_flow!(value::GenericArcImpedance, val) = value.max_flow = set_value(value, Val(:max_flow), val, Val(:mva))
"""Set [`GenericArcImpedance`](@ref) `arc`."""
set_arc!(value::GenericArcImpedance, val) = value.arc = val
"""Set [`GenericArcImpedance`](@ref) `r`."""
set_r!(value::GenericArcImpedance, val) = value.r = set_value(value, Val(:r), val, Val(:ohm))
"""Set [`GenericArcImpedance`](@ref) `x`."""
set_x!(value::GenericArcImpedance, val) = value.x = set_value(value, Val(:x), val, Val(:ohm))
"""Set [`GenericArcImpedance`](@ref) `ext`."""
set_ext!(value::GenericArcImpedance, val) = value.ext = val
================================================
FILE: src/models/generated/GenericDER.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct GenericDER <: DynamicInjection
name::String
Qref_Flag::Int
PQ_Flag::Int
Gen_Flag::Int
PerOp_Flag::Int
Recon_Flag::Int
Trv::Float64
VV_pnts::NamedTuple{(:V1, :V2, :V3, :V4), Tuple{Float64, Float64, Float64, Float64}}
Q_lim::MinMax
Tp::Float64
e_lim::MinMax
Kpq::Float64
Kiq::Float64
Iqr_lim::MinMax
I_max::Float64
Tg::Float64
kWh_Cap::Float64
SOC_ini::Float64
SOC_lim::MinMax
Trf::Float64
fdbd_pnts::NamedTuple{(:fdbd1, :fdbd2), Tuple{Float64, Float64}}
D_dn::Float64
D_up::Float64
fe_lim::MinMax
Kpp::Float64
Kip::Float64
P_lim::MinMax
dP_lim::MinMax
T_pord::Float64
rrpwr::Float64
VRT_pnts::NamedTuple{(:vrt1, :vrt2, :vrt3, :vrt4, :vrt5), Tuple{Float64, Float64, Float64, Float64, Float64}}
TVRT_pnts::NamedTuple{(:tvrt1, :tvrt2, :tvrt3), Tuple{Float64, Float64, Float64}}
tV_delay::Float64
VES_lim::MinMax
FRT_pnts::NamedTuple{(:frt1, :frt2, :frt3, :frt4), Tuple{Float64, Float64, Float64, Float64}}
TFRT_pnts::NamedTuple{(:tfrt1, :tfrt2), Tuple{Float64, Float64}}
tF_delay::Float64
FES_lim::MinMax
Pfa_ref::Float64
Q_ref::Float64
P_ref::Float64
base_power::Float64
states::Vector{Symbol}
n_states::Int
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
Parameters of a Generic Distributed Energy Resource Model. Based on ["Modeling Framework and Coordination of DER and Flexible Loads for Ancillary Service Provision."](http://hdl.handle.net/10125/70994)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `Qref_Flag::Int`: Reactive Power Control Mode. 1 VoltVar Control, 2 Constant Q Control, 3 Constant PF Control, validation range: `(1, 3)`
- `PQ_Flag::Int`: Active and reactive power priority mode. 0 for Q priority, 1 for P priority, validation range: `(0, 1)`
- `Gen_Flag::Int`: Define generator or storage system. 0 unit is a storage device, 1 unit is a generator, validation range: `(0, 1)`
- `PerOp_Flag::Int`: Defines operation of permisible region in VRT characteristic. 0 for cease, 1 for continuous operation, validation range: `(0, 1)`
- `Recon_Flag::Int`: Defines if DER can reconnect after voltage ride-through disconnection, validation range: `(0, 1)`
- `Trv::Float64`: Voltage measurement transducer's time constant, in s, validation range: `(0, nothing)`
- `VV_pnts::NamedTuple{(:V1, :V2, :V3, :V4), Tuple{Float64, Float64, Float64, Float64}}`: Y-axis Volt-var curve points (V1,V2,V3,V4)
- `Q_lim::MinMax`: Reactive power limits in pu (Q_min, Q_max)
- `Tp::Float64`: Power measurement transducer's time constant, in s, validation range: `(0, nothing)`
- `e_lim::MinMax`: Error limit in PI controller for q control (e_min, e_max)
- `Kpq::Float64`: PI controller proportional gain for q control, validation range: `(0, nothing)`
- `Kiq::Float64`: PI controller integral gain for q control, validation range: `(0, nothing)`
- `Iqr_lim::MinMax`: Limit on rate of change for reactive current (pu/s) (Iqr_min, Iqr_max)
- `I_max::Float64`: Max. inverter's current, validation range: `(0, nothing)`
- `Tg::Float64`: Current control's time constant, in s, validation range: `(0, nothing)`
- `kWh_Cap::Float64`: BESS capacity in kWh, validation range: `(0, nothing)`
- `SOC_ini::Float64`: Initial state of charge (SOC) in pu, validation range: `(0, 1)`
- `SOC_lim::MinMax`: Battery's SOC limits (SOC_min, SOC_max)
- `Trf::Float64`: Time constant to estimate system frequency, in s, validation range: `(0, nothing)`
- `fdbd_pnts::NamedTuple{(:fdbd1, :fdbd2), Tuple{Float64, Float64}}`: Frequency error dead band thresholds `(fdbd1, fdbd2)`
- `D_dn::Float64`: reciprocal of droop for over-frequency conditions, in pu, validation range: `(0, nothing)`
- `D_up::Float64`: reciprocal of droop for under-frequency conditions, in pu, validation range: `(0, nothing)`
- `fe_lim::MinMax`: Frequency error limits in pu (fe_min, fe_max)
- `Kpp::Float64`: PI controller proportional gain for p control, validation range: `(0, nothing)`
- `Kip::Float64`: PI controller integral gain for p control, validation range: `(0, nothing)`
- `P_lim::MinMax`: Active power limits in pu (P_min, P_max)
- `dP_lim::MinMax`: Ramp rate limits for active power in pu/s (dP_min, dP_max)
- `T_pord::Float64`: Power filter time constant in s, validation range: `(0, nothing)`
- `rrpwr::Float64`: Ramp rate for real power increase following a fault, in pu/s, validation range: `(0, nothing)`
- `VRT_pnts::NamedTuple{(:vrt1, :vrt2, :vrt3, :vrt4, :vrt5), Tuple{Float64, Float64, Float64, Float64, Float64}}`: Voltage ride through v points (vrt1,vrt2,vrt3,vrt4,vrt5)
- `TVRT_pnts::NamedTuple{(:tvrt1, :tvrt2, :tvrt3), Tuple{Float64, Float64, Float64}}`: Voltage ride through time points (tvrt1,tvrt2,tvrt3)
- `tV_delay::Float64`: Time delay for reconnection after voltage ride-through disconnection, validation range: `(0, nothing)`
- `VES_lim::MinMax`: Min and max voltage for entering service (VES_min,VES_max)
- `FRT_pnts::NamedTuple{(:frt1, :frt2, :frt3, :frt4), Tuple{Float64, Float64, Float64, Float64}}`: Frequency ride through v points (frt1,frt2,frt3,frt4)
- `TFRT_pnts::NamedTuple{(:tfrt1, :tfrt2), Tuple{Float64, Float64}}`: Frequency ride through time points (tfrt1,tfrt2)
- `tF_delay::Float64`: Time delay for reconnection after frequency ride-through disconnection, validation range: `(0, nothing)`
- `FES_lim::MinMax`: Min and max frequency for entering service (FES_min,FES_max)
- `Pfa_ref::Float64`: (default: `0.0`) Reference power factor, validation range: `(0, nothing)`
- `Q_ref::Float64`: (default: `0.0`) Reference reactive power, in pu, validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference active power, in pu, validation range: `(0, nothing)`
- `base_power::Float64`: (default: `100.0`) Base power of the unit (MVA) for [per unitization](@ref per_unit)
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of GenericDER depend on the Flags
- `n_states::Int`: (**Do not modify.**) The [states](@ref S) of GenericDER depend on the Flags
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct GenericDER <: DynamicInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Reactive Power Control Mode. 1 VoltVar Control, 2 Constant Q Control, 3 Constant PF Control"
Qref_Flag::Int
"Active and reactive power priority mode. 0 for Q priority, 1 for P priority"
PQ_Flag::Int
"Define generator or storage system. 0 unit is a storage device, 1 unit is a generator"
Gen_Flag::Int
"Defines operation of permisible region in VRT characteristic. 0 for cease, 1 for continuous operation"
PerOp_Flag::Int
"Defines if DER can reconnect after voltage ride-through disconnection"
Recon_Flag::Int
"Voltage measurement transducer's time constant, in s"
Trv::Float64
"Y-axis Volt-var curve points (V1,V2,V3,V4)"
VV_pnts::NamedTuple{(:V1, :V2, :V3, :V4), Tuple{Float64, Float64, Float64, Float64}}
"Reactive power limits in pu (Q_min, Q_max)"
Q_lim::MinMax
"Power measurement transducer's time constant, in s"
Tp::Float64
"Error limit in PI controller for q control (e_min, e_max)"
e_lim::MinMax
"PI controller proportional gain for q control"
Kpq::Float64
"PI controller integral gain for q control"
Kiq::Float64
"Limit on rate of change for reactive current (pu/s) (Iqr_min, Iqr_max)"
Iqr_lim::MinMax
"Max. inverter's current"
I_max::Float64
"Current control's time constant, in s"
Tg::Float64
"BESS capacity in kWh"
kWh_Cap::Float64
"Initial state of charge (SOC) in pu"
SOC_ini::Float64
"Battery's SOC limits (SOC_min, SOC_max)"
SOC_lim::MinMax
"Time constant to estimate system frequency, in s"
Trf::Float64
"Frequency error dead band thresholds `(fdbd1, fdbd2)`"
fdbd_pnts::NamedTuple{(:fdbd1, :fdbd2), Tuple{Float64, Float64}}
"reciprocal of droop for over-frequency conditions, in pu"
D_dn::Float64
"reciprocal of droop for under-frequency conditions, in pu"
D_up::Float64
"Frequency error limits in pu (fe_min, fe_max)"
fe_lim::MinMax
"PI controller proportional gain for p control"
Kpp::Float64
"PI controller integral gain for p control"
Kip::Float64
"Active power limits in pu (P_min, P_max)"
P_lim::MinMax
"Ramp rate limits for active power in pu/s (dP_min, dP_max)"
dP_lim::MinMax
"Power filter time constant in s"
T_pord::Float64
"Ramp rate for real power increase following a fault, in pu/s"
rrpwr::Float64
"Voltage ride through v points (vrt1,vrt2,vrt3,vrt4,vrt5)"
VRT_pnts::NamedTuple{(:vrt1, :vrt2, :vrt3, :vrt4, :vrt5), Tuple{Float64, Float64, Float64, Float64, Float64}}
"Voltage ride through time points (tvrt1,tvrt2,tvrt3)"
TVRT_pnts::NamedTuple{(:tvrt1, :tvrt2, :tvrt3), Tuple{Float64, Float64, Float64}}
"Time delay for reconnection after voltage ride-through disconnection"
tV_delay::Float64
"Min and max voltage for entering service (VES_min,VES_max)"
VES_lim::MinMax
"Frequency ride through v points (frt1,frt2,frt3,frt4)"
FRT_pnts::NamedTuple{(:frt1, :frt2, :frt3, :frt4), Tuple{Float64, Float64, Float64, Float64}}
"Frequency ride through time points (tfrt1,tfrt2)"
TFRT_pnts::NamedTuple{(:tfrt1, :tfrt2), Tuple{Float64, Float64}}
"Time delay for reconnection after frequency ride-through disconnection"
tF_delay::Float64
"Min and max frequency for entering service (FES_min,FES_max)"
FES_lim::MinMax
"Reference power factor"
Pfa_ref::Float64
"Reference reactive power, in pu"
Q_ref::Float64
"Reference active power, in pu"
P_ref::Float64
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"(**Do not modify.**) The [states](@ref S) of GenericDER depend on the Flags"
states::Vector{Symbol}
"(**Do not modify.**) The [states](@ref S) of GenericDER depend on the Flags"
n_states::Int
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function GenericDER(name, Qref_Flag, PQ_Flag, Gen_Flag, PerOp_Flag, Recon_Flag, Trv, VV_pnts, Q_lim, Tp, e_lim, Kpq, Kiq, Iqr_lim, I_max, Tg, kWh_Cap, SOC_ini, SOC_lim, Trf, fdbd_pnts, D_dn, D_up, fe_lim, Kpp, Kip, P_lim, dP_lim, T_pord, rrpwr, VRT_pnts, TVRT_pnts, tV_delay, VES_lim, FRT_pnts, TFRT_pnts, tF_delay, FES_lim, Pfa_ref=0.0, Q_ref=0.0, P_ref=1.0, base_power=100.0, ext=Dict{String, Any}(), )
GenericDER(name, Qref_Flag, PQ_Flag, Gen_Flag, PerOp_Flag, Recon_Flag, Trv, VV_pnts, Q_lim, Tp, e_lim, Kpq, Kiq, Iqr_lim, I_max, Tg, kWh_Cap, SOC_ini, SOC_lim, Trf, fdbd_pnts, D_dn, D_up, fe_lim, Kpp, Kip, P_lim, dP_lim, T_pord, rrpwr, VRT_pnts, TVRT_pnts, tV_delay, VES_lim, FRT_pnts, TFRT_pnts, tF_delay, FES_lim, Pfa_ref, Q_ref, P_ref, base_power, ext, PowerSystems.get_GenericDER_states(Qref_Flag)[1], PowerSystems.get_GenericDER_states(Qref_Flag)[2], InfrastructureSystemsInternal(), )
end
function GenericDER(; name, Qref_Flag, PQ_Flag, Gen_Flag, PerOp_Flag, Recon_Flag, Trv, VV_pnts, Q_lim, Tp, e_lim, Kpq, Kiq, Iqr_lim, I_max, Tg, kWh_Cap, SOC_ini, SOC_lim, Trf, fdbd_pnts, D_dn, D_up, fe_lim, Kpp, Kip, P_lim, dP_lim, T_pord, rrpwr, VRT_pnts, TVRT_pnts, tV_delay, VES_lim, FRT_pnts, TFRT_pnts, tF_delay, FES_lim, Pfa_ref=0.0, Q_ref=0.0, P_ref=1.0, base_power=100.0, states=PowerSystems.get_GenericDER_states(Qref_Flag)[1], n_states=PowerSystems.get_GenericDER_states(Qref_Flag)[2], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
GenericDER(name, Qref_Flag, PQ_Flag, Gen_Flag, PerOp_Flag, Recon_Flag, Trv, VV_pnts, Q_lim, Tp, e_lim, Kpq, Kiq, Iqr_lim, I_max, Tg, kWh_Cap, SOC_ini, SOC_lim, Trf, fdbd_pnts, D_dn, D_up, fe_lim, Kpp, Kip, P_lim, dP_lim, T_pord, rrpwr, VRT_pnts, TVRT_pnts, tV_delay, VES_lim, FRT_pnts, TFRT_pnts, tF_delay, FES_lim, Pfa_ref, Q_ref, P_ref, base_power, states, n_states, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function GenericDER(::Nothing)
GenericDER(;
name="init",
Qref_Flag=1,
PQ_Flag=0,
Gen_Flag=0,
PerOp_Flag=0,
Recon_Flag=0,
Trv=0,
VV_pnts=(V1=0.0, V2=0.0, V3=0.0, V4=0.0),
Q_lim=(min=0.0, max=0.0),
Tp=0,
e_lim=(min=0.0, max=0.0),
Kpq=0,
Kiq=0,
Iqr_lim=(min=0.0, max=0.0),
I_max=0,
Tg=0,
kWh_Cap=0,
SOC_ini=0,
SOC_lim=(min=0.0, max=0.0),
Trf=0,
fdbd_pnts=(fdbd1=0.0, fdbd2=0.0),
D_dn=0,
D_up=0,
fe_lim=(min=0.0, max=0.0),
Kpp=0,
Kip=0,
P_lim=(min=0.0, max=0.0),
dP_lim=(min=0.0, max=0.0),
T_pord=0,
rrpwr=0,
VRT_pnts=(vrt1=0.0, vrt2=0.0, vrt3=0.0, vrt4=0.0, vrt5=0.0),
TVRT_pnts=(tvrt1=0.0, tvrt2=0.0, tvrt3=0.0),
tV_delay=0,
VES_lim=(min=0.0, max=0.0),
FRT_pnts=(frt1=0.0, frt2=0.0, frt3=0.0, frt4=0.0),
TFRT_pnts=(tfrt1=0.0, tfrt2=0.0),
tF_delay=0,
FES_lim=(min=0.0, max=0.0),
Pfa_ref=0,
Q_ref=0,
P_ref=0,
base_power=0,
ext=Dict{String, Any}(),
)
end
"""Get [`GenericDER`](@ref) `name`."""
get_name(value::GenericDER) = value.name
"""Get [`GenericDER`](@ref) `Qref_Flag`."""
get_Qref_Flag(value::GenericDER) = value.Qref_Flag
"""Get [`GenericDER`](@ref) `PQ_Flag`."""
get_PQ_Flag(value::GenericDER) = value.PQ_Flag
"""Get [`GenericDER`](@ref) `Gen_Flag`."""
get_Gen_Flag(value::GenericDER) = value.Gen_Flag
"""Get [`GenericDER`](@ref) `PerOp_Flag`."""
get_PerOp_Flag(value::GenericDER) = value.PerOp_Flag
"""Get [`GenericDER`](@ref) `Recon_Flag`."""
get_Recon_Flag(value::GenericDER) = value.Recon_Flag
"""Get [`GenericDER`](@ref) `Trv`."""
get_Trv(value::GenericDER) = value.Trv
"""Get [`GenericDER`](@ref) `VV_pnts`."""
get_VV_pnts(value::GenericDER) = value.VV_pnts
"""Get [`GenericDER`](@ref) `Q_lim`."""
get_Q_lim(value::GenericDER) = value.Q_lim
"""Get [`GenericDER`](@ref) `Tp`."""
get_Tp(value::GenericDER) = value.Tp
"""Get [`GenericDER`](@ref) `e_lim`."""
get_e_lim(value::GenericDER) = value.e_lim
"""Get [`GenericDER`](@ref) `Kpq`."""
get_Kpq(value::GenericDER) = value.Kpq
"""Get [`GenericDER`](@ref) `Kiq`."""
get_Kiq(value::GenericDER) = value.Kiq
"""Get [`GenericDER`](@ref) `Iqr_lim`."""
get_Iqr_lim(value::GenericDER) = value.Iqr_lim
"""Get [`GenericDER`](@ref) `I_max`."""
get_I_max(value::GenericDER) = value.I_max
"""Get [`GenericDER`](@ref) `Tg`."""
get_Tg(value::GenericDER) = value.Tg
"""Get [`GenericDER`](@ref) `kWh_Cap`."""
get_kWh_Cap(value::GenericDER) = value.kWh_Cap
"""Get [`GenericDER`](@ref) `SOC_ini`."""
get_SOC_ini(value::GenericDER) = value.SOC_ini
"""Get [`GenericDER`](@ref) `SOC_lim`."""
get_SOC_lim(value::GenericDER) = value.SOC_lim
"""Get [`GenericDER`](@ref) `Trf`."""
get_Trf(value::GenericDER) = value.Trf
"""Get [`GenericDER`](@ref) `fdbd_pnts`."""
get_fdbd_pnts(value::GenericDER) = value.fdbd_pnts
"""Get [`GenericDER`](@ref) `D_dn`."""
get_D_dn(value::GenericDER) = value.D_dn
"""Get [`GenericDER`](@ref) `D_up`."""
get_D_up(value::GenericDER) = value.D_up
"""Get [`GenericDER`](@ref) `fe_lim`."""
get_fe_lim(value::GenericDER) = value.fe_lim
"""Get [`GenericDER`](@ref) `Kpp`."""
get_Kpp(value::GenericDER) = value.Kpp
"""Get [`GenericDER`](@ref) `Kip`."""
get_Kip(value::GenericDER) = value.Kip
"""Get [`GenericDER`](@ref) `P_lim`."""
get_P_lim(value::GenericDER) = value.P_lim
"""Get [`GenericDER`](@ref) `dP_lim`."""
get_dP_lim(value::GenericDER) = value.dP_lim
"""Get [`GenericDER`](@ref) `T_pord`."""
get_T_pord(value::GenericDER) = value.T_pord
"""Get [`GenericDER`](@ref) `rrpwr`."""
get_rrpwr(value::GenericDER) = value.rrpwr
"""Get [`GenericDER`](@ref) `VRT_pnts`."""
get_VRT_pnts(value::GenericDER) = value.VRT_pnts
"""Get [`GenericDER`](@ref) `TVRT_pnts`."""
get_TVRT_pnts(value::GenericDER) = value.TVRT_pnts
"""Get [`GenericDER`](@ref) `tV_delay`."""
get_tV_delay(value::GenericDER) = value.tV_delay
"""Get [`GenericDER`](@ref) `VES_lim`."""
get_VES_lim(value::GenericDER) = value.VES_lim
"""Get [`GenericDER`](@ref) `FRT_pnts`."""
get_FRT_pnts(value::GenericDER) = value.FRT_pnts
"""Get [`GenericDER`](@ref) `TFRT_pnts`."""
get_TFRT_pnts(value::GenericDER) = value.TFRT_pnts
"""Get [`GenericDER`](@ref) `tF_delay`."""
get_tF_delay(value::GenericDER) = value.tF_delay
"""Get [`GenericDER`](@ref) `FES_lim`."""
get_FES_lim(value::GenericDER) = value.FES_lim
"""Get [`GenericDER`](@ref) `Pfa_ref`."""
get_Pfa_ref(value::GenericDER) = value.Pfa_ref
"""Get [`GenericDER`](@ref) `Q_ref`."""
get_Q_ref(value::GenericDER) = value.Q_ref
"""Get [`GenericDER`](@ref) `P_ref`."""
get_P_ref(value::GenericDER) = value.P_ref
"""Get [`GenericDER`](@ref) `base_power`."""
get_base_power(value::GenericDER) = value.base_power
"""Get [`GenericDER`](@ref) `states`."""
get_states(value::GenericDER) = value.states
"""Get [`GenericDER`](@ref) `n_states`."""
get_n_states(value::GenericDER) = value.n_states
"""Get [`GenericDER`](@ref) `ext`."""
get_ext(value::GenericDER) = value.ext
"""Get [`GenericDER`](@ref) `internal`."""
get_internal(value::GenericDER) = value.internal
"""Set [`GenericDER`](@ref) `Qref_Flag`."""
set_Qref_Flag!(value::GenericDER, val) = value.Qref_Flag = val
"""Set [`GenericDER`](@ref) `PQ_Flag`."""
set_PQ_Flag!(value::GenericDER, val) = value.PQ_Flag = val
"""Set [`GenericDER`](@ref) `Gen_Flag`."""
set_Gen_Flag!(value::GenericDER, val) = value.Gen_Flag = val
"""Set [`GenericDER`](@ref) `PerOp_Flag`."""
set_PerOp_Flag!(value::GenericDER, val) = value.PerOp_Flag = val
"""Set [`GenericDER`](@ref) `Recon_Flag`."""
set_Recon_Flag!(value::GenericDER, val) = value.Recon_Flag = val
"""Set [`GenericDER`](@ref) `Trv`."""
set_Trv!(value::GenericDER, val) = value.Trv = val
"""Set [`GenericDER`](@ref) `VV_pnts`."""
set_VV_pnts!(value::GenericDER, val) = value.VV_pnts = val
"""Set [`GenericDER`](@ref) `Q_lim`."""
set_Q_lim!(value::GenericDER, val) = value.Q_lim = val
"""Set [`GenericDER`](@ref) `Tp`."""
set_Tp!(value::GenericDER, val) = value.Tp = val
"""Set [`GenericDER`](@ref) `e_lim`."""
set_e_lim!(value::GenericDER, val) = value.e_lim = val
"""Set [`GenericDER`](@ref) `Kpq`."""
set_Kpq!(value::GenericDER, val) = value.Kpq = val
"""Set [`GenericDER`](@ref) `Kiq`."""
set_Kiq!(value::GenericDER, val) = value.Kiq = val
"""Set [`GenericDER`](@ref) `Iqr_lim`."""
set_Iqr_lim!(value::GenericDER, val) = value.Iqr_lim = val
"""Set [`GenericDER`](@ref) `I_max`."""
set_I_max!(value::GenericDER, val) = value.I_max = val
"""Set [`GenericDER`](@ref) `Tg`."""
set_Tg!(value::GenericDER, val) = value.Tg = val
"""Set [`GenericDER`](@ref) `kWh_Cap`."""
set_kWh_Cap!(value::GenericDER, val) = value.kWh_Cap = val
"""Set [`GenericDER`](@ref) `SOC_ini`."""
set_SOC_ini!(value::GenericDER, val) = value.SOC_ini = val
"""Set [`GenericDER`](@ref) `SOC_lim`."""
set_SOC_lim!(value::GenericDER, val) = value.SOC_lim = val
"""Set [`GenericDER`](@ref) `Trf`."""
set_Trf!(value::GenericDER, val) = value.Trf = val
"""Set [`GenericDER`](@ref) `fdbd_pnts`."""
set_fdbd_pnts!(value::GenericDER, val) = value.fdbd_pnts = val
"""Set [`GenericDER`](@ref) `D_dn`."""
set_D_dn!(value::GenericDER, val) = value.D_dn = val
"""Set [`GenericDER`](@ref) `D_up`."""
set_D_up!(value::GenericDER, val) = value.D_up = val
"""Set [`GenericDER`](@ref) `fe_lim`."""
set_fe_lim!(value::GenericDER, val) = value.fe_lim = val
"""Set [`GenericDER`](@ref) `Kpp`."""
set_Kpp!(value::GenericDER, val) = value.Kpp = val
"""Set [`GenericDER`](@ref) `Kip`."""
set_Kip!(value::GenericDER, val) = value.Kip = val
"""Set [`GenericDER`](@ref) `P_lim`."""
set_P_lim!(value::GenericDER, val) = value.P_lim = val
"""Set [`GenericDER`](@ref) `dP_lim`."""
set_dP_lim!(value::GenericDER, val) = value.dP_lim = val
"""Set [`GenericDER`](@ref) `T_pord`."""
set_T_pord!(value::GenericDER, val) = value.T_pord = val
"""Set [`GenericDER`](@ref) `rrpwr`."""
set_rrpwr!(value::GenericDER, val) = value.rrpwr = val
"""Set [`GenericDER`](@ref) `VRT_pnts`."""
set_VRT_pnts!(value::GenericDER, val) = value.VRT_pnts = val
"""Set [`GenericDER`](@ref) `TVRT_pnts`."""
set_TVRT_pnts!(value::GenericDER, val) = value.TVRT_pnts = val
"""Set [`GenericDER`](@ref) `tV_delay`."""
set_tV_delay!(value::GenericDER, val) = value.tV_delay = val
"""Set [`GenericDER`](@ref) `VES_lim`."""
set_VES_lim!(value::GenericDER, val) = value.VES_lim = val
"""Set [`GenericDER`](@ref) `FRT_pnts`."""
set_FRT_pnts!(value::GenericDER, val) = value.FRT_pnts = val
"""Set [`GenericDER`](@ref) `TFRT_pnts`."""
set_TFRT_pnts!(value::GenericDER, val) = value.TFRT_pnts = val
"""Set [`GenericDER`](@ref) `tF_delay`."""
set_tF_delay!(value::GenericDER, val) = value.tF_delay = val
"""Set [`GenericDER`](@ref) `FES_lim`."""
set_FES_lim!(value::GenericDER, val) = value.FES_lim = val
"""Set [`GenericDER`](@ref) `Pfa_ref`."""
set_Pfa_ref!(value::GenericDER, val) = value.Pfa_ref = val
"""Set [`GenericDER`](@ref) `Q_ref`."""
set_Q_ref!(value::GenericDER, val) = value.Q_ref = val
"""Set [`GenericDER`](@ref) `P_ref`."""
set_P_ref!(value::GenericDER, val) = value.P_ref = val
"""Set [`GenericDER`](@ref) `base_power`."""
set_base_power!(value::GenericDER, val) = value.base_power = val
"""Set [`GenericDER`](@ref) `ext`."""
set_ext!(value::GenericDER, val) = value.ext = val
================================================
FILE: src/models/generated/HybridOutputCurrentLimiter.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct HybridOutputCurrentLimiter <: OutputCurrentLimiter
I_max::Float64
rv::Float64
lv::Float64
ext::Dict{String, Any}
end
Parameters of Hybrid Current Controller Limiter. Regulates the magnitude of the inverter output current, but with a closed loop feedback regulated by a virtual impedance which provides ant-windup. Described in: Novel Hybrid Current Limiter for Grid-Forming Inverter Control During Unbalanced Faults by Baeckland and Seo, 2023
# Arguments
- `I_max::Float64`: Maximum limit on current controller input current (device base), validation range: `(0, nothing)`
- `rv::Float64`: Real part of the virtual impedance, validation range: `(0, nothing)`
- `lv::Float64`: Imaginary part of the virtual impedance, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`)
"""
mutable struct HybridOutputCurrentLimiter <: OutputCurrentLimiter
"Maximum limit on current controller input current (device base)"
I_max::Float64
"Real part of the virtual impedance"
rv::Float64
"Imaginary part of the virtual impedance"
lv::Float64
ext::Dict{String, Any}
end
function HybridOutputCurrentLimiter(; I_max, rv, lv, ext=Dict{String, Any}(), )
HybridOutputCurrentLimiter(I_max, rv, lv, ext, )
end
# Constructor for demo purposes; non-functional.
function HybridOutputCurrentLimiter(::Nothing)
HybridOutputCurrentLimiter(;
I_max=0,
rv=0,
lv=0,
ext=Dict{String, Any}(),
)
end
"""Get [`HybridOutputCurrentLimiter`](@ref) `I_max`."""
get_I_max(value::HybridOutputCurrentLimiter) = value.I_max
"""Get [`HybridOutputCurrentLimiter`](@ref) `rv`."""
get_rv(value::HybridOutputCurrentLimiter) = value.rv
"""Get [`HybridOutputCurrentLimiter`](@ref) `lv`."""
get_lv(value::HybridOutputCurrentLimiter) = value.lv
"""Get [`HybridOutputCurrentLimiter`](@ref) `ext`."""
get_ext(value::HybridOutputCurrentLimiter) = value.ext
"""Set [`HybridOutputCurrentLimiter`](@ref) `I_max`."""
set_I_max!(value::HybridOutputCurrentLimiter, val) = value.I_max = val
"""Set [`HybridOutputCurrentLimiter`](@ref) `rv`."""
set_rv!(value::HybridOutputCurrentLimiter, val) = value.rv = val
"""Set [`HybridOutputCurrentLimiter`](@ref) `lv`."""
set_lv!(value::HybridOutputCurrentLimiter, val) = value.lv = val
"""Set [`HybridOutputCurrentLimiter`](@ref) `ext`."""
set_ext!(value::HybridOutputCurrentLimiter, val) = value.ext = val
================================================
FILE: src/models/generated/HydroDispatch.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct HydroDispatch <: HydroGen
name::String
available::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
rating::Float64
prime_mover_type::PrimeMovers
active_power_limits::MinMax
reactive_power_limits::Union{Nothing, MinMax}
ramp_limits::Union{Nothing, UpDown}
time_limits::Union{Nothing, UpDown}
base_power::Float64
status::Bool
time_at_status::Float64
operation_cost::Union{HydroGenerationCost, MarketBidCost}
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A hydropower generator without a reservoir, suitable for modeling run-of-river hydropower.
For hydro generators with an upper reservoir, see [`HydroReservoir`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used
- `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR), validation range: `reactive_power_limits`
- `rating::Float64`: Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power, validation range: `(0, nothing)`
- `prime_mover_type::PrimeMovers`: Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)
- `active_power_limits::MinMax`: Minimum and maximum stable active power levels (MW), validation range: `(0, nothing)`
- `reactive_power_limits::Union{Nothing, MinMax}`: Minimum and maximum reactive power limits. Set to `Nothing` if not applicable
- `ramp_limits::Union{Nothing, UpDown}`: ramp up and ramp down limits in MW/min, validation range: `(0, nothing)`
- `time_limits::Union{Nothing, UpDown}`: Minimum up and Minimum down time limits in hours, validation range: `(0, nothing)`
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `status::Bool`: (default: `false`) Initial commitment condition at the start of a simulation (`true` = on or `false` = off)
- `time_at_status::Float64`: (default: `INFINITE_TIME`) Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`
- `operation_cost::Union{HydroGenerationCost, MarketBidCost}`: (default: `HydroGenerationCost(nothing)`) [`OperationalCost`](@ref) of generation
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct HydroDispatch <: HydroGen
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used"
active_power::Float64
"Initial reactive power set point of the unit (MVAR)"
reactive_power::Float64
"Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power"
rating::Float64
"Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)"
prime_mover_type::PrimeMovers
"Minimum and maximum stable active power levels (MW)"
active_power_limits::MinMax
"Minimum and maximum reactive power limits. Set to `Nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
"ramp up and ramp down limits in MW/min"
ramp_limits::Union{Nothing, UpDown}
"Minimum up and Minimum down time limits in hours"
time_limits::Union{Nothing, UpDown}
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Initial commitment condition at the start of a simulation (`true` = on or `false` = off)"
status::Bool
"Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`"
time_at_status::Float64
"[`OperationalCost`](@ref) of generation"
operation_cost::Union{HydroGenerationCost, MarketBidCost}
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function HydroDispatch(name, available, bus, active_power, reactive_power, rating, prime_mover_type, active_power_limits, reactive_power_limits, ramp_limits, time_limits, base_power, status=false, time_at_status=INFINITE_TIME, operation_cost=HydroGenerationCost(nothing), services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
HydroDispatch(name, available, bus, active_power, reactive_power, rating, prime_mover_type, active_power_limits, reactive_power_limits, ramp_limits, time_limits, base_power, status, time_at_status, operation_cost, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function HydroDispatch(; name, available, bus, active_power, reactive_power, rating, prime_mover_type, active_power_limits, reactive_power_limits, ramp_limits, time_limits, base_power, status=false, time_at_status=INFINITE_TIME, operation_cost=HydroGenerationCost(nothing), services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
HydroDispatch(name, available, bus, active_power, reactive_power, rating, prime_mover_type, active_power_limits, reactive_power_limits, ramp_limits, time_limits, base_power, status, time_at_status, operation_cost, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function HydroDispatch(::Nothing)
HydroDispatch(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
rating=0.0,
prime_mover_type=PrimeMovers.HY,
active_power_limits=(min=0.0, max=0.0),
reactive_power_limits=nothing,
ramp_limits=nothing,
time_limits=nothing,
base_power=100.0,
status=false,
time_at_status=INFINITE_TIME,
operation_cost=HydroGenerationCost(nothing),
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`HydroDispatch`](@ref) `name`."""
get_name(value::HydroDispatch) = value.name
"""Get [`HydroDispatch`](@ref) `available`."""
get_available(value::HydroDispatch) = value.available
"""Get [`HydroDispatch`](@ref) `bus`."""
get_bus(value::HydroDispatch) = value.bus
"""Get [`HydroDispatch`](@ref) `active_power`."""
get_active_power(value::HydroDispatch) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`HydroDispatch`](@ref) `reactive_power`."""
get_reactive_power(value::HydroDispatch) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`HydroDispatch`](@ref) `rating`."""
get_rating(value::HydroDispatch) = get_value(value, Val(:rating), Val(:mva))
"""Get [`HydroDispatch`](@ref) `prime_mover_type`."""
get_prime_mover_type(value::HydroDispatch) = value.prime_mover_type
"""Get [`HydroDispatch`](@ref) `active_power_limits`."""
get_active_power_limits(value::HydroDispatch) = get_value(value, Val(:active_power_limits), Val(:mva))
"""Get [`HydroDispatch`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::HydroDispatch) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`HydroDispatch`](@ref) `ramp_limits`."""
get_ramp_limits(value::HydroDispatch) = get_value(value, Val(:ramp_limits), Val(:mva))
"""Get [`HydroDispatch`](@ref) `time_limits`."""
get_time_limits(value::HydroDispatch) = value.time_limits
"""Get [`HydroDispatch`](@ref) `base_power`."""
get_base_power(value::HydroDispatch) = value.base_power
"""Get [`HydroDispatch`](@ref) `status`."""
get_status(value::HydroDispatch) = value.status
"""Get [`HydroDispatch`](@ref) `time_at_status`."""
get_time_at_status(value::HydroDispatch) = value.time_at_status
"""Get [`HydroDispatch`](@ref) `operation_cost`."""
get_operation_cost(value::HydroDispatch) = value.operation_cost
"""Get [`HydroDispatch`](@ref) `services`."""
get_services(value::HydroDispatch) = value.services
"""Get [`HydroDispatch`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::HydroDispatch) = value.dynamic_injector
"""Get [`HydroDispatch`](@ref) `ext`."""
get_ext(value::HydroDispatch) = value.ext
"""Get [`HydroDispatch`](@ref) `internal`."""
get_internal(value::HydroDispatch) = value.internal
"""Set [`HydroDispatch`](@ref) `available`."""
set_available!(value::HydroDispatch, val) = value.available = val
"""Set [`HydroDispatch`](@ref) `bus`."""
set_bus!(value::HydroDispatch, val) = value.bus = val
"""Set [`HydroDispatch`](@ref) `active_power`."""
set_active_power!(value::HydroDispatch, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`HydroDispatch`](@ref) `reactive_power`."""
set_reactive_power!(value::HydroDispatch, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`HydroDispatch`](@ref) `rating`."""
set_rating!(value::HydroDispatch, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`HydroDispatch`](@ref) `prime_mover_type`."""
set_prime_mover_type!(value::HydroDispatch, val) = value.prime_mover_type = val
"""Set [`HydroDispatch`](@ref) `active_power_limits`."""
set_active_power_limits!(value::HydroDispatch, val) = value.active_power_limits = set_value(value, Val(:active_power_limits), val, Val(:mva))
"""Set [`HydroDispatch`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::HydroDispatch, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`HydroDispatch`](@ref) `ramp_limits`."""
set_ramp_limits!(value::HydroDispatch, val) = value.ramp_limits = set_value(value, Val(:ramp_limits), val, Val(:mva))
"""Set [`HydroDispatch`](@ref) `time_limits`."""
set_time_limits!(value::HydroDispatch, val) = value.time_limits = val
"""Set [`HydroDispatch`](@ref) `base_power`."""
set_base_power!(value::HydroDispatch, val) = value.base_power = val
"""Set [`HydroDispatch`](@ref) `status`."""
set_status!(value::HydroDispatch, val) = value.status = val
"""Set [`HydroDispatch`](@ref) `time_at_status`."""
set_time_at_status!(value::HydroDispatch, val) = value.time_at_status = val
"""Set [`HydroDispatch`](@ref) `operation_cost`."""
set_operation_cost!(value::HydroDispatch, val) = value.operation_cost = val
"""Set [`HydroDispatch`](@ref) `services`."""
set_services!(value::HydroDispatch, val) = value.services = val
"""Set [`HydroDispatch`](@ref) `ext`."""
set_ext!(value::HydroDispatch, val) = value.ext = val
================================================
FILE: src/models/generated/HydroPumpTurbine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct HydroPumpTurbine <: HydroUnit
name::String
available::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
rating::Float64
active_power_limits::MinMax
reactive_power_limits::Union{Nothing, MinMax}
active_power_limits_pump::MinMax
outflow_limits::Union{Nothing, MinMax}
powerhouse_elevation::Float64
ramp_limits::Union{Nothing, UpDown}
time_limits::Union{Nothing, UpDown}
base_power::Float64
status::PumpHydroStatus
time_at_status::Float64
operation_cost::Union{HydroGenerationCost, MarketBidCost}
active_power_pump::Float64
efficiency::TurbinePump
transition_time::TurbinePump
minimum_time::TurbinePump
travel_time::Union{Nothing, Float64}
conversion_factor::Float64
must_run::Bool
prime_mover_type::PrimeMovers
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A hydropower pumped turbine that needs to have two [`HydroReservoir`](@ref)s attached, suitable for modeling independent pumped hydro with reservoirs.
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial active power set point of the turbine unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used
- `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR), validation range: `reactive_power_limits`
- `rating::Float64`: Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power, validation range: `(0, nothing)`
- `active_power_limits::MinMax`: Minimum and maximum stable active power levels (MW) for the turbine, validation range: `(0, nothing)`
- `reactive_power_limits::Union{Nothing, MinMax}`: Minimum and maximum reactive power limits. Set to `Nothing` if not applicable
- `active_power_limits_pump::MinMax`: Minimum and maximum stable active power levels (MW) for the pump, validation range: `(0, nothing)`
- `outflow_limits::Union{Nothing, MinMax}`: Turbine/Pump outflow limits in m3/s. Set to `Nothing` if not applicable
- `powerhouse_elevation::Float64`: Height level in meters above the sea level of the powerhouse on which the turbine is installed., validation range: `(0, nothing)`
- `ramp_limits::Union{Nothing, UpDown}`: ramp up and ramp down limits in MW/min, validation range: `(0, nothing)`
- `time_limits::Union{Nothing, UpDown}`: Minimum up and Minimum down time limits in hours, validation range: `(0, nothing)`
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `status::PumpHydroStatus`: (default: `PumpHydroStatus.OFF`) Initial Operating status of a pumped‑storage hydro unit. See [PumpHydroStatus](@ref) for reference
- `time_at_status::Float64`: (default: `INFINITE_TIME`) Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`
- `operation_cost::Union{HydroGenerationCost, MarketBidCost}`: (default: `HydroGenerationCost(nothing)`) [`OperationalCost`](@ref) of generation
- `active_power_pump::Float64`: (default: `0.0`) Initial active power set point of the pump unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used
- `efficiency::TurbinePump`: (default: `(turbine = 1.0, pump = 1.0)`) Turbine/Pump efficiency [0, 1.0]
- `transition_time::TurbinePump`: (default: `(turbine = 0.0, pump = 0.0)`) Transition time in hours to switch into the specific mode.
- `minimum_time::TurbinePump`: (default: `(turbine = 0.0, pump = 0.0)`) Minimum operating time in hours for the specific mode.
- `travel_time::Union{Nothing, Float64}`: (default: `nothing`) Downstream (from reservoir into turbine) travel time in hours.
- `conversion_factor::Float64`: (default: `1.0`) Conversion factor from flow/volume to energy: m^3 -> p.u-hr
- `must_run::Bool`: (default: `false`) Whether the unit must run (i.e., cannot be curtailed)
- `prime_mover_type::PrimeMovers`: (default: `PrimeMovers.PS`) Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct HydroPumpTurbine <: HydroUnit
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial active power set point of the turbine unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used"
active_power::Float64
"Initial reactive power set point of the unit (MVAR)"
reactive_power::Float64
"Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power"
rating::Float64
"Minimum and maximum stable active power levels (MW) for the turbine"
active_power_limits::MinMax
"Minimum and maximum reactive power limits. Set to `Nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
"Minimum and maximum stable active power levels (MW) for the pump"
active_power_limits_pump::MinMax
"Turbine/Pump outflow limits in m3/s. Set to `Nothing` if not applicable"
outflow_limits::Union{Nothing, MinMax}
"Height level in meters above the sea level of the powerhouse on which the turbine is installed."
powerhouse_elevation::Float64
"ramp up and ramp down limits in MW/min"
ramp_limits::Union{Nothing, UpDown}
"Minimum up and Minimum down time limits in hours"
time_limits::Union{Nothing, UpDown}
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Initial Operating status of a pumped‑storage hydro unit. See [PumpHydroStatus](@ref) for reference"
status::PumpHydroStatus
"Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`"
time_at_status::Float64
"[`OperationalCost`](@ref) of generation"
operation_cost::Union{HydroGenerationCost, MarketBidCost}
"Initial active power set point of the pump unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used"
active_power_pump::Float64
"Turbine/Pump efficiency [0, 1.0]"
efficiency::TurbinePump
"Transition time in hours to switch into the specific mode."
transition_time::TurbinePump
"Minimum operating time in hours for the specific mode."
minimum_time::TurbinePump
"Downstream (from reservoir into turbine) travel time in hours."
travel_time::Union{Nothing, Float64}
"Conversion factor from flow/volume to energy: m^3 -> p.u-hr"
conversion_factor::Float64
"Whether the unit must run (i.e., cannot be curtailed)"
must_run::Bool
"Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)"
prime_mover_type::PrimeMovers
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function HydroPumpTurbine(name, available, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, active_power_limits_pump, outflow_limits, powerhouse_elevation, ramp_limits, time_limits, base_power, status=PumpHydroStatus.OFF, time_at_status=INFINITE_TIME, operation_cost=HydroGenerationCost(nothing), active_power_pump=0.0, efficiency=(turbine = 1.0, pump = 1.0), transition_time=(turbine = 0.0, pump = 0.0), minimum_time=(turbine = 0.0, pump = 0.0), travel_time=nothing, conversion_factor=1.0, must_run=false, prime_mover_type=PrimeMovers.PS, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
HydroPumpTurbine(name, available, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, active_power_limits_pump, outflow_limits, powerhouse_elevation, ramp_limits, time_limits, base_power, status, time_at_status, operation_cost, active_power_pump, efficiency, transition_time, minimum_time, travel_time, conversion_factor, must_run, prime_mover_type, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function HydroPumpTurbine(; name, available, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, active_power_limits_pump, outflow_limits, powerhouse_elevation, ramp_limits, time_limits, base_power, status=PumpHydroStatus.OFF, time_at_status=INFINITE_TIME, operation_cost=HydroGenerationCost(nothing), active_power_pump=0.0, efficiency=(turbine = 1.0, pump = 1.0), transition_time=(turbine = 0.0, pump = 0.0), minimum_time=(turbine = 0.0, pump = 0.0), travel_time=nothing, conversion_factor=1.0, must_run=false, prime_mover_type=PrimeMovers.PS, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
HydroPumpTurbine(name, available, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, active_power_limits_pump, outflow_limits, powerhouse_elevation, ramp_limits, time_limits, base_power, status, time_at_status, operation_cost, active_power_pump, efficiency, transition_time, minimum_time, travel_time, conversion_factor, must_run, prime_mover_type, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function HydroPumpTurbine(::Nothing)
HydroPumpTurbine(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
rating=0.0,
active_power_limits=(min=0.0, max=0.0),
reactive_power_limits=nothing,
active_power_limits_pump=(min=0.0, max=0.0),
outflow_limits=nothing,
powerhouse_elevation=0.0,
ramp_limits=nothing,
time_limits=nothing,
base_power=100.0,
status=PumpHydroStatus.OFF,
time_at_status=INFINITE_TIME,
operation_cost=HydroGenerationCost(nothing),
active_power_pump=0.0,
efficiency=(turbine = 1.0, pump = 1.0),
transition_time=(turbine = 0.0, pump = 0.0),
minimum_time=(turbine = 0.0, pump = 0.0),
travel_time=nothing,
conversion_factor=1.0,
must_run=false,
prime_mover_type=PrimeMovers.OT,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`HydroPumpTurbine`](@ref) `name`."""
get_name(value::HydroPumpTurbine) = value.name
"""Get [`HydroPumpTurbine`](@ref) `available`."""
get_available(value::HydroPumpTurbine) = value.available
"""Get [`HydroPumpTurbine`](@ref) `bus`."""
get_bus(value::HydroPumpTurbine) = value.bus
"""Get [`HydroPumpTurbine`](@ref) `active_power`."""
get_active_power(value::HydroPumpTurbine) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`HydroPumpTurbine`](@ref) `reactive_power`."""
get_reactive_power(value::HydroPumpTurbine) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`HydroPumpTurbine`](@ref) `rating`."""
get_rating(value::HydroPumpTurbine) = get_value(value, Val(:rating), Val(:mva))
"""Get [`HydroPumpTurbine`](@ref) `active_power_limits`."""
get_active_power_limits(value::HydroPumpTurbine) = get_value(value, Val(:active_power_limits), Val(:mva))
"""Get [`HydroPumpTurbine`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::HydroPumpTurbine) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`HydroPumpTurbine`](@ref) `active_power_limits_pump`."""
get_active_power_limits_pump(value::HydroPumpTurbine) = get_value(value, Val(:active_power_limits_pump), Val(:mva))
"""Get [`HydroPumpTurbine`](@ref) `outflow_limits`."""
get_outflow_limits(value::HydroPumpTurbine) = value.outflow_limits
"""Get [`HydroPumpTurbine`](@ref) `powerhouse_elevation`."""
get_powerhouse_elevation(value::HydroPumpTurbine) = value.powerhouse_elevation
"""Get [`HydroPumpTurbine`](@ref) `ramp_limits`."""
get_ramp_limits(value::HydroPumpTurbine) = get_value(value, Val(:ramp_limits), Val(:mva))
"""Get [`HydroPumpTurbine`](@ref) `time_limits`."""
get_time_limits(value::HydroPumpTurbine) = value.time_limits
"""Get [`HydroPumpTurbine`](@ref) `base_power`."""
get_base_power(value::HydroPumpTurbine) = value.base_power
"""Get [`HydroPumpTurbine`](@ref) `status`."""
get_status(value::HydroPumpTurbine) = value.status
"""Get [`HydroPumpTurbine`](@ref) `time_at_status`."""
get_time_at_status(value::HydroPumpTurbine) = value.time_at_status
"""Get [`HydroPumpTurbine`](@ref) `operation_cost`."""
get_operation_cost(value::HydroPumpTurbine) = value.operation_cost
"""Get [`HydroPumpTurbine`](@ref) `active_power_pump`."""
get_active_power_pump(value::HydroPumpTurbine) = get_value(value, Val(:active_power_pump), Val(:mva))
"""Get [`HydroPumpTurbine`](@ref) `efficiency`."""
get_efficiency(value::HydroPumpTurbine) = value.efficiency
"""Get [`HydroPumpTurbine`](@ref) `transition_time`."""
get_transition_time(value::HydroPumpTurbine) = value.transition_time
"""Get [`HydroPumpTurbine`](@ref) `minimum_time`."""
get_minimum_time(value::HydroPumpTurbine) = value.minimum_time
"""Get [`HydroPumpTurbine`](@ref) `travel_time`."""
get_travel_time(value::HydroPumpTurbine) = value.travel_time
"""Get [`HydroPumpTurbine`](@ref) `conversion_factor`."""
get_conversion_factor(value::HydroPumpTurbine) = value.conversion_factor
"""Get [`HydroPumpTurbine`](@ref) `must_run`."""
get_must_run(value::HydroPumpTurbine) = value.must_run
"""Get [`HydroPumpTurbine`](@ref) `prime_mover_type`."""
get_prime_mover_type(value::HydroPumpTurbine) = value.prime_mover_type
"""Get [`HydroPumpTurbine`](@ref) `services`."""
get_services(value::HydroPumpTurbine) = value.services
"""Get [`HydroPumpTurbine`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::HydroPumpTurbine) = value.dynamic_injector
"""Get [`HydroPumpTurbine`](@ref) `ext`."""
get_ext(value::HydroPumpTurbine) = value.ext
"""Get [`HydroPumpTurbine`](@ref) `internal`."""
get_internal(value::HydroPumpTurbine) = value.internal
"""Set [`HydroPumpTurbine`](@ref) `available`."""
set_available!(value::HydroPumpTurbine, val) = value.available = val
"""Set [`HydroPumpTurbine`](@ref) `bus`."""
set_bus!(value::HydroPumpTurbine, val) = value.bus = val
"""Set [`HydroPumpTurbine`](@ref) `active_power`."""
set_active_power!(value::HydroPumpTurbine, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`HydroPumpTurbine`](@ref) `reactive_power`."""
set_reactive_power!(value::HydroPumpTurbine, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`HydroPumpTurbine`](@ref) `rating`."""
set_rating!(value::HydroPumpTurbine, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`HydroPumpTurbine`](@ref) `active_power_limits`."""
set_active_power_limits!(value::HydroPumpTurbine, val) = value.active_power_limits = set_value(value, Val(:active_power_limits), val, Val(:mva))
"""Set [`HydroPumpTurbine`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::HydroPumpTurbine, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`HydroPumpTurbine`](@ref) `active_power_limits_pump`."""
set_active_power_limits_pump!(value::HydroPumpTurbine, val) = value.active_power_limits_pump = set_value(value, Val(:active_power_limits_pump), val, Val(:mva))
"""Set [`HydroPumpTurbine`](@ref) `outflow_limits`."""
set_outflow_limits!(value::HydroPumpTurbine, val) = value.outflow_limits = val
"""Set [`HydroPumpTurbine`](@ref) `powerhouse_elevation`."""
set_powerhouse_elevation!(value::HydroPumpTurbine, val) = value.powerhouse_elevation = val
"""Set [`HydroPumpTurbine`](@ref) `ramp_limits`."""
set_ramp_limits!(value::HydroPumpTurbine, val) = value.ramp_limits = set_value(value, Val(:ramp_limits), val, Val(:mva))
"""Set [`HydroPumpTurbine`](@ref) `time_limits`."""
set_time_limits!(value::HydroPumpTurbine, val) = value.time_limits = val
"""Set [`HydroPumpTurbine`](@ref) `base_power`."""
set_base_power!(value::HydroPumpTurbine, val) = value.base_power = val
"""Set [`HydroPumpTurbine`](@ref) `status`."""
set_status!(value::HydroPumpTurbine, val) = value.status = val
"""Set [`HydroPumpTurbine`](@ref) `time_at_status`."""
set_time_at_status!(value::HydroPumpTurbine, val) = value.time_at_status = val
"""Set [`HydroPumpTurbine`](@ref) `operation_cost`."""
set_operation_cost!(value::HydroPumpTurbine, val) = value.operation_cost = val
"""Set [`HydroPumpTurbine`](@ref) `active_power_pump`."""
set_active_power_pump!(value::HydroPumpTurbine, val) = value.active_power_pump = set_value(value, Val(:active_power_pump), val, Val(:mva))
"""Set [`HydroPumpTurbine`](@ref) `efficiency`."""
set_efficiency!(value::HydroPumpTurbine, val) = value.efficiency = val
"""Set [`HydroPumpTurbine`](@ref) `transition_time`."""
set_transition_time!(value::HydroPumpTurbine, val) = value.transition_time = val
"""Set [`HydroPumpTurbine`](@ref) `minimum_time`."""
set_minimum_time!(value::HydroPumpTurbine, val) = value.minimum_time = val
"""Set [`HydroPumpTurbine`](@ref) `travel_time`."""
set_travel_time!(value::HydroPumpTurbine, val) = value.travel_time = val
"""Set [`HydroPumpTurbine`](@ref) `conversion_factor`."""
set_conversion_factor!(value::HydroPumpTurbine, val) = value.conversion_factor = val
"""Set [`HydroPumpTurbine`](@ref) `must_run`."""
set_must_run!(value::HydroPumpTurbine, val) = value.must_run = val
"""Set [`HydroPumpTurbine`](@ref) `prime_mover_type`."""
set_prime_mover_type!(value::HydroPumpTurbine, val) = value.prime_mover_type = val
"""Set [`HydroPumpTurbine`](@ref) `services`."""
set_services!(value::HydroPumpTurbine, val) = value.services = val
"""Set [`HydroPumpTurbine`](@ref) `ext`."""
set_ext!(value::HydroPumpTurbine, val) = value.ext = val
================================================
FILE: src/models/generated/HydroReservoir.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct HydroReservoir <: Device
name::String
available::Bool
storage_level_limits::MinMax
initial_level::Float64
spillage_limits::Union{Nothing, MinMax}
inflow::Float64
outflow::Float64
level_targets::Union{Nothing, Float64}
intake_elevation::Float64
head_to_volume_factor::ValueCurve
upstream_turbines::Vector{HydroUnit}
downstream_turbines::Vector{HydroUnit}
upstream_reservoirs::Vector{Device}
operation_cost::HydroReservoirCost
level_data_type::ReservoirDataType
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A hydropower reservoir that have attached [`HydroTurbine`](@ref)(s) or [`HydroPumpTurbine`](@ref)(s) used to generate power.
See [How to Define Hydro Generators with Reservoirs](@ref hydro_resv) for supported configurations.
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `storage_level_limits::MinMax`: Storage level limits for the reservoir in m^3, m, or MWh, based on the [`ReservoirDataType`](@ref hydroreservoir_list) selected for `level_data_type`
- `initial_level::Float64`: Initial level of the reservoir relative to the `storage_level_limits.max`.
- `spillage_limits::Union{Nothing, MinMax}`: Amount of water allowed to be spilled from the reservoir. If nothing, infinite spillage is allowed.
- `inflow::Float64`: Amount of water refilling the reservoir in m^3/h or MW (if `level_data_type` is [`ReservoirDataType`](@ref hydroreservoir_list)`.ENERGY`).
- `outflow::Float64`: Amount of water naturally going out of the reservoir in m^3/h or MW (if `level_data_type` is [`ReservoirDataType`](@ref hydroreservoir_list)`.ENERGY`).
- `level_targets::Union{Nothing, Float64}`: Reservoir level targets at the end of a simulation as a fraction of the `storage_level_limits.max`.
- `intake_elevation::Float64`: Height of the intake of the reservoir, towards the downstream turbines, in meters above the sea level.
- `head_to_volume_factor::ValueCurve`: Head to volume relationship for the reservoir.
- `upstream_turbines::Vector{HydroUnit}`: (default: `Device[]`) Vector of [HydroUnit](@ref)(s) that are immediately upstream of this reservoir. This reservoir is the tail reservoir for these units, and their flow goes into this reservoir.
- `downstream_turbines::Vector{HydroUnit}`: (default: `Device[]`) Vector of [HydroUnit](@ref)(s) that are immediately downstream of this reservoir. This reservoir is the head reservoir for these units, and its feed flow into these units.
- `upstream_reservoirs::Vector{Device}`: (default: `Device[]`) Vector of [Device](@ref)(s) reservoirs that are immediately upstream of this reservoir. This reservoir receives the spillage flow from upstream_reservoirs.
- `operation_cost::HydroReservoirCost`: (default: `HydroReservoirCost(nothing)`) [`OperationalCost`](@ref) of reservoir.
- `level_data_type::ReservoirDataType`: (default: `ReservoirDataType.USABLE_VOLUME`) Reservoir level data type. See [ReservoirDataType](@ref) for reference.
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct HydroReservoir <: Device
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Storage level limits for the reservoir in m^3, m, or MWh, based on the [`ReservoirDataType`](@ref hydroreservoir_list) selected for `level_data_type`"
storage_level_limits::MinMax
"Initial level of the reservoir relative to the `storage_level_limits.max`."
initial_level::Float64
"Amount of water allowed to be spilled from the reservoir. If nothing, infinite spillage is allowed."
spillage_limits::Union{Nothing, MinMax}
"Amount of water refilling the reservoir in m^3/h or MW (if `level_data_type` is [`ReservoirDataType`](@ref hydroreservoir_list)`.ENERGY`)."
inflow::Float64
"Amount of water naturally going out of the reservoir in m^3/h or MW (if `level_data_type` is [`ReservoirDataType`](@ref hydroreservoir_list)`.ENERGY`)."
outflow::Float64
"Reservoir level targets at the end of a simulation as a fraction of the `storage_level_limits.max`."
level_targets::Union{Nothing, Float64}
"Height of the intake of the reservoir, towards the downstream turbines, in meters above the sea level."
intake_elevation::Float64
"Head to volume relationship for the reservoir."
head_to_volume_factor::ValueCurve
"Vector of [HydroUnit](@ref)(s) that are immediately upstream of this reservoir. This reservoir is the tail reservoir for these units, and their flow goes into this reservoir."
upstream_turbines::Vector{HydroUnit}
"Vector of [HydroUnit](@ref)(s) that are immediately downstream of this reservoir. This reservoir is the head reservoir for these units, and its feed flow into these units."
downstream_turbines::Vector{HydroUnit}
"Vector of [Device](@ref)(s) reservoirs that are immediately upstream of this reservoir. This reservoir receives the spillage flow from upstream_reservoirs."
upstream_reservoirs::Vector{Device}
"[`OperationalCost`](@ref) of reservoir."
operation_cost::HydroReservoirCost
"Reservoir level data type. See [ReservoirDataType](@ref) for reference."
level_data_type::ReservoirDataType
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function HydroReservoir(name, available, storage_level_limits, initial_level, spillage_limits, inflow, outflow, level_targets, intake_elevation, head_to_volume_factor, upstream_turbines=Device[], downstream_turbines=Device[], upstream_reservoirs=Device[], operation_cost=HydroReservoirCost(nothing), level_data_type=ReservoirDataType.USABLE_VOLUME, ext=Dict{String, Any}(), )
HydroReservoir(name, available, storage_level_limits, initial_level, spillage_limits, inflow, outflow, level_targets, intake_elevation, head_to_volume_factor, upstream_turbines, downstream_turbines, upstream_reservoirs, operation_cost, level_data_type, ext, InfrastructureSystemsInternal(), )
end
function HydroReservoir(; name, available, storage_level_limits, initial_level, spillage_limits, inflow, outflow, level_targets, intake_elevation, head_to_volume_factor, upstream_turbines=Device[], downstream_turbines=Device[], upstream_reservoirs=Device[], operation_cost=HydroReservoirCost(nothing), level_data_type=ReservoirDataType.USABLE_VOLUME, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
HydroReservoir(name, available, storage_level_limits, initial_level, spillage_limits, inflow, outflow, level_targets, intake_elevation, head_to_volume_factor, upstream_turbines, downstream_turbines, upstream_reservoirs, operation_cost, level_data_type, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function HydroReservoir(::Nothing)
HydroReservoir(;
name="init",
available=false,
storage_level_limits=(min=0.0, max=0.0),
initial_level=0.0,
spillage_limits=nothing,
inflow=0.0,
outflow=0.0,
level_targets=nothing,
intake_elevation=0.0,
head_to_volume_factor=LinearCurve(0.0),
upstream_turbines=Device[],
downstream_turbines=Device[],
upstream_reservoirs=Device[],
operation_cost=HydroReservoirCost(nothing),
level_data_type=ReservoirDataType.USABLE_VOLUME,
ext=Dict{String, Any}(),
)
end
"""Get [`HydroReservoir`](@ref) `name`."""
get_name(value::HydroReservoir) = value.name
"""Get [`HydroReservoir`](@ref) `available`."""
get_available(value::HydroReservoir) = value.available
"""Get [`HydroReservoir`](@ref) `storage_level_limits`."""
get_storage_level_limits(value::HydroReservoir) = value.storage_level_limits
"""Get [`HydroReservoir`](@ref) `initial_level`."""
get_initial_level(value::HydroReservoir) = value.initial_level
"""Get [`HydroReservoir`](@ref) `spillage_limits`."""
get_spillage_limits(value::HydroReservoir) = value.spillage_limits
"""Get [`HydroReservoir`](@ref) `inflow`."""
get_inflow(value::HydroReservoir) = value.inflow
"""Get [`HydroReservoir`](@ref) `outflow`."""
get_outflow(value::HydroReservoir) = value.outflow
"""Get [`HydroReservoir`](@ref) `level_targets`."""
get_level_targets(value::HydroReservoir) = value.level_targets
"""Get [`HydroReservoir`](@ref) `intake_elevation`."""
get_intake_elevation(value::HydroReservoir) = value.intake_elevation
"""Get [`HydroReservoir`](@ref) `head_to_volume_factor`."""
get_head_to_volume_factor(value::HydroReservoir) = value.head_to_volume_factor
"""Get [`HydroReservoir`](@ref) `upstream_turbines`."""
get_upstream_turbines(value::HydroReservoir) = value.upstream_turbines
"""Get [`HydroReservoir`](@ref) `downstream_turbines`."""
get_downstream_turbines(value::HydroReservoir) = value.downstream_turbines
"""Get [`HydroReservoir`](@ref) `upstream_reservoirs`."""
get_upstream_reservoirs(value::HydroReservoir) = value.upstream_reservoirs
"""Get [`HydroReservoir`](@ref) `operation_cost`."""
get_operation_cost(value::HydroReservoir) = value.operation_cost
"""Get [`HydroReservoir`](@ref) `level_data_type`."""
get_level_data_type(value::HydroReservoir) = value.level_data_type
"""Get [`HydroReservoir`](@ref) `ext`."""
get_ext(value::HydroReservoir) = value.ext
"""Get [`HydroReservoir`](@ref) `internal`."""
get_internal(value::HydroReservoir) = value.internal
"""Set [`HydroReservoir`](@ref) `available`."""
set_available!(value::HydroReservoir, val) = value.available = val
"""Set [`HydroReservoir`](@ref) `storage_level_limits`."""
set_storage_level_limits!(value::HydroReservoir, val) = value.storage_level_limits = val
"""Set [`HydroReservoir`](@ref) `initial_level`."""
set_initial_level!(value::HydroReservoir, val) = value.initial_level = val
"""Set [`HydroReservoir`](@ref) `spillage_limits`."""
set_spillage_limits!(value::HydroReservoir, val) = value.spillage_limits = val
"""Set [`HydroReservoir`](@ref) `inflow`."""
set_inflow!(value::HydroReservoir, val) = value.inflow = val
"""Set [`HydroReservoir`](@ref) `outflow`."""
set_outflow!(value::HydroReservoir, val) = value.outflow = val
"""Set [`HydroReservoir`](@ref) `level_targets`."""
set_level_targets!(value::HydroReservoir, val) = value.level_targets = val
"""Set [`HydroReservoir`](@ref) `intake_elevation`."""
set_intake_elevation!(value::HydroReservoir, val) = value.intake_elevation = val
"""Set [`HydroReservoir`](@ref) `head_to_volume_factor`."""
set_head_to_volume_factor!(value::HydroReservoir, val) = value.head_to_volume_factor = val
"""Set [`HydroReservoir`](@ref) `upstream_turbines`."""
set_upstream_turbines!(value::HydroReservoir, val) = value.upstream_turbines = val
"""Set [`HydroReservoir`](@ref) `downstream_turbines`."""
set_downstream_turbines!(value::HydroReservoir, val) = value.downstream_turbines = val
"""Set [`HydroReservoir`](@ref) `upstream_reservoirs`."""
set_upstream_reservoirs!(value::HydroReservoir, val) = value.upstream_reservoirs = val
"""Set [`HydroReservoir`](@ref) `operation_cost`."""
set_operation_cost!(value::HydroReservoir, val) = value.operation_cost = val
"""Set [`HydroReservoir`](@ref) `level_data_type`."""
set_level_data_type!(value::HydroReservoir, val) = value.level_data_type = val
"""Set [`HydroReservoir`](@ref) `ext`."""
set_ext!(value::HydroReservoir, val) = value.ext = val
================================================
FILE: src/models/generated/HydroTurbine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct HydroTurbine <: HydroUnit
name::String
available::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
rating::Float64
active_power_limits::MinMax
reactive_power_limits::Union{Nothing, MinMax}
base_power::Float64
operation_cost::Union{HydroGenerationCost, MarketBidCost}
powerhouse_elevation::Float64
ramp_limits::Union{Nothing, UpDown}
time_limits::Union{Nothing, UpDown}
outflow_limits::Union{Nothing, MinMax}
efficiency::Float64
turbine_type::HydroTurbineType
conversion_factor::Float64
prime_mover_type::PrimeMovers
travel_time::Union{Nothing, Float64}
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A hydropower generator that must have a [`HydroReservoir`](@ref) attached, suitable for modeling independent turbines and reservoirs.
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used
- `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR), validation range: `reactive_power_limits`
- `rating::Float64`: Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power, validation range: `(0, nothing)`
- `active_power_limits::MinMax`: Minimum and maximum stable active power levels (MW), validation range: `(0, nothing)`
- `reactive_power_limits::Union{Nothing, MinMax}`: Minimum and maximum reactive power limits. Set to `Nothing` if not applicable
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `operation_cost::Union{HydroGenerationCost, MarketBidCost}`: (default: `HydroGenerationCost(nothing)`) [`OperationalCost`](@ref) of generation
- `powerhouse_elevation::Float64`: (default: `0.0`) Height level in meters above the sea level of the powerhouse on which the turbine is installed., validation range: `(0, nothing)`
- `ramp_limits::Union{Nothing, UpDown}`: (default: `nothing`) ramp up and ramp down limits in MW/min, validation range: `(0, nothing)`
- `time_limits::Union{Nothing, UpDown}`: (default: `nothing`) Minimum up and Minimum down time limits in hours, validation range: `(0, nothing)`
- `outflow_limits::Union{Nothing, MinMax}`: (default: `nothing`) Turbine outflow limits in m3/s. Set to `Nothing` if not applicable
- `efficiency::Float64`: (default: `1.0`) Turbine efficiency [0, 1.0], validation range: `(0, 1)`
- `turbine_type::HydroTurbineType`: (default: `HydroTurbineType.UNKNOWN`) Type of the turbine
- `conversion_factor::Float64`: (default: `1.0`) Conversion factor from flow/volume to energy: m^3 -> p.u-hr
- `prime_mover_type::PrimeMovers`: (default: `PrimeMovers.HY`) Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)
- `travel_time::Union{Nothing, Float64}`: (default: `nothing`) Downstream (from reservoir into turbine) travel time in hours.
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct HydroTurbine <: HydroUnit
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used"
active_power::Float64
"Initial reactive power set point of the unit (MVAR)"
reactive_power::Float64
"Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power"
rating::Float64
"Minimum and maximum stable active power levels (MW)"
active_power_limits::MinMax
"Minimum and maximum reactive power limits. Set to `Nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"[`OperationalCost`](@ref) of generation"
operation_cost::Union{HydroGenerationCost, MarketBidCost}
"Height level in meters above the sea level of the powerhouse on which the turbine is installed."
powerhouse_elevation::Float64
"ramp up and ramp down limits in MW/min"
ramp_limits::Union{Nothing, UpDown}
"Minimum up and Minimum down time limits in hours"
time_limits::Union{Nothing, UpDown}
"Turbine outflow limits in m3/s. Set to `Nothing` if not applicable"
outflow_limits::Union{Nothing, MinMax}
"Turbine efficiency [0, 1.0]"
efficiency::Float64
"Type of the turbine"
turbine_type::HydroTurbineType
"Conversion factor from flow/volume to energy: m^3 -> p.u-hr"
conversion_factor::Float64
"Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)"
prime_mover_type::PrimeMovers
"Downstream (from reservoir into turbine) travel time in hours."
travel_time::Union{Nothing, Float64}
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function HydroTurbine(name, available, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, base_power, operation_cost=HydroGenerationCost(nothing), powerhouse_elevation=0.0, ramp_limits=nothing, time_limits=nothing, outflow_limits=nothing, efficiency=1.0, turbine_type=HydroTurbineType.UNKNOWN, conversion_factor=1.0, prime_mover_type=PrimeMovers.HY, travel_time=nothing, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
HydroTurbine(name, available, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, base_power, operation_cost, powerhouse_elevation, ramp_limits, time_limits, outflow_limits, efficiency, turbine_type, conversion_factor, prime_mover_type, travel_time, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function HydroTurbine(; name, available, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, base_power, operation_cost=HydroGenerationCost(nothing), powerhouse_elevation=0.0, ramp_limits=nothing, time_limits=nothing, outflow_limits=nothing, efficiency=1.0, turbine_type=HydroTurbineType.UNKNOWN, conversion_factor=1.0, prime_mover_type=PrimeMovers.HY, travel_time=nothing, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
HydroTurbine(name, available, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, base_power, operation_cost, powerhouse_elevation, ramp_limits, time_limits, outflow_limits, efficiency, turbine_type, conversion_factor, prime_mover_type, travel_time, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function HydroTurbine(::Nothing)
HydroTurbine(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
rating=0.0,
active_power_limits=(min=0.0, max=0.0),
reactive_power_limits=nothing,
base_power=100.0,
operation_cost=HydroGenerationCost(nothing),
powerhouse_elevation=0.0,
ramp_limits=nothing,
time_limits=nothing,
outflow_limits=nothing,
efficiency=1.0,
turbine_type=HydroTurbineType.UNKNOWN,
conversion_factor=1.0,
prime_mover_type=PrimeMovers.OT,
travel_time=nothing,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`HydroTurbine`](@ref) `name`."""
get_name(value::HydroTurbine) = value.name
"""Get [`HydroTurbine`](@ref) `available`."""
get_available(value::HydroTurbine) = value.available
"""Get [`HydroTurbine`](@ref) `bus`."""
get_bus(value::HydroTurbine) = value.bus
"""Get [`HydroTurbine`](@ref) `active_power`."""
get_active_power(value::HydroTurbine) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`HydroTurbine`](@ref) `reactive_power`."""
get_reactive_power(value::HydroTurbine) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`HydroTurbine`](@ref) `rating`."""
get_rating(value::HydroTurbine) = get_value(value, Val(:rating), Val(:mva))
"""Get [`HydroTurbine`](@ref) `active_power_limits`."""
get_active_power_limits(value::HydroTurbine) = get_value(value, Val(:active_power_limits), Val(:mva))
"""Get [`HydroTurbine`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::HydroTurbine) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`HydroTurbine`](@ref) `base_power`."""
get_base_power(value::HydroTurbine) = value.base_power
"""Get [`HydroTurbine`](@ref) `operation_cost`."""
get_operation_cost(value::HydroTurbine) = value.operation_cost
"""Get [`HydroTurbine`](@ref) `powerhouse_elevation`."""
get_powerhouse_elevation(value::HydroTurbine) = value.powerhouse_elevation
"""Get [`HydroTurbine`](@ref) `ramp_limits`."""
get_ramp_limits(value::HydroTurbine) = get_value(value, Val(:ramp_limits), Val(:mva))
"""Get [`HydroTurbine`](@ref) `time_limits`."""
get_time_limits(value::HydroTurbine) = value.time_limits
"""Get [`HydroTurbine`](@ref) `outflow_limits`."""
get_outflow_limits(value::HydroTurbine) = value.outflow_limits
"""Get [`HydroTurbine`](@ref) `efficiency`."""
get_efficiency(value::HydroTurbine) = value.efficiency
"""Get [`HydroTurbine`](@ref) `turbine_type`."""
get_turbine_type(value::HydroTurbine) = value.turbine_type
"""Get [`HydroTurbine`](@ref) `conversion_factor`."""
get_conversion_factor(value::HydroTurbine) = value.conversion_factor
"""Get [`HydroTurbine`](@ref) `prime_mover_type`."""
get_prime_mover_type(value::HydroTurbine) = value.prime_mover_type
"""Get [`HydroTurbine`](@ref) `travel_time`."""
get_travel_time(value::HydroTurbine) = value.travel_time
"""Get [`HydroTurbine`](@ref) `services`."""
get_services(value::HydroTurbine) = value.services
"""Get [`HydroTurbine`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::HydroTurbine) = value.dynamic_injector
"""Get [`HydroTurbine`](@ref) `ext`."""
get_ext(value::HydroTurbine) = value.ext
"""Get [`HydroTurbine`](@ref) `internal`."""
get_internal(value::HydroTurbine) = value.internal
"""Set [`HydroTurbine`](@ref) `available`."""
set_available!(value::HydroTurbine, val) = value.available = val
"""Set [`HydroTurbine`](@ref) `bus`."""
set_bus!(value::HydroTurbine, val) = value.bus = val
"""Set [`HydroTurbine`](@ref) `active_power`."""
set_active_power!(value::HydroTurbine, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`HydroTurbine`](@ref) `reactive_power`."""
set_reactive_power!(value::HydroTurbine, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`HydroTurbine`](@ref) `rating`."""
set_rating!(value::HydroTurbine, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`HydroTurbine`](@ref) `active_power_limits`."""
set_active_power_limits!(value::HydroTurbine, val) = value.active_power_limits = set_value(value, Val(:active_power_limits), val, Val(:mva))
"""Set [`HydroTurbine`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::HydroTurbine, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`HydroTurbine`](@ref) `base_power`."""
set_base_power!(value::HydroTurbine, val) = value.base_power = val
"""Set [`HydroTurbine`](@ref) `operation_cost`."""
set_operation_cost!(value::HydroTurbine, val) = value.operation_cost = val
"""Set [`HydroTurbine`](@ref) `powerhouse_elevation`."""
set_powerhouse_elevation!(value::HydroTurbine, val) = value.powerhouse_elevation = val
"""Set [`HydroTurbine`](@ref) `ramp_limits`."""
set_ramp_limits!(value::HydroTurbine, val) = value.ramp_limits = set_value(value, Val(:ramp_limits), val, Val(:mva))
"""Set [`HydroTurbine`](@ref) `time_limits`."""
set_time_limits!(value::HydroTurbine, val) = value.time_limits = val
"""Set [`HydroTurbine`](@ref) `outflow_limits`."""
set_outflow_limits!(value::HydroTurbine, val) = value.outflow_limits = val
"""Set [`HydroTurbine`](@ref) `efficiency`."""
set_efficiency!(value::HydroTurbine, val) = value.efficiency = val
"""Set [`HydroTurbine`](@ref) `turbine_type`."""
set_turbine_type!(value::HydroTurbine, val) = value.turbine_type = val
"""Set [`HydroTurbine`](@ref) `conversion_factor`."""
set_conversion_factor!(value::HydroTurbine, val) = value.conversion_factor = val
"""Set [`HydroTurbine`](@ref) `prime_mover_type`."""
set_prime_mover_type!(value::HydroTurbine, val) = value.prime_mover_type = val
"""Set [`HydroTurbine`](@ref) `travel_time`."""
set_travel_time!(value::HydroTurbine, val) = value.travel_time = val
"""Set [`HydroTurbine`](@ref) `services`."""
set_services!(value::HydroTurbine, val) = value.services = val
"""Set [`HydroTurbine`](@ref) `ext`."""
set_ext!(value::HydroTurbine, val) = value.ext = val
================================================
FILE: src/models/generated/HydroTurbineGov.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct HydroTurbineGov <: TurbineGov
R::Float64
r::Float64
Tr::Float64
Tf::Float64
Tg::Float64
VELM::Float64
gate_position_limits::MinMax
Tw::Float64
At::Float64
D_T::Float64
q_nl::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Hydro Turbine-Governor
# Arguments
- `R::Float64`: Permanent droop parameter, validation range: `(0, 0.1)`
- `r::Float64`: Temporary Droop, validation range: `(0, 2)`
- `Tr::Float64`: Governor time constant, validation range: `(eps(), 30)`
- `Tf::Float64`: Filter Time constant, validation range: `(eps(), 0.1)`
- `Tg::Float64`: Servo time constant, validation range: `(eps(), 1)`
- `VELM::Float64`: gate velocity limit, validation range: `(eps(), 0.3)`
- `gate_position_limits::MinMax`: Gate position limits
- `Tw::Float64`: water time constant, validation range: `(eps(), 3)`
- `At::Float64`: Turbine gain, validation range: `(0.8, 1.5)`
- `D_T::Float64`: Turbine Damping, validation range: `(0, 0.5)`
- `q_nl::Float64`: No-power flow, validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the HydroTurbineGov model are:
x_g1: filter_output,
x_g2: desired gate,
x_g3: gate opening,
x_g4: turbine flow
- `n_states::Int`: (**Do not modify.**) HYGOV has 4 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) HYGOV has 4 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct HydroTurbineGov <: TurbineGov
"Permanent droop parameter"
R::Float64
"Temporary Droop"
r::Float64
"Governor time constant"
Tr::Float64
"Filter Time constant"
Tf::Float64
"Servo time constant"
Tg::Float64
"gate velocity limit"
VELM::Float64
"Gate position limits"
gate_position_limits::MinMax
"water time constant"
Tw::Float64
"Turbine gain"
At::Float64
"Turbine Damping"
D_T::Float64
"No-power flow"
q_nl::Float64
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the HydroTurbineGov model are:
x_g1: filter_output,
x_g2: desired gate,
x_g3: gate opening,
x_g4: turbine flow"
states::Vector{Symbol}
"(**Do not modify.**) HYGOV has 4 states"
n_states::Int
"(**Do not modify.**) HYGOV has 4 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function HydroTurbineGov(R, r, Tr, Tf, Tg, VELM, gate_position_limits, Tw, At, D_T, q_nl, P_ref=1.0, ext=Dict{String, Any}(), )
HydroTurbineGov(R, r, Tr, Tf, Tg, VELM, gate_position_limits, Tw, At, D_T, q_nl, P_ref, ext, [:x_g1, :x_g2, :x_g3, :x_g4], 4, [StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function HydroTurbineGov(; R, r, Tr, Tf, Tg, VELM, gate_position_limits, Tw, At, D_T, q_nl, P_ref=1.0, ext=Dict{String, Any}(), states=[:x_g1, :x_g2, :x_g3, :x_g4], n_states=4, states_types=[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
HydroTurbineGov(R, r, Tr, Tf, Tg, VELM, gate_position_limits, Tw, At, D_T, q_nl, P_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function HydroTurbineGov(::Nothing)
HydroTurbineGov(;
R=0,
r=0,
Tr=0,
Tf=0,
Tg=0,
VELM=0,
gate_position_limits=(min=0.0, max=0.0),
Tw=0,
At=0,
D_T=0,
q_nl=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`HydroTurbineGov`](@ref) `R`."""
get_R(value::HydroTurbineGov) = value.R
"""Get [`HydroTurbineGov`](@ref) `r`."""
get_r(value::HydroTurbineGov) = value.r
"""Get [`HydroTurbineGov`](@ref) `Tr`."""
get_Tr(value::HydroTurbineGov) = value.Tr
"""Get [`HydroTurbineGov`](@ref) `Tf`."""
get_Tf(value::HydroTurbineGov) = value.Tf
"""Get [`HydroTurbineGov`](@ref) `Tg`."""
get_Tg(value::HydroTurbineGov) = value.Tg
"""Get [`HydroTurbineGov`](@ref) `VELM`."""
get_VELM(value::HydroTurbineGov) = value.VELM
"""Get [`HydroTurbineGov`](@ref) `gate_position_limits`."""
get_gate_position_limits(value::HydroTurbineGov) = value.gate_position_limits
"""Get [`HydroTurbineGov`](@ref) `Tw`."""
get_Tw(value::HydroTurbineGov) = value.Tw
"""Get [`HydroTurbineGov`](@ref) `At`."""
get_At(value::HydroTurbineGov) = value.At
"""Get [`HydroTurbineGov`](@ref) `D_T`."""
get_D_T(value::HydroTurbineGov) = value.D_T
"""Get [`HydroTurbineGov`](@ref) `q_nl`."""
get_q_nl(value::HydroTurbineGov) = value.q_nl
"""Get [`HydroTurbineGov`](@ref) `P_ref`."""
get_P_ref(value::HydroTurbineGov) = value.P_ref
"""Get [`HydroTurbineGov`](@ref) `ext`."""
get_ext(value::HydroTurbineGov) = value.ext
"""Get [`HydroTurbineGov`](@ref) `states`."""
get_states(value::HydroTurbineGov) = value.states
"""Get [`HydroTurbineGov`](@ref) `n_states`."""
get_n_states(value::HydroTurbineGov) = value.n_states
"""Get [`HydroTurbineGov`](@ref) `states_types`."""
get_states_types(value::HydroTurbineGov) = value.states_types
"""Get [`HydroTurbineGov`](@ref) `internal`."""
get_internal(value::HydroTurbineGov) = value.internal
"""Set [`HydroTurbineGov`](@ref) `R`."""
set_R!(value::HydroTurbineGov, val) = value.R = val
"""Set [`HydroTurbineGov`](@ref) `r`."""
set_r!(value::HydroTurbineGov, val) = value.r = val
"""Set [`HydroTurbineGov`](@ref) `Tr`."""
set_Tr!(value::HydroTurbineGov, val) = value.Tr = val
"""Set [`HydroTurbineGov`](@ref) `Tf`."""
set_Tf!(value::HydroTurbineGov, val) = value.Tf = val
"""Set [`HydroTurbineGov`](@ref) `Tg`."""
set_Tg!(value::HydroTurbineGov, val) = value.Tg = val
"""Set [`HydroTurbineGov`](@ref) `VELM`."""
set_VELM!(value::HydroTurbineGov, val) = value.VELM = val
"""Set [`HydroTurbineGov`](@ref) `gate_position_limits`."""
set_gate_position_limits!(value::HydroTurbineGov, val) = value.gate_position_limits = val
"""Set [`HydroTurbineGov`](@ref) `Tw`."""
set_Tw!(value::HydroTurbineGov, val) = value.Tw = val
"""Set [`HydroTurbineGov`](@ref) `At`."""
set_At!(value::HydroTurbineGov, val) = value.At = val
"""Set [`HydroTurbineGov`](@ref) `D_T`."""
set_D_T!(value::HydroTurbineGov, val) = value.D_T = val
"""Set [`HydroTurbineGov`](@ref) `q_nl`."""
set_q_nl!(value::HydroTurbineGov, val) = value.q_nl = val
"""Set [`HydroTurbineGov`](@ref) `P_ref`."""
set_P_ref!(value::HydroTurbineGov, val) = value.P_ref = val
"""Set [`HydroTurbineGov`](@ref) `ext`."""
set_ext!(value::HydroTurbineGov, val) = value.ext = val
"""Set [`HydroTurbineGov`](@ref) `states_types`."""
set_states_types!(value::HydroTurbineGov, val) = value.states_types = val
================================================
FILE: src/models/generated/IEEEST.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct IEEEST <: PSS
input_code::Int
remote_bus_control::Int
A1::Float64
A2::Float64
A3::Float64
A4::Float64
A5::Float64
A6::Float64
T1::Float64
T2::Float64
T3::Float64
T4::Float64
T5::Float64
T6::Float64
Ks::Float64
Ls_lim::Tuple{Float64, Float64}
Vcu::Float64
Vcl::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
IEEE Stabilizing Model PSS.
# Arguments
- `input_code::Int`: Code input for stabilizer, validation range: `(1, 6)`
- `remote_bus_control::Int`: ACBus identification [`number`](@ref ACBus) for control. `0` identifies the bus connected to this component
- `A1::Float64`: Filter coefficient, validation range: `(0, nothing)`
- `A2::Float64`: Filter coefficient, validation range: `(0, nothing)`
- `A3::Float64`: Filter coefficient, validation range: `(0, nothing)`
- `A4::Float64`: Filter coefficient, validation range: `(0, nothing)`
- `A5::Float64`: Filter coefficient, validation range: `(0, nothing)`
- `A6::Float64`: Filter coefficient, validation range: `(0, nothing)`
- `T1::Float64`: Time constant, validation range: `(0, 10)`
- `T2::Float64`: Time constant, validation range: `(0, 10)`
- `T3::Float64`: Time constant, validation range: `(0, 10)`
- `T4::Float64`: Time constant, validation range: `(0, 10)`
- `T5::Float64`: Time constant, validation range: `(0, 10)`
- `T6::Float64`: Time constant, validation range: `(eps(), 2.0)`
- `Ks::Float64`: Proportional gain, validation range: `(0, nothing)`
- `Ls_lim::Tuple{Float64, Float64}`: PSS output limits for regulator output `(Ls_min, Ls_max)`
- `Vcu::Float64`: Cutoff limiter upper bound, validation range: `(0, 1.25)`
- `Vcl::Float64`: Cutoff limiter lower bound, validation range: `(0, 1.0)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
x_p1: 1st filter integration,
x_p2: 2nd filter integration,
x_p3: 3rd filter integration,
x_p4: 4rd filter integration,
x_p5: T1/T2 lead-lag integrator,
x_p6: T3/T4 lead-lag integrator,
:x_p7 last integer,
- `n_states::Int`: (**Do not modify.**) IEEEST has 7 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) IEEEST has 7 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct IEEEST <: PSS
"Code input for stabilizer"
input_code::Int
"ACBus identification [`number`](@ref ACBus) for control. `0` identifies the bus connected to this component"
remote_bus_control::Int
"Filter coefficient"
A1::Float64
"Filter coefficient"
A2::Float64
"Filter coefficient"
A3::Float64
"Filter coefficient"
A4::Float64
"Filter coefficient"
A5::Float64
"Filter coefficient"
A6::Float64
"Time constant"
T1::Float64
"Time constant"
T2::Float64
"Time constant"
T3::Float64
"Time constant"
T4::Float64
"Time constant"
T5::Float64
"Time constant"
T6::Float64
"Proportional gain"
Ks::Float64
"PSS output limits for regulator output `(Ls_min, Ls_max)`"
Ls_lim::Tuple{Float64, Float64}
"Cutoff limiter upper bound"
Vcu::Float64
"Cutoff limiter lower bound"
Vcl::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
x_p1: 1st filter integration,
x_p2: 2nd filter integration,
x_p3: 3rd filter integration,
x_p4: 4rd filter integration,
x_p5: T1/T2 lead-lag integrator,
x_p6: T3/T4 lead-lag integrator,
:x_p7 last integer,"
states::Vector{Symbol}
"(**Do not modify.**) IEEEST has 7 states"
n_states::Int
"(**Do not modify.**) IEEEST has 7 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function IEEEST(input_code, remote_bus_control, A1, A2, A3, A4, A5, A6, T1, T2, T3, T4, T5, T6, Ks, Ls_lim, Vcu, Vcl, ext=Dict{String, Any}(), )
IEEEST(input_code, remote_bus_control, A1, A2, A3, A4, A5, A6, T1, T2, T3, T4, T5, T6, Ks, Ls_lim, Vcu, Vcl, ext, [:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7], 7, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function IEEEST(; input_code, remote_bus_control, A1, A2, A3, A4, A5, A6, T1, T2, T3, T4, T5, T6, Ks, Ls_lim, Vcu, Vcl, ext=Dict{String, Any}(), states=[:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7], n_states=7, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
IEEEST(input_code, remote_bus_control, A1, A2, A3, A4, A5, A6, T1, T2, T3, T4, T5, T6, Ks, Ls_lim, Vcu, Vcl, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function IEEEST(::Nothing)
IEEEST(;
input_code=1,
remote_bus_control=0,
A1=0,
A2=0,
A3=0,
A4=0,
A5=0,
A6=0,
T1=0,
T2=0,
T3=0,
T4=0,
T5=0,
T6=0,
Ks=0,
Ls_lim=(0.0, 0.0),
Vcu=0,
Vcl=0,
ext=Dict{String, Any}(),
)
end
"""Get [`IEEEST`](@ref) `input_code`."""
get_input_code(value::IEEEST) = value.input_code
"""Get [`IEEEST`](@ref) `remote_bus_control`."""
get_remote_bus_control(value::IEEEST) = value.remote_bus_control
"""Get [`IEEEST`](@ref) `A1`."""
get_A1(value::IEEEST) = value.A1
"""Get [`IEEEST`](@ref) `A2`."""
get_A2(value::IEEEST) = value.A2
"""Get [`IEEEST`](@ref) `A3`."""
get_A3(value::IEEEST) = value.A3
"""Get [`IEEEST`](@ref) `A4`."""
get_A4(value::IEEEST) = value.A4
"""Get [`IEEEST`](@ref) `A5`."""
get_A5(value::IEEEST) = value.A5
"""Get [`IEEEST`](@ref) `A6`."""
get_A6(value::IEEEST) = value.A6
"""Get [`IEEEST`](@ref) `T1`."""
get_T1(value::IEEEST) = value.T1
"""Get [`IEEEST`](@ref) `T2`."""
get_T2(value::IEEEST) = value.T2
"""Get [`IEEEST`](@ref) `T3`."""
get_T3(value::IEEEST) = value.T3
"""Get [`IEEEST`](@ref) `T4`."""
get_T4(value::IEEEST) = value.T4
"""Get [`IEEEST`](@ref) `T5`."""
get_T5(value::IEEEST) = value.T5
"""Get [`IEEEST`](@ref) `T6`."""
get_T6(value::IEEEST) = value.T6
"""Get [`IEEEST`](@ref) `Ks`."""
get_Ks(value::IEEEST) = value.Ks
"""Get [`IEEEST`](@ref) `Ls_lim`."""
get_Ls_lim(value::IEEEST) = value.Ls_lim
"""Get [`IEEEST`](@ref) `Vcu`."""
get_Vcu(value::IEEEST) = value.Vcu
"""Get [`IEEEST`](@ref) `Vcl`."""
get_Vcl(value::IEEEST) = value.Vcl
"""Get [`IEEEST`](@ref) `ext`."""
get_ext(value::IEEEST) = value.ext
"""Get [`IEEEST`](@ref) `states`."""
get_states(value::IEEEST) = value.states
"""Get [`IEEEST`](@ref) `n_states`."""
get_n_states(value::IEEEST) = value.n_states
"""Get [`IEEEST`](@ref) `states_types`."""
get_states_types(value::IEEEST) = value.states_types
"""Get [`IEEEST`](@ref) `internal`."""
get_internal(value::IEEEST) = value.internal
"""Set [`IEEEST`](@ref) `input_code`."""
set_input_code!(value::IEEEST, val) = value.input_code = val
"""Set [`IEEEST`](@ref) `remote_bus_control`."""
set_remote_bus_control!(value::IEEEST, val) = value.remote_bus_control = val
"""Set [`IEEEST`](@ref) `A1`."""
set_A1!(value::IEEEST, val) = value.A1 = val
"""Set [`IEEEST`](@ref) `A2`."""
set_A2!(value::IEEEST, val) = value.A2 = val
"""Set [`IEEEST`](@ref) `A3`."""
set_A3!(value::IEEEST, val) = value.A3 = val
"""Set [`IEEEST`](@ref) `A4`."""
set_A4!(value::IEEEST, val) = value.A4 = val
"""Set [`IEEEST`](@ref) `A5`."""
set_A5!(value::IEEEST, val) = value.A5 = val
"""Set [`IEEEST`](@ref) `A6`."""
set_A6!(value::IEEEST, val) = value.A6 = val
"""Set [`IEEEST`](@ref) `T1`."""
set_T1!(value::IEEEST, val) = value.T1 = val
"""Set [`IEEEST`](@ref) `T2`."""
set_T2!(value::IEEEST, val) = value.T2 = val
"""Set [`IEEEST`](@ref) `T3`."""
set_T3!(value::IEEEST, val) = value.T3 = val
"""Set [`IEEEST`](@ref) `T4`."""
set_T4!(value::IEEEST, val) = value.T4 = val
"""Set [`IEEEST`](@ref) `T5`."""
set_T5!(value::IEEEST, val) = value.T5 = val
"""Set [`IEEEST`](@ref) `T6`."""
set_T6!(value::IEEEST, val) = value.T6 = val
"""Set [`IEEEST`](@ref) `Ks`."""
set_Ks!(value::IEEEST, val) = value.Ks = val
"""Set [`IEEEST`](@ref) `Ls_lim`."""
set_Ls_lim!(value::IEEEST, val) = value.Ls_lim = val
"""Set [`IEEEST`](@ref) `Vcu`."""
set_Vcu!(value::IEEEST, val) = value.Vcu = val
"""Set [`IEEEST`](@ref) `Vcl`."""
set_Vcl!(value::IEEEST, val) = value.Vcl = val
"""Set [`IEEEST`](@ref) `ext`."""
set_ext!(value::IEEEST, val) = value.ext = val
"""Set [`IEEEST`](@ref) `states_types`."""
set_states_types!(value::IEEEST, val) = value.states_types = val
================================================
FILE: src/models/generated/IEEET1.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct IEEET1 <: AVR
Tr::Float64
Ka::Float64
Ta::Float64
Vr_lim::MinMax
Ke::Float64
Te::Float64
Kf::Float64
Tf::Float64
switch::Int
E_sat::Tuple{Float64, Float64}
Se::Tuple{Float64, Float64}
V_ref::Float64
saturation_coeffs::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
1968 IEEE type 1 excitation system model
# Arguments
- `Tr::Float64`: Voltage Measurement Time Constant in s, validation range: `(0, 0.5)`
- `Ka::Float64`: Amplifier Gain, validation range: `(10, 500)`
- `Ta::Float64`: Amplifier Time Constant in s, validation range: `(0, 1)`
- `Vr_lim::MinMax`: Voltage regulator limits (regulator output) (Vi_min, Vi_max)
- `Ke::Float64`: Exciter constant related to self-excited field, validation range: `(-1, 1)`
- `Te::Float64`: Exciter time constant, integration rate associated with exciter control, validation range: `(eps(), 1)`
- `Kf::Float64`: Excitation control system stabilizer gain, validation range: `(eps(), 0.3)`
- `Tf::Float64`: Excitation control system stabilizer time constant. Appropiate Data: 5 <= Tf/Kf <= 15, validation range: `(eps(), nothing)`
- `switch::Int`: Switch, validation range: `(0, 1)`
- `E_sat::Tuple{Float64, Float64}`: Exciter output voltage for saturation factor: (E1, E2)
- `Se::Tuple{Float64, Float64}`: Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `saturation_coeffs::Tuple{Float64, Float64}`: (default: `PowerSystems.get_avr_saturation(E_sat, Se)`) (**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vt: Terminal Voltage,
Vr: Regulator Output,
Vf: Exciter Output,
Vr3: Rate feedback integrator
- `n_states::Int`: (**Do not modify.**) The IEEET1 has 4 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) IEEET1 I has 4 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct IEEET1 <: AVR
"Voltage Measurement Time Constant in s"
Tr::Float64
"Amplifier Gain"
Ka::Float64
"Amplifier Time Constant in s"
Ta::Float64
"Voltage regulator limits (regulator output) (Vi_min, Vi_max)"
Vr_lim::MinMax
"Exciter constant related to self-excited field"
Ke::Float64
"Exciter time constant, integration rate associated with exciter control"
Te::Float64
"Excitation control system stabilizer gain"
Kf::Float64
"Excitation control system stabilizer time constant. Appropiate Data: 5 <= Tf/Kf <= 15"
Tf::Float64
"Switch"
switch::Int
"Exciter output voltage for saturation factor: (E1, E2)"
E_sat::Tuple{Float64, Float64}
"Exciter saturation factor at exciter output voltage: (Se(E1), Se(E2))"
Se::Tuple{Float64, Float64}
"Reference Voltage Set-point (pu)"
V_ref::Float64
"(**Do not modify.**) Coefficients (A,B) of the function: Se(V) = B(V - A)^2/V"
saturation_coeffs::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vt: Terminal Voltage,
Vr: Regulator Output,
Vf: Exciter Output,
Vr3: Rate feedback integrator"
states::Vector{Symbol}
"(**Do not modify.**) The IEEET1 has 4 states"
n_states::Int
"(**Do not modify.**) IEEET1 I has 4 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function IEEET1(Tr, Ka, Ta, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), )
IEEET1(Tr, Ka, Ta, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref, saturation_coeffs, ext, [:Vt, :Vr1, :Vf, :Vr2], 4, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function IEEET1(; Tr, Ka, Ta, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref=1.0, saturation_coeffs=PowerSystems.get_avr_saturation(E_sat, Se), ext=Dict{String, Any}(), states=[:Vt, :Vr1, :Vf, :Vr2], n_states=4, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
IEEET1(Tr, Ka, Ta, Vr_lim, Ke, Te, Kf, Tf, switch, E_sat, Se, V_ref, saturation_coeffs, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function IEEET1(::Nothing)
IEEET1(;
Tr=0,
Ka=0,
Ta=0,
Vr_lim=(min=0.0, max=0.0),
Ke=0,
Te=0,
Kf=0,
Tf=0,
switch=0,
E_sat=(0.0, 0.0),
Se=(0.0, 0.0),
V_ref=0,
saturation_coeffs=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`IEEET1`](@ref) `Tr`."""
get_Tr(value::IEEET1) = value.Tr
"""Get [`IEEET1`](@ref) `Ka`."""
get_Ka(value::IEEET1) = value.Ka
"""Get [`IEEET1`](@ref) `Ta`."""
get_Ta(value::IEEET1) = value.Ta
"""Get [`IEEET1`](@ref) `Vr_lim`."""
get_Vr_lim(value::IEEET1) = value.Vr_lim
"""Get [`IEEET1`](@ref) `Ke`."""
get_Ke(value::IEEET1) = value.Ke
"""Get [`IEEET1`](@ref) `Te`."""
get_Te(value::IEEET1) = value.Te
"""Get [`IEEET1`](@ref) `Kf`."""
get_Kf(value::IEEET1) = value.Kf
"""Get [`IEEET1`](@ref) `Tf`."""
get_Tf(value::IEEET1) = value.Tf
"""Get [`IEEET1`](@ref) `switch`."""
get_switch(value::IEEET1) = value.switch
"""Get [`IEEET1`](@ref) `E_sat`."""
get_E_sat(value::IEEET1) = value.E_sat
"""Get [`IEEET1`](@ref) `Se`."""
get_Se(value::IEEET1) = value.Se
"""Get [`IEEET1`](@ref) `V_ref`."""
get_V_ref(value::IEEET1) = value.V_ref
"""Get [`IEEET1`](@ref) `saturation_coeffs`."""
get_saturation_coeffs(value::IEEET1) = value.saturation_coeffs
"""Get [`IEEET1`](@ref) `ext`."""
get_ext(value::IEEET1) = value.ext
"""Get [`IEEET1`](@ref) `states`."""
get_states(value::IEEET1) = value.states
"""Get [`IEEET1`](@ref) `n_states`."""
get_n_states(value::IEEET1) = value.n_states
"""Get [`IEEET1`](@ref) `states_types`."""
get_states_types(value::IEEET1) = value.states_types
"""Get [`IEEET1`](@ref) `internal`."""
get_internal(value::IEEET1) = value.internal
"""Set [`IEEET1`](@ref) `Tr`."""
set_Tr!(value::IEEET1, val) = value.Tr = val
"""Set [`IEEET1`](@ref) `Ka`."""
set_Ka!(value::IEEET1, val) = value.Ka = val
"""Set [`IEEET1`](@ref) `Ta`."""
set_Ta!(value::IEEET1, val) = value.Ta = val
"""Set [`IEEET1`](@ref) `Vr_lim`."""
set_Vr_lim!(value::IEEET1, val) = value.Vr_lim = val
"""Set [`IEEET1`](@ref) `Ke`."""
set_Ke!(value::IEEET1, val) = value.Ke = val
"""Set [`IEEET1`](@ref) `Te`."""
set_Te!(value::IEEET1, val) = value.Te = val
"""Set [`IEEET1`](@ref) `Kf`."""
set_Kf!(value::IEEET1, val) = value.Kf = val
"""Set [`IEEET1`](@ref) `Tf`."""
set_Tf!(value::IEEET1, val) = value.Tf = val
"""Set [`IEEET1`](@ref) `switch`."""
set_switch!(value::IEEET1, val) = value.switch = val
"""Set [`IEEET1`](@ref) `E_sat`."""
set_E_sat!(value::IEEET1, val) = value.E_sat = val
"""Set [`IEEET1`](@ref) `Se`."""
set_Se!(value::IEEET1, val) = value.Se = val
"""Set [`IEEET1`](@ref) `V_ref`."""
set_V_ref!(value::IEEET1, val) = value.V_ref = val
"""Set [`IEEET1`](@ref) `saturation_coeffs`."""
set_saturation_coeffs!(value::IEEET1, val) = value.saturation_coeffs = val
"""Set [`IEEET1`](@ref) `ext`."""
set_ext!(value::IEEET1, val) = value.ext = val
"""Set [`IEEET1`](@ref) `states_types`."""
set_states_types!(value::IEEET1, val) = value.states_types = val
================================================
FILE: src/models/generated/IEEETurbineGov1.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct IEEETurbineGov1 <: TurbineGov
K::Float64
T1::Float64
T2::Float64
T3::Float64
U0::Float64
U_c::Float64
valve_position_limits::MinMax
T4::Float64
K1::Float64
K2::Float64
T5::Float64
K3::Float64
K4::Float64
T6::Float64
K5::Float64
K6::Float64
T7::Float64
K7::Float64
K8::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
IEEE Type 1 Speed-Governing Model
# Arguments
- `K::Float64`: Governor Gain, validation range: `(5, 30)`
- `T1::Float64`: Input Filter Lag, validation range: `(0, 5)`
- `T2::Float64`: Input Filter Lead, validation range: `(0, 10)`
- `T3::Float64`: Valve position Time Constant, validation range: `(eps(), 1)`
- `U0::Float64`: Maximum Valve Opening Rate, validation range: `(0.01, 0.03)`
- `U_c::Float64`: Maximum Valve closing rate, validation range: `(-0.3, 0)`
- `valve_position_limits::MinMax`: Valve position limits in MW
- `T4::Float64`: Time Constant inlet steam, validation range: `(0, 1)`
- `K1::Float64`: Fraction of high presure shaft power, validation range: `(-2, 1)`
- `K2::Float64`: Fraction of low presure shaft power, validation range: `(0, nothing)`
- `T5::Float64`: Time constant for second boiler pass, validation range: `(0, 10)`
- `K3::Float64`: Fraction of high presure shaft power second boiler pass, validation range: `(0, 0.5)`
- `K4::Float64`: Fraction of low presure shaft power second boiler pass, validation range: `(0, 0.5)`
- `T6::Float64`: Time constant for third boiler pass, validation range: `(0, 10)`
- `K5::Float64`: Fraction of high presure shaft power third boiler pass, validation range: `(0, 0.35)`
- `K6::Float64`: Fraction of low presure shaft power third boiler pass, validation range: `(0, 0.55)`
- `T7::Float64`: Time constant for fourth boiler pass, validation range: `(0, 10)`
- `K7::Float64`: Fraction of high presure shaft power fourth boiler pass, validation range: `(0, 0.3)`
- `K8::Float64`: Fraction of low presure shaft power fourth boiler pass, validation range: `(0, 0.3)`
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the IEEETurbineGov model are:
x_g1: First Governor integrator,
x_g2: Governor output,
x_g3: First Turbine integrator,
x_g4: Second Turbine Integrator,
x_g5: Third Turbine Integrator,
x_g6: Fourth Turbine Integrator,
- `n_states::Int`: (**Do not modify.**) IEEEG1 has 6 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) IEEEG1 has 6 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct IEEETurbineGov1 <: TurbineGov
"Governor Gain"
K::Float64
"Input Filter Lag"
T1::Float64
"Input Filter Lead"
T2::Float64
"Valve position Time Constant"
T3::Float64
"Maximum Valve Opening Rate"
U0::Float64
"Maximum Valve closing rate"
U_c::Float64
"Valve position limits in MW"
valve_position_limits::MinMax
"Time Constant inlet steam"
T4::Float64
"Fraction of high presure shaft power"
K1::Float64
"Fraction of low presure shaft power"
K2::Float64
"Time constant for second boiler pass"
T5::Float64
"Fraction of high presure shaft power second boiler pass"
K3::Float64
"Fraction of low presure shaft power second boiler pass"
K4::Float64
"Time constant for third boiler pass"
T6::Float64
"Fraction of high presure shaft power third boiler pass"
K5::Float64
"Fraction of low presure shaft power third boiler pass"
K6::Float64
"Time constant for fourth boiler pass"
T7::Float64
"Fraction of high presure shaft power fourth boiler pass"
K7::Float64
"Fraction of low presure shaft power fourth boiler pass"
K8::Float64
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the IEEETurbineGov model are:
x_g1: First Governor integrator,
x_g2: Governor output,
x_g3: First Turbine integrator,
x_g4: Second Turbine Integrator,
x_g5: Third Turbine Integrator,
x_g6: Fourth Turbine Integrator, "
states::Vector{Symbol}
"(**Do not modify.**) IEEEG1 has 6 states"
n_states::Int
"(**Do not modify.**) IEEEG1 has 6 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function IEEETurbineGov1(K, T1, T2, T3, U0, U_c, valve_position_limits, T4, K1, K2, T5, K3, K4, T6, K5, K6, T7, K7, K8, P_ref=1.0, ext=Dict{String, Any}(), )
IEEETurbineGov1(K, T1, T2, T3, U0, U_c, valve_position_limits, T4, K1, K2, T5, K3, K4, T6, K5, K6, T7, K7, K8, P_ref, ext, [:x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6], 6, [StateTypes.Differential, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], InfrastructureSystemsInternal(), )
end
function IEEETurbineGov1(; K, T1, T2, T3, U0, U_c, valve_position_limits, T4, K1, K2, T5, K3, K4, T6, K5, K6, T7, K7, K8, P_ref=1.0, ext=Dict{String, Any}(), states=[:x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6], n_states=6, states_types=[StateTypes.Differential, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], internal=InfrastructureSystemsInternal(), )
IEEETurbineGov1(K, T1, T2, T3, U0, U_c, valve_position_limits, T4, K1, K2, T5, K3, K4, T6, K5, K6, T7, K7, K8, P_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function IEEETurbineGov1(::Nothing)
IEEETurbineGov1(;
K=0,
T1=0,
T2=0,
T3=0,
U0=0,
U_c=0,
valve_position_limits=(min=0.0, max=0.0),
T4=0,
K1=0,
K2=0,
T5=0,
K3=0,
K4=0,
T6=0,
K5=0,
K6=0,
T7=0,
K7=0,
K8=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`IEEETurbineGov1`](@ref) `K`."""
get_K(value::IEEETurbineGov1) = value.K
"""Get [`IEEETurbineGov1`](@ref) `T1`."""
get_T1(value::IEEETurbineGov1) = value.T1
"""Get [`IEEETurbineGov1`](@ref) `T2`."""
get_T2(value::IEEETurbineGov1) = value.T2
"""Get [`IEEETurbineGov1`](@ref) `T3`."""
get_T3(value::IEEETurbineGov1) = value.T3
"""Get [`IEEETurbineGov1`](@ref) `U0`."""
get_U0(value::IEEETurbineGov1) = value.U0
"""Get [`IEEETurbineGov1`](@ref) `U_c`."""
get_U_c(value::IEEETurbineGov1) = value.U_c
"""Get [`IEEETurbineGov1`](@ref) `valve_position_limits`."""
get_valve_position_limits(value::IEEETurbineGov1) = value.valve_position_limits
"""Get [`IEEETurbineGov1`](@ref) `T4`."""
get_T4(value::IEEETurbineGov1) = value.T4
"""Get [`IEEETurbineGov1`](@ref) `K1`."""
get_K1(value::IEEETurbineGov1) = value.K1
"""Get [`IEEETurbineGov1`](@ref) `K2`."""
get_K2(value::IEEETurbineGov1) = value.K2
"""Get [`IEEETurbineGov1`](@ref) `T5`."""
get_T5(value::IEEETurbineGov1) = value.T5
"""Get [`IEEETurbineGov1`](@ref) `K3`."""
get_K3(value::IEEETurbineGov1) = value.K3
"""Get [`IEEETurbineGov1`](@ref) `K4`."""
get_K4(value::IEEETurbineGov1) = value.K4
"""Get [`IEEETurbineGov1`](@ref) `T6`."""
get_T6(value::IEEETurbineGov1) = value.T6
"""Get [`IEEETurbineGov1`](@ref) `K5`."""
get_K5(value::IEEETurbineGov1) = value.K5
"""Get [`IEEETurbineGov1`](@ref) `K6`."""
get_K6(value::IEEETurbineGov1) = value.K6
"""Get [`IEEETurbineGov1`](@ref) `T7`."""
get_T7(value::IEEETurbineGov1) = value.T7
"""Get [`IEEETurbineGov1`](@ref) `K7`."""
get_K7(value::IEEETurbineGov1) = value.K7
"""Get [`IEEETurbineGov1`](@ref) `K8`."""
get_K8(value::IEEETurbineGov1) = value.K8
"""Get [`IEEETurbineGov1`](@ref) `P_ref`."""
get_P_ref(value::IEEETurbineGov1) = value.P_ref
"""Get [`IEEETurbineGov1`](@ref) `ext`."""
get_ext(value::IEEETurbineGov1) = value.ext
"""Get [`IEEETurbineGov1`](@ref) `states`."""
get_states(value::IEEETurbineGov1) = value.states
"""Get [`IEEETurbineGov1`](@ref) `n_states`."""
get_n_states(value::IEEETurbineGov1) = value.n_states
"""Get [`IEEETurbineGov1`](@ref) `states_types`."""
get_states_types(value::IEEETurbineGov1) = value.states_types
"""Get [`IEEETurbineGov1`](@ref) `internal`."""
get_internal(value::IEEETurbineGov1) = value.internal
"""Set [`IEEETurbineGov1`](@ref) `K`."""
set_K!(value::IEEETurbineGov1, val) = value.K = val
"""Set [`IEEETurbineGov1`](@ref) `T1`."""
set_T1!(value::IEEETurbineGov1, val) = value.T1 = val
"""Set [`IEEETurbineGov1`](@ref) `T2`."""
set_T2!(value::IEEETurbineGov1, val) = value.T2 = val
"""Set [`IEEETurbineGov1`](@ref) `T3`."""
set_T3!(value::IEEETurbineGov1, val) = value.T3 = val
"""Set [`IEEETurbineGov1`](@ref) `U0`."""
set_U0!(value::IEEETurbineGov1, val) = value.U0 = val
"""Set [`IEEETurbineGov1`](@ref) `U_c`."""
set_U_c!(value::IEEETurbineGov1, val) = value.U_c = val
"""Set [`IEEETurbineGov1`](@ref) `valve_position_limits`."""
set_valve_position_limits!(value::IEEETurbineGov1, val) = value.valve_position_limits = val
"""Set [`IEEETurbineGov1`](@ref) `T4`."""
set_T4!(value::IEEETurbineGov1, val) = value.T4 = val
"""Set [`IEEETurbineGov1`](@ref) `K1`."""
set_K1!(value::IEEETurbineGov1, val) = value.K1 = val
"""Set [`IEEETurbineGov1`](@ref) `K2`."""
set_K2!(value::IEEETurbineGov1, val) = value.K2 = val
"""Set [`IEEETurbineGov1`](@ref) `T5`."""
set_T5!(value::IEEETurbineGov1, val) = value.T5 = val
"""Set [`IEEETurbineGov1`](@ref) `K3`."""
set_K3!(value::IEEETurbineGov1, val) = value.K3 = val
"""Set [`IEEETurbineGov1`](@ref) `K4`."""
set_K4!(value::IEEETurbineGov1, val) = value.K4 = val
"""Set [`IEEETurbineGov1`](@ref) `T6`."""
set_T6!(value::IEEETurbineGov1, val) = value.T6 = val
"""Set [`IEEETurbineGov1`](@ref) `K5`."""
set_K5!(value::IEEETurbineGov1, val) = value.K5 = val
"""Set [`IEEETurbineGov1`](@ref) `K6`."""
set_K6!(value::IEEETurbineGov1, val) = value.K6 = val
"""Set [`IEEETurbineGov1`](@ref) `T7`."""
set_T7!(value::IEEETurbineGov1, val) = value.T7 = val
"""Set [`IEEETurbineGov1`](@ref) `K7`."""
set_K7!(value::IEEETurbineGov1, val) = value.K7 = val
"""Set [`IEEETurbineGov1`](@ref) `K8`."""
set_K8!(value::IEEETurbineGov1, val) = value.K8 = val
"""Set [`IEEETurbineGov1`](@ref) `P_ref`."""
set_P_ref!(value::IEEETurbineGov1, val) = value.P_ref = val
"""Set [`IEEETurbineGov1`](@ref) `ext`."""
set_ext!(value::IEEETurbineGov1, val) = value.ext = val
"""Set [`IEEETurbineGov1`](@ref) `states_types`."""
set_states_types!(value::IEEETurbineGov1, val) = value.states_types = val
================================================
FILE: src/models/generated/InstantaneousOutputCurrentLimiter.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct InstantaneousOutputCurrentLimiter <: OutputCurrentLimiter
Id_max::Float64
Iq_max::Float64
ext::Dict{String, Any}
end
Parameters of Instantaneous (Square) Current Controller Limiter. Regulates inverter output current on the d and q axis separately
# Arguments
- `Id_max::Float64`: Maximum limit on d-axis current controller input current in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `Iq_max::Float64`: Maximum limit on d-axis current controller input current in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
"""
mutable struct InstantaneousOutputCurrentLimiter <: OutputCurrentLimiter
"Maximum limit on d-axis current controller input current in pu ([`DEVICE_BASE`](@ref per_unit))"
Id_max::Float64
"Maximum limit on d-axis current controller input current in pu ([`DEVICE_BASE`](@ref per_unit))"
Iq_max::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
end
function InstantaneousOutputCurrentLimiter(; Id_max, Iq_max, ext=Dict{String, Any}(), )
InstantaneousOutputCurrentLimiter(Id_max, Iq_max, ext, )
end
# Constructor for demo purposes; non-functional.
function InstantaneousOutputCurrentLimiter(::Nothing)
InstantaneousOutputCurrentLimiter(;
Id_max=0,
Iq_max=0,
ext=Dict{String, Any}(),
)
end
"""Get [`InstantaneousOutputCurrentLimiter`](@ref) `Id_max`."""
get_Id_max(value::InstantaneousOutputCurrentLimiter) = value.Id_max
"""Get [`InstantaneousOutputCurrentLimiter`](@ref) `Iq_max`."""
get_Iq_max(value::InstantaneousOutputCurrentLimiter) = value.Iq_max
"""Get [`InstantaneousOutputCurrentLimiter`](@ref) `ext`."""
get_ext(value::InstantaneousOutputCurrentLimiter) = value.ext
"""Set [`InstantaneousOutputCurrentLimiter`](@ref) `Id_max`."""
set_Id_max!(value::InstantaneousOutputCurrentLimiter, val) = value.Id_max = val
"""Set [`InstantaneousOutputCurrentLimiter`](@ref) `Iq_max`."""
set_Iq_max!(value::InstantaneousOutputCurrentLimiter, val) = value.Iq_max = val
"""Set [`InstantaneousOutputCurrentLimiter`](@ref) `ext`."""
set_ext!(value::InstantaneousOutputCurrentLimiter, val) = value.ext = val
================================================
FILE: src/models/generated/InterconnectingConverter.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct InterconnectingConverter <: StaticInjection
name::String
available::Bool
bus::ACBus
dc_bus::DCBus
active_power::Float64
rating::Float64
active_power_limits::MinMax
base_power::Float64
reactive_power_limits::Union{Nothing, MinMax}
dc_current::Float64
max_dc_current::Float64
loss_function::Union{LinearCurve, QuadraticCurve}
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
Interconnecting Power Converter (IPC) for transforming power from an ACBus to a DCBus
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus on the AC side of this converter
- `dc_bus::DCBus`: Bus on the DC side of this converter
- `active_power::Float64`: Active power (MW) on the DC side, validation range: `active_power_limits`
- `rating::Float64`: Maximum output power rating of the converter (MVA), validation range: `(0, nothing)`
- `active_power_limits::MinMax`: Minimum and maximum stable active power levels (MW)
- `base_power::Float64`: Base power of the converter in MVA, validation range: `(0.0001, nothing)`
- `reactive_power_limits::Union{Nothing, MinMax}`: (default: `nothing`) Minimum and maximum reactive power limits. Set to `Nothing` if not applicable
- `dc_current::Float64`: (default: `0.0`) DC current (A) on the converter
- `max_dc_current::Float64`: (default: `1e8`) Maximum stable dc current limits (A)
- `loss_function::Union{LinearCurve, QuadraticCurve}`: (default: `LinearCurve(0.0)`) Linear or quadratic loss function with respect to the converter current
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct InterconnectingConverter <: StaticInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus on the AC side of this converter"
bus::ACBus
"Bus on the DC side of this converter"
dc_bus::DCBus
"Active power (MW) on the DC side"
active_power::Float64
"Maximum output power rating of the converter (MVA)"
rating::Float64
"Minimum and maximum stable active power levels (MW)"
active_power_limits::MinMax
"Base power of the converter in MVA"
base_power::Float64
"Minimum and maximum reactive power limits. Set to `Nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
"DC current (A) on the converter"
dc_current::Float64
"Maximum stable dc current limits (A)"
max_dc_current::Float64
"Linear or quadratic loss function with respect to the converter current"
loss_function::Union{LinearCurve, QuadraticCurve}
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function InterconnectingConverter(name, available, bus, dc_bus, active_power, rating, active_power_limits, base_power, reactive_power_limits=nothing, dc_current=0.0, max_dc_current=1e8, loss_function=LinearCurve(0.0), services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
InterconnectingConverter(name, available, bus, dc_bus, active_power, rating, active_power_limits, base_power, reactive_power_limits, dc_current, max_dc_current, loss_function, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function InterconnectingConverter(; name, available, bus, dc_bus, active_power, rating, active_power_limits, base_power, reactive_power_limits=nothing, dc_current=0.0, max_dc_current=1e8, loss_function=LinearCurve(0.0), services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
InterconnectingConverter(name, available, bus, dc_bus, active_power, rating, active_power_limits, base_power, reactive_power_limits, dc_current, max_dc_current, loss_function, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function InterconnectingConverter(::Nothing)
InterconnectingConverter(;
name="init",
available=false,
bus=ACBus(nothing),
dc_bus=DCBus(nothing),
active_power=0.0,
rating=0.0,
active_power_limits=(min=0.0, max=0.0),
base_power=100,
reactive_power_limits=nothing,
dc_current=0.0,
max_dc_current=0.0,
loss_function=LinearCurve(0.0),
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`InterconnectingConverter`](@ref) `name`."""
get_name(value::InterconnectingConverter) = value.name
"""Get [`InterconnectingConverter`](@ref) `available`."""
get_available(value::InterconnectingConverter) = value.available
"""Get [`InterconnectingConverter`](@ref) `bus`."""
get_bus(value::InterconnectingConverter) = value.bus
"""Get [`InterconnectingConverter`](@ref) `dc_bus`."""
get_dc_bus(value::InterconnectingConverter) = value.dc_bus
"""Get [`InterconnectingConverter`](@ref) `active_power`."""
get_active_power(value::InterconnectingConverter) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`InterconnectingConverter`](@ref) `rating`."""
get_rating(value::InterconnectingConverter) = get_value(value, Val(:rating), Val(:mva))
"""Get [`InterconnectingConverter`](@ref) `active_power_limits`."""
get_active_power_limits(value::InterconnectingConverter) = get_value(value, Val(:active_power_limits), Val(:mva))
"""Get [`InterconnectingConverter`](@ref) `base_power`."""
get_base_power(value::InterconnectingConverter) = value.base_power
"""Get [`InterconnectingConverter`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::InterconnectingConverter) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`InterconnectingConverter`](@ref) `dc_current`."""
get_dc_current(value::InterconnectingConverter) = value.dc_current
"""Get [`InterconnectingConverter`](@ref) `max_dc_current`."""
get_max_dc_current(value::InterconnectingConverter) = value.max_dc_current
"""Get [`InterconnectingConverter`](@ref) `loss_function`."""
get_loss_function(value::InterconnectingConverter) = value.loss_function
"""Get [`InterconnectingConverter`](@ref) `services`."""
get_services(value::InterconnectingConverter) = value.services
"""Get [`InterconnectingConverter`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::InterconnectingConverter) = value.dynamic_injector
"""Get [`InterconnectingConverter`](@ref) `ext`."""
get_ext(value::InterconnectingConverter) = value.ext
"""Get [`InterconnectingConverter`](@ref) `internal`."""
get_internal(value::InterconnectingConverter) = value.internal
"""Set [`InterconnectingConverter`](@ref) `available`."""
set_available!(value::InterconnectingConverter, val) = value.available = val
"""Set [`InterconnectingConverter`](@ref) `bus`."""
set_bus!(value::InterconnectingConverter, val) = value.bus = val
"""Set [`InterconnectingConverter`](@ref) `dc_bus`."""
set_dc_bus!(value::InterconnectingConverter, val) = value.dc_bus = val
"""Set [`InterconnectingConverter`](@ref) `active_power`."""
set_active_power!(value::InterconnectingConverter, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`InterconnectingConverter`](@ref) `rating`."""
set_rating!(value::InterconnectingConverter, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`InterconnectingConverter`](@ref) `active_power_limits`."""
set_active_power_limits!(value::InterconnectingConverter, val) = value.active_power_limits = set_value(value, Val(:active_power_limits), val, Val(:mva))
"""Set [`InterconnectingConverter`](@ref) `base_power`."""
set_base_power!(value::InterconnectingConverter, val) = value.base_power = val
"""Set [`InterconnectingConverter`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::InterconnectingConverter, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`InterconnectingConverter`](@ref) `dc_current`."""
set_dc_current!(value::InterconnectingConverter, val) = value.dc_current = val
"""Set [`InterconnectingConverter`](@ref) `max_dc_current`."""
set_max_dc_current!(value::InterconnectingConverter, val) = value.max_dc_current = val
"""Set [`InterconnectingConverter`](@ref) `loss_function`."""
set_loss_function!(value::InterconnectingConverter, val) = value.loss_function = val
"""Set [`InterconnectingConverter`](@ref) `services`."""
set_services!(value::InterconnectingConverter, val) = value.services = val
"""Set [`InterconnectingConverter`](@ref) `ext`."""
set_ext!(value::InterconnectingConverter, val) = value.ext = val
================================================
FILE: src/models/generated/InterruptiblePowerLoad.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct InterruptiblePowerLoad <: ControllableLoad
name::String
available::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
max_active_power::Float64
max_reactive_power::Float64
base_power::Float64
operation_cost::Union{LoadCost, MarketBidCost}
conformity::LoadConformity
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A [static](@ref S) power load that can be compensated for temporary or continuous interruptions to its requested demand.
These loads are most commonly used for operational optimizations and can be used to model, for example, large commercial and industrial customers enrolled in demand response programs. This load has a target demand profile (set by a [`max_active_power` time series](@ref ts_data) for an operational simulation) that can be reduced to satisfy other system needs. For simpler loads without an operating cost for demand response, see [`PowerLoad`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial steady state active power demand (MW)
- `reactive_power::Float64`: Initial steady state reactive power demand (MVAR)
- `max_active_power::Float64`: Maximum active power (MW) that this load can demand
- `max_reactive_power::Float64`: Maximum reactive power (MVAR) that this load can demand
- `base_power::Float64`: Base power (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `operation_cost::Union{LoadCost, MarketBidCost}`: [`OperationalCost`](@ref) of interrupting load
- `conformity::LoadConformity`: (default: `LoadConformity.UNDEFINED`) Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list).
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct InterruptiblePowerLoad <: ControllableLoad
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial steady state active power demand (MW)"
active_power::Float64
"Initial steady state reactive power demand (MVAR)"
reactive_power::Float64
"Maximum active power (MW) that this load can demand"
max_active_power::Float64
"Maximum reactive power (MVAR) that this load can demand"
max_reactive_power::Float64
"Base power (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"[`OperationalCost`](@ref) of interrupting load"
operation_cost::Union{LoadCost, MarketBidCost}
"Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list)."
conformity::LoadConformity
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function InterruptiblePowerLoad(name, available, bus, active_power, reactive_power, max_active_power, max_reactive_power, base_power, operation_cost, conformity=LoadConformity.UNDEFINED, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
InterruptiblePowerLoad(name, available, bus, active_power, reactive_power, max_active_power, max_reactive_power, base_power, operation_cost, conformity, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function InterruptiblePowerLoad(; name, available, bus, active_power, reactive_power, max_active_power, max_reactive_power, base_power, operation_cost, conformity=LoadConformity.UNDEFINED, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
InterruptiblePowerLoad(name, available, bus, active_power, reactive_power, max_active_power, max_reactive_power, base_power, operation_cost, conformity, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function InterruptiblePowerLoad(::Nothing)
InterruptiblePowerLoad(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
max_active_power=0.0,
max_reactive_power=0.0,
base_power=100.0,
operation_cost=LoadCost(nothing),
conformity=LoadConformity.UNDEFINED,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`InterruptiblePowerLoad`](@ref) `name`."""
get_name(value::InterruptiblePowerLoad) = value.name
"""Get [`InterruptiblePowerLoad`](@ref) `available`."""
get_available(value::InterruptiblePowerLoad) = value.available
"""Get [`InterruptiblePowerLoad`](@ref) `bus`."""
get_bus(value::InterruptiblePowerLoad) = value.bus
"""Get [`InterruptiblePowerLoad`](@ref) `active_power`."""
get_active_power(value::InterruptiblePowerLoad) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`InterruptiblePowerLoad`](@ref) `reactive_power`."""
get_reactive_power(value::InterruptiblePowerLoad) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`InterruptiblePowerLoad`](@ref) `max_active_power`."""
get_max_active_power(value::InterruptiblePowerLoad) = get_value(value, Val(:max_active_power), Val(:mva))
"""Get [`InterruptiblePowerLoad`](@ref) `max_reactive_power`."""
get_max_reactive_power(value::InterruptiblePowerLoad) = get_value(value, Val(:max_reactive_power), Val(:mva))
"""Get [`InterruptiblePowerLoad`](@ref) `base_power`."""
get_base_power(value::InterruptiblePowerLoad) = value.base_power
"""Get [`InterruptiblePowerLoad`](@ref) `operation_cost`."""
get_operation_cost(value::InterruptiblePowerLoad) = value.operation_cost
"""Get [`InterruptiblePowerLoad`](@ref) `conformity`."""
get_conformity(value::InterruptiblePowerLoad) = value.conformity
"""Get [`InterruptiblePowerLoad`](@ref) `services`."""
get_services(value::InterruptiblePowerLoad) = value.services
"""Get [`InterruptiblePowerLoad`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::InterruptiblePowerLoad) = value.dynamic_injector
"""Get [`InterruptiblePowerLoad`](@ref) `ext`."""
get_ext(value::InterruptiblePowerLoad) = value.ext
"""Get [`InterruptiblePowerLoad`](@ref) `internal`."""
get_internal(value::InterruptiblePowerLoad) = value.internal
"""Set [`InterruptiblePowerLoad`](@ref) `available`."""
set_available!(value::InterruptiblePowerLoad, val) = value.available = val
"""Set [`InterruptiblePowerLoad`](@ref) `bus`."""
set_bus!(value::InterruptiblePowerLoad, val) = value.bus = val
"""Set [`InterruptiblePowerLoad`](@ref) `active_power`."""
set_active_power!(value::InterruptiblePowerLoad, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`InterruptiblePowerLoad`](@ref) `reactive_power`."""
set_reactive_power!(value::InterruptiblePowerLoad, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`InterruptiblePowerLoad`](@ref) `max_active_power`."""
set_max_active_power!(value::InterruptiblePowerLoad, val) = value.max_active_power = set_value(value, Val(:max_active_power), val, Val(:mva))
"""Set [`InterruptiblePowerLoad`](@ref) `max_reactive_power`."""
set_max_reactive_power!(value::InterruptiblePowerLoad, val) = value.max_reactive_power = set_value(value, Val(:max_reactive_power), val, Val(:mva))
"""Set [`InterruptiblePowerLoad`](@ref) `base_power`."""
set_base_power!(value::InterruptiblePowerLoad, val) = value.base_power = val
"""Set [`InterruptiblePowerLoad`](@ref) `operation_cost`."""
set_operation_cost!(value::InterruptiblePowerLoad, val) = value.operation_cost = val
"""Set [`InterruptiblePowerLoad`](@ref) `conformity`."""
set_conformity!(value::InterruptiblePowerLoad, val) = value.conformity = val
"""Set [`InterruptiblePowerLoad`](@ref) `services`."""
set_services!(value::InterruptiblePowerLoad, val) = value.services = val
"""Set [`InterruptiblePowerLoad`](@ref) `ext`."""
set_ext!(value::InterruptiblePowerLoad, val) = value.ext = val
================================================
FILE: src/models/generated/InterruptibleStandardLoad.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct InterruptibleStandardLoad <: ControllableLoad
name::String
available::Bool
bus::ACBus
base_power::Float64
operation_cost::Union{LoadCost, MarketBidCost}
conformity::LoadConformity
constant_active_power::Float64
constant_reactive_power::Float64
impedance_active_power::Float64
impedance_reactive_power::Float64
current_active_power::Float64
current_reactive_power::Float64
max_constant_active_power::Float64
max_constant_reactive_power::Float64
max_impedance_active_power::Float64
max_impedance_reactive_power::Float64
max_current_active_power::Float64
max_current_reactive_power::Float64
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A voltage-dependent [ZIP load](@ref Z), most commonly used for dynamics modeling.
A `StandardLoad` breaks the ZIP into three pieces: Z (constant impedance), I (constant current), and P (constant power), according to `P = P_P * V^0 + P_I * V^1 + P_Z * V^2` for active power and `Q = Q_P * V^0 + Q_I * V^1 + Q_Z * V^2` for reactive power. (Voltage V is in per unit.)
For an alternative exponential formulation of the ZIP model, see [`ExponentialLoad`](@ref). For a simpler load model with no voltage dependency, see [`PowerLoad`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `base_power::Float64`: Base power of the load (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `operation_cost::Union{LoadCost, MarketBidCost}`: [`OperationalCost`](@ref) of interrupting load
- `conformity::LoadConformity`: (default: `LoadConformity.UNDEFINED`) Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list).
- `constant_active_power::Float64`: (default: `0.0`) Constant active power demand in MW (P_P)
- `constant_reactive_power::Float64`: (default: `0.0`) Constant reactive power demand in MVAR (Q_P)
- `impedance_active_power::Float64`: (default: `0.0`) Active power coefficient in MW for constant impedance load (P_Z)
- `impedance_reactive_power::Float64`: (default: `0.0`) Reactive power coefficient in MVAR for constant impedance load (Q_Z)
- `current_active_power::Float64`: (default: `0.0`) Active power coefficient in MW for constant current load (P_I)
- `current_reactive_power::Float64`: (default: `0.0`) Reactive power coefficient in MVAR for constant current load (Q_I)
- `max_constant_active_power::Float64`: (default: `0.0`) Maximum active power (MW) drawn by constant power load
- `max_constant_reactive_power::Float64`: (default: `0.0`) Maximum reactive power (MVAR) drawn by constant power load
- `max_impedance_active_power::Float64`: (default: `0.0`) Maximum active power (MW) drawn by constant impedance load
- `max_impedance_reactive_power::Float64`: (default: `0.0`) Maximum reactive power (MVAR) drawn by constant impedance load
- `max_current_active_power::Float64`: (default: `0.0`) Maximum active power (MW) drawn by constant current load
- `max_current_reactive_power::Float64`: (default: `0.0`) Maximum reactive power (MVAR) drawn by constant current load
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct InterruptibleStandardLoad <: ControllableLoad
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Base power of the load (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"[`OperationalCost`](@ref) of interrupting load"
operation_cost::Union{LoadCost, MarketBidCost}
"Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list)."
conformity::LoadConformity
"Constant active power demand in MW (P_P)"
constant_active_power::Float64
"Constant reactive power demand in MVAR (Q_P)"
constant_reactive_power::Float64
"Active power coefficient in MW for constant impedance load (P_Z)"
impedance_active_power::Float64
"Reactive power coefficient in MVAR for constant impedance load (Q_Z)"
impedance_reactive_power::Float64
"Active power coefficient in MW for constant current load (P_I)"
current_active_power::Float64
"Reactive power coefficient in MVAR for constant current load (Q_I)"
current_reactive_power::Float64
"Maximum active power (MW) drawn by constant power load"
max_constant_active_power::Float64
"Maximum reactive power (MVAR) drawn by constant power load"
max_constant_reactive_power::Float64
"Maximum active power (MW) drawn by constant impedance load"
max_impedance_active_power::Float64
"Maximum reactive power (MVAR) drawn by constant impedance load"
max_impedance_reactive_power::Float64
"Maximum active power (MW) drawn by constant current load"
max_current_active_power::Float64
"Maximum reactive power (MVAR) drawn by constant current load"
max_current_reactive_power::Float64
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function InterruptibleStandardLoad(name, available, bus, base_power, operation_cost, conformity=LoadConformity.UNDEFINED, constant_active_power=0.0, constant_reactive_power=0.0, impedance_active_power=0.0, impedance_reactive_power=0.0, current_active_power=0.0, current_reactive_power=0.0, max_constant_active_power=0.0, max_constant_reactive_power=0.0, max_impedance_active_power=0.0, max_impedance_reactive_power=0.0, max_current_active_power=0.0, max_current_reactive_power=0.0, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
InterruptibleStandardLoad(name, available, bus, base_power, operation_cost, conformity, constant_active_power, constant_reactive_power, impedance_active_power, impedance_reactive_power, current_active_power, current_reactive_power, max_constant_active_power, max_constant_reactive_power, max_impedance_active_power, max_impedance_reactive_power, max_current_active_power, max_current_reactive_power, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function InterruptibleStandardLoad(; name, available, bus, base_power, operation_cost, conformity=LoadConformity.UNDEFINED, constant_active_power=0.0, constant_reactive_power=0.0, impedance_active_power=0.0, impedance_reactive_power=0.0, current_active_power=0.0, current_reactive_power=0.0, max_constant_active_power=0.0, max_constant_reactive_power=0.0, max_impedance_active_power=0.0, max_impedance_reactive_power=0.0, max_current_active_power=0.0, max_current_reactive_power=0.0, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
InterruptibleStandardLoad(name, available, bus, base_power, operation_cost, conformity, constant_active_power, constant_reactive_power, impedance_active_power, impedance_reactive_power, current_active_power, current_reactive_power, max_constant_active_power, max_constant_reactive_power, max_impedance_active_power, max_impedance_reactive_power, max_current_active_power, max_current_reactive_power, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function InterruptibleStandardLoad(::Nothing)
InterruptibleStandardLoad(;
name="init",
available=false,
bus=ACBus(nothing),
base_power=100.0,
operation_cost=LoadCost(nothing),
conformity=LoadConformity.UNDEFINED,
constant_active_power=0.0,
constant_reactive_power=0.0,
impedance_active_power=0.0,
impedance_reactive_power=0.0,
current_active_power=0.0,
current_reactive_power=0.0,
max_constant_active_power=0.0,
max_constant_reactive_power=0.0,
max_impedance_active_power=0.0,
max_impedance_reactive_power=0.0,
max_current_active_power=0.0,
max_current_reactive_power=0.0,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`InterruptibleStandardLoad`](@ref) `name`."""
get_name(value::InterruptibleStandardLoad) = value.name
"""Get [`InterruptibleStandardLoad`](@ref) `available`."""
get_available(value::InterruptibleStandardLoad) = value.available
"""Get [`InterruptibleStandardLoad`](@ref) `bus`."""
get_bus(value::InterruptibleStandardLoad) = value.bus
"""Get [`InterruptibleStandardLoad`](@ref) `base_power`."""
get_base_power(value::InterruptibleStandardLoad) = value.base_power
"""Get [`InterruptibleStandardLoad`](@ref) `operation_cost`."""
get_operation_cost(value::InterruptibleStandardLoad) = value.operation_cost
"""Get [`InterruptibleStandardLoad`](@ref) `conformity`."""
get_conformity(value::InterruptibleStandardLoad) = value.conformity
"""Get [`InterruptibleStandardLoad`](@ref) `constant_active_power`."""
get_constant_active_power(value::InterruptibleStandardLoad) = get_value(value, Val(:constant_active_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `constant_reactive_power`."""
get_constant_reactive_power(value::InterruptibleStandardLoad) = get_value(value, Val(:constant_reactive_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `impedance_active_power`."""
get_impedance_active_power(value::InterruptibleStandardLoad) = get_value(value, Val(:impedance_active_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `impedance_reactive_power`."""
get_impedance_reactive_power(value::InterruptibleStandardLoad) = get_value(value, Val(:impedance_reactive_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `current_active_power`."""
get_current_active_power(value::InterruptibleStandardLoad) = get_value(value, Val(:current_active_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `current_reactive_power`."""
get_current_reactive_power(value::InterruptibleStandardLoad) = get_value(value, Val(:current_reactive_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `max_constant_active_power`."""
get_max_constant_active_power(value::InterruptibleStandardLoad) = get_value(value, Val(:max_constant_active_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `max_constant_reactive_power`."""
get_max_constant_reactive_power(value::InterruptibleStandardLoad) = get_value(value, Val(:max_constant_reactive_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `max_impedance_active_power`."""
get_max_impedance_active_power(value::InterruptibleStandardLoad) = get_value(value, Val(:max_impedance_active_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `max_impedance_reactive_power`."""
get_max_impedance_reactive_power(value::InterruptibleStandardLoad) = get_value(value, Val(:max_impedance_reactive_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `max_current_active_power`."""
get_max_current_active_power(value::InterruptibleStandardLoad) = get_value(value, Val(:max_current_active_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `max_current_reactive_power`."""
get_max_current_reactive_power(value::InterruptibleStandardLoad) = get_value(value, Val(:max_current_reactive_power), Val(:mva))
"""Get [`InterruptibleStandardLoad`](@ref) `services`."""
get_services(value::InterruptibleStandardLoad) = value.services
"""Get [`InterruptibleStandardLoad`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::InterruptibleStandardLoad) = value.dynamic_injector
"""Get [`InterruptibleStandardLoad`](@ref) `ext`."""
get_ext(value::InterruptibleStandardLoad) = value.ext
"""Get [`InterruptibleStandardLoad`](@ref) `internal`."""
get_internal(value::InterruptibleStandardLoad) = value.internal
"""Set [`InterruptibleStandardLoad`](@ref) `available`."""
set_available!(value::InterruptibleStandardLoad, val) = value.available = val
"""Set [`InterruptibleStandardLoad`](@ref) `bus`."""
set_bus!(value::InterruptibleStandardLoad, val) = value.bus = val
"""Set [`InterruptibleStandardLoad`](@ref) `base_power`."""
set_base_power!(value::InterruptibleStandardLoad, val) = value.base_power = val
"""Set [`InterruptibleStandardLoad`](@ref) `operation_cost`."""
set_operation_cost!(value::InterruptibleStandardLoad, val) = value.operation_cost = val
"""Set [`InterruptibleStandardLoad`](@ref) `conformity`."""
set_conformity!(value::InterruptibleStandardLoad, val) = value.conformity = val
"""Set [`InterruptibleStandardLoad`](@ref) `constant_active_power`."""
set_constant_active_power!(value::InterruptibleStandardLoad, val) = value.constant_active_power = set_value(value, Val(:constant_active_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `constant_reactive_power`."""
set_constant_reactive_power!(value::InterruptibleStandardLoad, val) = value.constant_reactive_power = set_value(value, Val(:constant_reactive_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `impedance_active_power`."""
set_impedance_active_power!(value::InterruptibleStandardLoad, val) = value.impedance_active_power = set_value(value, Val(:impedance_active_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `impedance_reactive_power`."""
set_impedance_reactive_power!(value::InterruptibleStandardLoad, val) = value.impedance_reactive_power = set_value(value, Val(:impedance_reactive_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `current_active_power`."""
set_current_active_power!(value::InterruptibleStandardLoad, val) = value.current_active_power = set_value(value, Val(:current_active_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `current_reactive_power`."""
set_current_reactive_power!(value::InterruptibleStandardLoad, val) = value.current_reactive_power = set_value(value, Val(:current_reactive_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `max_constant_active_power`."""
set_max_constant_active_power!(value::InterruptibleStandardLoad, val) = value.max_constant_active_power = set_value(value, Val(:max_constant_active_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `max_constant_reactive_power`."""
set_max_constant_reactive_power!(value::InterruptibleStandardLoad, val) = value.max_constant_reactive_power = set_value(value, Val(:max_constant_reactive_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `max_impedance_active_power`."""
set_max_impedance_active_power!(value::InterruptibleStandardLoad, val) = value.max_impedance_active_power = set_value(value, Val(:max_impedance_active_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `max_impedance_reactive_power`."""
set_max_impedance_reactive_power!(value::InterruptibleStandardLoad, val) = value.max_impedance_reactive_power = set_value(value, Val(:max_impedance_reactive_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `max_current_active_power`."""
set_max_current_active_power!(value::InterruptibleStandardLoad, val) = value.max_current_active_power = set_value(value, Val(:max_current_active_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `max_current_reactive_power`."""
set_max_current_reactive_power!(value::InterruptibleStandardLoad, val) = value.max_current_reactive_power = set_value(value, Val(:max_current_reactive_power), val, Val(:mva))
"""Set [`InterruptibleStandardLoad`](@ref) `services`."""
set_services!(value::InterruptibleStandardLoad, val) = value.services = val
"""Set [`InterruptibleStandardLoad`](@ref) `ext`."""
set_ext!(value::InterruptibleStandardLoad, val) = value.ext = val
================================================
FILE: src/models/generated/KauraPLL.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct KauraPLL <: FrequencyEstimator
ω_lp::Float64
kp_pll::Float64
ki_pll::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a Phase-Locked Loop (PLL) based on ["Operation of a phase locked loop system under distorted utility conditions"](https://doi.org/10.1109/28.567077) by Vikram Kaura, and Vladimir Blasko
# Arguments
- `ω_lp::Float64`: PLL low-pass filter frequency (rad/sec), validation range: `(0, nothing)`
- `kp_pll::Float64`: PLL proportional gain, validation range: `(0, nothing)`
- `ki_pll::Float64`: PLL integral gain, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the KauraPLL model are:
vd_pll: d-axis of the measured voltage in the PLL synchronous reference frame (SRF),
vq_pll: q-axis of the measured voltage in the PLL SRF,
ε_pll: Integrator state of the PI controller,
θ_pll: Phase angle displacement in the PLL SRF
- `n_states::Int`: (**Do not modify.**) KauraPLL has 4 states
"""
mutable struct KauraPLL <: FrequencyEstimator
"PLL low-pass filter frequency (rad/sec)"
ω_lp::Float64
"PLL proportional gain"
kp_pll::Float64
"PLL integral gain"
ki_pll::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the KauraPLL model are:
vd_pll: d-axis of the measured voltage in the PLL synchronous reference frame (SRF),
vq_pll: q-axis of the measured voltage in the PLL SRF,
ε_pll: Integrator state of the PI controller,
θ_pll: Phase angle displacement in the PLL SRF"
states::Vector{Symbol}
"(**Do not modify.**) KauraPLL has 4 states"
n_states::Int
end
function KauraPLL(ω_lp, kp_pll, ki_pll, ext=Dict{String, Any}(), )
KauraPLL(ω_lp, kp_pll, ki_pll, ext, [:vd_pll, :vq_pll, :ε_pll, :θ_pll], 4, )
end
function KauraPLL(; ω_lp, kp_pll, ki_pll, ext=Dict{String, Any}(), states=[:vd_pll, :vq_pll, :ε_pll, :θ_pll], n_states=4, )
KauraPLL(ω_lp, kp_pll, ki_pll, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function KauraPLL(::Nothing)
KauraPLL(;
ω_lp=0,
kp_pll=0,
ki_pll=0,
ext=Dict{String, Any}(),
)
end
"""Get [`KauraPLL`](@ref) `ω_lp`."""
get_ω_lp(value::KauraPLL) = value.ω_lp
"""Get [`KauraPLL`](@ref) `kp_pll`."""
get_kp_pll(value::KauraPLL) = value.kp_pll
"""Get [`KauraPLL`](@ref) `ki_pll`."""
get_ki_pll(value::KauraPLL) = value.ki_pll
"""Get [`KauraPLL`](@ref) `ext`."""
get_ext(value::KauraPLL) = value.ext
"""Get [`KauraPLL`](@ref) `states`."""
get_states(value::KauraPLL) = value.states
"""Get [`KauraPLL`](@ref) `n_states`."""
get_n_states(value::KauraPLL) = value.n_states
"""Set [`KauraPLL`](@ref) `ω_lp`."""
set_ω_lp!(value::KauraPLL, val) = value.ω_lp = val
"""Set [`KauraPLL`](@ref) `kp_pll`."""
set_kp_pll!(value::KauraPLL, val) = value.kp_pll = val
"""Set [`KauraPLL`](@ref) `ki_pll`."""
set_ki_pll!(value::KauraPLL, val) = value.ki_pll = val
"""Set [`KauraPLL`](@ref) `ext`."""
set_ext!(value::KauraPLL, val) = value.ext = val
================================================
FILE: src/models/generated/LCFilter.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct LCFilter <: Filter
lf::Float64
rf::Float64
cf::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a LCL filter outside the converter
# Arguments
- `lf::Float64`: filter inductance, validation range: `(0, nothing)`
- `rf::Float64`: filter resistance, validation range: `(0, nothing)`
- `cf::Float64`: filter capacitance, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the LCFilter model are:
ir_filter: Real current out of the filter,
ii_filter: Imaginary current out of the filter
- `n_states::Int`: (**Do not modify.**) LCFilter has two states
"""
mutable struct LCFilter <: Filter
"filter inductance"
lf::Float64
"filter resistance"
rf::Float64
"filter capacitance"
cf::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the LCFilter model are:
ir_filter: Real current out of the filter,
ii_filter: Imaginary current out of the filter"
states::Vector{Symbol}
"(**Do not modify.**) LCFilter has two states"
n_states::Int
end
function LCFilter(lf, rf, cf, ext=Dict{String, Any}(), )
LCFilter(lf, rf, cf, ext, [:ir_filter, :ii_filter], 2, )
end
function LCFilter(; lf, rf, cf, ext=Dict{String, Any}(), states=[:ir_filter, :ii_filter], n_states=2, )
LCFilter(lf, rf, cf, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function LCFilter(::Nothing)
LCFilter(;
lf=0,
rf=0,
cf=0,
ext=Dict{String, Any}(),
)
end
"""Get [`LCFilter`](@ref) `lf`."""
get_lf(value::LCFilter) = value.lf
"""Get [`LCFilter`](@ref) `rf`."""
get_rf(value::LCFilter) = value.rf
"""Get [`LCFilter`](@ref) `cf`."""
get_cf(value::LCFilter) = value.cf
"""Get [`LCFilter`](@ref) `ext`."""
get_ext(value::LCFilter) = value.ext
"""Get [`LCFilter`](@ref) `states`."""
get_states(value::LCFilter) = value.states
"""Get [`LCFilter`](@ref) `n_states`."""
get_n_states(value::LCFilter) = value.n_states
"""Set [`LCFilter`](@ref) `lf`."""
set_lf!(value::LCFilter, val) = value.lf = val
"""Set [`LCFilter`](@ref) `rf`."""
set_rf!(value::LCFilter, val) = value.rf = val
"""Set [`LCFilter`](@ref) `cf`."""
set_cf!(value::LCFilter, val) = value.cf = val
"""Set [`LCFilter`](@ref) `ext`."""
set_ext!(value::LCFilter, val) = value.ext = val
================================================
FILE: src/models/generated/LCLFilter.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct LCLFilter <: Filter
lf::Float64
rf::Float64
cf::Float64
lg::Float64
rg::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a LCL filter outside the converter, the [states](@ref S) are in the grid's reference frame
# Arguments
- `lf::Float64`: Series inductance in p.u. of converter filter, validation range: `(0, nothing)`
- `rf::Float64`: Series resistance in p.u. of converter filter, validation range: `(0, nothing)`
- `cf::Float64`: Shunt capacitance in p.u. of converter filter, validation range: `(0, nothing)`
- `lg::Float64`: Series inductance in p.u. of converter filter to the grid, validation range: `(0, nothing)`
- `rg::Float64`: Series resistance in p.u. of converter filter to the grid, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the LCLFilter model are:
ir_cnv: Real current out of the converter,
ii_cnv: Imaginary current out of the converter,
vr_filter: Real voltage at the filter's capacitor,
vi_filter: Imaginary voltage at the filter's capacitor,
ir_filter: Real current out of the filter,
ii_filter: Imaginary current out of the filter
- `n_states::Int`: (**Do not modify.**) LCLFilter has 6 states
"""
mutable struct LCLFilter <: Filter
"Series inductance in p.u. of converter filter"
lf::Float64
"Series resistance in p.u. of converter filter"
rf::Float64
"Shunt capacitance in p.u. of converter filter"
cf::Float64
"Series inductance in p.u. of converter filter to the grid"
lg::Float64
"Series resistance in p.u. of converter filter to the grid"
rg::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the LCLFilter model are:
ir_cnv: Real current out of the converter,
ii_cnv: Imaginary current out of the converter,
vr_filter: Real voltage at the filter's capacitor,
vi_filter: Imaginary voltage at the filter's capacitor,
ir_filter: Real current out of the filter,
ii_filter: Imaginary current out of the filter"
states::Vector{Symbol}
"(**Do not modify.**) LCLFilter has 6 states"
n_states::Int
end
function LCLFilter(lf, rf, cf, lg, rg, ext=Dict{String, Any}(), )
LCLFilter(lf, rf, cf, lg, rg, ext, [:ir_cnv, :ii_cnv, :vr_filter, :vi_filter, :ir_filter, :ii_filter], 6, )
end
function LCLFilter(; lf, rf, cf, lg, rg, ext=Dict{String, Any}(), states=[:ir_cnv, :ii_cnv, :vr_filter, :vi_filter, :ir_filter, :ii_filter], n_states=6, )
LCLFilter(lf, rf, cf, lg, rg, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function LCLFilter(::Nothing)
LCLFilter(;
lf=0,
rf=0,
cf=0,
lg=0,
rg=0,
ext=Dict{String, Any}(),
)
end
"""Get [`LCLFilter`](@ref) `lf`."""
get_lf(value::LCLFilter) = value.lf
"""Get [`LCLFilter`](@ref) `rf`."""
get_rf(value::LCLFilter) = value.rf
"""Get [`LCLFilter`](@ref) `cf`."""
get_cf(value::LCLFilter) = value.cf
"""Get [`LCLFilter`](@ref) `lg`."""
get_lg(value::LCLFilter) = value.lg
"""Get [`LCLFilter`](@ref) `rg`."""
get_rg(value::LCLFilter) = value.rg
"""Get [`LCLFilter`](@ref) `ext`."""
get_ext(value::LCLFilter) = value.ext
"""Get [`LCLFilter`](@ref) `states`."""
get_states(value::LCLFilter) = value.states
"""Get [`LCLFilter`](@ref) `n_states`."""
get_n_states(value::LCLFilter) = value.n_states
"""Set [`LCLFilter`](@ref) `lf`."""
set_lf!(value::LCLFilter, val) = value.lf = val
"""Set [`LCLFilter`](@ref) `rf`."""
set_rf!(value::LCLFilter, val) = value.rf = val
"""Set [`LCLFilter`](@ref) `cf`."""
set_cf!(value::LCLFilter, val) = value.cf = val
"""Set [`LCLFilter`](@ref) `lg`."""
set_lg!(value::LCLFilter, val) = value.lg = val
"""Set [`LCLFilter`](@ref) `rg`."""
set_rg!(value::LCLFilter, val) = value.rg = val
"""Set [`LCLFilter`](@ref) `ext`."""
set_ext!(value::LCLFilter, val) = value.ext = val
================================================
FILE: src/models/generated/Line.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct Line <: ACTransmission
name::String
available::Bool
active_power_flow::Float64
reactive_power_flow::Float64
arc::Arc
r::Float64
x::Float64
b::FromTo
rating::Float64
angle_limits::MinMax
rating_b::Union{Nothing, Float64}
rating_c::Union{Nothing, Float64}
g::FromTo
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
An AC transmission line
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow::Float64`: Initial condition of active power flow on the line (MW)
- `reactive_power_flow::Float64`: Initial condition of reactive power flow on the line (MVAR)
- `arc::Arc`: An [`Arc`](@ref) defining this line `from` a bus `to` another bus
- `r::Float64`: Resistance in pu ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(0, 4)`
- `x::Float64`: Reactance in pu ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(0, 4)`
- `b::FromTo`: Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value, validation range: `(0, 100)`
- `rating::Float64`: Thermal rating (MVA). Flow on the line must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to
- `angle_limits::MinMax`: Minimum and maximum angle limits (radians)
- `rating_b::Union{Nothing, Float64}`: (default: `nothing`) Second current rating; entered in MVA.
- `rating_c::Union{Nothing, Float64}`: (default: `nothing`) Third current rating; entered in MVA.
- `g::FromTo`: (default: `(from=0.0, to=0.0)`) Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value, validation range: `(0, 100)`
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct Line <: ACTransmission
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial condition of active power flow on the line (MW)"
active_power_flow::Float64
"Initial condition of reactive power flow on the line (MVAR)"
reactive_power_flow::Float64
"An [`Arc`](@ref) defining this line `from` a bus `to` another bus"
arc::Arc
"Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))"
r::Float64
"Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))"
x::Float64
"Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value"
b::FromTo
"Thermal rating (MVA). Flow on the line must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to"
rating::Float64
"Minimum and maximum angle limits (radians)"
angle_limits::MinMax
"Second current rating; entered in MVA."
rating_b::Union{Nothing, Float64}
"Third current rating; entered in MVA."
rating_c::Union{Nothing, Float64}
"Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value"
g::FromTo
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function Line(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, rating_b=nothing, rating_c=nothing, g=(from=0.0, to=0.0), services=Device[], ext=Dict{String, Any}(), )
Line(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, rating_b, rating_c, g, services, ext, InfrastructureSystemsInternal(), )
end
function Line(; name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, rating_b=nothing, rating_c=nothing, g=(from=0.0, to=0.0), services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
Line(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, rating_b, rating_c, g, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function Line(::Nothing)
Line(;
name="init",
available=false,
active_power_flow=0.0,
reactive_power_flow=0.0,
arc=Arc(ACBus(nothing), ACBus(nothing)),
r=0.0,
x=0.0,
b=(from=0.0, to=0.0),
rating=0.0,
angle_limits=(min=-3.1416, max=3.1416),
rating_b=0.0,
rating_c=0.0,
g=(from=0.0, to=0.0),
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`Line`](@ref) `name`."""
get_name(value::Line) = value.name
"""Get [`Line`](@ref) `available`."""
get_available(value::Line) = value.available
"""Get [`Line`](@ref) `active_power_flow`."""
get_active_power_flow(value::Line) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`Line`](@ref) `reactive_power_flow`."""
get_reactive_power_flow(value::Line) = get_value(value, Val(:reactive_power_flow), Val(:mva))
"""Get [`Line`](@ref) `arc`."""
get_arc(value::Line) = value.arc
"""Get [`Line`](@ref) `r`."""
get_r(value::Line) = get_value(value, Val(:r), Val(:ohm))
"""Get [`Line`](@ref) `x`."""
get_x(value::Line) = get_value(value, Val(:x), Val(:ohm))
"""Get [`Line`](@ref) `b`."""
get_b(value::Line) = get_value(value, Val(:b), Val(:siemens))
"""Get [`Line`](@ref) `rating`."""
get_rating(value::Line) = get_value(value, Val(:rating), Val(:mva))
"""Get [`Line`](@ref) `angle_limits`."""
get_angle_limits(value::Line) = value.angle_limits
"""Get [`Line`](@ref) `rating_b`."""
get_rating_b(value::Line) = get_value(value, Val(:rating_b), Val(:mva))
"""Get [`Line`](@ref) `rating_c`."""
get_rating_c(value::Line) = get_value(value, Val(:rating_c), Val(:mva))
"""Get [`Line`](@ref) `g`."""
get_g(value::Line) = get_value(value, Val(:g), Val(:siemens))
"""Get [`Line`](@ref) `services`."""
get_services(value::Line) = value.services
"""Get [`Line`](@ref) `ext`."""
get_ext(value::Line) = value.ext
"""Get [`Line`](@ref) `internal`."""
get_internal(value::Line) = value.internal
"""Set [`Line`](@ref) `available`."""
set_available!(value::Line, val) = value.available = val
"""Set [`Line`](@ref) `active_power_flow`."""
set_active_power_flow!(value::Line, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`Line`](@ref) `reactive_power_flow`."""
set_reactive_power_flow!(value::Line, val) = value.reactive_power_flow = set_value(value, Val(:reactive_power_flow), val, Val(:mva))
"""Set [`Line`](@ref) `arc`."""
set_arc!(value::Line, val) = value.arc = val
"""Set [`Line`](@ref) `r`."""
set_r!(value::Line, val) = value.r = set_value(value, Val(:r), val, Val(:ohm))
"""Set [`Line`](@ref) `x`."""
set_x!(value::Line, val) = value.x = set_value(value, Val(:x), val, Val(:ohm))
"""Set [`Line`](@ref) `b`."""
set_b!(value::Line, val) = value.b = set_value(value, Val(:b), val, Val(:siemens))
"""Set [`Line`](@ref) `rating`."""
set_rating!(value::Line, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`Line`](@ref) `angle_limits`."""
set_angle_limits!(value::Line, val) = value.angle_limits = val
"""Set [`Line`](@ref) `rating_b`."""
set_rating_b!(value::Line, val) = value.rating_b = set_value(value, Val(:rating_b), val, Val(:mva))
"""Set [`Line`](@ref) `rating_c`."""
set_rating_c!(value::Line, val) = value.rating_c = set_value(value, Val(:rating_c), val, Val(:mva))
"""Set [`Line`](@ref) `g`."""
set_g!(value::Line, val) = value.g = set_value(value, Val(:g), val, Val(:siemens))
"""Set [`Line`](@ref) `services`."""
set_services!(value::Line, val) = value.services = val
"""Set [`Line`](@ref) `ext`."""
set_ext!(value::Line, val) = value.ext = val
================================================
FILE: src/models/generated/LoadZone.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct LoadZone <: AggregationTopology
name::String
peak_active_power::Float64
peak_reactive_power::Float64
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A load zone for electricity price analysis.
The load zone can be specified when defining each [`ACBus`](@ref) or [`DCBus`](@ref) in the zone
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `peak_active_power::Float64`: Peak active power in the zone (MW)
- `peak_reactive_power::Float64`: Peak reactive power in the zone (MVAR)
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct LoadZone <: AggregationTopology
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Peak active power in the zone (MW)"
peak_active_power::Float64
"Peak reactive power in the zone (MVAR)"
peak_reactive_power::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function LoadZone(name, peak_active_power, peak_reactive_power, ext=Dict{String, Any}(), )
LoadZone(name, peak_active_power, peak_reactive_power, ext, InfrastructureSystemsInternal(), )
end
function LoadZone(; name, peak_active_power, peak_reactive_power, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
LoadZone(name, peak_active_power, peak_reactive_power, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function LoadZone(::Nothing)
LoadZone(;
name="init",
peak_active_power=0.0,
peak_reactive_power=0.0,
ext=Dict{String, Any}(),
)
end
"""Get [`LoadZone`](@ref) `name`."""
get_name(value::LoadZone) = value.name
"""Get [`LoadZone`](@ref) `peak_active_power`."""
get_peak_active_power(value::LoadZone) = get_value(value, Val(:peak_active_power), Val(:mva))
"""Get [`LoadZone`](@ref) `peak_reactive_power`."""
get_peak_reactive_power(value::LoadZone) = get_value(value, Val(:peak_reactive_power), Val(:mva))
"""Get [`LoadZone`](@ref) `ext`."""
get_ext(value::LoadZone) = value.ext
"""Get [`LoadZone`](@ref) `internal`."""
get_internal(value::LoadZone) = value.internal
"""Set [`LoadZone`](@ref) `peak_active_power`."""
set_peak_active_power!(value::LoadZone, val) = value.peak_active_power = set_value(value, Val(:peak_active_power), val, Val(:mva))
"""Set [`LoadZone`](@ref) `peak_reactive_power`."""
set_peak_reactive_power!(value::LoadZone, val) = value.peak_reactive_power = set_value(value, Val(:peak_reactive_power), val, Val(:mva))
"""Set [`LoadZone`](@ref) `ext`."""
set_ext!(value::LoadZone, val) = value.ext = val
================================================
FILE: src/models/generated/MagnitudeOutputCurrentLimiter.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct MagnitudeOutputCurrentLimiter <: OutputCurrentLimiter
I_max::Float64
ext::Dict{String, Any}
end
Parameters of Magnitude (Circular) Current Controller Limiter. Regulates only the magnitude of the inverter output current
# Arguments
- `I_max::Float64`: Maximum limit on current controller input current in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
"""
mutable struct MagnitudeOutputCurrentLimiter <: OutputCurrentLimiter
"Maximum limit on current controller input current in pu ([`DEVICE_BASE`](@ref per_unit))"
I_max::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
end
function MagnitudeOutputCurrentLimiter(; I_max, ext=Dict{String, Any}(), )
MagnitudeOutputCurrentLimiter(I_max, ext, )
end
# Constructor for demo purposes; non-functional.
function MagnitudeOutputCurrentLimiter(::Nothing)
MagnitudeOutputCurrentLimiter(;
I_max=0,
ext=Dict{String, Any}(),
)
end
"""Get [`MagnitudeOutputCurrentLimiter`](@ref) `I_max`."""
get_I_max(value::MagnitudeOutputCurrentLimiter) = value.I_max
"""Get [`MagnitudeOutputCurrentLimiter`](@ref) `ext`."""
get_ext(value::MagnitudeOutputCurrentLimiter) = value.ext
"""Set [`MagnitudeOutputCurrentLimiter`](@ref) `I_max`."""
set_I_max!(value::MagnitudeOutputCurrentLimiter, val) = value.I_max = val
"""Set [`MagnitudeOutputCurrentLimiter`](@ref) `ext`."""
set_ext!(value::MagnitudeOutputCurrentLimiter, val) = value.ext = val
================================================
FILE: src/models/generated/MarconatoMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct MarconatoMachine <: Machine
R::Float64
Xd::Float64
Xq::Float64
Xd_p::Float64
Xq_p::Float64
Xd_pp::Float64
Xq_pp::Float64
Td0_p::Float64
Tq0_p::Float64
Td0_pp::Float64
Tq0_pp::Float64
T_AA::Float64
ext::Dict{String, Any}
γd::Float64
γq::Float64
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 6-[states](@ref S) synchronous machine: Marconato model
# Arguments
- `R::Float64`: Resistance after EMF in machine per unit, validation range: `(0, nothing)`
- `Xd::Float64`: Reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq::Float64`: Reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_p::Float64`: Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_p::Float64`: Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_pp::Float64`: Sub-Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_pp::Float64`: Sub-Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Td0_p::Float64`: Time constant of transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_p::Float64`: Time constant of transient q-axis voltage, validation range: `(0, nothing)`
- `Td0_pp::Float64`: Time constant of sub-transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_pp::Float64`: Time constant of sub-transient q-axis voltage, validation range: `(0, nothing)`
- `T_AA::Float64`: Time constant of d-axis additional leakage, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `γd::Float64`: (**Do not modify.**) Internal equation
- `γq::Float64`: (**Do not modify.**) Internal equation
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
ψq: q-axis stator flux,
ψd: d-axis stator flux,
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage,
eq_pp: q-axis subtransient voltage,
ed_pp: d-axis subtransient voltage
- `n_states::Int`: (**Do not modify.**) MarconatoMachine has 6 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct MarconatoMachine <: Machine
"Resistance after EMF in machine per unit"
R::Float64
"Reactance after EMF in d-axis per unit"
Xd::Float64
"Reactance after EMF in q-axis per unit"
Xq::Float64
"Transient reactance after EMF in d-axis per unit"
Xd_p::Float64
"Transient reactance after EMF in q-axis per unit"
Xq_p::Float64
"Sub-Transient reactance after EMF in d-axis per unit"
Xd_pp::Float64
"Sub-Transient reactance after EMF in q-axis per unit"
Xq_pp::Float64
"Time constant of transient d-axis voltage"
Td0_p::Float64
"Time constant of transient q-axis voltage"
Tq0_p::Float64
"Time constant of sub-transient d-axis voltage"
Td0_pp::Float64
"Time constant of sub-transient q-axis voltage"
Tq0_pp::Float64
"Time constant of d-axis additional leakage"
T_AA::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) Internal equation"
γd::Float64
"(**Do not modify.**) Internal equation"
γq::Float64
"(**Do not modify.**) The [states](@ref S) are:
ψq: q-axis stator flux,
ψd: d-axis stator flux,
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage,
eq_pp: q-axis subtransient voltage,
ed_pp: d-axis subtransient voltage"
states::Vector{Symbol}
"(**Do not modify.**) MarconatoMachine has 6 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function MarconatoMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, T_AA, ext=Dict{String, Any}(), )
MarconatoMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, T_AA, ext, ((Td0_pp*Xd_pp)/(Td0_p*Xd_p) )*(Xd-Xd_p), ((Tq0_pp*Xq_pp)/(Tq0_p*Xq_p) )*(Xq-Xq_p), [:ψq, :ψd, :eq_p, :ed_p, :eq_pp, :ed_pp], 6, InfrastructureSystemsInternal(), )
end
function MarconatoMachine(; R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, T_AA, ext=Dict{String, Any}(), γd=((Td0_pp*Xd_pp)/(Td0_p*Xd_p) )*(Xd-Xd_p), γq=((Tq0_pp*Xq_pp)/(Tq0_p*Xq_p) )*(Xq-Xq_p), states=[:ψq, :ψd, :eq_p, :ed_p, :eq_pp, :ed_pp], n_states=6, internal=InfrastructureSystemsInternal(), )
MarconatoMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, T_AA, ext, γd, γq, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function MarconatoMachine(::Nothing)
MarconatoMachine(;
R=0,
Xd=0,
Xq=0,
Xd_p=0,
Xq_p=0,
Xd_pp=0,
Xq_pp=0,
Td0_p=0,
Tq0_p=0,
Td0_pp=0,
Tq0_pp=0,
T_AA=0,
ext=Dict{String, Any}(),
)
end
"""Get [`MarconatoMachine`](@ref) `R`."""
get_R(value::MarconatoMachine) = value.R
"""Get [`MarconatoMachine`](@ref) `Xd`."""
get_Xd(value::MarconatoMachine) = value.Xd
"""Get [`MarconatoMachine`](@ref) `Xq`."""
get_Xq(value::MarconatoMachine) = value.Xq
"""Get [`MarconatoMachine`](@ref) `Xd_p`."""
get_Xd_p(value::MarconatoMachine) = value.Xd_p
"""Get [`MarconatoMachine`](@ref) `Xq_p`."""
get_Xq_p(value::MarconatoMachine) = value.Xq_p
"""Get [`MarconatoMachine`](@ref) `Xd_pp`."""
get_Xd_pp(value::MarconatoMachine) = value.Xd_pp
"""Get [`MarconatoMachine`](@ref) `Xq_pp`."""
get_Xq_pp(value::MarconatoMachine) = value.Xq_pp
"""Get [`MarconatoMachine`](@ref) `Td0_p`."""
get_Td0_p(value::MarconatoMachine) = value.Td0_p
"""Get [`MarconatoMachine`](@ref) `Tq0_p`."""
get_Tq0_p(value::MarconatoMachine) = value.Tq0_p
"""Get [`MarconatoMachine`](@ref) `Td0_pp`."""
get_Td0_pp(value::MarconatoMachine) = value.Td0_pp
"""Get [`MarconatoMachine`](@ref) `Tq0_pp`."""
get_Tq0_pp(value::MarconatoMachine) = value.Tq0_pp
"""Get [`MarconatoMachine`](@ref) `T_AA`."""
get_T_AA(value::MarconatoMachine) = value.T_AA
"""Get [`MarconatoMachine`](@ref) `ext`."""
get_ext(value::MarconatoMachine) = value.ext
"""Get [`MarconatoMachine`](@ref) `γd`."""
get_γd(value::MarconatoMachine) = value.γd
"""Get [`MarconatoMachine`](@ref) `γq`."""
get_γq(value::MarconatoMachine) = value.γq
"""Get [`MarconatoMachine`](@ref) `states`."""
get_states(value::MarconatoMachine) = value.states
"""Get [`MarconatoMachine`](@ref) `n_states`."""
get_n_states(value::MarconatoMachine) = value.n_states
"""Get [`MarconatoMachine`](@ref) `internal`."""
get_internal(value::MarconatoMachine) = value.internal
"""Set [`MarconatoMachine`](@ref) `R`."""
set_R!(value::MarconatoMachine, val) = value.R = val
"""Set [`MarconatoMachine`](@ref) `Xd`."""
set_Xd!(value::MarconatoMachine, val) = value.Xd = val
"""Set [`MarconatoMachine`](@ref) `Xq`."""
set_Xq!(value::MarconatoMachine, val) = value.Xq = val
"""Set [`MarconatoMachine`](@ref) `Xd_p`."""
set_Xd_p!(value::MarconatoMachine, val) = value.Xd_p = val
"""Set [`MarconatoMachine`](@ref) `Xq_p`."""
set_Xq_p!(value::MarconatoMachine, val) = value.Xq_p = val
"""Set [`MarconatoMachine`](@ref) `Xd_pp`."""
set_Xd_pp!(value::MarconatoMachine, val) = value.Xd_pp = val
"""Set [`MarconatoMachine`](@ref) `Xq_pp`."""
set_Xq_pp!(value::MarconatoMachine, val) = value.Xq_pp = val
"""Set [`MarconatoMachine`](@ref) `Td0_p`."""
set_Td0_p!(value::MarconatoMachine, val) = value.Td0_p = val
"""Set [`MarconatoMachine`](@ref) `Tq0_p`."""
set_Tq0_p!(value::MarconatoMachine, val) = value.Tq0_p = val
"""Set [`MarconatoMachine`](@ref) `Td0_pp`."""
set_Td0_pp!(value::MarconatoMachine, val) = value.Td0_pp = val
"""Set [`MarconatoMachine`](@ref) `Tq0_pp`."""
set_Tq0_pp!(value::MarconatoMachine, val) = value.Tq0_pp = val
"""Set [`MarconatoMachine`](@ref) `T_AA`."""
set_T_AA!(value::MarconatoMachine, val) = value.T_AA = val
"""Set [`MarconatoMachine`](@ref) `ext`."""
set_ext!(value::MarconatoMachine, val) = value.ext = val
"""Set [`MarconatoMachine`](@ref) `γd`."""
set_γd!(value::MarconatoMachine, val) = value.γd = val
"""Set [`MarconatoMachine`](@ref) `γq`."""
set_γq!(value::MarconatoMachine, val) = value.γq = val
================================================
FILE: src/models/generated/MonitoredLine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct MonitoredLine <: ACTransmission
name::String
available::Bool
active_power_flow::Float64
reactive_power_flow::Float64
arc::Arc
r::Float64
x::Float64
b::FromTo
flow_limits::FromTo_ToFrom
rating::Float64
angle_limits::MinMax
rating_b::Union{Nothing, Float64}
rating_c::Union{Nothing, Float64}
g::FromTo
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
An AC transmission line with additional power flow constraints specified by the system operator, more restrictive than the line's thermal limits.
For example, monitored lines can be used to restrict line flow following a contingency elsewhere in the network. See the `flow_limits` parameter. If monitoring is not needed, see [`Line`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow::Float64`: Initial condition of active power flow on the line (MW)
- `reactive_power_flow::Float64`: Initial condition of reactive power flow on the line (MVAR)
- `arc::Arc`: An [`Arc`](@ref) defining this line `from` a bus `to` another bus
- `r::Float64`: Resistance in pu ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(0, 4)`
- `x::Float64`: Reactance in pu ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(0, 4)`
- `b::FromTo`: Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value, validation range: `(0, 2)`
- `flow_limits::FromTo_ToFrom`: Minimum and maximum permissable flow on the line (MVA), if different from the thermal rating defined in `rating`
- `rating::Float64`: Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to
- `angle_limits::MinMax`: Minimum and maximum angle limits (radians)
- `rating_b::Union{Nothing, Float64}`: (default: `nothing`) Second current rating; entered in MVA.
- `rating_c::Union{Nothing, Float64}`: (default: `nothing`) Third current rating; entered in MVA.
- `g::FromTo`: (default: `(from=0.0, to=0.0)`) Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value, validation range: `(0, 100)`
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct MonitoredLine <: ACTransmission
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial condition of active power flow on the line (MW)"
active_power_flow::Float64
"Initial condition of reactive power flow on the line (MVAR)"
reactive_power_flow::Float64
"An [`Arc`](@ref) defining this line `from` a bus `to` another bus"
arc::Arc
"Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))"
r::Float64
"Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))"
x::Float64
"Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value"
b::FromTo
"Minimum and maximum permissable flow on the line (MVA), if different from the thermal rating defined in `rating`"
flow_limits::FromTo_ToFrom
"Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to"
rating::Float64
"Minimum and maximum angle limits (radians)"
angle_limits::MinMax
"Second current rating; entered in MVA."
rating_b::Union{Nothing, Float64}
"Third current rating; entered in MVA."
rating_c::Union{Nothing, Float64}
"Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value"
g::FromTo
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function MonitoredLine(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, rating_b=nothing, rating_c=nothing, g=(from=0.0, to=0.0), services=Device[], ext=Dict{String, Any}(), )
MonitoredLine(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, rating_b, rating_c, g, services, ext, InfrastructureSystemsInternal(), )
end
function MonitoredLine(; name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, rating_b=nothing, rating_c=nothing, g=(from=0.0, to=0.0), services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
MonitoredLine(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, rating_b, rating_c, g, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function MonitoredLine(::Nothing)
MonitoredLine(;
name="init",
available=false,
active_power_flow=0.0,
reactive_power_flow=0.0,
arc=Arc(ACBus(nothing), ACBus(nothing)),
r=0.0,
x=0.0,
b=(from=0.0, to=0.0),
flow_limits=(from_to=0.0, to_from=0.0),
rating=0.0,
angle_limits=(min=-3.1416, max=3.1416),
rating_b=0.0,
rating_c=0.0,
g=(from=0.0, to=0.0),
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`MonitoredLine`](@ref) `name`."""
get_name(value::MonitoredLine) = value.name
"""Get [`MonitoredLine`](@ref) `available`."""
get_available(value::MonitoredLine) = value.available
"""Get [`MonitoredLine`](@ref) `active_power_flow`."""
get_active_power_flow(value::MonitoredLine) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`MonitoredLine`](@ref) `reactive_power_flow`."""
get_reactive_power_flow(value::MonitoredLine) = get_value(value, Val(:reactive_power_flow), Val(:mva))
"""Get [`MonitoredLine`](@ref) `arc`."""
get_arc(value::MonitoredLine) = value.arc
"""Get [`MonitoredLine`](@ref) `r`."""
get_r(value::MonitoredLine) = get_value(value, Val(:r), Val(:ohm))
"""Get [`MonitoredLine`](@ref) `x`."""
get_x(value::MonitoredLine) = get_value(value, Val(:x), Val(:ohm))
"""Get [`MonitoredLine`](@ref) `b`."""
get_b(value::MonitoredLine) = get_value(value, Val(:b), Val(:siemens))
"""Get [`MonitoredLine`](@ref) `flow_limits`."""
get_flow_limits(value::MonitoredLine) = get_value(value, Val(:flow_limits), Val(:mva))
"""Get [`MonitoredLine`](@ref) `rating`."""
get_rating(value::MonitoredLine) = get_value(value, Val(:rating), Val(:mva))
"""Get [`MonitoredLine`](@ref) `angle_limits`."""
get_angle_limits(value::MonitoredLine) = value.angle_limits
"""Get [`MonitoredLine`](@ref) `rating_b`."""
get_rating_b(value::MonitoredLine) = get_value(value, Val(:rating_b), Val(:mva))
"""Get [`MonitoredLine`](@ref) `rating_c`."""
get_rating_c(value::MonitoredLine) = get_value(value, Val(:rating_c), Val(:mva))
"""Get [`MonitoredLine`](@ref) `g`."""
get_g(value::MonitoredLine) = get_value(value, Val(:g), Val(:siemens))
"""Get [`MonitoredLine`](@ref) `services`."""
get_services(value::MonitoredLine) = value.services
"""Get [`MonitoredLine`](@ref) `ext`."""
get_ext(value::MonitoredLine) = value.ext
"""Get [`MonitoredLine`](@ref) `internal`."""
get_internal(value::MonitoredLine) = value.internal
"""Set [`MonitoredLine`](@ref) `available`."""
set_available!(value::MonitoredLine, val) = value.available = val
"""Set [`MonitoredLine`](@ref) `active_power_flow`."""
set_active_power_flow!(value::MonitoredLine, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`MonitoredLine`](@ref) `reactive_power_flow`."""
set_reactive_power_flow!(value::MonitoredLine, val) = value.reactive_power_flow = set_value(value, Val(:reactive_power_flow), val, Val(:mva))
"""Set [`MonitoredLine`](@ref) `arc`."""
set_arc!(value::MonitoredLine, val) = value.arc = val
"""Set [`MonitoredLine`](@ref) `r`."""
set_r!(value::MonitoredLine, val) = value.r = set_value(value, Val(:r), val, Val(:ohm))
"""Set [`MonitoredLine`](@ref) `x`."""
set_x!(value::MonitoredLine, val) = value.x = set_value(value, Val(:x), val, Val(:ohm))
"""Set [`MonitoredLine`](@ref) `b`."""
set_b!(value::MonitoredLine, val) = value.b = set_value(value, Val(:b), val, Val(:siemens))
"""Set [`MonitoredLine`](@ref) `flow_limits`."""
set_flow_limits!(value::MonitoredLine, val) = value.flow_limits = set_value(value, Val(:flow_limits), val, Val(:mva))
"""Set [`MonitoredLine`](@ref) `rating`."""
set_rating!(value::MonitoredLine, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`MonitoredLine`](@ref) `angle_limits`."""
set_angle_limits!(value::MonitoredLine, val) = value.angle_limits = val
"""Set [`MonitoredLine`](@ref) `rating_b`."""
set_rating_b!(value::MonitoredLine, val) = value.rating_b = set_value(value, Val(:rating_b), val, Val(:mva))
"""Set [`MonitoredLine`](@ref) `rating_c`."""
set_rating_c!(value::MonitoredLine, val) = value.rating_c = set_value(value, Val(:rating_c), val, Val(:mva))
"""Set [`MonitoredLine`](@ref) `g`."""
set_g!(value::MonitoredLine, val) = value.g = set_value(value, Val(:g), val, Val(:siemens))
"""Set [`MonitoredLine`](@ref) `services`."""
set_services!(value::MonitoredLine, val) = value.services = val
"""Set [`MonitoredLine`](@ref) `ext`."""
set_ext!(value::MonitoredLine, val) = value.ext = val
================================================
FILE: src/models/generated/MotorLoad.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct MotorLoad <: StaticLoad
name::String
available::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
base_power::Float64
rating::Float64
max_active_power::Float64
reactive_power_limits::Union{Nothing, MinMax}
motor_technology::MotorLoadTechnology
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A [static](@ref S) power load, most commonly used for operational models such as power flow and operational optimizations.
This load consumes a set amount of power (set by `active_power` for a power flow simulation or a `max_active_power` time series for an operational simulation). For loads that can be compensated for load interruptions through demand response programs, see [`InterruptiblePowerLoad`](@ref). For voltage-dependent loads used in [dynamics](@ref D) modeling, see [`StandardLoad`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `MotorLoad`) must have unique names, but components of different types (e.g., `MotorLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial steady-state active power demand (MW). A positive value indicates power consumption.
- `reactive_power::Float64`: Initial steady-state reactive power demand (MVAR). A positive value indicates reactive power consumption.
- `base_power::Float64`: Base power (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `rating::Float64`: Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power, validation range: `(0, nothing)`
- `max_active_power::Float64`: Maximum active power (MW) that this load can demand
- `reactive_power_limits::Union{Nothing, MinMax}`: (default: `nothing`) Minimum and maximum reactive power limits. Set to `Nothing` if not applicable
- `motor_technology::MotorLoadTechnology`: (default: `MotorLoadTechnology.UNDETERMINED`) AC Motor type. Options are listed [here](@ref motor_list)
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct MotorLoad <: StaticLoad
"Name of the component. Components of the same type (e.g., `MotorLoad`) must have unique names, but components of different types (e.g., `MotorLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial steady-state active power demand (MW). A positive value indicates power consumption."
active_power::Float64
"Initial steady-state reactive power demand (MVAR). A positive value indicates reactive power consumption."
reactive_power::Float64
"Base power (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power"
rating::Float64
"Maximum active power (MW) that this load can demand"
max_active_power::Float64
"Minimum and maximum reactive power limits. Set to `Nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
"AC Motor type. Options are listed [here](@ref motor_list)"
motor_technology::MotorLoadTechnology
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function MotorLoad(name, available, bus, active_power, reactive_power, base_power, rating, max_active_power, reactive_power_limits=nothing, motor_technology=MotorLoadTechnology.UNDETERMINED, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
MotorLoad(name, available, bus, active_power, reactive_power, base_power, rating, max_active_power, reactive_power_limits, motor_technology, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function MotorLoad(; name, available, bus, active_power, reactive_power, base_power, rating, max_active_power, reactive_power_limits=nothing, motor_technology=MotorLoadTechnology.UNDETERMINED, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
MotorLoad(name, available, bus, active_power, reactive_power, base_power, rating, max_active_power, reactive_power_limits, motor_technology, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function MotorLoad(::Nothing)
MotorLoad(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
base_power=100.0,
rating=0.0,
max_active_power=0.0,
reactive_power_limits=nothing,
motor_technology=MotorLoadTechnology.UNDETERMINED,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`MotorLoad`](@ref) `name`."""
get_name(value::MotorLoad) = value.name
"""Get [`MotorLoad`](@ref) `available`."""
get_available(value::MotorLoad) = value.available
"""Get [`MotorLoad`](@ref) `bus`."""
get_bus(value::MotorLoad) = value.bus
"""Get [`MotorLoad`](@ref) `active_power`."""
get_active_power(value::MotorLoad) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`MotorLoad`](@ref) `reactive_power`."""
get_reactive_power(value::MotorLoad) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`MotorLoad`](@ref) `base_power`."""
get_base_power(value::MotorLoad) = value.base_power
"""Get [`MotorLoad`](@ref) `rating`."""
get_rating(value::MotorLoad) = get_value(value, Val(:rating), Val(:mva))
"""Get [`MotorLoad`](@ref) `max_active_power`."""
get_max_active_power(value::MotorLoad) = get_value(value, Val(:max_active_power), Val(:mva))
"""Get [`MotorLoad`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::MotorLoad) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`MotorLoad`](@ref) `motor_technology`."""
get_motor_technology(value::MotorLoad) = value.motor_technology
"""Get [`MotorLoad`](@ref) `services`."""
get_services(value::MotorLoad) = value.services
"""Get [`MotorLoad`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::MotorLoad) = value.dynamic_injector
"""Get [`MotorLoad`](@ref) `ext`."""
get_ext(value::MotorLoad) = value.ext
"""Get [`MotorLoad`](@ref) `internal`."""
get_internal(value::MotorLoad) = value.internal
"""Set [`MotorLoad`](@ref) `available`."""
set_available!(value::MotorLoad, val) = value.available = val
"""Set [`MotorLoad`](@ref) `bus`."""
set_bus!(value::MotorLoad, val) = value.bus = val
"""Set [`MotorLoad`](@ref) `active_power`."""
set_active_power!(value::MotorLoad, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`MotorLoad`](@ref) `reactive_power`."""
set_reactive_power!(value::MotorLoad, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`MotorLoad`](@ref) `base_power`."""
set_base_power!(value::MotorLoad, val) = value.base_power = val
"""Set [`MotorLoad`](@ref) `rating`."""
set_rating!(value::MotorLoad, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`MotorLoad`](@ref) `max_active_power`."""
set_max_active_power!(value::MotorLoad, val) = value.max_active_power = set_value(value, Val(:max_active_power), val, Val(:mva))
"""Set [`MotorLoad`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::MotorLoad, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`MotorLoad`](@ref) `motor_technology`."""
set_motor_technology!(value::MotorLoad, val) = value.motor_technology = val
"""Set [`MotorLoad`](@ref) `services`."""
set_services!(value::MotorLoad, val) = value.services = val
"""Set [`MotorLoad`](@ref) `ext`."""
set_ext!(value::MotorLoad, val) = value.ext = val
================================================
FILE: src/models/generated/OneDOneQMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct OneDOneQMachine <: Machine
R::Float64
Xd::Float64
Xq::Float64
Xd_p::Float64
Xq_p::Float64
Td0_p::Float64
Tq0_p::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 4-[states](@ref S) synchronous machine: Simplified Marconato model
The derivative of stator fluxes (ψd and ψq) is neglected and ωψd = ψd and
ωψq = ψq is assumed (i.e. ω=1.0). This is standard when
transmission network dynamics is neglected
# Arguments
- `R::Float64`: Resistance after EMF in machine per unit, validation range: `(0, nothing)`
- `Xd::Float64`: Reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq::Float64`: Reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_p::Float64`: Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_p::Float64`: Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Td0_p::Float64`: Time constant of transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_p::Float64`: Time constant of transient q-axis voltage, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage
- `n_states::Int`: (**Do not modify.**) OneDOneQMachine has 2 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct OneDOneQMachine <: Machine
"Resistance after EMF in machine per unit"
R::Float64
"Reactance after EMF in d-axis per unit"
Xd::Float64
"Reactance after EMF in q-axis per unit"
Xq::Float64
"Transient reactance after EMF in d-axis per unit"
Xd_p::Float64
"Transient reactance after EMF in q-axis per unit"
Xq_p::Float64
"Time constant of transient d-axis voltage"
Td0_p::Float64
"Time constant of transient q-axis voltage"
Tq0_p::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage"
states::Vector{Symbol}
"(**Do not modify.**) OneDOneQMachine has 2 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function OneDOneQMachine(R, Xd, Xq, Xd_p, Xq_p, Td0_p, Tq0_p, ext=Dict{String, Any}(), )
OneDOneQMachine(R, Xd, Xq, Xd_p, Xq_p, Td0_p, Tq0_p, ext, [:eq_p, :ed_p], 2, InfrastructureSystemsInternal(), )
end
function OneDOneQMachine(; R, Xd, Xq, Xd_p, Xq_p, Td0_p, Tq0_p, ext=Dict{String, Any}(), states=[:eq_p, :ed_p], n_states=2, internal=InfrastructureSystemsInternal(), )
OneDOneQMachine(R, Xd, Xq, Xd_p, Xq_p, Td0_p, Tq0_p, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function OneDOneQMachine(::Nothing)
OneDOneQMachine(;
R=0,
Xd=0,
Xq=0,
Xd_p=0,
Xq_p=0,
Td0_p=0,
Tq0_p=0,
ext=Dict{String, Any}(),
)
end
"""Get [`OneDOneQMachine`](@ref) `R`."""
get_R(value::OneDOneQMachine) = value.R
"""Get [`OneDOneQMachine`](@ref) `Xd`."""
get_Xd(value::OneDOneQMachine) = value.Xd
"""Get [`OneDOneQMachine`](@ref) `Xq`."""
get_Xq(value::OneDOneQMachine) = value.Xq
"""Get [`OneDOneQMachine`](@ref) `Xd_p`."""
get_Xd_p(value::OneDOneQMachine) = value.Xd_p
"""Get [`OneDOneQMachine`](@ref) `Xq_p`."""
get_Xq_p(value::OneDOneQMachine) = value.Xq_p
"""Get [`OneDOneQMachine`](@ref) `Td0_p`."""
get_Td0_p(value::OneDOneQMachine) = value.Td0_p
"""Get [`OneDOneQMachine`](@ref) `Tq0_p`."""
get_Tq0_p(value::OneDOneQMachine) = value.Tq0_p
"""Get [`OneDOneQMachine`](@ref) `ext`."""
get_ext(value::OneDOneQMachine) = value.ext
"""Get [`OneDOneQMachine`](@ref) `states`."""
get_states(value::OneDOneQMachine) = value.states
"""Get [`OneDOneQMachine`](@ref) `n_states`."""
get_n_states(value::OneDOneQMachine) = value.n_states
"""Get [`OneDOneQMachine`](@ref) `internal`."""
get_internal(value::OneDOneQMachine) = value.internal
"""Set [`OneDOneQMachine`](@ref) `R`."""
set_R!(value::OneDOneQMachine, val) = value.R = val
"""Set [`OneDOneQMachine`](@ref) `Xd`."""
set_Xd!(value::OneDOneQMachine, val) = value.Xd = val
"""Set [`OneDOneQMachine`](@ref) `Xq`."""
set_Xq!(value::OneDOneQMachine, val) = value.Xq = val
"""Set [`OneDOneQMachine`](@ref) `Xd_p`."""
set_Xd_p!(value::OneDOneQMachine, val) = value.Xd_p = val
"""Set [`OneDOneQMachine`](@ref) `Xq_p`."""
set_Xq_p!(value::OneDOneQMachine, val) = value.Xq_p = val
"""Set [`OneDOneQMachine`](@ref) `Td0_p`."""
set_Td0_p!(value::OneDOneQMachine, val) = value.Td0_p = val
"""Set [`OneDOneQMachine`](@ref) `Tq0_p`."""
set_Tq0_p!(value::OneDOneQMachine, val) = value.Tq0_p = val
"""Set [`OneDOneQMachine`](@ref) `ext`."""
set_ext!(value::OneDOneQMachine, val) = value.ext = val
================================================
FILE: src/models/generated/PIDGOV.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PIDGOV <: TurbineGov
feedback_flag::Int
Rperm::Float64
T_reg::Float64
Kp::Float64
Ki::Float64
Kd::Float64
Ta::Float64
Tb::Float64
D_turb::Float64
gate_openings::Tuple{Float64, Float64, Float64}
power_gate_openings::Tuple{Float64, Float64, Float64}
G_lim::MinMax
A_tw::Float64
Tw::Float64
V_lim::MinMax
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Hydro Turbine-Governor with PID controller.
# Arguments
- `feedback_flag::Int`: Feedback signal for governor droop: 0 for electrical power, and 1 for gate position., validation range: `(0, 1)`
- `Rperm::Float64`: Speed permanent droop parameter, validation range: `(0, nothing)`
- `T_reg::Float64`: Speed detector time constant, validation range: `(0, nothing)`
- `Kp::Float64`: Governor proportional gain, validation range: `(0, nothing)`
- `Ki::Float64`: Governor integral gain, validation range: `(0, nothing)`
- `Kd::Float64`: Governor derivative gain, validation range: `(0, nothing)`
- `Ta::Float64`: Governor derivative time constant, validation range: `(0, nothing)`
- `Tb::Float64`: Gate-servo time constant, validation range: `(0, nothing)`
- `D_turb::Float64`: Turbine damping factor, validation range: `(0, nothing)`
- `gate_openings::Tuple{Float64, Float64, Float64}`: Gate-opening speed at different loads
- `power_gate_openings::Tuple{Float64, Float64, Float64}`: Power at gate_openings
- `G_lim::MinMax`: Minimum/Maximum Gate openings `(G_min, G_max)`.
- `A_tw::Float64`: Factor multiplying Tw, validation range: `(eps(), nothing)`
- `Tw::Float64`: Water inertia time constant, sec, validation range: `(eps(), nothing)`
- `V_lim::MinMax`: Gate opening velocity limits `(G_min, G_max)`.
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the PIDGOV model are:
x_g1: Filtered input measurement,
x_g2: PI block internal state,
x_g3: First regulator state,
x_g4: Derivative block internal state,
x_g5: Second regulator state,
x_g6: Gate position state,
x_g7: Water inertia state
- `n_states::Int`: (**Do not modify.**) PIDGOV has 7 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) PIDGOV has 7 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct PIDGOV <: TurbineGov
"Feedback signal for governor droop: 0 for electrical power, and 1 for gate position."
feedback_flag::Int
"Speed permanent droop parameter"
Rperm::Float64
"Speed detector time constant"
T_reg::Float64
"Governor proportional gain"
Kp::Float64
"Governor integral gain"
Ki::Float64
"Governor derivative gain"
Kd::Float64
"Governor derivative time constant"
Ta::Float64
"Gate-servo time constant"
Tb::Float64
"Turbine damping factor"
D_turb::Float64
"Gate-opening speed at different loads"
gate_openings::Tuple{Float64, Float64, Float64}
"Power at gate_openings"
power_gate_openings::Tuple{Float64, Float64, Float64}
"Minimum/Maximum Gate openings `(G_min, G_max)`."
G_lim::MinMax
"Factor multiplying Tw"
A_tw::Float64
"Water inertia time constant, sec"
Tw::Float64
"Gate opening velocity limits `(G_min, G_max)`."
V_lim::MinMax
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the PIDGOV model are:
x_g1: Filtered input measurement,
x_g2: PI block internal state,
x_g3: First regulator state,
x_g4: Derivative block internal state,
x_g5: Second regulator state,
x_g6: Gate position state,
x_g7: Water inertia state"
states::Vector{Symbol}
"(**Do not modify.**) PIDGOV has 7 states"
n_states::Int
"(**Do not modify.**) PIDGOV has 7 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function PIDGOV(feedback_flag, Rperm, T_reg, Kp, Ki, Kd, Ta, Tb, D_turb, gate_openings, power_gate_openings, G_lim, A_tw, Tw, V_lim, P_ref=1.0, ext=Dict{String, Any}(), )
PIDGOV(feedback_flag, Rperm, T_reg, Kp, Ki, Kd, Ta, Tb, D_turb, gate_openings, power_gate_openings, G_lim, A_tw, Tw, V_lim, P_ref, ext, [:x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6, :x_g7], 7, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], InfrastructureSystemsInternal(), )
end
function PIDGOV(; feedback_flag, Rperm, T_reg, Kp, Ki, Kd, Ta, Tb, D_turb, gate_openings, power_gate_openings, G_lim, A_tw, Tw, V_lim, P_ref=1.0, ext=Dict{String, Any}(), states=[:x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6, :x_g7], n_states=7, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], internal=InfrastructureSystemsInternal(), )
PIDGOV(feedback_flag, Rperm, T_reg, Kp, Ki, Kd, Ta, Tb, D_turb, gate_openings, power_gate_openings, G_lim, A_tw, Tw, V_lim, P_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function PIDGOV(::Nothing)
PIDGOV(;
feedback_flag=1,
Rperm=0,
T_reg=0,
Kp=0,
Ki=0,
Kd=0,
Ta=0,
Tb=0,
D_turb=0,
gate_openings=(0.0, 0.0, 0.0),
power_gate_openings=(0.0, 0.0, 0.0),
G_lim=(min=0.0, max=0.0),
A_tw=0,
Tw=0,
V_lim=(min=0.0, max=0.0),
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`PIDGOV`](@ref) `feedback_flag`."""
get_feedback_flag(value::PIDGOV) = value.feedback_flag
"""Get [`PIDGOV`](@ref) `Rperm`."""
get_Rperm(value::PIDGOV) = value.Rperm
"""Get [`PIDGOV`](@ref) `T_reg`."""
get_T_reg(value::PIDGOV) = value.T_reg
"""Get [`PIDGOV`](@ref) `Kp`."""
get_Kp(value::PIDGOV) = value.Kp
"""Get [`PIDGOV`](@ref) `Ki`."""
get_Ki(value::PIDGOV) = value.Ki
"""Get [`PIDGOV`](@ref) `Kd`."""
get_Kd(value::PIDGOV) = value.Kd
"""Get [`PIDGOV`](@ref) `Ta`."""
get_Ta(value::PIDGOV) = value.Ta
"""Get [`PIDGOV`](@ref) `Tb`."""
get_Tb(value::PIDGOV) = value.Tb
"""Get [`PIDGOV`](@ref) `D_turb`."""
get_D_turb(value::PIDGOV) = value.D_turb
"""Get [`PIDGOV`](@ref) `gate_openings`."""
get_gate_openings(value::PIDGOV) = value.gate_openings
"""Get [`PIDGOV`](@ref) `power_gate_openings`."""
get_power_gate_openings(value::PIDGOV) = value.power_gate_openings
"""Get [`PIDGOV`](@ref) `G_lim`."""
get_G_lim(value::PIDGOV) = value.G_lim
"""Get [`PIDGOV`](@ref) `A_tw`."""
get_A_tw(value::PIDGOV) = value.A_tw
"""Get [`PIDGOV`](@ref) `Tw`."""
get_Tw(value::PIDGOV) = value.Tw
"""Get [`PIDGOV`](@ref) `V_lim`."""
get_V_lim(value::PIDGOV) = value.V_lim
"""Get [`PIDGOV`](@ref) `P_ref`."""
get_P_ref(value::PIDGOV) = value.P_ref
"""Get [`PIDGOV`](@ref) `ext`."""
get_ext(value::PIDGOV) = value.ext
"""Get [`PIDGOV`](@ref) `states`."""
get_states(value::PIDGOV) = value.states
"""Get [`PIDGOV`](@ref) `n_states`."""
get_n_states(value::PIDGOV) = value.n_states
"""Get [`PIDGOV`](@ref) `states_types`."""
get_states_types(value::PIDGOV) = value.states_types
"""Get [`PIDGOV`](@ref) `internal`."""
get_internal(value::PIDGOV) = value.internal
"""Set [`PIDGOV`](@ref) `feedback_flag`."""
set_feedback_flag!(value::PIDGOV, val) = value.feedback_flag = val
"""Set [`PIDGOV`](@ref) `Rperm`."""
set_Rperm!(value::PIDGOV, val) = value.Rperm = val
"""Set [`PIDGOV`](@ref) `T_reg`."""
set_T_reg!(value::PIDGOV, val) = value.T_reg = val
"""Set [`PIDGOV`](@ref) `Kp`."""
set_Kp!(value::PIDGOV, val) = value.Kp = val
"""Set [`PIDGOV`](@ref) `Ki`."""
set_Ki!(value::PIDGOV, val) = value.Ki = val
"""Set [`PIDGOV`](@ref) `Kd`."""
set_Kd!(value::PIDGOV, val) = value.Kd = val
"""Set [`PIDGOV`](@ref) `Ta`."""
set_Ta!(value::PIDGOV, val) = value.Ta = val
"""Set [`PIDGOV`](@ref) `Tb`."""
set_Tb!(value::PIDGOV, val) = value.Tb = val
"""Set [`PIDGOV`](@ref) `D_turb`."""
set_D_turb!(value::PIDGOV, val) = value.D_turb = val
"""Set [`PIDGOV`](@ref) `gate_openings`."""
set_gate_openings!(value::PIDGOV, val) = value.gate_openings = val
"""Set [`PIDGOV`](@ref) `power_gate_openings`."""
set_power_gate_openings!(value::PIDGOV, val) = value.power_gate_openings = val
"""Set [`PIDGOV`](@ref) `G_lim`."""
set_G_lim!(value::PIDGOV, val) = value.G_lim = val
"""Set [`PIDGOV`](@ref) `A_tw`."""
set_A_tw!(value::PIDGOV, val) = value.A_tw = val
"""Set [`PIDGOV`](@ref) `Tw`."""
set_Tw!(value::PIDGOV, val) = value.Tw = val
"""Set [`PIDGOV`](@ref) `V_lim`."""
set_V_lim!(value::PIDGOV, val) = value.V_lim = val
"""Set [`PIDGOV`](@ref) `P_ref`."""
set_P_ref!(value::PIDGOV, val) = value.P_ref = val
"""Set [`PIDGOV`](@ref) `ext`."""
set_ext!(value::PIDGOV, val) = value.ext = val
"""Set [`PIDGOV`](@ref) `states_types`."""
set_states_types!(value::PIDGOV, val) = value.states_types = val
================================================
FILE: src/models/generated/PSS2A.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PSS2A <: PSS
input_code_1::Int
remote_bus_control_1::Int
input_code_2::Int
remote_bus_control_2::Int
M_rtf::Int
N_rtf::Int
Tw1::Float64
Tw2::Float64
T6::Float64
Tw3::Float64
Tw4::Float64
T7::Float64
Ks2::Float64
Ks3::Float64
T8::Float64
T9::Float64
Ks1::Float64
T1::Float64
T2::Float64
T3::Float64
T4::Float64
Vst_lim::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
IEEE Dual-Input Stabilizer Model
# Arguments
- `input_code_1::Int`: First Input Code for stabilizer, validation range: `(1, 6)`
- `remote_bus_control_1::Int`: First Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component
- `input_code_2::Int`: Second Input Code for stabilizer, validation range: `(1, 6)`
- `remote_bus_control_2::Int`: Second Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component
- `M_rtf::Int`: M parameter for ramp tracking filter, validation range: `(0, 8)`
- `N_rtf::Int`: N parameter for ramp tracking filter, validation range: `(0, 8)`
- `Tw1::Float64`: Time constant for first washout filter for first input, validation range: `(eps(), nothing)`
- `Tw2::Float64`: Time constant for second washout filter for first input, validation range: `(0, nothing)`
- `T6::Float64`: Time constant for low-pass filter for first input, validation range: `(0, nothing)`
- `Tw3::Float64`: Time constant for first washout filter for second input, validation range: `(eps(), nothing)`
- `Tw4::Float64`: Time constant for second washout filter for second input, validation range: `(0, nothing)`
- `T7::Float64`: Time constant for low-pass filter for second input, validation range: `(0, nothing)`
- `Ks2::Float64`: Gain for low-pass filter for second input, validation range: `(0, nothing)`
- `Ks3::Float64`: Gain for second input, validation range: `(0, nothing)`
- `T8::Float64`: Time constant for ramp tracking filter, validation range: `(0, nothing)`
- `T9::Float64`: Time constant for ramp tracking filter, validation range: `(eps(), nothing)`
- `Ks1::Float64`: Gain before lead-lag blocks, validation range: `(0, nothing)`
- `T1::Float64`: Time constant for first lead-lag block, validation range: `(0, nothing)`
- `T2::Float64`: Time constant for first lead-lag block, validation range: `(0, nothing)`
- `T3::Float64`: Time constant for second lead-lag block, validation range: `(0, nothing)`
- `T4::Float64`: Time constant for second lead-lag block, validation range: `(0, nothing)`
- `Vst_lim::Tuple{Float64, Float64}`: PSS output limits `(Vst_min, Vst_max)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
x_p1: 1st washout 1st input,
x_p2: 2nd washout 1st input,
x_p3: transducer 1st input,
x_p4: 1st washout 2nd input,
x_p5: 2nd washout 2nd input,
x_p6: transducer 2nd input,
x_p7: ramp tracking filter state 1,
x_p8: ramp tracking filter state 2,
x_p9: ramp tracking filter state 3,
x_p10: ramp tracking filter state 4,
x_p11: ramp tracking filter state 5,
x_p12: ramp tracking filter state 6,
x_p13: ramp tracking filter state 7,
x_p14: ramp tracking filter state 8,
x_p15: 1st lead-lag,
x_p16: 2nd lead-lag,
- `n_states::Int`: (**Do not modify.**) IEEEST has 16 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) IEEEST has 16 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct PSS2A <: PSS
"First Input Code for stabilizer"
input_code_1::Int
"First Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component"
remote_bus_control_1::Int
"Second Input Code for stabilizer"
input_code_2::Int
"Second Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component"
remote_bus_control_2::Int
"M parameter for ramp tracking filter"
M_rtf::Int
"N parameter for ramp tracking filter"
N_rtf::Int
"Time constant for first washout filter for first input"
Tw1::Float64
"Time constant for second washout filter for first input"
Tw2::Float64
"Time constant for low-pass filter for first input"
T6::Float64
"Time constant for first washout filter for second input"
Tw3::Float64
"Time constant for second washout filter for second input"
Tw4::Float64
"Time constant for low-pass filter for second input"
T7::Float64
"Gain for low-pass filter for second input"
Ks2::Float64
"Gain for second input"
Ks3::Float64
"Time constant for ramp tracking filter"
T8::Float64
"Time constant for ramp tracking filter"
T9::Float64
"Gain before lead-lag blocks"
Ks1::Float64
"Time constant for first lead-lag block"
T1::Float64
"Time constant for first lead-lag block"
T2::Float64
"Time constant for second lead-lag block"
T3::Float64
"Time constant for second lead-lag block"
T4::Float64
"PSS output limits `(Vst_min, Vst_max)`"
Vst_lim::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
x_p1: 1st washout 1st input,
x_p2: 2nd washout 1st input,
x_p3: transducer 1st input,
x_p4: 1st washout 2nd input,
x_p5: 2nd washout 2nd input,
x_p6: transducer 2nd input,
x_p7: ramp tracking filter state 1,
x_p8: ramp tracking filter state 2,
x_p9: ramp tracking filter state 3,
x_p10: ramp tracking filter state 4,
x_p11: ramp tracking filter state 5,
x_p12: ramp tracking filter state 6,
x_p13: ramp tracking filter state 7,
x_p14: ramp tracking filter state 8,
x_p15: 1st lead-lag,
x_p16: 2nd lead-lag,"
states::Vector{Symbol}
"(**Do not modify.**) IEEEST has 16 states"
n_states::Int
"(**Do not modify.**) IEEEST has 16 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function PSS2A(input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, Vst_lim, ext=Dict{String, Any}(), )
PSS2A(input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, Vst_lim, ext, [:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7, :x_p8, :x_p9, :x_p10, :x_p11, :x_p12, :x_p13, :x_p14, :x_p15, :x_p16], 16, [StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function PSS2A(; input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, Vst_lim, ext=Dict{String, Any}(), states=[:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7, :x_p8, :x_p9, :x_p10, :x_p11, :x_p12, :x_p13, :x_p14, :x_p15, :x_p16], n_states=16, states_types=[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
PSS2A(input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, Vst_lim, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function PSS2A(::Nothing)
PSS2A(;
input_code_1=1,
remote_bus_control_1=0,
input_code_2=1,
remote_bus_control_2=0,
M_rtf=0,
N_rtf=0,
Tw1=0,
Tw2=0,
T6=0,
Tw3=0,
Tw4=0,
T7=0,
Ks2=0,
Ks3=0,
T8=0,
T9=0,
Ks1=0,
T1=0,
T2=0,
T3=0,
T4=0,
Vst_lim=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`PSS2A`](@ref) `input_code_1`."""
get_input_code_1(value::PSS2A) = value.input_code_1
"""Get [`PSS2A`](@ref) `remote_bus_control_1`."""
get_remote_bus_control_1(value::PSS2A) = value.remote_bus_control_1
"""Get [`PSS2A`](@ref) `input_code_2`."""
get_input_code_2(value::PSS2A) = value.input_code_2
"""Get [`PSS2A`](@ref) `remote_bus_control_2`."""
get_remote_bus_control_2(value::PSS2A) = value.remote_bus_control_2
"""Get [`PSS2A`](@ref) `M_rtf`."""
get_M_rtf(value::PSS2A) = value.M_rtf
"""Get [`PSS2A`](@ref) `N_rtf`."""
get_N_rtf(value::PSS2A) = value.N_rtf
"""Get [`PSS2A`](@ref) `Tw1`."""
get_Tw1(value::PSS2A) = value.Tw1
"""Get [`PSS2A`](@ref) `Tw2`."""
get_Tw2(value::PSS2A) = value.Tw2
"""Get [`PSS2A`](@ref) `T6`."""
get_T6(value::PSS2A) = value.T6
"""Get [`PSS2A`](@ref) `Tw3`."""
get_Tw3(value::PSS2A) = value.Tw3
"""Get [`PSS2A`](@ref) `Tw4`."""
get_Tw4(value::PSS2A) = value.Tw4
"""Get [`PSS2A`](@ref) `T7`."""
get_T7(value::PSS2A) = value.T7
"""Get [`PSS2A`](@ref) `Ks2`."""
get_Ks2(value::PSS2A) = value.Ks2
"""Get [`PSS2A`](@ref) `Ks3`."""
get_Ks3(value::PSS2A) = value.Ks3
"""Get [`PSS2A`](@ref) `T8`."""
get_T8(value::PSS2A) = value.T8
"""Get [`PSS2A`](@ref) `T9`."""
get_T9(value::PSS2A) = value.T9
"""Get [`PSS2A`](@ref) `Ks1`."""
get_Ks1(value::PSS2A) = value.Ks1
"""Get [`PSS2A`](@ref) `T1`."""
get_T1(value::PSS2A) = value.T1
"""Get [`PSS2A`](@ref) `T2`."""
get_T2(value::PSS2A) = value.T2
"""Get [`PSS2A`](@ref) `T3`."""
get_T3(value::PSS2A) = value.T3
"""Get [`PSS2A`](@ref) `T4`."""
get_T4(value::PSS2A) = value.T4
"""Get [`PSS2A`](@ref) `Vst_lim`."""
get_Vst_lim(value::PSS2A) = value.Vst_lim
"""Get [`PSS2A`](@ref) `ext`."""
get_ext(value::PSS2A) = value.ext
"""Get [`PSS2A`](@ref) `states`."""
get_states(value::PSS2A) = value.states
"""Get [`PSS2A`](@ref) `n_states`."""
get_n_states(value::PSS2A) = value.n_states
"""Get [`PSS2A`](@ref) `states_types`."""
get_states_types(value::PSS2A) = value.states_types
"""Get [`PSS2A`](@ref) `internal`."""
get_internal(value::PSS2A) = value.internal
"""Set [`PSS2A`](@ref) `input_code_1`."""
set_input_code_1!(value::PSS2A, val) = value.input_code_1 = val
"""Set [`PSS2A`](@ref) `remote_bus_control_1`."""
set_remote_bus_control_1!(value::PSS2A, val) = value.remote_bus_control_1 = val
"""Set [`PSS2A`](@ref) `input_code_2`."""
set_input_code_2!(value::PSS2A, val) = value.input_code_2 = val
"""Set [`PSS2A`](@ref) `remote_bus_control_2`."""
set_remote_bus_control_2!(value::PSS2A, val) = value.remote_bus_control_2 = val
"""Set [`PSS2A`](@ref) `M_rtf`."""
set_M_rtf!(value::PSS2A, val) = value.M_rtf = val
"""Set [`PSS2A`](@ref) `N_rtf`."""
set_N_rtf!(value::PSS2A, val) = value.N_rtf = val
"""Set [`PSS2A`](@ref) `Tw1`."""
set_Tw1!(value::PSS2A, val) = value.Tw1 = val
"""Set [`PSS2A`](@ref) `Tw2`."""
set_Tw2!(value::PSS2A, val) = value.Tw2 = val
"""Set [`PSS2A`](@ref) `T6`."""
set_T6!(value::PSS2A, val) = value.T6 = val
"""Set [`PSS2A`](@ref) `Tw3`."""
set_Tw3!(value::PSS2A, val) = value.Tw3 = val
"""Set [`PSS2A`](@ref) `Tw4`."""
set_Tw4!(value::PSS2A, val) = value.Tw4 = val
"""Set [`PSS2A`](@ref) `T7`."""
set_T7!(value::PSS2A, val) = value.T7 = val
"""Set [`PSS2A`](@ref) `Ks2`."""
set_Ks2!(value::PSS2A, val) = value.Ks2 = val
"""Set [`PSS2A`](@ref) `Ks3`."""
set_Ks3!(value::PSS2A, val) = value.Ks3 = val
"""Set [`PSS2A`](@ref) `T8`."""
set_T8!(value::PSS2A, val) = value.T8 = val
"""Set [`PSS2A`](@ref) `T9`."""
set_T9!(value::PSS2A, val) = value.T9 = val
"""Set [`PSS2A`](@ref) `Ks1`."""
set_Ks1!(value::PSS2A, val) = value.Ks1 = val
"""Set [`PSS2A`](@ref) `T1`."""
set_T1!(value::PSS2A, val) = value.T1 = val
"""Set [`PSS2A`](@ref) `T2`."""
set_T2!(value::PSS2A, val) = value.T2 = val
"""Set [`PSS2A`](@ref) `T3`."""
set_T3!(value::PSS2A, val) = value.T3 = val
"""Set [`PSS2A`](@ref) `T4`."""
set_T4!(value::PSS2A, val) = value.T4 = val
"""Set [`PSS2A`](@ref) `Vst_lim`."""
set_Vst_lim!(value::PSS2A, val) = value.Vst_lim = val
"""Set [`PSS2A`](@ref) `ext`."""
set_ext!(value::PSS2A, val) = value.ext = val
"""Set [`PSS2A`](@ref) `states_types`."""
set_states_types!(value::PSS2A, val) = value.states_types = val
================================================
FILE: src/models/generated/PSS2B.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PSS2B <: PSS
input_code_1::Int
remote_bus_control_1::Int
input_code_2::Int
remote_bus_control_2::Int
M_rtf::Int
N_rtf::Int
Tw1::Float64
Tw2::Float64
T6::Float64
Tw3::Float64
Tw4::Float64
T7::Float64
Ks2::Float64
Ks3::Float64
T8::Float64
T9::Float64
Ks1::Float64
T1::Float64
T2::Float64
T3::Float64
T4::Float64
T10::Float64
T11::Float64
Vs1_lim::Tuple{Float64, Float64}
Vs2_lim::Tuple{Float64, Float64}
Vst_lim::Tuple{Float64, Float64}
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
IEEE 421.5 2005 PSS2B IEEE Dual-Input Stabilizer Model
# Arguments
- `input_code_1::Int`: First Input Code for stabilizer, validation range: `(1, 6)`
- `remote_bus_control_1::Int`: First Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component
- `input_code_2::Int`: Second Input Code for stabilizer, validation range: `(1, 6)`
- `remote_bus_control_2::Int`: Second Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component
- `M_rtf::Int`: M parameter for ramp tracking filter, validation range: `(0, 8)`
- `N_rtf::Int`: N parameter for ramp tracking filter, validation range: `(0, 8)`
- `Tw1::Float64`: Time constant for first washout filter for first input, validation range: `(eps(), nothing)`
- `Tw2::Float64`: Time constant for second washout filter for first input, validation range: `(0, nothing)`
- `T6::Float64`: Time constant for low-pass filter for first input, validation range: `(0, nothing)`
- `Tw3::Float64`: Time constant for first washout filter for second input, validation range: `(eps(), nothing)`
- `Tw4::Float64`: Time constant for second washout filter for second input, validation range: `(0, nothing)`
- `T7::Float64`: Time constant for low-pass filter for second input, validation range: `(0, nothing)`
- `Ks2::Float64`: Gain for low-pass filter for second input, validation range: `(0, nothing)`
- `Ks3::Float64`: Gain for second input, validation range: `(0, nothing)`
- `T8::Float64`: Time constant for ramp tracking filter, validation range: `(0, nothing)`
- `T9::Float64`: Time constant for ramp tracking filter, validation range: `(eps(), nothing)`
- `Ks1::Float64`: Gain before lead-lag blocks, validation range: `(0, nothing)`
- `T1::Float64`: Time constant for first lead-lag block, validation range: `(0, nothing)`
- `T2::Float64`: Time constant for first lead-lag block, validation range: `(0, nothing)`
- `T3::Float64`: Time constant for second lead-lag block, validation range: `(0, nothing)`
- `T4::Float64`: Time constant for second lead-lag block, validation range: `(0, nothing)`
- `T10::Float64`: Time constant for third lead-lag block, validation range: `(0, nothing)`
- `T11::Float64`: Time constant for third lead-lag block, validation range: `(0, nothing)`
- `Vs1_lim::Tuple{Float64, Float64}`: First input limits `(Vs1_min, Vs1_max)`
- `Vs2_lim::Tuple{Float64, Float64}`: Second input limits `(Vs2_min, Vs2_max)`
- `Vst_lim::Tuple{Float64, Float64}`: PSS output limits `(Vst_min, Vst_max)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
x_p1: 1st washout 1st input,
x_p2: 2nd washout 1st input,
x_p3: transducer 1st input,
x_p4: 1st washout 2nd input,
x_p5: 2nd washout 2nd input,
x_p6: transducer 2nd input,
x_p7: ramp tracking filter state 1,
x_p8: ramp tracking filter state 2,
x_p9: ramp tracking filter state 3,
x_p10: ramp tracking filter state 4,
x_p11: ramp tracking filter state 5,
x_p12: ramp tracking filter state 6,
x_p13: ramp tracking filter state 7,
x_p14: ramp tracking filter state 8,
x_p15: 1st lead-lag,
x_p16: 2nd lead-lag,
x_p17: 3rd lead-lag,
- `n_states::Int`: (**Do not modify.**) IEEEST has 17 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) IEEEST has 17 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct PSS2B <: PSS
"First Input Code for stabilizer"
input_code_1::Int
"First Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component"
remote_bus_control_1::Int
"Second Input Code for stabilizer"
input_code_2::Int
"Second Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component"
remote_bus_control_2::Int
"M parameter for ramp tracking filter"
M_rtf::Int
"N parameter for ramp tracking filter"
N_rtf::Int
"Time constant for first washout filter for first input"
Tw1::Float64
"Time constant for second washout filter for first input"
Tw2::Float64
"Time constant for low-pass filter for first input"
T6::Float64
"Time constant for first washout filter for second input"
Tw3::Float64
"Time constant for second washout filter for second input"
Tw4::Float64
"Time constant for low-pass filter for second input"
T7::Float64
"Gain for low-pass filter for second input"
Ks2::Float64
"Gain for second input"
Ks3::Float64
"Time constant for ramp tracking filter"
T8::Float64
"Time constant for ramp tracking filter"
T9::Float64
"Gain before lead-lag blocks"
Ks1::Float64
"Time constant for first lead-lag block"
T1::Float64
"Time constant for first lead-lag block"
T2::Float64
"Time constant for second lead-lag block"
T3::Float64
"Time constant for second lead-lag block"
T4::Float64
"Time constant for third lead-lag block"
T10::Float64
"Time constant for third lead-lag block"
T11::Float64
"First input limits `(Vs1_min, Vs1_max)`"
Vs1_lim::Tuple{Float64, Float64}
"Second input limits `(Vs2_min, Vs2_max)`"
Vs2_lim::Tuple{Float64, Float64}
"PSS output limits `(Vst_min, Vst_max)`"
Vst_lim::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
x_p1: 1st washout 1st input,
x_p2: 2nd washout 1st input,
x_p3: transducer 1st input,
x_p4: 1st washout 2nd input,
x_p5: 2nd washout 2nd input,
x_p6: transducer 2nd input,
x_p7: ramp tracking filter state 1,
x_p8: ramp tracking filter state 2,
x_p9: ramp tracking filter state 3,
x_p10: ramp tracking filter state 4,
x_p11: ramp tracking filter state 5,
x_p12: ramp tracking filter state 6,
x_p13: ramp tracking filter state 7,
x_p14: ramp tracking filter state 8,
x_p15: 1st lead-lag,
x_p16: 2nd lead-lag,
x_p17: 3rd lead-lag,"
states::Vector{Symbol}
"(**Do not modify.**) IEEEST has 17 states"
n_states::Int
"(**Do not modify.**) IEEEST has 17 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function PSS2B(input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, T10, T11, Vs1_lim, Vs2_lim, Vst_lim, ext=Dict{String, Any}(), )
PSS2B(input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, T10, T11, Vs1_lim, Vs2_lim, Vst_lim, ext, [:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7, :x_p8, :x_p9, :x_p10, :x_p11, :x_p12, :x_p13, :x_p14, :x_p15, :x_p16, :x_p17], 17, [StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function PSS2B(; input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, T10, T11, Vs1_lim, Vs2_lim, Vst_lim, ext=Dict{String, Any}(), states=[:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7, :x_p8, :x_p9, :x_p10, :x_p11, :x_p12, :x_p13, :x_p14, :x_p15, :x_p16, :x_p17], n_states=17, states_types=[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
PSS2B(input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, T10, T11, Vs1_lim, Vs2_lim, Vst_lim, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function PSS2B(::Nothing)
PSS2B(;
input_code_1=1,
remote_bus_control_1=0,
input_code_2=1,
remote_bus_control_2=0,
M_rtf=0,
N_rtf=0,
Tw1=0,
Tw2=0,
T6=0,
Tw3=0,
Tw4=0,
T7=0,
Ks2=0,
Ks3=0,
T8=0,
T9=0,
Ks1=0,
T1=0,
T2=0,
T3=0,
T4=0,
T10=0,
T11=0,
Vs1_lim=(0.0, 0.0),
Vs2_lim=(0.0, 0.0),
Vst_lim=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`PSS2B`](@ref) `input_code_1`."""
get_input_code_1(value::PSS2B) = value.input_code_1
"""Get [`PSS2B`](@ref) `remote_bus_control_1`."""
get_remote_bus_control_1(value::PSS2B) = value.remote_bus_control_1
"""Get [`PSS2B`](@ref) `input_code_2`."""
get_input_code_2(value::PSS2B) = value.input_code_2
"""Get [`PSS2B`](@ref) `remote_bus_control_2`."""
get_remote_bus_control_2(value::PSS2B) = value.remote_bus_control_2
"""Get [`PSS2B`](@ref) `M_rtf`."""
get_M_rtf(value::PSS2B) = value.M_rtf
"""Get [`PSS2B`](@ref) `N_rtf`."""
get_N_rtf(value::PSS2B) = value.N_rtf
"""Get [`PSS2B`](@ref) `Tw1`."""
get_Tw1(value::PSS2B) = value.Tw1
"""Get [`PSS2B`](@ref) `Tw2`."""
get_Tw2(value::PSS2B) = value.Tw2
"""Get [`PSS2B`](@ref) `T6`."""
get_T6(value::PSS2B) = value.T6
"""Get [`PSS2B`](@ref) `Tw3`."""
get_Tw3(value::PSS2B) = value.Tw3
"""Get [`PSS2B`](@ref) `Tw4`."""
get_Tw4(value::PSS2B) = value.Tw4
"""Get [`PSS2B`](@ref) `T7`."""
get_T7(value::PSS2B) = value.T7
"""Get [`PSS2B`](@ref) `Ks2`."""
get_Ks2(value::PSS2B) = value.Ks2
"""Get [`PSS2B`](@ref) `Ks3`."""
get_Ks3(value::PSS2B) = value.Ks3
"""Get [`PSS2B`](@ref) `T8`."""
get_T8(value::PSS2B) = value.T8
"""Get [`PSS2B`](@ref) `T9`."""
get_T9(value::PSS2B) = value.T9
"""Get [`PSS2B`](@ref) `Ks1`."""
get_Ks1(value::PSS2B) = value.Ks1
"""Get [`PSS2B`](@ref) `T1`."""
get_T1(value::PSS2B) = value.T1
"""Get [`PSS2B`](@ref) `T2`."""
get_T2(value::PSS2B) = value.T2
"""Get [`PSS2B`](@ref) `T3`."""
get_T3(value::PSS2B) = value.T3
"""Get [`PSS2B`](@ref) `T4`."""
get_T4(value::PSS2B) = value.T4
"""Get [`PSS2B`](@ref) `T10`."""
get_T10(value::PSS2B) = value.T10
"""Get [`PSS2B`](@ref) `T11`."""
get_T11(value::PSS2B) = value.T11
"""Get [`PSS2B`](@ref) `Vs1_lim`."""
get_Vs1_lim(value::PSS2B) = value.Vs1_lim
"""Get [`PSS2B`](@ref) `Vs2_lim`."""
get_Vs2_lim(value::PSS2B) = value.Vs2_lim
"""Get [`PSS2B`](@ref) `Vst_lim`."""
get_Vst_lim(value::PSS2B) = value.Vst_lim
"""Get [`PSS2B`](@ref) `ext`."""
get_ext(value::PSS2B) = value.ext
"""Get [`PSS2B`](@ref) `states`."""
get_states(value::PSS2B) = value.states
"""Get [`PSS2B`](@ref) `n_states`."""
get_n_states(value::PSS2B) = value.n_states
"""Get [`PSS2B`](@ref) `states_types`."""
get_states_types(value::PSS2B) = value.states_types
"""Get [`PSS2B`](@ref) `internal`."""
get_internal(value::PSS2B) = value.internal
"""Set [`PSS2B`](@ref) `input_code_1`."""
set_input_code_1!(value::PSS2B, val) = value.input_code_1 = val
"""Set [`PSS2B`](@ref) `remote_bus_control_1`."""
set_remote_bus_control_1!(value::PSS2B, val) = value.remote_bus_control_1 = val
"""Set [`PSS2B`](@ref) `input_code_2`."""
set_input_code_2!(value::PSS2B, val) = value.input_code_2 = val
"""Set [`PSS2B`](@ref) `remote_bus_control_2`."""
set_remote_bus_control_2!(value::PSS2B, val) = value.remote_bus_control_2 = val
"""Set [`PSS2B`](@ref) `M_rtf`."""
set_M_rtf!(value::PSS2B, val) = value.M_rtf = val
"""Set [`PSS2B`](@ref) `N_rtf`."""
set_N_rtf!(value::PSS2B, val) = value.N_rtf = val
"""Set [`PSS2B`](@ref) `Tw1`."""
set_Tw1!(value::PSS2B, val) = value.Tw1 = val
"""Set [`PSS2B`](@ref) `Tw2`."""
set_Tw2!(value::PSS2B, val) = value.Tw2 = val
"""Set [`PSS2B`](@ref) `T6`."""
set_T6!(value::PSS2B, val) = value.T6 = val
"""Set [`PSS2B`](@ref) `Tw3`."""
set_Tw3!(value::PSS2B, val) = value.Tw3 = val
"""Set [`PSS2B`](@ref) `Tw4`."""
set_Tw4!(value::PSS2B, val) = value.Tw4 = val
"""Set [`PSS2B`](@ref) `T7`."""
set_T7!(value::PSS2B, val) = value.T7 = val
"""Set [`PSS2B`](@ref) `Ks2`."""
set_Ks2!(value::PSS2B, val) = value.Ks2 = val
"""Set [`PSS2B`](@ref) `Ks3`."""
set_Ks3!(value::PSS2B, val) = value.Ks3 = val
"""Set [`PSS2B`](@ref) `T8`."""
set_T8!(value::PSS2B, val) = value.T8 = val
"""Set [`PSS2B`](@ref) `T9`."""
set_T9!(value::PSS2B, val) = value.T9 = val
"""Set [`PSS2B`](@ref) `Ks1`."""
set_Ks1!(value::PSS2B, val) = value.Ks1 = val
"""Set [`PSS2B`](@ref) `T1`."""
set_T1!(value::PSS2B, val) = value.T1 = val
"""Set [`PSS2B`](@ref) `T2`."""
set_T2!(value::PSS2B, val) = value.T2 = val
"""Set [`PSS2B`](@ref) `T3`."""
set_T3!(value::PSS2B, val) = value.T3 = val
"""Set [`PSS2B`](@ref) `T4`."""
set_T4!(value::PSS2B, val) = value.T4 = val
"""Set [`PSS2B`](@ref) `T10`."""
set_T10!(value::PSS2B, val) = value.T10 = val
"""Set [`PSS2B`](@ref) `T11`."""
set_T11!(value::PSS2B, val) = value.T11 = val
"""Set [`PSS2B`](@ref) `Vs1_lim`."""
set_Vs1_lim!(value::PSS2B, val) = value.Vs1_lim = val
"""Set [`PSS2B`](@ref) `Vs2_lim`."""
set_Vs2_lim!(value::PSS2B, val) = value.Vs2_lim = val
"""Set [`PSS2B`](@ref) `Vst_lim`."""
set_Vst_lim!(value::PSS2B, val) = value.Vst_lim = val
"""Set [`PSS2B`](@ref) `ext`."""
set_ext!(value::PSS2B, val) = value.ext = val
"""Set [`PSS2B`](@ref) `states_types`."""
set_states_types!(value::PSS2B, val) = value.states_types = val
================================================
FILE: src/models/generated/PSS2C.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PSS2C <: PSS
input_code_1::Int
remote_bus_control_1::Int
input_code_2::Int
remote_bus_control_2::Int
M_rtf::Int
N_rtf::Int
Tw1::Float64
Tw2::Float64
T6::Float64
Tw3::Float64
Tw4::Float64
T7::Float64
Ks2::Float64
Ks3::Float64
T8::Float64
T9::Float64
Ks1::Float64
T1::Float64
T2::Float64
T3::Float64
T4::Float64
T10::Float64
T11::Float64
Vs1_lim::Tuple{Float64, Float64}
Vs2_lim::Tuple{Float64, Float64}
Vst_lim::Tuple{Float64, Float64}
T12::Float64
T13::Float64
PSS_Hysteresis_param::Tuple{Float64, Float64}
Xcomp::Float64
Tcomp::Float64
hysteresis_binary_logic::Int
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
IEEE 421.5 2016 PSS2C IEEE Dual-Input Stabilizer Model
# Arguments
- `input_code_1::Int`: First Input Code for stabilizer, validation range: `(1, 7)`
- `remote_bus_control_1::Int`: First Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component
- `input_code_2::Int`: Second Input Code for stabilizer, validation range: `(1, 6)`
- `remote_bus_control_2::Int`: Second Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component
- `M_rtf::Int`: M parameter for ramp tracking filter, validation range: `(0, 8)`
- `N_rtf::Int`: N parameter for ramp tracking filter, validation range: `(0, 8)`
- `Tw1::Float64`: Time constant for first washout filter for first input, validation range: `(eps(), nothing)`
- `Tw2::Float64`: Time constant for second washout filter for first input, validation range: `(0, nothing)`
- `T6::Float64`: Time constant for low-pass filter for first input, validation range: `(0, nothing)`
- `Tw3::Float64`: Time constant for first washout filter for second input, validation range: `(eps(), nothing)`
- `Tw4::Float64`: Time constant for second washout filter for second input, validation range: `(0, nothing)`
- `T7::Float64`: Time constant for low-pass filter for second input, validation range: `(0, nothing)`
- `Ks2::Float64`: Gain for low-pass filter for second input, validation range: `(0, nothing)`
- `Ks3::Float64`: Gain for second input, validation range: `(0, nothing)`
- `T8::Float64`: Time constant for ramp tracking filter, validation range: `(0, nothing)`
- `T9::Float64`: Time constant for ramp tracking filter, validation range: `(eps(), nothing)`
- `Ks1::Float64`: Gain before lead-lag blocks, validation range: `(0, nothing)`
- `T1::Float64`: Time constant for first lead-lag block, validation range: `(0, nothing)`
- `T2::Float64`: Time constant for first lead-lag block, validation range: `(0, nothing)`
- `T3::Float64`: Time constant for second lead-lag block, validation range: `(0, nothing)`
- `T4::Float64`: Time constant for second lead-lag block, validation range: `(0, nothing)`
- `T10::Float64`: Time constant for third lead-lag block, validation range: `(0, nothing)`
- `T11::Float64`: Time constant for third lead-lag block, validation range: `(0, nothing)`
- `Vs1_lim::Tuple{Float64, Float64}`: First input limits `(Vs1_min, Vs1_max)`
- `Vs2_lim::Tuple{Float64, Float64}`: Second input limits `(Vs2_min, Vs2_max)`
- `Vst_lim::Tuple{Float64, Float64}`: PSS output limits `(Vst_min, Vst_max)`
- `T12::Float64`: Time constant for fourth lead-lag block, validation range: `(0, nothing)`
- `T13::Float64`: Time constant for fourth lead-lag block, validation range: `(0, nothing)`
- `PSS_Hysteresis_param::Tuple{Float64, Float64}`: PSS output hysteresis parameters `(PSSOFF, PSSON)`
- `Xcomp::Float64`: Stator Leakage Reactance, validation range: `(0, nothing)`
- `Tcomp::Float64`: Time measured with compensated frequency, validation range: `(eps(), nothing)`
- `hysteresis_binary_logic::Int`: (default: `1`) Hysteresis memory variable
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
x_p1: 1st washout 1st input,
x_p2: 2nd washout 1st input,
x_p3: transducer 1st input,
x_p4: 1st washout 2nd input,
x_p5: 2nd washout 2nd input,
x_p6: transducer 2nd input,
x_p7: ramp tracking filter state 1,
x_p8: ramp tracking filter state 2,
x_p9: ramp tracking filter state 3,
x_p10: ramp tracking filter state 4,
x_p11: ramp tracking filter state 5,
x_p12: ramp tracking filter state 6,
x_p13: ramp tracking filter state 7,
x_p14: ramp tracking filter state 8,
x_p15: 1st lead-lag,
x_p16: 2nd lead-lag,
x_p17: 3rd lead-lag,
x_p18: 4th lead-lag,
x_p19: washout block for compensated frequency,
- `n_states::Int`: (**Do not modify.**) IEEEST has 19 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) IEEEST has 19 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct PSS2C <: PSS
"First Input Code for stabilizer"
input_code_1::Int
"First Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component"
remote_bus_control_1::Int
"Second Input Code for stabilizer"
input_code_2::Int
"Second Input remote bus identification [`number`](@ref ACBus) for control. `0` identifies the local bus connected to this component"
remote_bus_control_2::Int
"M parameter for ramp tracking filter"
M_rtf::Int
"N parameter for ramp tracking filter"
N_rtf::Int
"Time constant for first washout filter for first input"
Tw1::Float64
"Time constant for second washout filter for first input"
Tw2::Float64
"Time constant for low-pass filter for first input"
T6::Float64
"Time constant for first washout filter for second input"
Tw3::Float64
"Time constant for second washout filter for second input"
Tw4::Float64
"Time constant for low-pass filter for second input"
T7::Float64
"Gain for low-pass filter for second input"
Ks2::Float64
"Gain for second input"
Ks3::Float64
"Time constant for ramp tracking filter"
T8::Float64
"Time constant for ramp tracking filter"
T9::Float64
"Gain before lead-lag blocks"
Ks1::Float64
"Time constant for first lead-lag block"
T1::Float64
"Time constant for first lead-lag block"
T2::Float64
"Time constant for second lead-lag block"
T3::Float64
"Time constant for second lead-lag block"
T4::Float64
"Time constant for third lead-lag block"
T10::Float64
"Time constant for third lead-lag block"
T11::Float64
"First input limits `(Vs1_min, Vs1_max)`"
Vs1_lim::Tuple{Float64, Float64}
"Second input limits `(Vs2_min, Vs2_max)`"
Vs2_lim::Tuple{Float64, Float64}
"PSS output limits `(Vst_min, Vst_max)`"
Vst_lim::Tuple{Float64, Float64}
"Time constant for fourth lead-lag block"
T12::Float64
"Time constant for fourth lead-lag block"
T13::Float64
"PSS output hysteresis parameters `(PSSOFF, PSSON)`"
PSS_Hysteresis_param::Tuple{Float64, Float64}
"Stator Leakage Reactance"
Xcomp::Float64
"Time measured with compensated frequency"
Tcomp::Float64
"Hysteresis memory variable"
hysteresis_binary_logic::Int
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
x_p1: 1st washout 1st input,
x_p2: 2nd washout 1st input,
x_p3: transducer 1st input,
x_p4: 1st washout 2nd input,
x_p5: 2nd washout 2nd input,
x_p6: transducer 2nd input,
x_p7: ramp tracking filter state 1,
x_p8: ramp tracking filter state 2,
x_p9: ramp tracking filter state 3,
x_p10: ramp tracking filter state 4,
x_p11: ramp tracking filter state 5,
x_p12: ramp tracking filter state 6,
x_p13: ramp tracking filter state 7,
x_p14: ramp tracking filter state 8,
x_p15: 1st lead-lag,
x_p16: 2nd lead-lag,
x_p17: 3rd lead-lag,
x_p18: 4th lead-lag,
x_p19: washout block for compensated frequency,"
states::Vector{Symbol}
"(**Do not modify.**) IEEEST has 19 states"
n_states::Int
"(**Do not modify.**) IEEEST has 19 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function PSS2C(input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, T10, T11, Vs1_lim, Vs2_lim, Vst_lim, T12, T13, PSS_Hysteresis_param, Xcomp, Tcomp, hysteresis_binary_logic=1, ext=Dict{String, Any}(), )
PSS2C(input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, T10, T11, Vs1_lim, Vs2_lim, Vst_lim, T12, T13, PSS_Hysteresis_param, Xcomp, Tcomp, hysteresis_binary_logic, ext, [:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7, :x_p8, :x_p9, :x_p10, :x_p11, :x_p12, :x_p13, :x_p14, :x_p15, :x_p16, :x_p17, :x_p18, :x_p19], 19, [StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function PSS2C(; input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, T10, T11, Vs1_lim, Vs2_lim, Vst_lim, T12, T13, PSS_Hysteresis_param, Xcomp, Tcomp, hysteresis_binary_logic=1, ext=Dict{String, Any}(), states=[:x_p1, :x_p2, :x_p3, :x_p4, :x_p5, :x_p6, :x_p7, :x_p8, :x_p9, :x_p10, :x_p11, :x_p12, :x_p13, :x_p14, :x_p15, :x_p16, :x_p17, :x_p18, :x_p19], n_states=19, states_types=[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
PSS2C(input_code_1, remote_bus_control_1, input_code_2, remote_bus_control_2, M_rtf, N_rtf, Tw1, Tw2, T6, Tw3, Tw4, T7, Ks2, Ks3, T8, T9, Ks1, T1, T2, T3, T4, T10, T11, Vs1_lim, Vs2_lim, Vst_lim, T12, T13, PSS_Hysteresis_param, Xcomp, Tcomp, hysteresis_binary_logic, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function PSS2C(::Nothing)
PSS2C(;
input_code_1=1,
remote_bus_control_1=0,
input_code_2=1,
remote_bus_control_2=0,
M_rtf=0,
N_rtf=0,
Tw1=0,
Tw2=0,
T6=0,
Tw3=0,
Tw4=0,
T7=0,
Ks2=0,
Ks3=0,
T8=0,
T9=0,
Ks1=0,
T1=0,
T2=0,
T3=0,
T4=0,
T10=0,
T11=0,
Vs1_lim=(0.0, 0.0),
Vs2_lim=(0.0, 0.0),
Vst_lim=(0.0, 0.0),
T12=0,
T13=0,
PSS_Hysteresis_param=(0.0, 0.0),
Xcomp=0,
Tcomp=0,
hysteresis_binary_logic=0,
ext=Dict{String, Any}(),
)
end
"""Get [`PSS2C`](@ref) `input_code_1`."""
get_input_code_1(value::PSS2C) = value.input_code_1
"""Get [`PSS2C`](@ref) `remote_bus_control_1`."""
get_remote_bus_control_1(value::PSS2C) = value.remote_bus_control_1
"""Get [`PSS2C`](@ref) `input_code_2`."""
get_input_code_2(value::PSS2C) = value.input_code_2
"""Get [`PSS2C`](@ref) `remote_bus_control_2`."""
get_remote_bus_control_2(value::PSS2C) = value.remote_bus_control_2
"""Get [`PSS2C`](@ref) `M_rtf`."""
get_M_rtf(value::PSS2C) = value.M_rtf
"""Get [`PSS2C`](@ref) `N_rtf`."""
get_N_rtf(value::PSS2C) = value.N_rtf
"""Get [`PSS2C`](@ref) `Tw1`."""
get_Tw1(value::PSS2C) = value.Tw1
"""Get [`PSS2C`](@ref) `Tw2`."""
get_Tw2(value::PSS2C) = value.Tw2
"""Get [`PSS2C`](@ref) `T6`."""
get_T6(value::PSS2C) = value.T6
"""Get [`PSS2C`](@ref) `Tw3`."""
get_Tw3(value::PSS2C) = value.Tw3
"""Get [`PSS2C`](@ref) `Tw4`."""
get_Tw4(value::PSS2C) = value.Tw4
"""Get [`PSS2C`](@ref) `T7`."""
get_T7(value::PSS2C) = value.T7
"""Get [`PSS2C`](@ref) `Ks2`."""
get_Ks2(value::PSS2C) = value.Ks2
"""Get [`PSS2C`](@ref) `Ks3`."""
get_Ks3(value::PSS2C) = value.Ks3
"""Get [`PSS2C`](@ref) `T8`."""
get_T8(value::PSS2C) = value.T8
"""Get [`PSS2C`](@ref) `T9`."""
get_T9(value::PSS2C) = value.T9
"""Get [`PSS2C`](@ref) `Ks1`."""
get_Ks1(value::PSS2C) = value.Ks1
"""Get [`PSS2C`](@ref) `T1`."""
get_T1(value::PSS2C) = value.T1
"""Get [`PSS2C`](@ref) `T2`."""
get_T2(value::PSS2C) = value.T2
"""Get [`PSS2C`](@ref) `T3`."""
get_T3(value::PSS2C) = value.T3
"""Get [`PSS2C`](@ref) `T4`."""
get_T4(value::PSS2C) = value.T4
"""Get [`PSS2C`](@ref) `T10`."""
get_T10(value::PSS2C) = value.T10
"""Get [`PSS2C`](@ref) `T11`."""
get_T11(value::PSS2C) = value.T11
"""Get [`PSS2C`](@ref) `Vs1_lim`."""
get_Vs1_lim(value::PSS2C) = value.Vs1_lim
"""Get [`PSS2C`](@ref) `Vs2_lim`."""
get_Vs2_lim(value::PSS2C) = value.Vs2_lim
"""Get [`PSS2C`](@ref) `Vst_lim`."""
get_Vst_lim(value::PSS2C) = value.Vst_lim
"""Get [`PSS2C`](@ref) `T12`."""
get_T12(value::PSS2C) = value.T12
"""Get [`PSS2C`](@ref) `T13`."""
get_T13(value::PSS2C) = value.T13
"""Get [`PSS2C`](@ref) `PSS_Hysteresis_param`."""
get_PSS_Hysteresis_param(value::PSS2C) = value.PSS_Hysteresis_param
"""Get [`PSS2C`](@ref) `Xcomp`."""
get_Xcomp(value::PSS2C) = value.Xcomp
"""Get [`PSS2C`](@ref) `Tcomp`."""
get_Tcomp(value::PSS2C) = value.Tcomp
"""Get [`PSS2C`](@ref) `hysteresis_binary_logic`."""
get_hysteresis_binary_logic(value::PSS2C) = value.hysteresis_binary_logic
"""Get [`PSS2C`](@ref) `ext`."""
get_ext(value::PSS2C) = value.ext
"""Get [`PSS2C`](@ref) `states`."""
get_states(value::PSS2C) = value.states
"""Get [`PSS2C`](@ref) `n_states`."""
get_n_states(value::PSS2C) = value.n_states
"""Get [`PSS2C`](@ref) `states_types`."""
get_states_types(value::PSS2C) = value.states_types
"""Get [`PSS2C`](@ref) `internal`."""
get_internal(value::PSS2C) = value.internal
"""Set [`PSS2C`](@ref) `input_code_1`."""
set_input_code_1!(value::PSS2C, val) = value.input_code_1 = val
"""Set [`PSS2C`](@ref) `remote_bus_control_1`."""
set_remote_bus_control_1!(value::PSS2C, val) = value.remote_bus_control_1 = val
"""Set [`PSS2C`](@ref) `input_code_2`."""
set_input_code_2!(value::PSS2C, val) = value.input_code_2 = val
"""Set [`PSS2C`](@ref) `remote_bus_control_2`."""
set_remote_bus_control_2!(value::PSS2C, val) = value.remote_bus_control_2 = val
"""Set [`PSS2C`](@ref) `M_rtf`."""
set_M_rtf!(value::PSS2C, val) = value.M_rtf = val
"""Set [`PSS2C`](@ref) `N_rtf`."""
set_N_rtf!(value::PSS2C, val) = value.N_rtf = val
"""Set [`PSS2C`](@ref) `Tw1`."""
set_Tw1!(value::PSS2C, val) = value.Tw1 = val
"""Set [`PSS2C`](@ref) `Tw2`."""
set_Tw2!(value::PSS2C, val) = value.Tw2 = val
"""Set [`PSS2C`](@ref) `T6`."""
set_T6!(value::PSS2C, val) = value.T6 = val
"""Set [`PSS2C`](@ref) `Tw3`."""
set_Tw3!(value::PSS2C, val) = value.Tw3 = val
"""Set [`PSS2C`](@ref) `Tw4`."""
set_Tw4!(value::PSS2C, val) = value.Tw4 = val
"""Set [`PSS2C`](@ref) `T7`."""
set_T7!(value::PSS2C, val) = value.T7 = val
"""Set [`PSS2C`](@ref) `Ks2`."""
set_Ks2!(value::PSS2C, val) = value.Ks2 = val
"""Set [`PSS2C`](@ref) `Ks3`."""
set_Ks3!(value::PSS2C, val) = value.Ks3 = val
"""Set [`PSS2C`](@ref) `T8`."""
set_T8!(value::PSS2C, val) = value.T8 = val
"""Set [`PSS2C`](@ref) `T9`."""
set_T9!(value::PSS2C, val) = value.T9 = val
"""Set [`PSS2C`](@ref) `Ks1`."""
set_Ks1!(value::PSS2C, val) = value.Ks1 = val
"""Set [`PSS2C`](@ref) `T1`."""
set_T1!(value::PSS2C, val) = value.T1 = val
"""Set [`PSS2C`](@ref) `T2`."""
set_T2!(value::PSS2C, val) = value.T2 = val
"""Set [`PSS2C`](@ref) `T3`."""
set_T3!(value::PSS2C, val) = value.T3 = val
"""Set [`PSS2C`](@ref) `T4`."""
set_T4!(value::PSS2C, val) = value.T4 = val
"""Set [`PSS2C`](@ref) `T10`."""
set_T10!(value::PSS2C, val) = value.T10 = val
"""Set [`PSS2C`](@ref) `T11`."""
set_T11!(value::PSS2C, val) = value.T11 = val
"""Set [`PSS2C`](@ref) `Vs1_lim`."""
set_Vs1_lim!(value::PSS2C, val) = value.Vs1_lim = val
"""Set [`PSS2C`](@ref) `Vs2_lim`."""
set_Vs2_lim!(value::PSS2C, val) = value.Vs2_lim = val
"""Set [`PSS2C`](@ref) `Vst_lim`."""
set_Vst_lim!(value::PSS2C, val) = value.Vst_lim = val
"""Set [`PSS2C`](@ref) `T12`."""
set_T12!(value::PSS2C, val) = value.T12 = val
"""Set [`PSS2C`](@ref) `T13`."""
set_T13!(value::PSS2C, val) = value.T13 = val
"""Set [`PSS2C`](@ref) `PSS_Hysteresis_param`."""
set_PSS_Hysteresis_param!(value::PSS2C, val) = value.PSS_Hysteresis_param = val
"""Set [`PSS2C`](@ref) `Xcomp`."""
set_Xcomp!(value::PSS2C, val) = value.Xcomp = val
"""Set [`PSS2C`](@ref) `Tcomp`."""
set_Tcomp!(value::PSS2C, val) = value.Tcomp = val
"""Set [`PSS2C`](@ref) `hysteresis_binary_logic`."""
set_hysteresis_binary_logic!(value::PSS2C, val) = value.hysteresis_binary_logic = val
"""Set [`PSS2C`](@ref) `ext`."""
set_ext!(value::PSS2C, val) = value.ext = val
"""Set [`PSS2C`](@ref) `states_types`."""
set_states_types!(value::PSS2C, val) = value.states_types = val
================================================
FILE: src/models/generated/PSSFixed.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PSSFixed <: PSS
V_pss::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of a PSS that returns a fixed voltage to add to the reference for the AVR
# Arguments
- `V_pss::Float64`: Fixed voltage stabilization signal in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) PSSFixed has no [states](@ref S)
- `n_states::Int`: (**Do not modify.**) PSSFixed has no states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct PSSFixed <: PSS
"Fixed voltage stabilization signal in pu ([`DEVICE_BASE`](@ref per_unit))"
V_pss::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PSSFixed has no [states](@ref S)"
states::Vector{Symbol}
"(**Do not modify.**) PSSFixed has no states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function PSSFixed(V_pss, ext=Dict{String, Any}(), )
PSSFixed(V_pss, ext, Vector{Symbol}(), 0, InfrastructureSystemsInternal(), )
end
function PSSFixed(; V_pss, ext=Dict{String, Any}(), states=Vector{Symbol}(), n_states=0, internal=InfrastructureSystemsInternal(), )
PSSFixed(V_pss, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function PSSFixed(::Nothing)
PSSFixed(;
V_pss=0,
ext=Dict{String, Any}(),
)
end
"""Get [`PSSFixed`](@ref) `V_pss`."""
get_V_pss(value::PSSFixed) = value.V_pss
"""Get [`PSSFixed`](@ref) `ext`."""
get_ext(value::PSSFixed) = value.ext
"""Get [`PSSFixed`](@ref) `states`."""
get_states(value::PSSFixed) = value.states
"""Get [`PSSFixed`](@ref) `n_states`."""
get_n_states(value::PSSFixed) = value.n_states
"""Get [`PSSFixed`](@ref) `internal`."""
get_internal(value::PSSFixed) = value.internal
"""Set [`PSSFixed`](@ref) `V_pss`."""
set_V_pss!(value::PSSFixed, val) = value.V_pss = val
"""Set [`PSSFixed`](@ref) `ext`."""
set_ext!(value::PSSFixed, val) = value.ext = val
================================================
FILE: src/models/generated/PSSSimple.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PSSSimple <: PSS
K_ω::Float64
K_p::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of a PSS that returns a proportional droop voltage to add to the reference for the AVR
# Arguments
- `K_ω::Float64`: Proportional gain for frequency, validation range: `(0, nothing)`
- `K_p::Float64`: Proportional gain for active power, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) PSSSimple has no [states](@ref S)
- `n_states::Int`: (**Do not modify.**) PSSSimple has no states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct PSSSimple <: PSS
"Proportional gain for frequency"
K_ω::Float64
"Proportional gain for active power"
K_p::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PSSSimple has no [states](@ref S)"
states::Vector{Symbol}
"(**Do not modify.**) PSSSimple has no states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function PSSSimple(K_ω, K_p, ext=Dict{String, Any}(), )
PSSSimple(K_ω, K_p, ext, Vector{Symbol}(), 0, InfrastructureSystemsInternal(), )
end
function PSSSimple(; K_ω, K_p, ext=Dict{String, Any}(), states=Vector{Symbol}(), n_states=0, internal=InfrastructureSystemsInternal(), )
PSSSimple(K_ω, K_p, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function PSSSimple(::Nothing)
PSSSimple(;
K_ω=0,
K_p=0,
ext=Dict{String, Any}(),
)
end
"""Get [`PSSSimple`](@ref) `K_ω`."""
get_K_ω(value::PSSSimple) = value.K_ω
"""Get [`PSSSimple`](@ref) `K_p`."""
get_K_p(value::PSSSimple) = value.K_p
"""Get [`PSSSimple`](@ref) `ext`."""
get_ext(value::PSSSimple) = value.ext
"""Get [`PSSSimple`](@ref) `states`."""
get_states(value::PSSSimple) = value.states
"""Get [`PSSSimple`](@ref) `n_states`."""
get_n_states(value::PSSSimple) = value.n_states
"""Get [`PSSSimple`](@ref) `internal`."""
get_internal(value::PSSSimple) = value.internal
"""Set [`PSSSimple`](@ref) `K_ω`."""
set_K_ω!(value::PSSSimple, val) = value.K_ω = val
"""Set [`PSSSimple`](@ref) `K_p`."""
set_K_p!(value::PSSSimple, val) = value.K_p = val
"""Set [`PSSSimple`](@ref) `ext`."""
set_ext!(value::PSSSimple, val) = value.ext = val
================================================
FILE: src/models/generated/PeriodicVariableSource.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PeriodicVariableSource <: DynamicInjection
name::String
R_th::Float64
X_th::Float64
internal_voltage_bias::Float64
internal_voltage_frequencies::Vector{Float64}
internal_voltage_coefficients::Vector{Tuple{Float64,Float64}}
internal_angle_bias::Float64
internal_angle_frequencies::Vector{Float64}
internal_angle_coefficients::Vector{Tuple{Float64,Float64}}
base_power::Float64
states::Vector{Symbol}
n_states::Int
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
This struct acts as an infinity bus with time varying phasor values magnitude and angle V(t) heta(t). Time varying functions are represented using fourier series
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `R_th::Float64`: Source Thevenin resistance, validation range: `(0, nothing)`
- `X_th::Float64`: Source Thevenin reactance, validation range: `(0, nothing)`
- `internal_voltage_bias::Float64`: (default: `0.0`) a0 term of the Fourier Series for the voltage
- `internal_voltage_frequencies::Vector{Float64}`: (default: `[0.0]`) Frequencies in radians/s
- `internal_voltage_coefficients::Vector{Tuple{Float64,Float64}}`: (default: `[(0.0, 0.0)]`) Coefficients for terms n > 1. First component corresponds to sin and second component to cos
- `internal_angle_bias::Float64`: (default: `0.0`) a0 term of the Fourier Series for the angle
- `internal_angle_frequencies::Vector{Float64}`: (default: `[0.0]`) Frequencies in radians/s
- `internal_angle_coefficients::Vector{Tuple{Float64,Float64}}`: (default: `[(0.0, 0.0)]`) Coefficients for terms n > 1. First component corresponds to sin and second component to cos
- `base_power::Float64`: (default: `100.0`) Base power of the source (MVA) for [per unitization](@ref per_unit)
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) for time, voltage and angle
- `n_states::Int`: (**Do not modify.**) PeriodicVariableSource has 2 states
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct PeriodicVariableSource <: DynamicInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Source Thevenin resistance"
R_th::Float64
"Source Thevenin reactance"
X_th::Float64
"a0 term of the Fourier Series for the voltage"
internal_voltage_bias::Float64
"Frequencies in radians/s"
internal_voltage_frequencies::Vector{Float64}
"Coefficients for terms n > 1. First component corresponds to sin and second component to cos"
internal_voltage_coefficients::Vector{Tuple{Float64,Float64}}
"a0 term of the Fourier Series for the angle"
internal_angle_bias::Float64
"Frequencies in radians/s"
internal_angle_frequencies::Vector{Float64}
"Coefficients for terms n > 1. First component corresponds to sin and second component to cos"
internal_angle_coefficients::Vector{Tuple{Float64,Float64}}
"Base power of the source (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"(**Do not modify.**) The [states](@ref S) for time, voltage and angle"
states::Vector{Symbol}
"(**Do not modify.**) PeriodicVariableSource has 2 states"
n_states::Int
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function PeriodicVariableSource(name, R_th, X_th, internal_voltage_bias=0.0, internal_voltage_frequencies=[0.0], internal_voltage_coefficients=[(0.0, 0.0)], internal_angle_bias=0.0, internal_angle_frequencies=[0.0], internal_angle_coefficients=[(0.0, 0.0)], base_power=100.0, ext=Dict{String, Any}(), )
PeriodicVariableSource(name, R_th, X_th, internal_voltage_bias, internal_voltage_frequencies, internal_voltage_coefficients, internal_angle_bias, internal_angle_frequencies, internal_angle_coefficients, base_power, ext, [:Vt, :θt], 2, InfrastructureSystemsInternal(), )
end
function PeriodicVariableSource(; name, R_th, X_th, internal_voltage_bias=0.0, internal_voltage_frequencies=[0.0], internal_voltage_coefficients=[(0.0, 0.0)], internal_angle_bias=0.0, internal_angle_frequencies=[0.0], internal_angle_coefficients=[(0.0, 0.0)], base_power=100.0, states=[:Vt, :θt], n_states=2, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
PeriodicVariableSource(name, R_th, X_th, internal_voltage_bias, internal_voltage_frequencies, internal_voltage_coefficients, internal_angle_bias, internal_angle_frequencies, internal_angle_coefficients, base_power, states, n_states, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function PeriodicVariableSource(::Nothing)
PeriodicVariableSource(;
name="init",
R_th=0,
X_th=0,
internal_voltage_bias=0,
internal_voltage_frequencies=Any[0],
internal_voltage_coefficients=[(0.0, 0.0)],
internal_angle_bias=0,
internal_angle_frequencies=Any[0],
internal_angle_coefficients=[(0.0, 0.0)],
base_power=0,
ext=Dict{String, Any}(),
)
end
"""Get [`PeriodicVariableSource`](@ref) `name`."""
get_name(value::PeriodicVariableSource) = value.name
"""Get [`PeriodicVariableSource`](@ref) `R_th`."""
get_R_th(value::PeriodicVariableSource) = value.R_th
"""Get [`PeriodicVariableSource`](@ref) `X_th`."""
get_X_th(value::PeriodicVariableSource) = value.X_th
"""Get [`PeriodicVariableSource`](@ref) `internal_voltage_bias`."""
get_internal_voltage_bias(value::PeriodicVariableSource) = value.internal_voltage_bias
"""Get [`PeriodicVariableSource`](@ref) `internal_voltage_frequencies`."""
get_internal_voltage_frequencies(value::PeriodicVariableSource) = value.internal_voltage_frequencies
"""Get [`PeriodicVariableSource`](@ref) `internal_voltage_coefficients`."""
get_internal_voltage_coefficients(value::PeriodicVariableSource) = value.internal_voltage_coefficients
"""Get [`PeriodicVariableSource`](@ref) `internal_angle_bias`."""
get_internal_angle_bias(value::PeriodicVariableSource) = value.internal_angle_bias
"""Get [`PeriodicVariableSource`](@ref) `internal_angle_frequencies`."""
get_internal_angle_frequencies(value::PeriodicVariableSource) = value.internal_angle_frequencies
"""Get [`PeriodicVariableSource`](@ref) `internal_angle_coefficients`."""
get_internal_angle_coefficients(value::PeriodicVariableSource) = value.internal_angle_coefficients
"""Get [`PeriodicVariableSource`](@ref) `base_power`."""
get_base_power(value::PeriodicVariableSource) = value.base_power
"""Get [`PeriodicVariableSource`](@ref) `states`."""
get_states(value::PeriodicVariableSource) = value.states
"""Get [`PeriodicVariableSource`](@ref) `n_states`."""
get_n_states(value::PeriodicVariableSource) = value.n_states
"""Get [`PeriodicVariableSource`](@ref) `ext`."""
get_ext(value::PeriodicVariableSource) = value.ext
"""Get [`PeriodicVariableSource`](@ref) `internal`."""
get_internal(value::PeriodicVariableSource) = value.internal
"""Set [`PeriodicVariableSource`](@ref) `R_th`."""
set_R_th!(value::PeriodicVariableSource, val) = value.R_th = val
"""Set [`PeriodicVariableSource`](@ref) `X_th`."""
set_X_th!(value::PeriodicVariableSource, val) = value.X_th = val
"""Set [`PeriodicVariableSource`](@ref) `internal_voltage_bias`."""
set_internal_voltage_bias!(value::PeriodicVariableSource, val) = value.internal_voltage_bias = val
"""Set [`PeriodicVariableSource`](@ref) `internal_voltage_frequencies`."""
set_internal_voltage_frequencies!(value::PeriodicVariableSource, val) = value.internal_voltage_frequencies = val
"""Set [`PeriodicVariableSource`](@ref) `internal_voltage_coefficients`."""
set_internal_voltage_coefficients!(value::PeriodicVariableSource, val) = value.internal_voltage_coefficients = val
"""Set [`PeriodicVariableSource`](@ref) `internal_angle_bias`."""
set_internal_angle_bias!(value::PeriodicVariableSource, val) = value.internal_angle_bias = val
"""Set [`PeriodicVariableSource`](@ref) `internal_angle_frequencies`."""
set_internal_angle_frequencies!(value::PeriodicVariableSource, val) = value.internal_angle_frequencies = val
"""Set [`PeriodicVariableSource`](@ref) `internal_angle_coefficients`."""
set_internal_angle_coefficients!(value::PeriodicVariableSource, val) = value.internal_angle_coefficients = val
"""Set [`PeriodicVariableSource`](@ref) `base_power`."""
set_base_power!(value::PeriodicVariableSource, val) = value.base_power = val
"""Set [`PeriodicVariableSource`](@ref) `ext`."""
set_ext!(value::PeriodicVariableSource, val) = value.ext = val
================================================
FILE: src/models/generated/PhaseShiftingTransformer.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PhaseShiftingTransformer <: TwoWindingTransformer
name::String
available::Bool
active_power_flow::Float64
reactive_power_flow::Float64
arc::Arc
r::Float64
x::Float64
primary_shunt::Complex{Float64}
tap::Float64
α::Float64
rating::Union{Nothing, Float64}
base_power::Float64
base_voltage_primary::Union{Nothing, Float64}
base_voltage_secondary::Union{Nothing, Float64}
rating_b::Union{Nothing, Float64}
rating_c::Union{Nothing, Float64}
phase_angle_limits::MinMax
control_objective::TransformerControlObjective
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A phase-shifting transformer regulating the phase angle between two buses to control active power flow in the system.
The model uses an equivalent circuit assuming the impedance is on the High Voltage Side of the transformer. The model allocates the iron losses and magnetizing susceptance to the primary side
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow::Float64`: Initial condition of active power flow through the transformer (MW)
- `reactive_power_flow::Float64`: Initial condition of reactive power flow through the transformer (MVAR)
- `arc::Arc`: An [`Arc`](@ref) defining this transformer `from` a bus `to` another bus
- `r::Float64`: Resistance in pu ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(0, 4)`
- `x::Float64`: Reactance in pu ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(-2, 4)`
- `primary_shunt::Complex{Float64}`: Primary shunt admittance in pu ([`SYSTEM_BASE`](@ref per_unit))
- `tap::Float64`: Normalized tap changer position for voltage control, varying between 0 and 2, with 1 centered at the nominal voltage, validation range: `(0, 2)`
- `α::Float64`: Initial condition of phase shift (radians) between the `from` and `to` buses , validation range: `(-1.571, 1.571)`
- `rating::Union{Nothing, Float64}`: Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to, validation range: `(0, nothing)`
- `base_power::Float64`: Base power (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `base_voltage_primary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_from(arc))`) Primary base voltage in kV, validation range: `(0, nothing)`
- `base_voltage_secondary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_to(arc))`) Secondary base voltage in kV, validation range: `(0, nothing)`
- `rating_b::Union{Nothing, Float64}`: (default: `nothing`) Second current rating; entered in MVA.
- `rating_c::Union{Nothing, Float64}`: (default: `nothing`) Third current rating; entered in MVA.
- `phase_angle_limits::MinMax`: (default: `(min=-3.1416, max=3.1416)`) Minimum and maximum phase angle limits (radians)
- `control_objective::TransformerControlObjective`: (default: `TransformerControlObjective.UNDEFINED`) Control objective for the tap changer for power flow calculations. See [`TransformerControlObjective`](@ref xtf_crtl)
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct PhaseShiftingTransformer <: TwoWindingTransformer
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial condition of active power flow through the transformer (MW)"
active_power_flow::Float64
"Initial condition of reactive power flow through the transformer (MVAR)"
reactive_power_flow::Float64
"An [`Arc`](@ref) defining this transformer `from` a bus `to` another bus"
arc::Arc
"Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))"
r::Float64
"Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))"
x::Float64
"Primary shunt admittance in pu ([`SYSTEM_BASE`](@ref per_unit))"
primary_shunt::Complex{Float64}
"Normalized tap changer position for voltage control, varying between 0 and 2, with 1 centered at the nominal voltage"
tap::Float64
"Initial condition of phase shift (radians) between the `from` and `to` buses "
α::Float64
"Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to"
rating::Union{Nothing, Float64}
"Base power (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Primary base voltage in kV"
base_voltage_primary::Union{Nothing, Float64}
"Secondary base voltage in kV"
base_voltage_secondary::Union{Nothing, Float64}
"Second current rating; entered in MVA."
rating_b::Union{Nothing, Float64}
"Third current rating; entered in MVA."
rating_c::Union{Nothing, Float64}
"Minimum and maximum phase angle limits (radians)"
phase_angle_limits::MinMax
"Control objective for the tap changer for power flow calculations. See [`TransformerControlObjective`](@ref xtf_crtl)"
control_objective::TransformerControlObjective
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function PhaseShiftingTransformer(name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, tap, α, rating, base_power, base_voltage_primary=get_base_voltage(get_from(arc)), base_voltage_secondary=get_base_voltage(get_to(arc)), rating_b=nothing, rating_c=nothing, phase_angle_limits=(min=-3.1416, max=3.1416), control_objective=TransformerControlObjective.UNDEFINED, services=Device[], ext=Dict{String, Any}(), )
PhaseShiftingTransformer(name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, tap, α, rating, base_power, base_voltage_primary, base_voltage_secondary, rating_b, rating_c, phase_angle_limits, control_objective, services, ext, InfrastructureSystemsInternal(), )
end
function PhaseShiftingTransformer(; name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, tap, α, rating, base_power, base_voltage_primary=get_base_voltage(get_from(arc)), base_voltage_secondary=get_base_voltage(get_to(arc)), rating_b=nothing, rating_c=nothing, phase_angle_limits=(min=-3.1416, max=3.1416), control_objective=TransformerControlObjective.UNDEFINED, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
PhaseShiftingTransformer(name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, tap, α, rating, base_power, base_voltage_primary, base_voltage_secondary, rating_b, rating_c, phase_angle_limits, control_objective, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function PhaseShiftingTransformer(::Nothing)
PhaseShiftingTransformer(;
name="init",
available=false,
active_power_flow=0.0,
reactive_power_flow=0.0,
arc=Arc(ACBus(nothing), ACBus(nothing)),
r=0.0,
x=0.0,
primary_shunt=0.0,
tap=1.0,
α=0.0,
rating=0.0,
base_power=100.0,
base_voltage_primary=nothing,
base_voltage_secondary=nothing,
rating_b=0.0,
rating_c=0.0,
phase_angle_limits=(min=-3.1416, max=3.1416),
control_objective=TransformerControlObjective.UNDEFINED,
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`PhaseShiftingTransformer`](@ref) `name`."""
get_name(value::PhaseShiftingTransformer) = value.name
"""Get [`PhaseShiftingTransformer`](@ref) `available`."""
get_available(value::PhaseShiftingTransformer) = value.available
"""Get [`PhaseShiftingTransformer`](@ref) `active_power_flow`."""
get_active_power_flow(value::PhaseShiftingTransformer) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`PhaseShiftingTransformer`](@ref) `reactive_power_flow`."""
get_reactive_power_flow(value::PhaseShiftingTransformer) = get_value(value, Val(:reactive_power_flow), Val(:mva))
"""Get [`PhaseShiftingTransformer`](@ref) `arc`."""
get_arc(value::PhaseShiftingTransformer) = value.arc
"""Get [`PhaseShiftingTransformer`](@ref) `r`."""
get_r(value::PhaseShiftingTransformer) = get_value(value, Val(:r), Val(:ohm))
"""Get [`PhaseShiftingTransformer`](@ref) `x`."""
get_x(value::PhaseShiftingTransformer) = get_value(value, Val(:x), Val(:ohm))
"""Get [`PhaseShiftingTransformer`](@ref) `primary_shunt`."""
get_primary_shunt(value::PhaseShiftingTransformer) = get_value(value, Val(:primary_shunt), Val(:siemens))
"""Get [`PhaseShiftingTransformer`](@ref) `tap`."""
get_tap(value::PhaseShiftingTransformer) = value.tap
"""Get [`PhaseShiftingTransformer`](@ref) `α`."""
get_α(value::PhaseShiftingTransformer) = value.α
"""Get [`PhaseShiftingTransformer`](@ref) `rating`."""
get_rating(value::PhaseShiftingTransformer) = get_value(value, Val(:rating), Val(:mva))
"""Get [`PhaseShiftingTransformer`](@ref) `base_power`."""
get_base_power(value::PhaseShiftingTransformer) = value.base_power
"""Get [`PhaseShiftingTransformer`](@ref) `base_voltage_primary`."""
get_base_voltage_primary(value::PhaseShiftingTransformer) = value.base_voltage_primary
"""Get [`PhaseShiftingTransformer`](@ref) `base_voltage_secondary`."""
get_base_voltage_secondary(value::PhaseShiftingTransformer) = value.base_voltage_secondary
"""Get [`PhaseShiftingTransformer`](@ref) `rating_b`."""
get_rating_b(value::PhaseShiftingTransformer) = get_value(value, Val(:rating_b), Val(:mva))
"""Get [`PhaseShiftingTransformer`](@ref) `rating_c`."""
get_rating_c(value::PhaseShiftingTransformer) = get_value(value, Val(:rating_c), Val(:mva))
"""Get [`PhaseShiftingTransformer`](@ref) `phase_angle_limits`."""
get_phase_angle_limits(value::PhaseShiftingTransformer) = value.phase_angle_limits
"""Get [`PhaseShiftingTransformer`](@ref) `control_objective`."""
get_control_objective(value::PhaseShiftingTransformer) = value.control_objective
"""Get [`PhaseShiftingTransformer`](@ref) `services`."""
get_services(value::PhaseShiftingTransformer) = value.services
"""Get [`PhaseShiftingTransformer`](@ref) `ext`."""
get_ext(value::PhaseShiftingTransformer) = value.ext
"""Get [`PhaseShiftingTransformer`](@ref) `internal`."""
get_internal(value::PhaseShiftingTransformer) = value.internal
"""Set [`PhaseShiftingTransformer`](@ref) `available`."""
set_available!(value::PhaseShiftingTransformer, val) = value.available = val
"""Set [`PhaseShiftingTransformer`](@ref) `active_power_flow`."""
set_active_power_flow!(value::PhaseShiftingTransformer, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`PhaseShiftingTransformer`](@ref) `reactive_power_flow`."""
set_reactive_power_flow!(value::PhaseShiftingTransformer, val) = value.reactive_power_flow = set_value(value, Val(:reactive_power_flow), val, Val(:mva))
"""Set [`PhaseShiftingTransformer`](@ref) `arc`."""
set_arc!(value::PhaseShiftingTransformer, val) = value.arc = val
"""Set [`PhaseShiftingTransformer`](@ref) `r`."""
set_r!(value::PhaseShiftingTransformer, val) = value.r = set_value(value, Val(:r), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer`](@ref) `x`."""
set_x!(value::PhaseShiftingTransformer, val) = value.x = set_value(value, Val(:x), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer`](@ref) `primary_shunt`."""
set_primary_shunt!(value::PhaseShiftingTransformer, val) = value.primary_shunt = set_value(value, Val(:primary_shunt), val, Val(:siemens))
"""Set [`PhaseShiftingTransformer`](@ref) `tap`."""
set_tap!(value::PhaseShiftingTransformer, val) = value.tap = val
"""Set [`PhaseShiftingTransformer`](@ref) `α`."""
set_α!(value::PhaseShiftingTransformer, val) = value.α = val
"""Set [`PhaseShiftingTransformer`](@ref) `rating`."""
set_rating!(value::PhaseShiftingTransformer, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`PhaseShiftingTransformer`](@ref) `base_power`."""
set_base_power!(value::PhaseShiftingTransformer, val) = value.base_power = val
"""Set [`PhaseShiftingTransformer`](@ref) `base_voltage_primary`."""
set_base_voltage_primary!(value::PhaseShiftingTransformer, val) = value.base_voltage_primary = val
"""Set [`PhaseShiftingTransformer`](@ref) `base_voltage_secondary`."""
set_base_voltage_secondary!(value::PhaseShiftingTransformer, val) = value.base_voltage_secondary = val
"""Set [`PhaseShiftingTransformer`](@ref) `rating_b`."""
set_rating_b!(value::PhaseShiftingTransformer, val) = value.rating_b = set_value(value, Val(:rating_b), val, Val(:mva))
"""Set [`PhaseShiftingTransformer`](@ref) `rating_c`."""
set_rating_c!(value::PhaseShiftingTransformer, val) = value.rating_c = set_value(value, Val(:rating_c), val, Val(:mva))
"""Set [`PhaseShiftingTransformer`](@ref) `phase_angle_limits`."""
set_phase_angle_limits!(value::PhaseShiftingTransformer, val) = value.phase_angle_limits = val
"""Set [`PhaseShiftingTransformer`](@ref) `control_objective`."""
set_control_objective!(value::PhaseShiftingTransformer, val) = value.control_objective = val
"""Set [`PhaseShiftingTransformer`](@ref) `services`."""
set_services!(value::PhaseShiftingTransformer, val) = value.services = val
"""Set [`PhaseShiftingTransformer`](@ref) `ext`."""
set_ext!(value::PhaseShiftingTransformer, val) = value.ext = val
================================================
FILE: src/models/generated/PhaseShiftingTransformer3W.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PhaseShiftingTransformer3W <: ThreeWindingTransformer
name::String
available::Bool
primary_star_arc::Arc
secondary_star_arc::Arc
tertiary_star_arc::Arc
star_bus::ACBus
active_power_flow_primary::Float64
reactive_power_flow_primary::Float64
active_power_flow_secondary::Float64
reactive_power_flow_secondary::Float64
active_power_flow_tertiary::Float64
reactive_power_flow_tertiary::Float64
r_primary::Float64
x_primary::Float64
r_secondary::Float64
x_secondary::Float64
r_tertiary::Float64
x_tertiary::Float64
rating::Union{Nothing, Float64}
r_12::Float64
x_12::Float64
r_23::Float64
x_23::Float64
r_13::Float64
x_13::Float64
α_primary::Float64
α_secondary::Float64
α_tertiary::Float64
base_power_12::Float64
base_power_23::Float64
base_power_13::Float64
base_voltage_primary::Union{Nothing, Float64}
base_voltage_secondary::Union{Nothing, Float64}
base_voltage_tertiary::Union{Nothing, Float64}
g::Float64
b::Float64
primary_turns_ratio::Float64
secondary_turns_ratio::Float64
tertiary_turns_ratio::Float64
available_primary::Bool
available_secondary::Bool
available_tertiary::Bool
rating_primary::Float64
rating_secondary::Float64
rating_tertiary::Float64
phase_angle_limits::MinMax
control_objective_primary::TransformerControlObjective
control_objective_secondary::TransformerControlObjective
control_objective_tertiary::TransformerControlObjective
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A 3-winding phase-shifting transformer.
. Phase shifts are specified in radians for primary, secondary, and tertiary windings.
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `primary_star_arc::Arc`: An [`Arc`](@ref) defining this transformer `from` a primary bus `to` the star bus
- `secondary_star_arc::Arc`: An [`Arc`](@ref) defining this transformer `from` a secondary bus `to` the star bus
- `tertiary_star_arc::Arc`: An [`Arc`](@ref) defining this transformer `from` a tertiary bus `to` the star bus
- `star_bus::ACBus`: Star (hidden) Bus that this component (equivalent model) is connected to
- `active_power_flow_primary::Float64`: Initial condition of active power flow through the transformer primary side to star (hidden) bus (MW)
- `reactive_power_flow_primary::Float64`: Initial condition of reactive power flow through the transformer primary side to star (hidden) bus (MW)
- `active_power_flow_secondary::Float64`: Initial condition of active power flow through the transformer secondary side to star (hidden) bus (MW)
- `reactive_power_flow_secondary::Float64`: Initial condition of reactive power flow through the transformer secondary side to star (hidden) bus (MW)
- `active_power_flow_tertiary::Float64`: Initial condition of active power flow through the transformer tertiary side to star (hidden) bus (MW)
- `reactive_power_flow_tertiary::Float64`: Initial condition of reactive power flow through the transformer tertiary side to star (hidden) bus (MW)
- `r_primary::Float64`: Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus., validation range: `(-2, 4)`
- `x_primary::Float64`: Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus., validation range: `(-2, 4)`
- `r_secondary::Float64`: Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus., validation range: `(-2, 4)`
- `x_secondary::Float64`: Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus., validation range: `(-2, 4)`
- `r_tertiary::Float64`: Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus., validation range: `(-2, 4)`
- `x_tertiary::Float64`: Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus., validation range: `(-2, 4)`
- `rating::Union{Nothing, Float64}`: Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to, validation range: `(0, nothing)`
- `r_12::Float64`: Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (R1-2 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `x_12::Float64`: Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (X1-2 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `r_23::Float64`: Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (R2-3 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `x_23::Float64`: Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (X2-3 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `r_13::Float64`: Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (R1-3 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `x_13::Float64`: Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (X1-3 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `α_primary::Float64`: Initial condition of primary phase shift (radians) between the `from` and `to` buses , validation range: `(-1.571, 1.571)`
- `α_secondary::Float64`: Initial condition of secondary phase shift (radians) between the `from` and `to` buses , validation range: `(-1.571, 1.571)`
- `α_tertiary::Float64`: Initial condition of tertiary phase shift (radians) between the `from` and `to` buses , validation range: `(-1.571, 1.571)`
- `base_power_12::Float64`: Base power (MVA) for [per unitization](@ref per_unit) for primary-secondary windings., validation range: `(0, nothing)`
- `base_power_23::Float64`: Base power (MVA) for [per unitization](@ref per_unit) for secondary-tertiary windings., validation range: `(0, nothing)`
- `base_power_13::Float64`: Base power (MVA) for [per unitization](@ref per_unit) for primary-tertiary windings., validation range: `(0, nothing)`
- `base_voltage_primary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_from(primary_star_arc))`) Primary base voltage in kV, validation range: `(0, nothing)`
- `base_voltage_secondary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_from(secondary_star_arc))`) Secondary base voltage in kV, validation range: `(0, nothing)`
- `base_voltage_tertiary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_from(tertiary_star_arc))`) Tertiary base voltage in kV, validation range: `(0, nothing)`
- `g::Float64`: (default: `0.0`) Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG1 in PSS/E).
- `b::Float64`: (default: `0.0`) Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG2 in PSS/E).
- `primary_turns_ratio::Float64`: (default: `1.0`) Primary side off-nominal turns ratio in p.u. with respect to connected primary bus (WINDV1 with CW = 1 in PSS/E).
- `secondary_turns_ratio::Float64`: (default: `1.0`) Secondary side off-nominal turns ratio in p.u. with respect to connected secondary bus (WINDV2 with CW = 1 in PSS/E).
- `tertiary_turns_ratio::Float64`: (default: `1.0`) Tertiary side off-nominal turns ratio in p.u. with respect to connected tertiary bus (WINDV3 with CW = 1 in PSS/E).
- `available_primary::Bool`: (default: `true`) Status if primary winding is available or not.
- `available_secondary::Bool`: (default: `true`) Status if primary winding is available or not.
- `available_tertiary::Bool`: (default: `true`) Status if primary winding is available or not.
- `rating_primary::Float64`: (default: `0.0`) Rating (in MVA) for primary winding.
- `rating_secondary::Float64`: (default: `0.0`) Rating (in MVA) for secondary winding.
- `rating_tertiary::Float64`: (default: `0.0`) Rating (in MVA) for tertiary winding.
- `phase_angle_limits::MinMax`: (default: `(min=-3.1416, max=3.1416)`) Minimum and maximum phase angle limits (radians)
- `control_objective_primary::TransformerControlObjective`: (default: `TransformerControlObjective.UNDEFINED`) Control objective for the tap changer for winding 1. See [`TransformerControlObjective`](@ref xtf_crtl)
- `control_objective_secondary::TransformerControlObjective`: (default: `TransformerControlObjective.UNDEFINED`) Control objective for the tap changer for winding 2. See [`TransformerControlObjective`](@ref xtf_crtl)
- `control_objective_tertiary::TransformerControlObjective`: (default: `TransformerControlObjective.UNDEFINED`) Control objective for the tap changer for winding 3. See [`TransformerControlObjective`](@ref xtf_crtl)
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct PhaseShiftingTransformer3W <: ThreeWindingTransformer
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"An [`Arc`](@ref) defining this transformer `from` a primary bus `to` the star bus"
primary_star_arc::Arc
"An [`Arc`](@ref) defining this transformer `from` a secondary bus `to` the star bus"
secondary_star_arc::Arc
"An [`Arc`](@ref) defining this transformer `from` a tertiary bus `to` the star bus"
tertiary_star_arc::Arc
"Star (hidden) Bus that this component (equivalent model) is connected to"
star_bus::ACBus
"Initial condition of active power flow through the transformer primary side to star (hidden) bus (MW)"
active_power_flow_primary::Float64
"Initial condition of reactive power flow through the transformer primary side to star (hidden) bus (MW)"
reactive_power_flow_primary::Float64
"Initial condition of active power flow through the transformer secondary side to star (hidden) bus (MW)"
active_power_flow_secondary::Float64
"Initial condition of reactive power flow through the transformer secondary side to star (hidden) bus (MW)"
reactive_power_flow_secondary::Float64
"Initial condition of active power flow through the transformer tertiary side to star (hidden) bus (MW)"
active_power_flow_tertiary::Float64
"Initial condition of reactive power flow through the transformer tertiary side to star (hidden) bus (MW)"
reactive_power_flow_tertiary::Float64
"Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus."
r_primary::Float64
"Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus."
x_primary::Float64
"Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus."
r_secondary::Float64
"Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus."
x_secondary::Float64
"Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus."
r_tertiary::Float64
"Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus."
x_tertiary::Float64
"Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to"
rating::Union{Nothing, Float64}
"Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (R1-2 with CZ = 1 in PSS/E)."
r_12::Float64
"Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (X1-2 with CZ = 1 in PSS/E)."
x_12::Float64
"Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (R2-3 with CZ = 1 in PSS/E)."
r_23::Float64
"Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (X2-3 with CZ = 1 in PSS/E)."
x_23::Float64
"Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (R1-3 with CZ = 1 in PSS/E)."
r_13::Float64
"Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (X1-3 with CZ = 1 in PSS/E)."
x_13::Float64
"Initial condition of primary phase shift (radians) between the `from` and `to` buses "
α_primary::Float64
"Initial condition of secondary phase shift (radians) between the `from` and `to` buses "
α_secondary::Float64
"Initial condition of tertiary phase shift (radians) between the `from` and `to` buses "
α_tertiary::Float64
"Base power (MVA) for [per unitization](@ref per_unit) for primary-secondary windings."
base_power_12::Float64
"Base power (MVA) for [per unitization](@ref per_unit) for secondary-tertiary windings."
base_power_23::Float64
"Base power (MVA) for [per unitization](@ref per_unit) for primary-tertiary windings."
base_power_13::Float64
"Primary base voltage in kV"
base_voltage_primary::Union{Nothing, Float64}
"Secondary base voltage in kV"
base_voltage_secondary::Union{Nothing, Float64}
"Tertiary base voltage in kV"
base_voltage_tertiary::Union{Nothing, Float64}
"Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG1 in PSS/E)."
g::Float64
"Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG2 in PSS/E)."
b::Float64
"Primary side off-nominal turns ratio in p.u. with respect to connected primary bus (WINDV1 with CW = 1 in PSS/E)."
primary_turns_ratio::Float64
"Secondary side off-nominal turns ratio in p.u. with respect to connected secondary bus (WINDV2 with CW = 1 in PSS/E)."
secondary_turns_ratio::Float64
"Tertiary side off-nominal turns ratio in p.u. with respect to connected tertiary bus (WINDV3 with CW = 1 in PSS/E)."
tertiary_turns_ratio::Float64
"Status if primary winding is available or not."
available_primary::Bool
"Status if primary winding is available or not."
available_secondary::Bool
"Status if primary winding is available or not."
available_tertiary::Bool
"Rating (in MVA) for primary winding."
rating_primary::Float64
"Rating (in MVA) for secondary winding."
rating_secondary::Float64
"Rating (in MVA) for tertiary winding."
rating_tertiary::Float64
"Minimum and maximum phase angle limits (radians)"
phase_angle_limits::MinMax
"Control objective for the tap changer for winding 1. See [`TransformerControlObjective`](@ref xtf_crtl)"
control_objective_primary::TransformerControlObjective
"Control objective for the tap changer for winding 2. See [`TransformerControlObjective`](@ref xtf_crtl)"
control_objective_secondary::TransformerControlObjective
"Control objective for the tap changer for winding 3. See [`TransformerControlObjective`](@ref xtf_crtl)"
control_objective_tertiary::TransformerControlObjective
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function PhaseShiftingTransformer3W(name, available, primary_star_arc, secondary_star_arc, tertiary_star_arc, star_bus, active_power_flow_primary, reactive_power_flow_primary, active_power_flow_secondary, reactive_power_flow_secondary, active_power_flow_tertiary, reactive_power_flow_tertiary, r_primary, x_primary, r_secondary, x_secondary, r_tertiary, x_tertiary, rating, r_12, x_12, r_23, x_23, r_13, x_13, α_primary, α_secondary, α_tertiary, base_power_12, base_power_23, base_power_13, base_voltage_primary=get_base_voltage(get_from(primary_star_arc)), base_voltage_secondary=get_base_voltage(get_from(secondary_star_arc)), base_voltage_tertiary=get_base_voltage(get_from(tertiary_star_arc)), g=0.0, b=0.0, primary_turns_ratio=1.0, secondary_turns_ratio=1.0, tertiary_turns_ratio=1.0, available_primary=true, available_secondary=true, available_tertiary=true, rating_primary=0.0, rating_secondary=0.0, rating_tertiary=0.0, phase_angle_limits=(min=-3.1416, max=3.1416), control_objective_primary=TransformerControlObjective.UNDEFINED, control_objective_secondary=TransformerControlObjective.UNDEFINED, control_objective_tertiary=TransformerControlObjective.UNDEFINED, services=Device[], ext=Dict{String, Any}(), )
PhaseShiftingTransformer3W(name, available, primary_star_arc, secondary_star_arc, tertiary_star_arc, star_bus, active_power_flow_primary, reactive_power_flow_primary, active_power_flow_secondary, reactive_power_flow_secondary, active_power_flow_tertiary, reactive_power_flow_tertiary, r_primary, x_primary, r_secondary, x_secondary, r_tertiary, x_tertiary, rating, r_12, x_12, r_23, x_23, r_13, x_13, α_primary, α_secondary, α_tertiary, base_power_12, base_power_23, base_power_13, base_voltage_primary, base_voltage_secondary, base_voltage_tertiary, g, b, primary_turns_ratio, secondary_turns_ratio, tertiary_turns_ratio, available_primary, available_secondary, available_tertiary, rating_primary, rating_secondary, rating_tertiary, phase_angle_limits, control_objective_primary, control_objective_secondary, control_objective_tertiary, services, ext, InfrastructureSystemsInternal(), )
end
function PhaseShiftingTransformer3W(; name, available, primary_star_arc, secondary_star_arc, tertiary_star_arc, star_bus, active_power_flow_primary, reactive_power_flow_primary, active_power_flow_secondary, reactive_power_flow_secondary, active_power_flow_tertiary, reactive_power_flow_tertiary, r_primary, x_primary, r_secondary, x_secondary, r_tertiary, x_tertiary, rating, r_12, x_12, r_23, x_23, r_13, x_13, α_primary, α_secondary, α_tertiary, base_power_12, base_power_23, base_power_13, base_voltage_primary=get_base_voltage(get_from(primary_star_arc)), base_voltage_secondary=get_base_voltage(get_from(secondary_star_arc)), base_voltage_tertiary=get_base_voltage(get_from(tertiary_star_arc)), g=0.0, b=0.0, primary_turns_ratio=1.0, secondary_turns_ratio=1.0, tertiary_turns_ratio=1.0, available_primary=true, available_secondary=true, available_tertiary=true, rating_primary=0.0, rating_secondary=0.0, rating_tertiary=0.0, phase_angle_limits=(min=-3.1416, max=3.1416), control_objective_primary=TransformerControlObjective.UNDEFINED, control_objective_secondary=TransformerControlObjective.UNDEFINED, control_objective_tertiary=TransformerControlObjective.UNDEFINED, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
PhaseShiftingTransformer3W(name, available, primary_star_arc, secondary_star_arc, tertiary_star_arc, star_bus, active_power_flow_primary, reactive_power_flow_primary, active_power_flow_secondary, reactive_power_flow_secondary, active_power_flow_tertiary, reactive_power_flow_tertiary, r_primary, x_primary, r_secondary, x_secondary, r_tertiary, x_tertiary, rating, r_12, x_12, r_23, x_23, r_13, x_13, α_primary, α_secondary, α_tertiary, base_power_12, base_power_23, base_power_13, base_voltage_primary, base_voltage_secondary, base_voltage_tertiary, g, b, primary_turns_ratio, secondary_turns_ratio, tertiary_turns_ratio, available_primary, available_secondary, available_tertiary, rating_primary, rating_secondary, rating_tertiary, phase_angle_limits, control_objective_primary, control_objective_secondary, control_objective_tertiary, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function PhaseShiftingTransformer3W(::Nothing)
PhaseShiftingTransformer3W(;
name="init",
available=false,
primary_star_arc=Arc(ACBus(nothing), ACBus(nothing)),
secondary_star_arc=Arc(ACBus(nothing), ACBus(nothing)),
tertiary_star_arc=Arc(ACBus(nothing), ACBus(nothing)),
star_bus=ACBus(nothing),
active_power_flow_primary=0.0,
reactive_power_flow_primary=0.0,
active_power_flow_secondary=0.0,
reactive_power_flow_secondary=0.0,
active_power_flow_tertiary=0.0,
reactive_power_flow_tertiary=0.0,
r_primary=0.0,
x_primary=0.0,
r_secondary=0.0,
x_secondary=0.0,
r_tertiary=0.0,
x_tertiary=0.0,
rating=nothing,
r_12=0.0,
x_12=0.0,
r_23=0.0,
x_23=0.0,
r_13=0.0,
x_13=0.0,
α_primary=0.0,
α_secondary=0.0,
α_tertiary=0.0,
base_power_12=0.0,
base_power_23=0.0,
base_power_13=0.0,
base_voltage_primary=nothing,
base_voltage_secondary=nothing,
base_voltage_tertiary=nothing,
g=0.0,
b=0.0,
primary_turns_ratio=0.0,
secondary_turns_ratio=0.0,
tertiary_turns_ratio=0.0,
available_primary=false,
available_secondary=false,
available_tertiary=false,
rating_primary=0.0,
rating_secondary=0.0,
rating_tertiary=0.0,
phase_angle_limits=(min=-3.1416, max=3.1416),
control_objective_primary=TransformerControlObjective.UNDEFINED,
control_objective_secondary=TransformerControlObjective.UNDEFINED,
control_objective_tertiary=TransformerControlObjective.UNDEFINED,
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`PhaseShiftingTransformer3W`](@ref) `name`."""
get_name(value::PhaseShiftingTransformer3W) = value.name
"""Get [`PhaseShiftingTransformer3W`](@ref) `available`."""
get_available(value::PhaseShiftingTransformer3W) = value.available
"""Get [`PhaseShiftingTransformer3W`](@ref) `primary_star_arc`."""
get_primary_star_arc(value::PhaseShiftingTransformer3W) = value.primary_star_arc
"""Get [`PhaseShiftingTransformer3W`](@ref) `secondary_star_arc`."""
get_secondary_star_arc(value::PhaseShiftingTransformer3W) = value.secondary_star_arc
"""Get [`PhaseShiftingTransformer3W`](@ref) `tertiary_star_arc`."""
get_tertiary_star_arc(value::PhaseShiftingTransformer3W) = value.tertiary_star_arc
"""Get [`PhaseShiftingTransformer3W`](@ref) `star_bus`."""
get_star_bus(value::PhaseShiftingTransformer3W) = value.star_bus
"""Get [`PhaseShiftingTransformer3W`](@ref) `active_power_flow_primary`."""
get_active_power_flow_primary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:active_power_flow_primary), Val(:mva))
"""Get [`PhaseShiftingTransformer3W`](@ref) `reactive_power_flow_primary`."""
get_reactive_power_flow_primary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:reactive_power_flow_primary), Val(:mva))
"""Get [`PhaseShiftingTransformer3W`](@ref) `active_power_flow_secondary`."""
get_active_power_flow_secondary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:active_power_flow_secondary), Val(:mva))
"""Get [`PhaseShiftingTransformer3W`](@ref) `reactive_power_flow_secondary`."""
get_reactive_power_flow_secondary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:reactive_power_flow_secondary), Val(:mva))
"""Get [`PhaseShiftingTransformer3W`](@ref) `active_power_flow_tertiary`."""
get_active_power_flow_tertiary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:active_power_flow_tertiary), Val(:mva))
"""Get [`PhaseShiftingTransformer3W`](@ref) `reactive_power_flow_tertiary`."""
get_reactive_power_flow_tertiary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:reactive_power_flow_tertiary), Val(:mva))
"""Get [`PhaseShiftingTransformer3W`](@ref) `r_primary`."""
get_r_primary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:r_primary), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `x_primary`."""
get_x_primary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:x_primary), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `r_secondary`."""
get_r_secondary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:r_secondary), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `x_secondary`."""
get_x_secondary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:x_secondary), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `r_tertiary`."""
get_r_tertiary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:r_tertiary), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `x_tertiary`."""
get_x_tertiary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:x_tertiary), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `rating`."""
get_rating(value::PhaseShiftingTransformer3W) = get_value(value, Val(:rating), Val(:mva))
"""Get [`PhaseShiftingTransformer3W`](@ref) `r_12`."""
get_r_12(value::PhaseShiftingTransformer3W) = get_value(value, Val(:r_12), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `x_12`."""
get_x_12(value::PhaseShiftingTransformer3W) = get_value(value, Val(:x_12), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `r_23`."""
get_r_23(value::PhaseShiftingTransformer3W) = get_value(value, Val(:r_23), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `x_23`."""
get_x_23(value::PhaseShiftingTransformer3W) = get_value(value, Val(:x_23), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `r_13`."""
get_r_13(value::PhaseShiftingTransformer3W) = get_value(value, Val(:r_13), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `x_13`."""
get_x_13(value::PhaseShiftingTransformer3W) = get_value(value, Val(:x_13), Val(:ohm))
"""Get [`PhaseShiftingTransformer3W`](@ref) `α_primary`."""
get_α_primary(value::PhaseShiftingTransformer3W) = value.α_primary
"""Get [`PhaseShiftingTransformer3W`](@ref) `α_secondary`."""
get_α_secondary(value::PhaseShiftingTransformer3W) = value.α_secondary
"""Get [`PhaseShiftingTransformer3W`](@ref) `α_tertiary`."""
get_α_tertiary(value::PhaseShiftingTransformer3W) = value.α_tertiary
"""Get [`PhaseShiftingTransformer3W`](@ref) `base_power_12`."""
get_base_power_12(value::PhaseShiftingTransformer3W) = value.base_power_12
"""Get [`PhaseShiftingTransformer3W`](@ref) `base_power_23`."""
get_base_power_23(value::PhaseShiftingTransformer3W) = value.base_power_23
"""Get [`PhaseShiftingTransformer3W`](@ref) `base_power_13`."""
get_base_power_13(value::PhaseShiftingTransformer3W) = value.base_power_13
"""Get [`PhaseShiftingTransformer3W`](@ref) `base_voltage_primary`."""
get_base_voltage_primary(value::PhaseShiftingTransformer3W) = value.base_voltage_primary
"""Get [`PhaseShiftingTransformer3W`](@ref) `base_voltage_secondary`."""
get_base_voltage_secondary(value::PhaseShiftingTransformer3W) = value.base_voltage_secondary
"""Get [`PhaseShiftingTransformer3W`](@ref) `base_voltage_tertiary`."""
get_base_voltage_tertiary(value::PhaseShiftingTransformer3W) = value.base_voltage_tertiary
"""Get [`PhaseShiftingTransformer3W`](@ref) `g`."""
get_g(value::PhaseShiftingTransformer3W) = get_value(value, Val(:g), Val(:siemens))
"""Get [`PhaseShiftingTransformer3W`](@ref) `b`."""
get_b(value::PhaseShiftingTransformer3W) = get_value(value, Val(:b), Val(:siemens))
"""Get [`PhaseShiftingTransformer3W`](@ref) `primary_turns_ratio`."""
get_primary_turns_ratio(value::PhaseShiftingTransformer3W) = value.primary_turns_ratio
"""Get [`PhaseShiftingTransformer3W`](@ref) `secondary_turns_ratio`."""
get_secondary_turns_ratio(value::PhaseShiftingTransformer3W) = value.secondary_turns_ratio
"""Get [`PhaseShiftingTransformer3W`](@ref) `tertiary_turns_ratio`."""
get_tertiary_turns_ratio(value::PhaseShiftingTransformer3W) = value.tertiary_turns_ratio
"""Get [`PhaseShiftingTransformer3W`](@ref) `available_primary`."""
get_available_primary(value::PhaseShiftingTransformer3W) = value.available_primary
"""Get [`PhaseShiftingTransformer3W`](@ref) `available_secondary`."""
get_available_secondary(value::PhaseShiftingTransformer3W) = value.available_secondary
"""Get [`PhaseShiftingTransformer3W`](@ref) `available_tertiary`."""
get_available_tertiary(value::PhaseShiftingTransformer3W) = value.available_tertiary
"""Get [`PhaseShiftingTransformer3W`](@ref) `rating_primary`."""
get_rating_primary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:rating_primary), Val(:mva))
"""Get [`PhaseShiftingTransformer3W`](@ref) `rating_secondary`."""
get_rating_secondary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:rating_secondary), Val(:mva))
"""Get [`PhaseShiftingTransformer3W`](@ref) `rating_tertiary`."""
get_rating_tertiary(value::PhaseShiftingTransformer3W) = get_value(value, Val(:rating_tertiary), Val(:mva))
"""Get [`PhaseShiftingTransformer3W`](@ref) `phase_angle_limits`."""
get_phase_angle_limits(value::PhaseShiftingTransformer3W) = value.phase_angle_limits
"""Get [`PhaseShiftingTransformer3W`](@ref) `control_objective_primary`."""
get_control_objective_primary(value::PhaseShiftingTransformer3W) = value.control_objective_primary
"""Get [`PhaseShiftingTransformer3W`](@ref) `control_objective_secondary`."""
get_control_objective_secondary(value::PhaseShiftingTransformer3W) = value.control_objective_secondary
"""Get [`PhaseShiftingTransformer3W`](@ref) `control_objective_tertiary`."""
get_control_objective_tertiary(value::PhaseShiftingTransformer3W) = value.control_objective_tertiary
"""Get [`PhaseShiftingTransformer3W`](@ref) `services`."""
get_services(value::PhaseShiftingTransformer3W) = value.services
"""Get [`PhaseShiftingTransformer3W`](@ref) `ext`."""
get_ext(value::PhaseShiftingTransformer3W) = value.ext
"""Get [`PhaseShiftingTransformer3W`](@ref) `internal`."""
get_internal(value::PhaseShiftingTransformer3W) = value.internal
"""Set [`PhaseShiftingTransformer3W`](@ref) `available`."""
set_available!(value::PhaseShiftingTransformer3W, val) = value.available = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `primary_star_arc`."""
set_primary_star_arc!(value::PhaseShiftingTransformer3W, val) = value.primary_star_arc = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `secondary_star_arc`."""
set_secondary_star_arc!(value::PhaseShiftingTransformer3W, val) = value.secondary_star_arc = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `tertiary_star_arc`."""
set_tertiary_star_arc!(value::PhaseShiftingTransformer3W, val) = value.tertiary_star_arc = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `star_bus`."""
set_star_bus!(value::PhaseShiftingTransformer3W, val) = value.star_bus = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `active_power_flow_primary`."""
set_active_power_flow_primary!(value::PhaseShiftingTransformer3W, val) = value.active_power_flow_primary = set_value(value, Val(:active_power_flow_primary), val, Val(:mva))
"""Set [`PhaseShiftingTransformer3W`](@ref) `reactive_power_flow_primary`."""
set_reactive_power_flow_primary!(value::PhaseShiftingTransformer3W, val) = value.reactive_power_flow_primary = set_value(value, Val(:reactive_power_flow_primary), val, Val(:mva))
"""Set [`PhaseShiftingTransformer3W`](@ref) `active_power_flow_secondary`."""
set_active_power_flow_secondary!(value::PhaseShiftingTransformer3W, val) = value.active_power_flow_secondary = set_value(value, Val(:active_power_flow_secondary), val, Val(:mva))
"""Set [`PhaseShiftingTransformer3W`](@ref) `reactive_power_flow_secondary`."""
set_reactive_power_flow_secondary!(value::PhaseShiftingTransformer3W, val) = value.reactive_power_flow_secondary = set_value(value, Val(:reactive_power_flow_secondary), val, Val(:mva))
"""Set [`PhaseShiftingTransformer3W`](@ref) `active_power_flow_tertiary`."""
set_active_power_flow_tertiary!(value::PhaseShiftingTransformer3W, val) = value.active_power_flow_tertiary = set_value(value, Val(:active_power_flow_tertiary), val, Val(:mva))
"""Set [`PhaseShiftingTransformer3W`](@ref) `reactive_power_flow_tertiary`."""
set_reactive_power_flow_tertiary!(value::PhaseShiftingTransformer3W, val) = value.reactive_power_flow_tertiary = set_value(value, Val(:reactive_power_flow_tertiary), val, Val(:mva))
"""Set [`PhaseShiftingTransformer3W`](@ref) `r_primary`."""
set_r_primary!(value::PhaseShiftingTransformer3W, val) = value.r_primary = set_value(value, Val(:r_primary), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `x_primary`."""
set_x_primary!(value::PhaseShiftingTransformer3W, val) = value.x_primary = set_value(value, Val(:x_primary), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `r_secondary`."""
set_r_secondary!(value::PhaseShiftingTransformer3W, val) = value.r_secondary = set_value(value, Val(:r_secondary), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `x_secondary`."""
set_x_secondary!(value::PhaseShiftingTransformer3W, val) = value.x_secondary = set_value(value, Val(:x_secondary), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `r_tertiary`."""
set_r_tertiary!(value::PhaseShiftingTransformer3W, val) = value.r_tertiary = set_value(value, Val(:r_tertiary), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `x_tertiary`."""
set_x_tertiary!(value::PhaseShiftingTransformer3W, val) = value.x_tertiary = set_value(value, Val(:x_tertiary), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `rating`."""
set_rating!(value::PhaseShiftingTransformer3W, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`PhaseShiftingTransformer3W`](@ref) `r_12`."""
set_r_12!(value::PhaseShiftingTransformer3W, val) = value.r_12 = set_value(value, Val(:r_12), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `x_12`."""
set_x_12!(value::PhaseShiftingTransformer3W, val) = value.x_12 = set_value(value, Val(:x_12), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `r_23`."""
set_r_23!(value::PhaseShiftingTransformer3W, val) = value.r_23 = set_value(value, Val(:r_23), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `x_23`."""
set_x_23!(value::PhaseShiftingTransformer3W, val) = value.x_23 = set_value(value, Val(:x_23), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `r_13`."""
set_r_13!(value::PhaseShiftingTransformer3W, val) = value.r_13 = set_value(value, Val(:r_13), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `x_13`."""
set_x_13!(value::PhaseShiftingTransformer3W, val) = value.x_13 = set_value(value, Val(:x_13), val, Val(:ohm))
"""Set [`PhaseShiftingTransformer3W`](@ref) `α_primary`."""
set_α_primary!(value::PhaseShiftingTransformer3W, val) = value.α_primary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `α_secondary`."""
set_α_secondary!(value::PhaseShiftingTransformer3W, val) = value.α_secondary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `α_tertiary`."""
set_α_tertiary!(value::PhaseShiftingTransformer3W, val) = value.α_tertiary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `base_power_12`."""
set_base_power_12!(value::PhaseShiftingTransformer3W, val) = value.base_power_12 = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `base_power_23`."""
set_base_power_23!(value::PhaseShiftingTransformer3W, val) = value.base_power_23 = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `base_power_13`."""
set_base_power_13!(value::PhaseShiftingTransformer3W, val) = value.base_power_13 = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `base_voltage_primary`."""
set_base_voltage_primary!(value::PhaseShiftingTransformer3W, val) = value.base_voltage_primary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `base_voltage_secondary`."""
set_base_voltage_secondary!(value::PhaseShiftingTransformer3W, val) = value.base_voltage_secondary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `base_voltage_tertiary`."""
set_base_voltage_tertiary!(value::PhaseShiftingTransformer3W, val) = value.base_voltage_tertiary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `g`."""
set_g!(value::PhaseShiftingTransformer3W, val) = value.g = set_value(value, Val(:g), val, Val(:siemens))
"""Set [`PhaseShiftingTransformer3W`](@ref) `b`."""
set_b!(value::PhaseShiftingTransformer3W, val) = value.b = set_value(value, Val(:b), val, Val(:siemens))
"""Set [`PhaseShiftingTransformer3W`](@ref) `primary_turns_ratio`."""
set_primary_turns_ratio!(value::PhaseShiftingTransformer3W, val) = value.primary_turns_ratio = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `secondary_turns_ratio`."""
set_secondary_turns_ratio!(value::PhaseShiftingTransformer3W, val) = value.secondary_turns_ratio = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `tertiary_turns_ratio`."""
set_tertiary_turns_ratio!(value::PhaseShiftingTransformer3W, val) = value.tertiary_turns_ratio = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `available_primary`."""
set_available_primary!(value::PhaseShiftingTransformer3W, val) = value.available_primary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `available_secondary`."""
set_available_secondary!(value::PhaseShiftingTransformer3W, val) = value.available_secondary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `available_tertiary`."""
set_available_tertiary!(value::PhaseShiftingTransformer3W, val) = value.available_tertiary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `rating_primary`."""
set_rating_primary!(value::PhaseShiftingTransformer3W, val) = value.rating_primary = set_value(value, Val(:rating_primary), val, Val(:mva))
"""Set [`PhaseShiftingTransformer3W`](@ref) `rating_secondary`."""
set_rating_secondary!(value::PhaseShiftingTransformer3W, val) = value.rating_secondary = set_value(value, Val(:rating_secondary), val, Val(:mva))
"""Set [`PhaseShiftingTransformer3W`](@ref) `rating_tertiary`."""
set_rating_tertiary!(value::PhaseShiftingTransformer3W, val) = value.rating_tertiary = set_value(value, Val(:rating_tertiary), val, Val(:mva))
"""Set [`PhaseShiftingTransformer3W`](@ref) `phase_angle_limits`."""
set_phase_angle_limits!(value::PhaseShiftingTransformer3W, val) = value.phase_angle_limits = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `control_objective_primary`."""
set_control_objective_primary!(value::PhaseShiftingTransformer3W, val) = value.control_objective_primary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `control_objective_secondary`."""
set_control_objective_secondary!(value::PhaseShiftingTransformer3W, val) = value.control_objective_secondary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `control_objective_tertiary`."""
set_control_objective_tertiary!(value::PhaseShiftingTransformer3W, val) = value.control_objective_tertiary = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `services`."""
set_services!(value::PhaseShiftingTransformer3W, val) = value.services = val
"""Set [`PhaseShiftingTransformer3W`](@ref) `ext`."""
set_ext!(value::PhaseShiftingTransformer3W, val) = value.ext = val
================================================
FILE: src/models/generated/PowerLoad.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PowerLoad <: StaticLoad
name::String
available::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
base_power::Float64
max_active_power::Float64
max_reactive_power::Float64
conformity::LoadConformity
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A [static](@ref S) power load, most commonly used for operational models such as power flow and operational optimizations.
This load consumes a set amount of power (set by `active_power` for a power flow simulation or a `max_active_power` time series for an operational simulation). For loads that can be compensated for load interruptions through demand response programs, see [`InterruptiblePowerLoad`](@ref). For voltage-dependent loads used in [dynamics](@ref D) modeling, see [`StandardLoad`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial steady-state active power demand (MW)
- `reactive_power::Float64`: Initial steady-state reactive power demand (MVAR)
- `base_power::Float64`: Base power (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `max_active_power::Float64`: Maximum active power (MW) that this load can demand
- `max_reactive_power::Float64`: Maximum reactive power (MVAR) that this load can demand
- `conformity::LoadConformity`: (default: `LoadConformity.UNDEFINED`) Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list).
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct PowerLoad <: StaticLoad
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial steady-state active power demand (MW)"
active_power::Float64
"Initial steady-state reactive power demand (MVAR)"
reactive_power::Float64
"Base power (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Maximum active power (MW) that this load can demand"
max_active_power::Float64
"Maximum reactive power (MVAR) that this load can demand"
max_reactive_power::Float64
"Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list)."
conformity::LoadConformity
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function PowerLoad(name, available, bus, active_power, reactive_power, base_power, max_active_power, max_reactive_power, conformity=LoadConformity.UNDEFINED, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
PowerLoad(name, available, bus, active_power, reactive_power, base_power, max_active_power, max_reactive_power, conformity, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function PowerLoad(; name, available, bus, active_power, reactive_power, base_power, max_active_power, max_reactive_power, conformity=LoadConformity.UNDEFINED, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
PowerLoad(name, available, bus, active_power, reactive_power, base_power, max_active_power, max_reactive_power, conformity, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function PowerLoad(::Nothing)
PowerLoad(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
base_power=100.0,
max_active_power=0.0,
max_reactive_power=0.0,
conformity=LoadConformity.UNDEFINED,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`PowerLoad`](@ref) `name`."""
get_name(value::PowerLoad) = value.name
"""Get [`PowerLoad`](@ref) `available`."""
get_available(value::PowerLoad) = value.available
"""Get [`PowerLoad`](@ref) `bus`."""
get_bus(value::PowerLoad) = value.bus
"""Get [`PowerLoad`](@ref) `active_power`."""
get_active_power(value::PowerLoad) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`PowerLoad`](@ref) `reactive_power`."""
get_reactive_power(value::PowerLoad) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`PowerLoad`](@ref) `base_power`."""
get_base_power(value::PowerLoad) = value.base_power
"""Get [`PowerLoad`](@ref) `max_active_power`."""
get_max_active_power(value::PowerLoad) = get_value(value, Val(:max_active_power), Val(:mva))
"""Get [`PowerLoad`](@ref) `max_reactive_power`."""
get_max_reactive_power(value::PowerLoad) = get_value(value, Val(:max_reactive_power), Val(:mva))
"""Get [`PowerLoad`](@ref) `conformity`."""
get_conformity(value::PowerLoad) = value.conformity
"""Get [`PowerLoad`](@ref) `services`."""
get_services(value::PowerLoad) = value.services
"""Get [`PowerLoad`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::PowerLoad) = value.dynamic_injector
"""Get [`PowerLoad`](@ref) `ext`."""
get_ext(value::PowerLoad) = value.ext
"""Get [`PowerLoad`](@ref) `internal`."""
get_internal(value::PowerLoad) = value.internal
"""Set [`PowerLoad`](@ref) `available`."""
set_available!(value::PowerLoad, val) = value.available = val
"""Set [`PowerLoad`](@ref) `bus`."""
set_bus!(value::PowerLoad, val) = value.bus = val
"""Set [`PowerLoad`](@ref) `active_power`."""
set_active_power!(value::PowerLoad, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`PowerLoad`](@ref) `reactive_power`."""
set_reactive_power!(value::PowerLoad, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`PowerLoad`](@ref) `base_power`."""
set_base_power!(value::PowerLoad, val) = value.base_power = val
"""Set [`PowerLoad`](@ref) `max_active_power`."""
set_max_active_power!(value::PowerLoad, val) = value.max_active_power = set_value(value, Val(:max_active_power), val, Val(:mva))
"""Set [`PowerLoad`](@ref) `max_reactive_power`."""
set_max_reactive_power!(value::PowerLoad, val) = value.max_reactive_power = set_value(value, Val(:max_reactive_power), val, Val(:mva))
"""Set [`PowerLoad`](@ref) `conformity`."""
set_conformity!(value::PowerLoad, val) = value.conformity = val
"""Set [`PowerLoad`](@ref) `services`."""
set_services!(value::PowerLoad, val) = value.services = val
"""Set [`PowerLoad`](@ref) `ext`."""
set_ext!(value::PowerLoad, val) = value.ext = val
================================================
FILE: src/models/generated/PriorityOutputCurrentLimiter.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct PriorityOutputCurrentLimiter <: OutputCurrentLimiter
I_max::Float64
ϕ_I::Float64
ext::Dict{String, Any}
end
Parameters of Priority-Based Current Controller Limiter. Regulates the magnitude of the inverter output current and prioritizes a specific angle for the resultant current signal
# Arguments
- `I_max::Float64`: Maximum limit on current controller input current in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `ϕ_I::Float64`: Pre-defined angle (measured against the d-axis) for I_ref once limit I_max is hit, validation range: `(-1.571, 1.571)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
"""
mutable struct PriorityOutputCurrentLimiter <: OutputCurrentLimiter
"Maximum limit on current controller input current in pu ([`DEVICE_BASE`](@ref per_unit))"
I_max::Float64
"Pre-defined angle (measured against the d-axis) for I_ref once limit I_max is hit"
ϕ_I::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
end
function PriorityOutputCurrentLimiter(; I_max, ϕ_I, ext=Dict{String, Any}(), )
PriorityOutputCurrentLimiter(I_max, ϕ_I, ext, )
end
# Constructor for demo purposes; non-functional.
function PriorityOutputCurrentLimiter(::Nothing)
PriorityOutputCurrentLimiter(;
I_max=0,
ϕ_I=0,
ext=Dict{String, Any}(),
)
end
"""Get [`PriorityOutputCurrentLimiter`](@ref) `I_max`."""
get_I_max(value::PriorityOutputCurrentLimiter) = value.I_max
"""Get [`PriorityOutputCurrentLimiter`](@ref) `ϕ_I`."""
get_ϕ_I(value::PriorityOutputCurrentLimiter) = value.ϕ_I
"""Get [`PriorityOutputCurrentLimiter`](@ref) `ext`."""
get_ext(value::PriorityOutputCurrentLimiter) = value.ext
"""Set [`PriorityOutputCurrentLimiter`](@ref) `I_max`."""
set_I_max!(value::PriorityOutputCurrentLimiter, val) = value.I_max = val
"""Set [`PriorityOutputCurrentLimiter`](@ref) `ϕ_I`."""
set_ϕ_I!(value::PriorityOutputCurrentLimiter, val) = value.ϕ_I = val
"""Set [`PriorityOutputCurrentLimiter`](@ref) `ext`."""
set_ext!(value::PriorityOutputCurrentLimiter, val) = value.ext = val
================================================
FILE: src/models/generated/RECurrentControlB.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct RECurrentControlB <: InnerControl
Q_Flag::Int
PQ_Flag::Int
Vdip_lim::MinMax
T_rv::Float64
dbd_pnts::Tuple{Float64, Float64}
K_qv::Float64
Iqinj_lim::MinMax
V_ref0::Float64
K_vp::Float64
K_vi::Float64
T_iq::Float64
I_max::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of the Inner Control part of the REECB model in PSS/E
# Arguments
- `Q_Flag::Int`: Q Flag used for I_qinj, validation range: `(0, 1)`
- `PQ_Flag::Int`: PQ Flag used for the Current Limit Logic, validation range: `(0, 1)`
- `Vdip_lim::MinMax`: Limits for Voltage Dip Logic `(Vdip, Vup)`
- `T_rv::Float64`: Voltage Filter Time Constant, validation range: `(0, nothing)`
- `dbd_pnts::Tuple{Float64, Float64}`: Voltage error deadband thresholds `(dbd1, dbd2)`
- `K_qv::Float64`: Reactive current injection gain during over and undervoltage conditions, validation range: `(0, nothing)`
- `Iqinj_lim::MinMax`: Limits for Iqinj `(I_qh1, I_ql1)`
- `V_ref0::Float64`: User defined reference. If 0, [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/) initializes to initial terminal voltage, validation range: `(0, nothing)`
- `K_vp::Float64`: Voltage regulator proportional gain (used when QFlag = 1), validation range: `(0, nothing)`
- `K_vi::Float64`: Voltage regulator integral gain (used when QFlag = 1), validation range: `(0, nothing)`
- `T_iq::Float64`: Time constant for low-pass filter for state q_V when QFlag = 0, validation range: `(0, nothing)`
- `I_max::Float64`: Maximum limit on total converter current, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the RECurrentControlB depends on the Flags
- `n_states::Int`: (**Do not modify.**) The states of the RECurrentControlB depends on the Flags
"""
mutable struct RECurrentControlB <: InnerControl
"Q Flag used for I_qinj"
Q_Flag::Int
"PQ Flag used for the Current Limit Logic"
PQ_Flag::Int
"Limits for Voltage Dip Logic `(Vdip, Vup)`"
Vdip_lim::MinMax
"Voltage Filter Time Constant"
T_rv::Float64
"Voltage error deadband thresholds `(dbd1, dbd2)`"
dbd_pnts::Tuple{Float64, Float64}
"Reactive current injection gain during over and undervoltage conditions"
K_qv::Float64
"Limits for Iqinj `(I_qh1, I_ql1)`"
Iqinj_lim::MinMax
"User defined reference. If 0, [`PowerSimulationsDynamics.jl`](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/) initializes to initial terminal voltage"
V_ref0::Float64
"Voltage regulator proportional gain (used when QFlag = 1)"
K_vp::Float64
"Voltage regulator integral gain (used when QFlag = 1)"
K_vi::Float64
"Time constant for low-pass filter for state q_V when QFlag = 0"
T_iq::Float64
"Maximum limit on total converter current"
I_max::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the RECurrentControlB depends on the Flags"
states::Vector{Symbol}
"(**Do not modify.**) The states of the RECurrentControlB depends on the Flags"
n_states::Int
end
function RECurrentControlB(Q_Flag, PQ_Flag, Vdip_lim, T_rv, dbd_pnts, K_qv, Iqinj_lim, V_ref0, K_vp, K_vi, T_iq, I_max, ext=Dict{String, Any}(), )
RECurrentControlB(Q_Flag, PQ_Flag, Vdip_lim, T_rv, dbd_pnts, K_qv, Iqinj_lim, V_ref0, K_vp, K_vi, T_iq, I_max, ext, PowerSystems.get_REControlB_states(Q_Flag), 2, )
end
function RECurrentControlB(; Q_Flag, PQ_Flag, Vdip_lim, T_rv, dbd_pnts, K_qv, Iqinj_lim, V_ref0, K_vp, K_vi, T_iq, I_max, ext=Dict{String, Any}(), states=PowerSystems.get_REControlB_states(Q_Flag), n_states=2, )
RECurrentControlB(Q_Flag, PQ_Flag, Vdip_lim, T_rv, dbd_pnts, K_qv, Iqinj_lim, V_ref0, K_vp, K_vi, T_iq, I_max, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function RECurrentControlB(::Nothing)
RECurrentControlB(;
Q_Flag=0,
PQ_Flag=0,
Vdip_lim=(min=0.0, max=0.0),
T_rv=0,
dbd_pnts=(0.0, 0.0),
K_qv=0,
Iqinj_lim=(min=0.0, max=0.0),
V_ref0=0,
K_vp=0,
K_vi=0,
T_iq=0,
I_max=0,
ext=Dict{String, Any}(),
)
end
"""Get [`RECurrentControlB`](@ref) `Q_Flag`."""
get_Q_Flag(value::RECurrentControlB) = value.Q_Flag
"""Get [`RECurrentControlB`](@ref) `PQ_Flag`."""
get_PQ_Flag(value::RECurrentControlB) = value.PQ_Flag
"""Get [`RECurrentControlB`](@ref) `Vdip_lim`."""
get_Vdip_lim(value::RECurrentControlB) = value.Vdip_lim
"""Get [`RECurrentControlB`](@ref) `T_rv`."""
get_T_rv(value::RECurrentControlB) = value.T_rv
"""Get [`RECurrentControlB`](@ref) `dbd_pnts`."""
get_dbd_pnts(value::RECurrentControlB) = value.dbd_pnts
"""Get [`RECurrentControlB`](@ref) `K_qv`."""
get_K_qv(value::RECurrentControlB) = value.K_qv
"""Get [`RECurrentControlB`](@ref) `Iqinj_lim`."""
get_Iqinj_lim(value::RECurrentControlB) = value.Iqinj_lim
"""Get [`RECurrentControlB`](@ref) `V_ref0`."""
get_V_ref0(value::RECurrentControlB) = value.V_ref0
"""Get [`RECurrentControlB`](@ref) `K_vp`."""
get_K_vp(value::RECurrentControlB) = value.K_vp
"""Get [`RECurrentControlB`](@ref) `K_vi`."""
get_K_vi(value::RECurrentControlB) = value.K_vi
"""Get [`RECurrentControlB`](@ref) `T_iq`."""
get_T_iq(value::RECurrentControlB) = value.T_iq
"""Get [`RECurrentControlB`](@ref) `I_max`."""
get_I_max(value::RECurrentControlB) = value.I_max
"""Get [`RECurrentControlB`](@ref) `ext`."""
get_ext(value::RECurrentControlB) = value.ext
"""Get [`RECurrentControlB`](@ref) `states`."""
get_states(value::RECurrentControlB) = value.states
"""Get [`RECurrentControlB`](@ref) `n_states`."""
get_n_states(value::RECurrentControlB) = value.n_states
"""Set [`RECurrentControlB`](@ref) `Q_Flag`."""
set_Q_Flag!(value::RECurrentControlB, val) = value.Q_Flag = val
"""Set [`RECurrentControlB`](@ref) `PQ_Flag`."""
set_PQ_Flag!(value::RECurrentControlB, val) = value.PQ_Flag = val
"""Set [`RECurrentControlB`](@ref) `Vdip_lim`."""
set_Vdip_lim!(value::RECurrentControlB, val) = value.Vdip_lim = val
"""Set [`RECurrentControlB`](@ref) `T_rv`."""
set_T_rv!(value::RECurrentControlB, val) = value.T_rv = val
"""Set [`RECurrentControlB`](@ref) `dbd_pnts`."""
set_dbd_pnts!(value::RECurrentControlB, val) = value.dbd_pnts = val
"""Set [`RECurrentControlB`](@ref) `K_qv`."""
set_K_qv!(value::RECurrentControlB, val) = value.K_qv = val
"""Set [`RECurrentControlB`](@ref) `Iqinj_lim`."""
set_Iqinj_lim!(value::RECurrentControlB, val) = value.Iqinj_lim = val
"""Set [`RECurrentControlB`](@ref) `V_ref0`."""
set_V_ref0!(value::RECurrentControlB, val) = value.V_ref0 = val
"""Set [`RECurrentControlB`](@ref) `K_vp`."""
set_K_vp!(value::RECurrentControlB, val) = value.K_vp = val
"""Set [`RECurrentControlB`](@ref) `K_vi`."""
set_K_vi!(value::RECurrentControlB, val) = value.K_vi = val
"""Set [`RECurrentControlB`](@ref) `T_iq`."""
set_T_iq!(value::RECurrentControlB, val) = value.T_iq = val
"""Set [`RECurrentControlB`](@ref) `I_max`."""
set_I_max!(value::RECurrentControlB, val) = value.I_max = val
"""Set [`RECurrentControlB`](@ref) `ext`."""
set_ext!(value::RECurrentControlB, val) = value.ext = val
================================================
FILE: src/models/generated/RLFilter.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct RLFilter <: Filter
rf::Float64
lf::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of RL series filter in algebraic representation
# Arguments
- `rf::Float64`: Series resistance in p.u. of converter filter to the grid, validation range: `(0, nothing)`
- `lf::Float64`: Series inductance in p.u. of converter filter to the grid, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) RLFilter has zero [states](@ref S)
- `n_states::Int`: (**Do not modify.**) RLFilter has zero states
"""
mutable struct RLFilter <: Filter
"Series resistance in p.u. of converter filter to the grid"
rf::Float64
"Series inductance in p.u. of converter filter to the grid"
lf::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) RLFilter has zero [states](@ref S)"
states::Vector{Symbol}
"(**Do not modify.**) RLFilter has zero states"
n_states::Int
end
function RLFilter(rf, lf, ext=Dict{String, Any}(), )
RLFilter(rf, lf, ext, Vector{Symbol}(), 0, )
end
function RLFilter(; rf, lf, ext=Dict{String, Any}(), states=Vector{Symbol}(), n_states=0, )
RLFilter(rf, lf, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function RLFilter(::Nothing)
RLFilter(;
rf=0,
lf=0,
ext=Dict{String, Any}(),
)
end
"""Get [`RLFilter`](@ref) `rf`."""
get_rf(value::RLFilter) = value.rf
"""Get [`RLFilter`](@ref) `lf`."""
get_lf(value::RLFilter) = value.lf
"""Get [`RLFilter`](@ref) `ext`."""
get_ext(value::RLFilter) = value.ext
"""Get [`RLFilter`](@ref) `states`."""
get_states(value::RLFilter) = value.states
"""Get [`RLFilter`](@ref) `n_states`."""
get_n_states(value::RLFilter) = value.n_states
"""Set [`RLFilter`](@ref) `rf`."""
set_rf!(value::RLFilter, val) = value.rf = val
"""Set [`RLFilter`](@ref) `lf`."""
set_lf!(value::RLFilter, val) = value.lf = val
"""Set [`RLFilter`](@ref) `ext`."""
set_ext!(value::RLFilter, val) = value.ext = val
================================================
FILE: src/models/generated/ReactivePowerDroop.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ReactivePowerDroop <: ReactivePowerControl
kq::Float64
ωf::Float64
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a Reactive Power droop controller
# Arguments
- `kq::Float64`: frequency droop gain, validation range: `(0, nothing)`
- `ωf::Float64`: filter frequency cutoff, validation range: `(0, nothing)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the ReactivePowerDroop model are:
q_oc: Filtered reactive output power
- `n_states::Int`: (**Do not modify.**) ReactivePowerDroop has 1 state
"""
mutable struct ReactivePowerDroop <: ReactivePowerControl
"frequency droop gain"
kq::Float64
"filter frequency cutoff"
ωf::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the ReactivePowerDroop model are:
q_oc: Filtered reactive output power"
states::Vector{Symbol}
"(**Do not modify.**) ReactivePowerDroop has 1 state"
n_states::Int
end
function ReactivePowerDroop(kq, ωf, V_ref=1.0, ext=Dict{String, Any}(), )
ReactivePowerDroop(kq, ωf, V_ref, ext, [:q_oc], 1, )
end
function ReactivePowerDroop(; kq, ωf, V_ref=1.0, ext=Dict{String, Any}(), states=[:q_oc], n_states=1, )
ReactivePowerDroop(kq, ωf, V_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function ReactivePowerDroop(::Nothing)
ReactivePowerDroop(;
kq=0,
ωf=0,
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ReactivePowerDroop`](@ref) `kq`."""
get_kq(value::ReactivePowerDroop) = value.kq
"""Get [`ReactivePowerDroop`](@ref) `ωf`."""
get_ωf(value::ReactivePowerDroop) = value.ωf
"""Get [`ReactivePowerDroop`](@ref) `V_ref`."""
get_V_ref(value::ReactivePowerDroop) = value.V_ref
"""Get [`ReactivePowerDroop`](@ref) `ext`."""
get_ext(value::ReactivePowerDroop) = value.ext
"""Get [`ReactivePowerDroop`](@ref) `states`."""
get_states(value::ReactivePowerDroop) = value.states
"""Get [`ReactivePowerDroop`](@ref) `n_states`."""
get_n_states(value::ReactivePowerDroop) = value.n_states
"""Set [`ReactivePowerDroop`](@ref) `kq`."""
set_kq!(value::ReactivePowerDroop, val) = value.kq = val
"""Set [`ReactivePowerDroop`](@ref) `ωf`."""
set_ωf!(value::ReactivePowerDroop, val) = value.ωf = val
"""Set [`ReactivePowerDroop`](@ref) `V_ref`."""
set_V_ref!(value::ReactivePowerDroop, val) = value.V_ref = val
"""Set [`ReactivePowerDroop`](@ref) `ext`."""
set_ext!(value::ReactivePowerDroop, val) = value.ext = val
================================================
FILE: src/models/generated/ReactivePowerPI.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ReactivePowerPI <: ReactivePowerControl
Kp_q::Float64
Ki_q::Float64
ωf::Float64
V_ref::Float64
Q_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a Proportional-Integral Reactive Power controller for a specified power reference
# Arguments
- `Kp_q::Float64`: Proportional Gain, validation range: `(0, nothing)`
- `Ki_q::Float64`: Integral Gain, validation range: `(0, nothing)`
- `ωf::Float64`: filter frequency cutoff, validation range: `(0, nothing)`
- `V_ref::Float64`: (default: `1.0`) Voltage Set-point (pu), validation range: `(0, nothing)`
- `Q_ref::Float64`: (default: `1.0`) Reactive Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the ReactivePowerPI model are:
σq_oc: Integrator state of the PI Controller,
q_oc: Measured reactive power of the inverter model
- `n_states::Int`: (**Do not modify.**) ReactivePowerPI has two states
"""
mutable struct ReactivePowerPI <: ReactivePowerControl
"Proportional Gain"
Kp_q::Float64
"Integral Gain"
Ki_q::Float64
"filter frequency cutoff"
ωf::Float64
"Voltage Set-point (pu)"
V_ref::Float64
"Reactive Power Set-point (pu)"
Q_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the ReactivePowerPI model are:
σq_oc: Integrator state of the PI Controller,
q_oc: Measured reactive power of the inverter model"
states::Vector{Symbol}
"(**Do not modify.**) ReactivePowerPI has two states"
n_states::Int
end
function ReactivePowerPI(Kp_q, Ki_q, ωf, V_ref=1.0, Q_ref=1.0, ext=Dict{String, Any}(), )
ReactivePowerPI(Kp_q, Ki_q, ωf, V_ref, Q_ref, ext, [:σq_oc, :q_oc], 2, )
end
function ReactivePowerPI(; Kp_q, Ki_q, ωf, V_ref=1.0, Q_ref=1.0, ext=Dict{String, Any}(), states=[:σq_oc, :q_oc], n_states=2, )
ReactivePowerPI(Kp_q, Ki_q, ωf, V_ref, Q_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function ReactivePowerPI(::Nothing)
ReactivePowerPI(;
Kp_q=0,
Ki_q=0,
ωf=0,
V_ref=0,
Q_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ReactivePowerPI`](@ref) `Kp_q`."""
get_Kp_q(value::ReactivePowerPI) = value.Kp_q
"""Get [`ReactivePowerPI`](@ref) `Ki_q`."""
get_Ki_q(value::ReactivePowerPI) = value.Ki_q
"""Get [`ReactivePowerPI`](@ref) `ωf`."""
get_ωf(value::ReactivePowerPI) = value.ωf
"""Get [`ReactivePowerPI`](@ref) `V_ref`."""
get_V_ref(value::ReactivePowerPI) = value.V_ref
"""Get [`ReactivePowerPI`](@ref) `Q_ref`."""
get_Q_ref(value::ReactivePowerPI) = value.Q_ref
"""Get [`ReactivePowerPI`](@ref) `ext`."""
get_ext(value::ReactivePowerPI) = value.ext
"""Get [`ReactivePowerPI`](@ref) `states`."""
get_states(value::ReactivePowerPI) = value.states
"""Get [`ReactivePowerPI`](@ref) `n_states`."""
get_n_states(value::ReactivePowerPI) = value.n_states
"""Set [`ReactivePowerPI`](@ref) `Kp_q`."""
set_Kp_q!(value::ReactivePowerPI, val) = value.Kp_q = val
"""Set [`ReactivePowerPI`](@ref) `Ki_q`."""
set_Ki_q!(value::ReactivePowerPI, val) = value.Ki_q = val
"""Set [`ReactivePowerPI`](@ref) `ωf`."""
set_ωf!(value::ReactivePowerPI, val) = value.ωf = val
"""Set [`ReactivePowerPI`](@ref) `V_ref`."""
set_V_ref!(value::ReactivePowerPI, val) = value.V_ref = val
"""Set [`ReactivePowerPI`](@ref) `Q_ref`."""
set_Q_ref!(value::ReactivePowerPI, val) = value.Q_ref = val
"""Set [`ReactivePowerPI`](@ref) `ext`."""
set_ext!(value::ReactivePowerPI, val) = value.ext = val
================================================
FILE: src/models/generated/ReactiveRenewableControllerAB.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ReactiveRenewableControllerAB <: ReactivePowerControl
bus_control::Int
from_branch_control::Int
to_branch_control::Int
branch_id_control::String
VC_Flag::Int
Ref_Flag::Int
PF_Flag::Int
V_Flag::Int
T_fltr::Float64
K_p::Float64
K_i::Float64
T_ft::Float64
T_fv::Float64
V_frz::Float64
R_c::Float64
X_c::Float64
K_c::Float64
e_lim::MinMax
dbd_pnts::Tuple{Float64, Float64}
Q_lim::MinMax
T_p::Float64
Q_lim_inner::MinMax
V_lim::MinMax
K_qp::Float64
K_qi::Float64
Q_ref::Float64
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of Reactive Power Controller including REPCA1 and REECB1
# Arguments
- `bus_control::Int`: ACBus identification [`number`](@ref ACBus) for voltage control. `0` identifies the local bus connected to this component, validation range: `(0, nothing)`
- `from_branch_control::Int`: Monitored branch FROM bus identification number for line drop compensation (if 0 generator power will be used), validation range: `(0, nothing)`
- `to_branch_control::Int`: Monitored branch TO bus identification number for line drop compensation (if 0 generator power will be used), validation range: `(0, nothing)`
- `branch_id_control::String`: Branch circuit id for line drop compensation (as a string). If 0 generator power will be used
- `VC_Flag::Int`: Voltage Compensator Flag for REPCA1, validation range: `(0, 1)`
- `Ref_Flag::Int`: Flag for Reactive Power Control for REPCA1. 0: Q-control, 1: V-control, validation range: `(0, 1)`
- `PF_Flag::Int`: Flag for Power Factor Control for Outer Control of REECB1. 0: Q-control, 1: Power Factor Control, validation range: `(0, 1)`
- `V_Flag::Int`: Flag for Voltage Control for Outer Control of REECB1. 0: Voltage Control, 1: Q-Control, validation range: `(0, 1)`
- `T_fltr::Float64`: Voltage or Q-power of REPCA Filter Time Constant, validation range: `(0, nothing)`
- `K_p::Float64`: Reactive power PI control proportional gain, validation range: `(0, nothing)`
- `K_i::Float64`: Reactive power PI control integral gain, validation range: `(0, nothing)`
- `T_ft::Float64`: Reactive power lead time constant (s), validation range: `(0, nothing)`
- `T_fv::Float64`: Reactive power lag time constant (s), validation range: `(0, nothing)`
- `V_frz::Float64`: Voltage below which state ξq_oc (integrator state) is freeze, validation range: `(0, nothing)`
- `R_c::Float64`: Line drop compensation resistance (used when VC_Flag = 1), validation range: `(0, nothing)`
- `X_c::Float64`: Line drop compensation reactance (used when VC_Flag = 1), validation range: `(0, nothing)`
- `K_c::Float64`: Reactive current compensation gain (pu) (used when VC_Flag = 0), validation range: `(0, nothing)`
- `e_lim::MinMax`: Upper/Lower limit on Voltage or Q-power deadband output `(e_min, e_max)`
- `dbd_pnts::Tuple{Float64, Float64}`: Voltage or Q-power error dead band thresholds `(dbd1, dbd2)`
- `Q_lim::MinMax`: Upper/Lower limit on reactive power V/Q control in REPCA `(Q_min, Q_max)`
- `T_p::Float64`: Active power lag time constant in REECB (s). Used only when PF_Flag = 1, validation range: `(0, nothing)`
- `Q_lim_inner::MinMax`: Upper/Lower limit on reactive power input in REECB `(Q_min_inner, Q_max_inner)`. Only used when V_Flag = 1
- `V_lim::MinMax`: Upper/Lower limit on reactive power PI controller in REECB `(V_min, V_max)`. Only used when V_Flag = 1
- `K_qp::Float64`: Reactive power regulator proportional gain (used when V_Flag = 1), validation range: `(0, nothing)`
- `K_qi::Float64`: Reactive power regulator integral gain (used when V_Flag = 1), validation range: `(0, nothing)`
- `Q_ref::Float64`: (default: `1.0`) Reference Reactive Power Set-point (pu), validation range: `(0, nothing)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the ReactiveRenewableControllerAB model depends on the Flag
- `n_states::Int`: (**Do not modify.**) The states of the ReactiveRenewableControllerAB model depends on the Flag
"""
mutable struct ReactiveRenewableControllerAB <: ReactivePowerControl
"ACBus identification [`number`](@ref ACBus) for voltage control. `0` identifies the local bus connected to this component"
bus_control::Int
"Monitored branch FROM bus identification number for line drop compensation (if 0 generator power will be used)"
from_branch_control::Int
"Monitored branch TO bus identification number for line drop compensation (if 0 generator power will be used)"
to_branch_control::Int
"Branch circuit id for line drop compensation (as a string). If 0 generator power will be used"
branch_id_control::String
"Voltage Compensator Flag for REPCA1"
VC_Flag::Int
"Flag for Reactive Power Control for REPCA1. 0: Q-control, 1: V-control"
Ref_Flag::Int
"Flag for Power Factor Control for Outer Control of REECB1. 0: Q-control, 1: Power Factor Control"
PF_Flag::Int
"Flag for Voltage Control for Outer Control of REECB1. 0: Voltage Control, 1: Q-Control"
V_Flag::Int
"Voltage or Q-power of REPCA Filter Time Constant"
T_fltr::Float64
"Reactive power PI control proportional gain"
K_p::Float64
"Reactive power PI control integral gain"
K_i::Float64
"Reactive power lead time constant (s)"
T_ft::Float64
"Reactive power lag time constant (s)"
T_fv::Float64
"Voltage below which state ξq_oc (integrator state) is freeze"
V_frz::Float64
"Line drop compensation resistance (used when VC_Flag = 1)"
R_c::Float64
"Line drop compensation reactance (used when VC_Flag = 1)"
X_c::Float64
"Reactive current compensation gain (pu) (used when VC_Flag = 0)"
K_c::Float64
"Upper/Lower limit on Voltage or Q-power deadband output `(e_min, e_max)`"
e_lim::MinMax
"Voltage or Q-power error dead band thresholds `(dbd1, dbd2)`"
dbd_pnts::Tuple{Float64, Float64}
"Upper/Lower limit on reactive power V/Q control in REPCA `(Q_min, Q_max)`"
Q_lim::MinMax
"Active power lag time constant in REECB (s). Used only when PF_Flag = 1"
T_p::Float64
"Upper/Lower limit on reactive power input in REECB `(Q_min_inner, Q_max_inner)`. Only used when V_Flag = 1"
Q_lim_inner::MinMax
"Upper/Lower limit on reactive power PI controller in REECB `(V_min, V_max)`. Only used when V_Flag = 1"
V_lim::MinMax
"Reactive power regulator proportional gain (used when V_Flag = 1)"
K_qp::Float64
"Reactive power regulator integral gain (used when V_Flag = 1)"
K_qi::Float64
"Reference Reactive Power Set-point (pu)"
Q_ref::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the ReactiveRenewableControllerAB model depends on the Flag"
states::Vector{Symbol}
"(**Do not modify.**) The states of the ReactiveRenewableControllerAB model depends on the Flag"
n_states::Int
end
function ReactiveRenewableControllerAB(bus_control, from_branch_control, to_branch_control, branch_id_control, VC_Flag, Ref_Flag, PF_Flag, V_Flag, T_fltr, K_p, K_i, T_ft, T_fv, V_frz, R_c, X_c, K_c, e_lim, dbd_pnts, Q_lim, T_p, Q_lim_inner, V_lim, K_qp, K_qi, Q_ref=1.0, V_ref=1.0, ext=Dict{String, Any}(), )
ReactiveRenewableControllerAB(bus_control, from_branch_control, to_branch_control, branch_id_control, VC_Flag, Ref_Flag, PF_Flag, V_Flag, T_fltr, K_p, K_i, T_ft, T_fv, V_frz, R_c, X_c, K_c, e_lim, dbd_pnts, Q_lim, T_p, Q_lim_inner, V_lim, K_qp, K_qi, Q_ref, V_ref, ext, PowerSystems.get_reactiveRETypeAB_states(Ref_Flag, PF_Flag, V_Flag)[1], PowerSystems.get_reactiveRETypeAB_states(Ref_Flag, PF_Flag, V_Flag)[2], )
end
function ReactiveRenewableControllerAB(; bus_control, from_branch_control, to_branch_control, branch_id_control, VC_Flag, Ref_Flag, PF_Flag, V_Flag, T_fltr, K_p, K_i, T_ft, T_fv, V_frz, R_c, X_c, K_c, e_lim, dbd_pnts, Q_lim, T_p, Q_lim_inner, V_lim, K_qp, K_qi, Q_ref=1.0, V_ref=1.0, ext=Dict{String, Any}(), states=PowerSystems.get_reactiveRETypeAB_states(Ref_Flag, PF_Flag, V_Flag)[1], n_states=PowerSystems.get_reactiveRETypeAB_states(Ref_Flag, PF_Flag, V_Flag)[2], )
ReactiveRenewableControllerAB(bus_control, from_branch_control, to_branch_control, branch_id_control, VC_Flag, Ref_Flag, PF_Flag, V_Flag, T_fltr, K_p, K_i, T_ft, T_fv, V_frz, R_c, X_c, K_c, e_lim, dbd_pnts, Q_lim, T_p, Q_lim_inner, V_lim, K_qp, K_qi, Q_ref, V_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function ReactiveRenewableControllerAB(::Nothing)
ReactiveRenewableControllerAB(;
bus_control=0,
from_branch_control=0,
to_branch_control=0,
branch_id_control="0",
VC_Flag=0,
Ref_Flag=0,
PF_Flag=0,
V_Flag=0,
T_fltr=0,
K_p=0,
K_i=0,
T_ft=0,
T_fv=0,
V_frz=0,
R_c=0,
X_c=0,
K_c=0,
e_lim=(min=0.0, max=0.0),
dbd_pnts=(0.0, 0.0),
Q_lim=(min=0.0, max=0.0),
T_p=0,
Q_lim_inner=(min=0.0, max=0.0),
V_lim=(min=0.0, max=0.0),
K_qp=0,
K_qi=0,
Q_ref=0,
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ReactiveRenewableControllerAB`](@ref) `bus_control`."""
get_bus_control(value::ReactiveRenewableControllerAB) = value.bus_control
"""Get [`ReactiveRenewableControllerAB`](@ref) `from_branch_control`."""
get_from_branch_control(value::ReactiveRenewableControllerAB) = value.from_branch_control
"""Get [`ReactiveRenewableControllerAB`](@ref) `to_branch_control`."""
get_to_branch_control(value::ReactiveRenewableControllerAB) = value.to_branch_control
"""Get [`ReactiveRenewableControllerAB`](@ref) `branch_id_control`."""
get_branch_id_control(value::ReactiveRenewableControllerAB) = value.branch_id_control
"""Get [`ReactiveRenewableControllerAB`](@ref) `VC_Flag`."""
get_VC_Flag(value::ReactiveRenewableControllerAB) = value.VC_Flag
"""Get [`ReactiveRenewableControllerAB`](@ref) `Ref_Flag`."""
get_Ref_Flag(value::ReactiveRenewableControllerAB) = value.Ref_Flag
"""Get [`ReactiveRenewableControllerAB`](@ref) `PF_Flag`."""
get_PF_Flag(value::ReactiveRenewableControllerAB) = value.PF_Flag
"""Get [`ReactiveRenewableControllerAB`](@ref) `V_Flag`."""
get_V_Flag(value::ReactiveRenewableControllerAB) = value.V_Flag
"""Get [`ReactiveRenewableControllerAB`](@ref) `T_fltr`."""
get_T_fltr(value::ReactiveRenewableControllerAB) = value.T_fltr
"""Get [`ReactiveRenewableControllerAB`](@ref) `K_p`."""
get_K_p(value::ReactiveRenewableControllerAB) = value.K_p
"""Get [`ReactiveRenewableControllerAB`](@ref) `K_i`."""
get_K_i(value::ReactiveRenewableControllerAB) = value.K_i
"""Get [`ReactiveRenewableControllerAB`](@ref) `T_ft`."""
get_T_ft(value::ReactiveRenewableControllerAB) = value.T_ft
"""Get [`ReactiveRenewableControllerAB`](@ref) `T_fv`."""
get_T_fv(value::ReactiveRenewableControllerAB) = value.T_fv
"""Get [`ReactiveRenewableControllerAB`](@ref) `V_frz`."""
get_V_frz(value::ReactiveRenewableControllerAB) = value.V_frz
"""Get [`ReactiveRenewableControllerAB`](@ref) `R_c`."""
get_R_c(value::ReactiveRenewableControllerAB) = value.R_c
"""Get [`ReactiveRenewableControllerAB`](@ref) `X_c`."""
get_X_c(value::ReactiveRenewableControllerAB) = value.X_c
"""Get [`ReactiveRenewableControllerAB`](@ref) `K_c`."""
get_K_c(value::ReactiveRenewableControllerAB) = value.K_c
"""Get [`ReactiveRenewableControllerAB`](@ref) `e_lim`."""
get_e_lim(value::ReactiveRenewableControllerAB) = value.e_lim
"""Get [`ReactiveRenewableControllerAB`](@ref) `dbd_pnts`."""
get_dbd_pnts(value::ReactiveRenewableControllerAB) = value.dbd_pnts
"""Get [`ReactiveRenewableControllerAB`](@ref) `Q_lim`."""
get_Q_lim(value::ReactiveRenewableControllerAB) = value.Q_lim
"""Get [`ReactiveRenewableControllerAB`](@ref) `T_p`."""
get_T_p(value::ReactiveRenewableControllerAB) = value.T_p
"""Get [`ReactiveRenewableControllerAB`](@ref) `Q_lim_inner`."""
get_Q_lim_inner(value::ReactiveRenewableControllerAB) = value.Q_lim_inner
"""Get [`ReactiveRenewableControllerAB`](@ref) `V_lim`."""
get_V_lim(value::ReactiveRenewableControllerAB) = value.V_lim
"""Get [`ReactiveRenewableControllerAB`](@ref) `K_qp`."""
get_K_qp(value::ReactiveRenewableControllerAB) = value.K_qp
"""Get [`ReactiveRenewableControllerAB`](@ref) `K_qi`."""
get_K_qi(value::ReactiveRenewableControllerAB) = value.K_qi
"""Get [`ReactiveRenewableControllerAB`](@ref) `Q_ref`."""
get_Q_ref(value::ReactiveRenewableControllerAB) = value.Q_ref
"""Get [`ReactiveRenewableControllerAB`](@ref) `V_ref`."""
get_V_ref(value::ReactiveRenewableControllerAB) = value.V_ref
"""Get [`ReactiveRenewableControllerAB`](@ref) `ext`."""
get_ext(value::ReactiveRenewableControllerAB) = value.ext
"""Get [`ReactiveRenewableControllerAB`](@ref) `states`."""
get_states(value::ReactiveRenewableControllerAB) = value.states
"""Get [`ReactiveRenewableControllerAB`](@ref) `n_states`."""
get_n_states(value::ReactiveRenewableControllerAB) = value.n_states
"""Set [`ReactiveRenewableControllerAB`](@ref) `bus_control`."""
set_bus_control!(value::ReactiveRenewableControllerAB, val) = value.bus_control = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `from_branch_control`."""
set_from_branch_control!(value::ReactiveRenewableControllerAB, val) = value.from_branch_control = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `to_branch_control`."""
set_to_branch_control!(value::ReactiveRenewableControllerAB, val) = value.to_branch_control = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `branch_id_control`."""
set_branch_id_control!(value::ReactiveRenewableControllerAB, val) = value.branch_id_control = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `VC_Flag`."""
set_VC_Flag!(value::ReactiveRenewableControllerAB, val) = value.VC_Flag = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `Ref_Flag`."""
set_Ref_Flag!(value::ReactiveRenewableControllerAB, val) = value.Ref_Flag = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `PF_Flag`."""
set_PF_Flag!(value::ReactiveRenewableControllerAB, val) = value.PF_Flag = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `V_Flag`."""
set_V_Flag!(value::ReactiveRenewableControllerAB, val) = value.V_Flag = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `T_fltr`."""
set_T_fltr!(value::ReactiveRenewableControllerAB, val) = value.T_fltr = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `K_p`."""
set_K_p!(value::ReactiveRenewableControllerAB, val) = value.K_p = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `K_i`."""
set_K_i!(value::ReactiveRenewableControllerAB, val) = value.K_i = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `T_ft`."""
set_T_ft!(value::ReactiveRenewableControllerAB, val) = value.T_ft = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `T_fv`."""
set_T_fv!(value::ReactiveRenewableControllerAB, val) = value.T_fv = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `V_frz`."""
set_V_frz!(value::ReactiveRenewableControllerAB, val) = value.V_frz = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `R_c`."""
set_R_c!(value::ReactiveRenewableControllerAB, val) = value.R_c = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `X_c`."""
set_X_c!(value::ReactiveRenewableControllerAB, val) = value.X_c = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `K_c`."""
set_K_c!(value::ReactiveRenewableControllerAB, val) = value.K_c = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `e_lim`."""
set_e_lim!(value::ReactiveRenewableControllerAB, val) = value.e_lim = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `dbd_pnts`."""
set_dbd_pnts!(value::ReactiveRenewableControllerAB, val) = value.dbd_pnts = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `Q_lim`."""
set_Q_lim!(value::ReactiveRenewableControllerAB, val) = value.Q_lim = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `T_p`."""
set_T_p!(value::ReactiveRenewableControllerAB, val) = value.T_p = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `Q_lim_inner`."""
set_Q_lim_inner!(value::ReactiveRenewableControllerAB, val) = value.Q_lim_inner = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `V_lim`."""
set_V_lim!(value::ReactiveRenewableControllerAB, val) = value.V_lim = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `K_qp`."""
set_K_qp!(value::ReactiveRenewableControllerAB, val) = value.K_qp = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `K_qi`."""
set_K_qi!(value::ReactiveRenewableControllerAB, val) = value.K_qi = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `Q_ref`."""
set_Q_ref!(value::ReactiveRenewableControllerAB, val) = value.Q_ref = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `V_ref`."""
set_V_ref!(value::ReactiveRenewableControllerAB, val) = value.V_ref = val
"""Set [`ReactiveRenewableControllerAB`](@ref) `ext`."""
set_ext!(value::ReactiveRenewableControllerAB, val) = value.ext = val
================================================
FILE: src/models/generated/ReactiveVirtualOscillator.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ReactiveVirtualOscillator <: ReactivePowerControl
k2::Float64
V_ref::Float64
Q_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a Reactive Virtual Oscillator controller. Model is based on ["Model Reduction for Inverters with Current Limiting and Dispatchable Virtual Oscillator Control."](https://doi.org/10.1109/TEC.2021.3083488)
# Arguments
- `k2::Float64`: VOC voltage-amplitude control gain, validation range: `(0, nothing)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `Q_ref::Float64`: (default: `1.0`) Reference Reactive Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the ReactiveVirtualOscilator model are:
E_oc: voltage reference state for inner control in the d-axis
- `n_states::Int`: (**Do not modify.**) ReactiveVirtualOscillator has 1 state
"""
mutable struct ReactiveVirtualOscillator <: ReactivePowerControl
"VOC voltage-amplitude control gain"
k2::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"Reference Reactive Power Set-point (pu)"
Q_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the ReactiveVirtualOscilator model are:
E_oc: voltage reference state for inner control in the d-axis"
states::Vector{Symbol}
"(**Do not modify.**) ReactiveVirtualOscillator has 1 state"
n_states::Int
end
function ReactiveVirtualOscillator(k2, V_ref=1.0, Q_ref=1.0, ext=Dict{String, Any}(), )
ReactiveVirtualOscillator(k2, V_ref, Q_ref, ext, [:E_oc], 1, )
end
function ReactiveVirtualOscillator(; k2, V_ref=1.0, Q_ref=1.0, ext=Dict{String, Any}(), states=[:E_oc], n_states=1, )
ReactiveVirtualOscillator(k2, V_ref, Q_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function ReactiveVirtualOscillator(::Nothing)
ReactiveVirtualOscillator(;
k2=0,
V_ref=0,
Q_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ReactiveVirtualOscillator`](@ref) `k2`."""
get_k2(value::ReactiveVirtualOscillator) = value.k2
"""Get [`ReactiveVirtualOscillator`](@ref) `V_ref`."""
get_V_ref(value::ReactiveVirtualOscillator) = value.V_ref
"""Get [`ReactiveVirtualOscillator`](@ref) `Q_ref`."""
get_Q_ref(value::ReactiveVirtualOscillator) = value.Q_ref
"""Get [`ReactiveVirtualOscillator`](@ref) `ext`."""
get_ext(value::ReactiveVirtualOscillator) = value.ext
"""Get [`ReactiveVirtualOscillator`](@ref) `states`."""
get_states(value::ReactiveVirtualOscillator) = value.states
"""Get [`ReactiveVirtualOscillator`](@ref) `n_states`."""
get_n_states(value::ReactiveVirtualOscillator) = value.n_states
"""Set [`ReactiveVirtualOscillator`](@ref) `k2`."""
set_k2!(value::ReactiveVirtualOscillator, val) = value.k2 = val
"""Set [`ReactiveVirtualOscillator`](@ref) `V_ref`."""
set_V_ref!(value::ReactiveVirtualOscillator, val) = value.V_ref = val
"""Set [`ReactiveVirtualOscillator`](@ref) `Q_ref`."""
set_Q_ref!(value::ReactiveVirtualOscillator, val) = value.Q_ref = val
"""Set [`ReactiveVirtualOscillator`](@ref) `ext`."""
set_ext!(value::ReactiveVirtualOscillator, val) = value.ext = val
================================================
FILE: src/models/generated/ReducedOrderPLL.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ReducedOrderPLL <: FrequencyEstimator
ω_lp::Float64
kp_pll::Float64
ki_pll::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a Phase-Locked Loop (PLL) based on ["Reduced-order Structure-preserving Model for Parallel-connected Three-phase Grid-tied Inverters."](https://doi.org/10.1109/COMPEL.2017.8013389)
# Arguments
- `ω_lp::Float64`: PLL low-pass filter frequency (rad/sec), validation range: `(0, nothing)`
- `kp_pll::Float64`: PLL proportional gain, validation range: `(0, nothing)`
- `ki_pll::Float64`: PLL integral gain, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the ReducedOrderPLL model are:
vq_pll: q-axis of the measured voltage in the PLL synchronous reference frame (SRF),
ε_pll: Integrator state of the PI controller,
θ_pll: Phase angle displacement in the PLL SRF
- `n_states::Int`: (**Do not modify.**) ReducedOrderPLL has 3 states
"""
mutable struct ReducedOrderPLL <: FrequencyEstimator
"PLL low-pass filter frequency (rad/sec)"
ω_lp::Float64
"PLL proportional gain"
kp_pll::Float64
"PLL integral gain"
ki_pll::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the ReducedOrderPLL model are:
vq_pll: q-axis of the measured voltage in the PLL synchronous reference frame (SRF),
ε_pll: Integrator state of the PI controller,
θ_pll: Phase angle displacement in the PLL SRF"
states::Vector{Symbol}
"(**Do not modify.**) ReducedOrderPLL has 3 states"
n_states::Int
end
function ReducedOrderPLL(ω_lp, kp_pll, ki_pll, ext=Dict{String, Any}(), )
ReducedOrderPLL(ω_lp, kp_pll, ki_pll, ext, [:vq_pll, :ε_pll, :θ_pll], 3, )
end
function ReducedOrderPLL(; ω_lp, kp_pll, ki_pll, ext=Dict{String, Any}(), states=[:vq_pll, :ε_pll, :θ_pll], n_states=3, )
ReducedOrderPLL(ω_lp, kp_pll, ki_pll, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function ReducedOrderPLL(::Nothing)
ReducedOrderPLL(;
ω_lp=0,
kp_pll=0,
ki_pll=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ReducedOrderPLL`](@ref) `ω_lp`."""
get_ω_lp(value::ReducedOrderPLL) = value.ω_lp
"""Get [`ReducedOrderPLL`](@ref) `kp_pll`."""
get_kp_pll(value::ReducedOrderPLL) = value.kp_pll
"""Get [`ReducedOrderPLL`](@ref) `ki_pll`."""
get_ki_pll(value::ReducedOrderPLL) = value.ki_pll
"""Get [`ReducedOrderPLL`](@ref) `ext`."""
get_ext(value::ReducedOrderPLL) = value.ext
"""Get [`ReducedOrderPLL`](@ref) `states`."""
get_states(value::ReducedOrderPLL) = value.states
"""Get [`ReducedOrderPLL`](@ref) `n_states`."""
get_n_states(value::ReducedOrderPLL) = value.n_states
"""Set [`ReducedOrderPLL`](@ref) `ω_lp`."""
set_ω_lp!(value::ReducedOrderPLL, val) = value.ω_lp = val
"""Set [`ReducedOrderPLL`](@ref) `kp_pll`."""
set_kp_pll!(value::ReducedOrderPLL, val) = value.kp_pll = val
"""Set [`ReducedOrderPLL`](@ref) `ki_pll`."""
set_ki_pll!(value::ReducedOrderPLL, val) = value.ki_pll = val
"""Set [`ReducedOrderPLL`](@ref) `ext`."""
set_ext!(value::ReducedOrderPLL, val) = value.ext = val
================================================
FILE: src/models/generated/RenewableDispatch.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct RenewableDispatch <: RenewableGen
name::String
available::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
rating::Float64
prime_mover_type::PrimeMovers
reactive_power_limits::Union{Nothing, MinMax}
power_factor::Float64
operation_cost::Union{RenewableGenerationCost, MarketBidCost}
base_power::Float64
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A renewable (e.g., wind or solar) generator whose output can be curtailed to satisfy power system constraints.
These generators can also participate in reserves markets, including upwards reserves by proactively curtailing some available power (based on its [`max_active_power` time series](@ref ts_data)). Example uses include: a utility-scale wind or solar generator whose PPA allows curtailment. For non-curtailable or must-take renewables, see [`RenewableNonDispatch`](@ref).
Renewable generators do not have a `max_active_power` parameter, which is instead calculated when calling [`get_max_active_power()`](@ref get_max_active_power(d::T) where {T <: RenewableGen})
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used
- `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR), used in some production cost modeling simulations. To set the reactive power in a load flow, use `power_factor`
- `rating::Float64`: Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power, validation range: `(0, nothing)`
- `prime_mover_type::PrimeMovers`: Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)
- `reactive_power_limits::Union{Nothing, MinMax}`: Minimum and maximum reactive power limits, used in some production cost model simulations and in power flow if the unit is connected to a [`PV`](@ref acbustypes_list) bus. Set to `nothing` if not applicable
- `power_factor::Float64`: Power factor [0, 1] set-point, used in some production cost modeling and in load flow if the unit is connected to a [`PQ`](@ref acbustypes_list) bus, validation range: `(0, 1)`
- `operation_cost::Union{RenewableGenerationCost, MarketBidCost}`: [`OperationalCost`](@ref) of generation
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct RenewableDispatch <: RenewableGen
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used"
active_power::Float64
"Initial reactive power set point of the unit (MVAR), used in some production cost modeling simulations. To set the reactive power in a load flow, use `power_factor`"
reactive_power::Float64
"Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power"
rating::Float64
"Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)"
prime_mover_type::PrimeMovers
"Minimum and maximum reactive power limits, used in some production cost model simulations and in power flow if the unit is connected to a [`PV`](@ref acbustypes_list) bus. Set to `nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
"Power factor [0, 1] set-point, used in some production cost modeling and in load flow if the unit is connected to a [`PQ`](@ref acbustypes_list) bus"
power_factor::Float64
"[`OperationalCost`](@ref) of generation"
operation_cost::Union{RenewableGenerationCost, MarketBidCost}
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function RenewableDispatch(name, available, bus, active_power, reactive_power, rating, prime_mover_type, reactive_power_limits, power_factor, operation_cost, base_power, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
RenewableDispatch(name, available, bus, active_power, reactive_power, rating, prime_mover_type, reactive_power_limits, power_factor, operation_cost, base_power, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function RenewableDispatch(; name, available, bus, active_power, reactive_power, rating, prime_mover_type, reactive_power_limits, power_factor, operation_cost, base_power, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
RenewableDispatch(name, available, bus, active_power, reactive_power, rating, prime_mover_type, reactive_power_limits, power_factor, operation_cost, base_power, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function RenewableDispatch(::Nothing)
RenewableDispatch(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
rating=0.0,
prime_mover_type=PrimeMovers.OT,
reactive_power_limits=nothing,
power_factor=1.0,
operation_cost=RenewableGenerationCost(nothing),
base_power=100.0,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`RenewableDispatch`](@ref) `name`."""
get_name(value::RenewableDispatch) = value.name
"""Get [`RenewableDispatch`](@ref) `available`."""
get_available(value::RenewableDispatch) = value.available
"""Get [`RenewableDispatch`](@ref) `bus`."""
get_bus(value::RenewableDispatch) = value.bus
"""Get [`RenewableDispatch`](@ref) `active_power`."""
get_active_power(value::RenewableDispatch) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`RenewableDispatch`](@ref) `reactive_power`."""
get_reactive_power(value::RenewableDispatch) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`RenewableDispatch`](@ref) `rating`."""
get_rating(value::RenewableDispatch) = get_value(value, Val(:rating), Val(:mva))
"""Get [`RenewableDispatch`](@ref) `prime_mover_type`."""
get_prime_mover_type(value::RenewableDispatch) = value.prime_mover_type
"""Get [`RenewableDispatch`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::RenewableDispatch) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`RenewableDispatch`](@ref) `power_factor`."""
get_power_factor(value::RenewableDispatch) = value.power_factor
"""Get [`RenewableDispatch`](@ref) `operation_cost`."""
get_operation_cost(value::RenewableDispatch) = value.operation_cost
"""Get [`RenewableDispatch`](@ref) `base_power`."""
get_base_power(value::RenewableDispatch) = value.base_power
"""Get [`RenewableDispatch`](@ref) `services`."""
get_services(value::RenewableDispatch) = value.services
"""Get [`RenewableDispatch`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::RenewableDispatch) = value.dynamic_injector
"""Get [`RenewableDispatch`](@ref) `ext`."""
get_ext(value::RenewableDispatch) = value.ext
"""Get [`RenewableDispatch`](@ref) `internal`."""
get_internal(value::RenewableDispatch) = value.internal
"""Set [`RenewableDispatch`](@ref) `available`."""
set_available!(value::RenewableDispatch, val) = value.available = val
"""Set [`RenewableDispatch`](@ref) `bus`."""
set_bus!(value::RenewableDispatch, val) = value.bus = val
"""Set [`RenewableDispatch`](@ref) `active_power`."""
set_active_power!(value::RenewableDispatch, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`RenewableDispatch`](@ref) `reactive_power`."""
set_reactive_power!(value::RenewableDispatch, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`RenewableDispatch`](@ref) `rating`."""
set_rating!(value::RenewableDispatch, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`RenewableDispatch`](@ref) `prime_mover_type`."""
set_prime_mover_type!(value::RenewableDispatch, val) = value.prime_mover_type = val
"""Set [`RenewableDispatch`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::RenewableDispatch, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`RenewableDispatch`](@ref) `power_factor`."""
set_power_factor!(value::RenewableDispatch, val) = value.power_factor = val
"""Set [`RenewableDispatch`](@ref) `operation_cost`."""
set_operation_cost!(value::RenewableDispatch, val) = value.operation_cost = val
"""Set [`RenewableDispatch`](@ref) `base_power`."""
set_base_power!(value::RenewableDispatch, val) = value.base_power = val
"""Set [`RenewableDispatch`](@ref) `services`."""
set_services!(value::RenewableDispatch, val) = value.services = val
"""Set [`RenewableDispatch`](@ref) `ext`."""
set_ext!(value::RenewableDispatch, val) = value.ext = val
================================================
FILE: src/models/generated/RenewableEnergyConverterTypeA.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct RenewableEnergyConverterTypeA <: Converter
T_g::Float64
Rrpwr::Float64
Brkpt::Float64
Zerox::Float64
Lvpl1::Float64
Vo_lim::Float64
Lv_pnts::MinMax
Io_lim::Float64
T_fltr::Float64
K_hv::Float64
Iqr_lims::MinMax
Accel::Float64
Lvpl_sw::Int
Q_ref::Float64
R_source::Float64
X_source::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a renewable energy generator/converter model, this model corresponds to REGCA1 in PSSE
# Arguments
- `T_g::Float64`: Converter time constant (s), validation range: `(0, nothing)`
- `Rrpwr::Float64`: Low Voltage Power Logic (LVPL) ramp rate limit (pu/s), validation range: `(0, nothing)`
- `Brkpt::Float64`: LVPL characteristic voltage 2 (pu), validation range: `(0, nothing)`
- `Zerox::Float64`: LVPL characteristic voltage 1 (pu), validation range: `(0, nothing)`
- `Lvpl1::Float64`: LVPL gain (pu), validation range: `(0, nothing)`
- `Vo_lim::Float64`: Voltage limit for high voltage reactive current management (pu), validation range: `(0, nothing)`
- `Lv_pnts::MinMax`: Voltage points for low voltage active current management (pu) (Lvpnt0, Lvpnt1)
- `Io_lim::Float64`: Current limit (pu) for high voltage reactive current management (specified as a negative value), validation range: `(nothing, 0)`
- `T_fltr::Float64`: Voltage filter time constant for low voltage active current management (s), validation range: `(0, nothing)`
- `K_hv::Float64`: Overvoltage compensation gain used in the high voltage reactive current management, validation range: `(0, nothing)`
- `Iqr_lims::MinMax`: Limit on rate of change for reactive current (pu/s) (Iqr_min, Iqr_max)
- `Accel::Float64`: Acceleration factor, validation range: `(0, 1)`
- `Lvpl_sw::Int`: Low voltage power logic (LVPL) switch. (0: LVPL not present, 1: LVPL present), validation range: `(0, 1)`
- `Q_ref::Float64`: (default: `1.0`) Initial condition of reactive power from power flow, validation range: `(0, nothing)`
- `R_source::Float64`: (default: `0.0`) Output resistor used for the Thevenin Equivalent, validation range: `(0, nothing)`
- `X_source::Float64`: (default: `1.0e5`) Output reactance used for the Thevenin Equivalent, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are: Ip: Converter lag for Ipcmd, Iq: Converter lag for Iqcmd, Vmeas: Voltage filter for low voltage active current management
- `n_states::Int`: (**Do not modify.**) RenewableEnergyConverterTypeA has 3 states
"""
mutable struct RenewableEnergyConverterTypeA <: Converter
"Converter time constant (s)"
T_g::Float64
"Low Voltage Power Logic (LVPL) ramp rate limit (pu/s)"
Rrpwr::Float64
"LVPL characteristic voltage 2 (pu)"
Brkpt::Float64
"LVPL characteristic voltage 1 (pu)"
Zerox::Float64
"LVPL gain (pu)"
Lvpl1::Float64
"Voltage limit for high voltage reactive current management (pu)"
Vo_lim::Float64
"Voltage points for low voltage active current management (pu) (Lvpnt0, Lvpnt1)"
Lv_pnts::MinMax
"Current limit (pu) for high voltage reactive current management (specified as a negative value)"
Io_lim::Float64
"Voltage filter time constant for low voltage active current management (s)"
T_fltr::Float64
"Overvoltage compensation gain used in the high voltage reactive current management"
K_hv::Float64
"Limit on rate of change for reactive current (pu/s) (Iqr_min, Iqr_max)"
Iqr_lims::MinMax
"Acceleration factor"
Accel::Float64
"Low voltage power logic (LVPL) switch. (0: LVPL not present, 1: LVPL present)"
Lvpl_sw::Int
"Initial condition of reactive power from power flow"
Q_ref::Float64
"Output resistor used for the Thevenin Equivalent"
R_source::Float64
"Output reactance used for the Thevenin Equivalent"
X_source::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are: Ip: Converter lag for Ipcmd, Iq: Converter lag for Iqcmd, Vmeas: Voltage filter for low voltage active current management"
states::Vector{Symbol}
"(**Do not modify.**) RenewableEnergyConverterTypeA has 3 states"
n_states::Int
end
function RenewableEnergyConverterTypeA(T_g, Rrpwr, Brkpt, Zerox, Lvpl1, Vo_lim, Lv_pnts, Io_lim, T_fltr, K_hv, Iqr_lims, Accel, Lvpl_sw, Q_ref=1.0, R_source=0.0, X_source=1.0e5, ext=Dict{String, Any}(), )
RenewableEnergyConverterTypeA(T_g, Rrpwr, Brkpt, Zerox, Lvpl1, Vo_lim, Lv_pnts, Io_lim, T_fltr, K_hv, Iqr_lims, Accel, Lvpl_sw, Q_ref, R_source, X_source, ext, [:Ip, :Iq, :Vmeas], 3, )
end
function RenewableEnergyConverterTypeA(; T_g, Rrpwr, Brkpt, Zerox, Lvpl1, Vo_lim, Lv_pnts, Io_lim, T_fltr, K_hv, Iqr_lims, Accel, Lvpl_sw, Q_ref=1.0, R_source=0.0, X_source=1.0e5, ext=Dict{String, Any}(), states=[:Ip, :Iq, :Vmeas], n_states=3, )
RenewableEnergyConverterTypeA(T_g, Rrpwr, Brkpt, Zerox, Lvpl1, Vo_lim, Lv_pnts, Io_lim, T_fltr, K_hv, Iqr_lims, Accel, Lvpl_sw, Q_ref, R_source, X_source, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function RenewableEnergyConverterTypeA(::Nothing)
RenewableEnergyConverterTypeA(;
T_g=0,
Rrpwr=0,
Brkpt=0,
Zerox=0,
Lvpl1=0,
Vo_lim=0,
Lv_pnts=(min=0.0, max=0.0),
Io_lim=0,
T_fltr=0,
K_hv=0,
Iqr_lims=(min=0.0, max=0.0),
Accel=0,
Lvpl_sw=0,
Q_ref=0,
R_source=0,
X_source=0,
ext=Dict{String, Any}(),
)
end
"""Get [`RenewableEnergyConverterTypeA`](@ref) `T_g`."""
get_T_g(value::RenewableEnergyConverterTypeA) = value.T_g
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Rrpwr`."""
get_Rrpwr(value::RenewableEnergyConverterTypeA) = value.Rrpwr
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Brkpt`."""
get_Brkpt(value::RenewableEnergyConverterTypeA) = value.Brkpt
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Zerox`."""
get_Zerox(value::RenewableEnergyConverterTypeA) = value.Zerox
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Lvpl1`."""
get_Lvpl1(value::RenewableEnergyConverterTypeA) = value.Lvpl1
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Vo_lim`."""
get_Vo_lim(value::RenewableEnergyConverterTypeA) = value.Vo_lim
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Lv_pnts`."""
get_Lv_pnts(value::RenewableEnergyConverterTypeA) = value.Lv_pnts
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Io_lim`."""
get_Io_lim(value::RenewableEnergyConverterTypeA) = value.Io_lim
"""Get [`RenewableEnergyConverterTypeA`](@ref) `T_fltr`."""
get_T_fltr(value::RenewableEnergyConverterTypeA) = value.T_fltr
"""Get [`RenewableEnergyConverterTypeA`](@ref) `K_hv`."""
get_K_hv(value::RenewableEnergyConverterTypeA) = value.K_hv
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Iqr_lims`."""
get_Iqr_lims(value::RenewableEnergyConverterTypeA) = value.Iqr_lims
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Accel`."""
get_Accel(value::RenewableEnergyConverterTypeA) = value.Accel
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Lvpl_sw`."""
get_Lvpl_sw(value::RenewableEnergyConverterTypeA) = value.Lvpl_sw
"""Get [`RenewableEnergyConverterTypeA`](@ref) `Q_ref`."""
get_Q_ref(value::RenewableEnergyConverterTypeA) = value.Q_ref
"""Get [`RenewableEnergyConverterTypeA`](@ref) `R_source`."""
get_R_source(value::RenewableEnergyConverterTypeA) = value.R_source
"""Get [`RenewableEnergyConverterTypeA`](@ref) `X_source`."""
get_X_source(value::RenewableEnergyConverterTypeA) = value.X_source
"""Get [`RenewableEnergyConverterTypeA`](@ref) `ext`."""
get_ext(value::RenewableEnergyConverterTypeA) = value.ext
"""Get [`RenewableEnergyConverterTypeA`](@ref) `states`."""
get_states(value::RenewableEnergyConverterTypeA) = value.states
"""Get [`RenewableEnergyConverterTypeA`](@ref) `n_states`."""
get_n_states(value::RenewableEnergyConverterTypeA) = value.n_states
"""Set [`RenewableEnergyConverterTypeA`](@ref) `T_g`."""
set_T_g!(value::RenewableEnergyConverterTypeA, val) = value.T_g = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Rrpwr`."""
set_Rrpwr!(value::RenewableEnergyConverterTypeA, val) = value.Rrpwr = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Brkpt`."""
set_Brkpt!(value::RenewableEnergyConverterTypeA, val) = value.Brkpt = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Zerox`."""
set_Zerox!(value::RenewableEnergyConverterTypeA, val) = value.Zerox = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Lvpl1`."""
set_Lvpl1!(value::RenewableEnergyConverterTypeA, val) = value.Lvpl1 = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Vo_lim`."""
set_Vo_lim!(value::RenewableEnergyConverterTypeA, val) = value.Vo_lim = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Lv_pnts`."""
set_Lv_pnts!(value::RenewableEnergyConverterTypeA, val) = value.Lv_pnts = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Io_lim`."""
set_Io_lim!(value::RenewableEnergyConverterTypeA, val) = value.Io_lim = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `T_fltr`."""
set_T_fltr!(value::RenewableEnergyConverterTypeA, val) = value.T_fltr = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `K_hv`."""
set_K_hv!(value::RenewableEnergyConverterTypeA, val) = value.K_hv = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Iqr_lims`."""
set_Iqr_lims!(value::RenewableEnergyConverterTypeA, val) = value.Iqr_lims = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Accel`."""
set_Accel!(value::RenewableEnergyConverterTypeA, val) = value.Accel = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Lvpl_sw`."""
set_Lvpl_sw!(value::RenewableEnergyConverterTypeA, val) = value.Lvpl_sw = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `Q_ref`."""
set_Q_ref!(value::RenewableEnergyConverterTypeA, val) = value.Q_ref = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `R_source`."""
set_R_source!(value::RenewableEnergyConverterTypeA, val) = value.R_source = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `X_source`."""
set_X_source!(value::RenewableEnergyConverterTypeA, val) = value.X_source = val
"""Set [`RenewableEnergyConverterTypeA`](@ref) `ext`."""
set_ext!(value::RenewableEnergyConverterTypeA, val) = value.ext = val
================================================
FILE: src/models/generated/RenewableEnergyVoltageConverterTypeA.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct RenewableEnergyVoltageConverterTypeA <: Converter
T_g::Float64
Rrpwr::Float64
Brkpt::Float64
Zerox::Float64
Lvpl1::Float64
Vo_lim::Float64
Lv_pnts::MinMax
Io_lim::Float64
T_fltr::Float64
K_hv::Float64
Iqr_lims::MinMax
Accel::Float64
Lvpl_sw::Int
Q_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a renewable energy generator/converter model, this model corresponds to REGCA1 in PSSE, but to be interfaced using a Voltage Source instead of a Current Source
# Arguments
- `T_g::Float64`: Converter time constant (s), validation range: `(0, nothing)`
- `Rrpwr::Float64`: Low Voltage Power Logic (LVPL) ramp rate limit (pu/s), validation range: `(0, nothing)`
- `Brkpt::Float64`: LVPL characteristic voltage 2 (pu), validation range: `(0, nothing)`
- `Zerox::Float64`: LVPL characteristic voltage 1 (pu), validation range: `(0, nothing)`
- `Lvpl1::Float64`: LVPL gain (pu), validation range: `(0, nothing)`
- `Vo_lim::Float64`: Voltage limit for high voltage reactive current management (pu), validation range: `(0, nothing)`
- `Lv_pnts::MinMax`: Voltage points for low voltage active current management (pu) (Lvpnt0, Lvpnt1)
- `Io_lim::Float64`: Current limit (pu) for high voltage reactive current management (specified as a negative value), validation range: `(nothing, 0)`
- `T_fltr::Float64`: Voltage filter time constant for low voltage active current management (s), validation range: `(0, nothing)`
- `K_hv::Float64`: Overvoltage compensation gain used in the high voltage reactive current management, validation range: `(0, nothing)`
- `Iqr_lims::MinMax`: Limit on rate of change for reactive current (pu/s) (Iqr_min, Iqr_max)
- `Accel::Float64`: Acceleration factor, validation range: `(0, 1)`
- `Lvpl_sw::Int`: Low voltage power logic (LVPL) switch. (0: LVPL not present, 1: LVPL present), validation range: `(0, 1)`
- `Q_ref::Float64`: (default: `1.0`) Initial condition of reactive power from power flow, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are: Ip: Converter lag for Ipcmd, Iq: Converter lag for Iqcmd, Vmeas: Voltage filter for low voltage active current management
- `n_states::Int`: (**Do not modify.**) RenewableEnergyVoltageConverterTypeA has 3 states
"""
mutable struct RenewableEnergyVoltageConverterTypeA <: Converter
"Converter time constant (s)"
T_g::Float64
"Low Voltage Power Logic (LVPL) ramp rate limit (pu/s)"
Rrpwr::Float64
"LVPL characteristic voltage 2 (pu)"
Brkpt::Float64
"LVPL characteristic voltage 1 (pu)"
Zerox::Float64
"LVPL gain (pu)"
Lvpl1::Float64
"Voltage limit for high voltage reactive current management (pu)"
Vo_lim::Float64
"Voltage points for low voltage active current management (pu) (Lvpnt0, Lvpnt1)"
Lv_pnts::MinMax
"Current limit (pu) for high voltage reactive current management (specified as a negative value)"
Io_lim::Float64
"Voltage filter time constant for low voltage active current management (s)"
T_fltr::Float64
"Overvoltage compensation gain used in the high voltage reactive current management"
K_hv::Float64
"Limit on rate of change for reactive current (pu/s) (Iqr_min, Iqr_max)"
Iqr_lims::MinMax
"Acceleration factor"
Accel::Float64
"Low voltage power logic (LVPL) switch. (0: LVPL not present, 1: LVPL present)"
Lvpl_sw::Int
"Initial condition of reactive power from power flow"
Q_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are: Ip: Converter lag for Ipcmd, Iq: Converter lag for Iqcmd, Vmeas: Voltage filter for low voltage active current management"
states::Vector{Symbol}
"(**Do not modify.**) RenewableEnergyVoltageConverterTypeA has 3 states"
n_states::Int
end
function RenewableEnergyVoltageConverterTypeA(T_g, Rrpwr, Brkpt, Zerox, Lvpl1, Vo_lim, Lv_pnts, Io_lim, T_fltr, K_hv, Iqr_lims, Accel, Lvpl_sw, Q_ref=1.0, ext=Dict{String, Any}(), )
RenewableEnergyVoltageConverterTypeA(T_g, Rrpwr, Brkpt, Zerox, Lvpl1, Vo_lim, Lv_pnts, Io_lim, T_fltr, K_hv, Iqr_lims, Accel, Lvpl_sw, Q_ref, ext, [:Ip, :Iq, :Vmeas], 3, )
end
function RenewableEnergyVoltageConverterTypeA(; T_g, Rrpwr, Brkpt, Zerox, Lvpl1, Vo_lim, Lv_pnts, Io_lim, T_fltr, K_hv, Iqr_lims, Accel, Lvpl_sw, Q_ref=1.0, ext=Dict{String, Any}(), states=[:Ip, :Iq, :Vmeas], n_states=3, )
RenewableEnergyVoltageConverterTypeA(T_g, Rrpwr, Brkpt, Zerox, Lvpl1, Vo_lim, Lv_pnts, Io_lim, T_fltr, K_hv, Iqr_lims, Accel, Lvpl_sw, Q_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function RenewableEnergyVoltageConverterTypeA(::Nothing)
RenewableEnergyVoltageConverterTypeA(;
T_g=0,
Rrpwr=0,
Brkpt=0,
Zerox=0,
Lvpl1=0,
Vo_lim=0,
Lv_pnts=(min=0.0, max=0.0),
Io_lim=0,
T_fltr=0,
K_hv=0,
Iqr_lims=(min=0.0, max=0.0),
Accel=0,
Lvpl_sw=0,
Q_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `T_g`."""
get_T_g(value::RenewableEnergyVoltageConverterTypeA) = value.T_g
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Rrpwr`."""
get_Rrpwr(value::RenewableEnergyVoltageConverterTypeA) = value.Rrpwr
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Brkpt`."""
get_Brkpt(value::RenewableEnergyVoltageConverterTypeA) = value.Brkpt
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Zerox`."""
get_Zerox(value::RenewableEnergyVoltageConverterTypeA) = value.Zerox
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Lvpl1`."""
get_Lvpl1(value::RenewableEnergyVoltageConverterTypeA) = value.Lvpl1
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Vo_lim`."""
get_Vo_lim(value::RenewableEnergyVoltageConverterTypeA) = value.Vo_lim
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Lv_pnts`."""
get_Lv_pnts(value::RenewableEnergyVoltageConverterTypeA) = value.Lv_pnts
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Io_lim`."""
get_Io_lim(value::RenewableEnergyVoltageConverterTypeA) = value.Io_lim
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `T_fltr`."""
get_T_fltr(value::RenewableEnergyVoltageConverterTypeA) = value.T_fltr
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `K_hv`."""
get_K_hv(value::RenewableEnergyVoltageConverterTypeA) = value.K_hv
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Iqr_lims`."""
get_Iqr_lims(value::RenewableEnergyVoltageConverterTypeA) = value.Iqr_lims
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Accel`."""
get_Accel(value::RenewableEnergyVoltageConverterTypeA) = value.Accel
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Lvpl_sw`."""
get_Lvpl_sw(value::RenewableEnergyVoltageConverterTypeA) = value.Lvpl_sw
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `Q_ref`."""
get_Q_ref(value::RenewableEnergyVoltageConverterTypeA) = value.Q_ref
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `ext`."""
get_ext(value::RenewableEnergyVoltageConverterTypeA) = value.ext
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `states`."""
get_states(value::RenewableEnergyVoltageConverterTypeA) = value.states
"""Get [`RenewableEnergyVoltageConverterTypeA`](@ref) `n_states`."""
get_n_states(value::RenewableEnergyVoltageConverterTypeA) = value.n_states
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `T_g`."""
set_T_g!(value::RenewableEnergyVoltageConverterTypeA, val) = value.T_g = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Rrpwr`."""
set_Rrpwr!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Rrpwr = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Brkpt`."""
set_Brkpt!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Brkpt = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Zerox`."""
set_Zerox!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Zerox = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Lvpl1`."""
set_Lvpl1!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Lvpl1 = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Vo_lim`."""
set_Vo_lim!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Vo_lim = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Lv_pnts`."""
set_Lv_pnts!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Lv_pnts = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Io_lim`."""
set_Io_lim!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Io_lim = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `T_fltr`."""
set_T_fltr!(value::RenewableEnergyVoltageConverterTypeA, val) = value.T_fltr = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `K_hv`."""
set_K_hv!(value::RenewableEnergyVoltageConverterTypeA, val) = value.K_hv = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Iqr_lims`."""
set_Iqr_lims!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Iqr_lims = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Accel`."""
set_Accel!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Accel = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Lvpl_sw`."""
set_Lvpl_sw!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Lvpl_sw = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `Q_ref`."""
set_Q_ref!(value::RenewableEnergyVoltageConverterTypeA, val) = value.Q_ref = val
"""Set [`RenewableEnergyVoltageConverterTypeA`](@ref) `ext`."""
set_ext!(value::RenewableEnergyVoltageConverterTypeA, val) = value.ext = val
================================================
FILE: src/models/generated/RenewableNonDispatch.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct RenewableNonDispatch <: RenewableGen
name::String
available::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
rating::Float64
prime_mover_type::PrimeMovers
power_factor::Float64
base_power::Float64
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A non-dispatchable (i.e., non-curtailable or must-take) renewable generator.
Its output is equal to its [`max_active_power` time series](@ref ts_data) by default. Example use: an aggregation of behind-the-meter distributed energy resources like rooftop solar. For curtailable or downward dispatachable generation, see [`RenewableDispatch`](@ref).
Renewable generators do not have a `max_active_power` parameter, which is instead calculated when calling [`get_max_active_power()`](@ref get_max_active_power(d::T) where {T <: RenewableGen})
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used
- `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR), used in some production cost modeling simulations. To set the reactive power in a load flow, use `power_factor`
- `rating::Float64`: Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power, validation range: `(0, nothing)`
- `prime_mover_type::PrimeMovers`: Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)
- `power_factor::Float64`: Power factor [0, 1] set-point, used in some production cost modeling and in load flow if the unit is connected to a [`PQ`](@ref acbustypes_list) bus, validation range: `(0, 1)`
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct RenewableNonDispatch <: RenewableGen
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used"
active_power::Float64
"Initial reactive power set point of the unit (MVAR), used in some production cost modeling simulations. To set the reactive power in a load flow, use `power_factor`"
reactive_power::Float64
"Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power"
rating::Float64
"Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)"
prime_mover_type::PrimeMovers
"Power factor [0, 1] set-point, used in some production cost modeling and in load flow if the unit is connected to a [`PQ`](@ref acbustypes_list) bus"
power_factor::Float64
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function RenewableNonDispatch(name, available, bus, active_power, reactive_power, rating, prime_mover_type, power_factor, base_power, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
RenewableNonDispatch(name, available, bus, active_power, reactive_power, rating, prime_mover_type, power_factor, base_power, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function RenewableNonDispatch(; name, available, bus, active_power, reactive_power, rating, prime_mover_type, power_factor, base_power, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
RenewableNonDispatch(name, available, bus, active_power, reactive_power, rating, prime_mover_type, power_factor, base_power, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function RenewableNonDispatch(::Nothing)
RenewableNonDispatch(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
rating=0.0,
prime_mover_type=PrimeMovers.OT,
power_factor=1.0,
base_power=100.0,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`RenewableNonDispatch`](@ref) `name`."""
get_name(value::RenewableNonDispatch) = value.name
"""Get [`RenewableNonDispatch`](@ref) `available`."""
get_available(value::RenewableNonDispatch) = value.available
"""Get [`RenewableNonDispatch`](@ref) `bus`."""
get_bus(value::RenewableNonDispatch) = value.bus
"""Get [`RenewableNonDispatch`](@ref) `active_power`."""
get_active_power(value::RenewableNonDispatch) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`RenewableNonDispatch`](@ref) `reactive_power`."""
get_reactive_power(value::RenewableNonDispatch) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`RenewableNonDispatch`](@ref) `rating`."""
get_rating(value::RenewableNonDispatch) = get_value(value, Val(:rating), Val(:mva))
"""Get [`RenewableNonDispatch`](@ref) `prime_mover_type`."""
get_prime_mover_type(value::RenewableNonDispatch) = value.prime_mover_type
"""Get [`RenewableNonDispatch`](@ref) `power_factor`."""
get_power_factor(value::RenewableNonDispatch) = value.power_factor
"""Get [`RenewableNonDispatch`](@ref) `base_power`."""
get_base_power(value::RenewableNonDispatch) = value.base_power
"""Get [`RenewableNonDispatch`](@ref) `services`."""
get_services(value::RenewableNonDispatch) = value.services
"""Get [`RenewableNonDispatch`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::RenewableNonDispatch) = value.dynamic_injector
"""Get [`RenewableNonDispatch`](@ref) `ext`."""
get_ext(value::RenewableNonDispatch) = value.ext
"""Get [`RenewableNonDispatch`](@ref) `internal`."""
get_internal(value::RenewableNonDispatch) = value.internal
"""Set [`RenewableNonDispatch`](@ref) `available`."""
set_available!(value::RenewableNonDispatch, val) = value.available = val
"""Set [`RenewableNonDispatch`](@ref) `bus`."""
set_bus!(value::RenewableNonDispatch, val) = value.bus = val
"""Set [`RenewableNonDispatch`](@ref) `active_power`."""
set_active_power!(value::RenewableNonDispatch, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`RenewableNonDispatch`](@ref) `reactive_power`."""
set_reactive_power!(value::RenewableNonDispatch, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`RenewableNonDispatch`](@ref) `rating`."""
set_rating!(value::RenewableNonDispatch, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`RenewableNonDispatch`](@ref) `prime_mover_type`."""
set_prime_mover_type!(value::RenewableNonDispatch, val) = value.prime_mover_type = val
"""Set [`RenewableNonDispatch`](@ref) `power_factor`."""
set_power_factor!(value::RenewableNonDispatch, val) = value.power_factor = val
"""Set [`RenewableNonDispatch`](@ref) `base_power`."""
set_base_power!(value::RenewableNonDispatch, val) = value.base_power = val
"""Set [`RenewableNonDispatch`](@ref) `services`."""
set_services!(value::RenewableNonDispatch, val) = value.services = val
"""Set [`RenewableNonDispatch`](@ref) `ext`."""
set_ext!(value::RenewableNonDispatch, val) = value.ext = val
================================================
FILE: src/models/generated/ReserveDemandCurve.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ReserveDemandCurve{T <: ReserveDirection} <: Reserve{T}
variable::Union{Nothing, TimeSeriesKey, CostCurve{PiecewiseIncrementalCurve}}
name::String
available::Bool
time_frame::Float64
sustained_time::Float64
max_participation_factor::Float64
deployed_fraction::Float64
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A reserve product with an [Operating Reserve Demand Curve (ORDC)](https://hepg.hks.harvard.edu/files/hepg/files/ordcupdate-final.pdf) for operational simulations.
The ORDC is modeled as a discretized set of `(Reserve capacity (MW), Price (\$/MWh))` steps, which can vary with time. Use [`set_variable_cost!`](@ref) to define the ORDCs.
When defining the reserve, the `ReserveDirection` must be specified to define this as a [`ReserveUp`](@ref), [`ReserveDown`](@ref), or [`ReserveSymmetric`](@ref)
# Arguments
- `variable::Union{Nothing, TimeSeriesKey, CostCurve{PiecewiseIncrementalCurve}}`: Create this object with `variable` = `nothing`, then add assign a cost curve or time-series of `variable_cost` using the [`set_variable_cost!`](@ref) function, which will automatically update this parameter
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `time_frame::Float64`: the saturation time_frame in minutes to provide reserve contribution, validation range: `(0, nothing)`
- `sustained_time::Float64`: (default: `3600.0`) the time in seconds that the reserve contribution must sustained at a specified level, validation range: `(0, nothing)`
- `max_participation_factor::Float64`: (default: `1.0`) the maximum portion [0, 1.0] of the reserve that can be contributed per device, validation range: `(0, 1)`
- `deployed_fraction::Float64`: (default: `0.0`) Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0, validation range: `(0, 1)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ReserveDemandCurve{T <: ReserveDirection} <: Reserve{T}
"Create this object with `variable` = `nothing`, then add assign a cost curve or time-series of `variable_cost` using the [`set_variable_cost!`](@ref) function, which will automatically update this parameter"
variable::Union{Nothing, TimeSeriesKey, CostCurve{PiecewiseIncrementalCurve}}
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"the saturation time_frame in minutes to provide reserve contribution"
time_frame::Float64
"the time in seconds that the reserve contribution must sustained at a specified level"
sustained_time::Float64
"the maximum portion [0, 1.0] of the reserve that can be contributed per device"
max_participation_factor::Float64
"Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0"
deployed_fraction::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ReserveDemandCurve{T}(variable, name, available, time_frame, sustained_time=3600.0, max_participation_factor=1.0, deployed_fraction=0.0, ext=Dict{String, Any}(), ) where T <: ReserveDirection
ReserveDemandCurve{T}(variable, name, available, time_frame, sustained_time, max_participation_factor, deployed_fraction, ext, InfrastructureSystemsInternal(), )
end
function ReserveDemandCurve{T}(; variable, name, available, time_frame, sustained_time=3600.0, max_participation_factor=1.0, deployed_fraction=0.0, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), ) where T <: ReserveDirection
ReserveDemandCurve{T}(variable, name, available, time_frame, sustained_time, max_participation_factor, deployed_fraction, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function ReserveDemandCurve{T}(::Nothing) where T <: ReserveDirection
ReserveDemandCurve{T}(;
variable=nothing,
name="init",
available=false,
time_frame=0.0,
sustained_time=0.0,
max_participation_factor=1.0,
deployed_fraction=0.0,
ext=Dict{String, Any}(),
)
end
"""Get [`ReserveDemandCurve`](@ref) `variable`."""
get_variable(value::ReserveDemandCurve) = value.variable
"""Get [`ReserveDemandCurve`](@ref) `name`."""
get_name(value::ReserveDemandCurve) = value.name
"""Get [`ReserveDemandCurve`](@ref) `available`."""
get_available(value::ReserveDemandCurve) = value.available
"""Get [`ReserveDemandCurve`](@ref) `time_frame`."""
get_time_frame(value::ReserveDemandCurve) = value.time_frame
"""Get [`ReserveDemandCurve`](@ref) `sustained_time`."""
get_sustained_time(value::ReserveDemandCurve) = value.sustained_time
"""Get [`ReserveDemandCurve`](@ref) `max_participation_factor`."""
get_max_participation_factor(value::ReserveDemandCurve) = value.max_participation_factor
"""Get [`ReserveDemandCurve`](@ref) `deployed_fraction`."""
get_deployed_fraction(value::ReserveDemandCurve) = value.deployed_fraction
"""Get [`ReserveDemandCurve`](@ref) `ext`."""
get_ext(value::ReserveDemandCurve) = value.ext
"""Get [`ReserveDemandCurve`](@ref) `internal`."""
get_internal(value::ReserveDemandCurve) = value.internal
"""Set [`ReserveDemandCurve`](@ref) `variable`."""
set_variable!(value::ReserveDemandCurve, val) = value.variable = val
"""Set [`ReserveDemandCurve`](@ref) `available`."""
set_available!(value::ReserveDemandCurve, val) = value.available = val
"""Set [`ReserveDemandCurve`](@ref) `time_frame`."""
set_time_frame!(value::ReserveDemandCurve, val) = value.time_frame = val
"""Set [`ReserveDemandCurve`](@ref) `sustained_time`."""
set_sustained_time!(value::ReserveDemandCurve, val) = value.sustained_time = val
"""Set [`ReserveDemandCurve`](@ref) `max_participation_factor`."""
set_max_participation_factor!(value::ReserveDemandCurve, val) = value.max_participation_factor = val
"""Set [`ReserveDemandCurve`](@ref) `deployed_fraction`."""
set_deployed_fraction!(value::ReserveDemandCurve, val) = value.deployed_fraction = val
"""Set [`ReserveDemandCurve`](@ref) `ext`."""
set_ext!(value::ReserveDemandCurve, val) = value.ext = val
================================================
FILE: src/models/generated/RoundRotorMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct RoundRotorMachine <: Machine
R::Float64
Td0_p::Float64
Td0_pp::Float64
Tq0_p::Float64
Tq0_pp::Float64
Xd::Float64
Xq::Float64
Xd_p::Float64
Xq_p::Float64
Xd_pp::Float64
Xl::Float64
Se::Tuple{Float64, Float64}
ext::Dict{String, Any}
γ_d1::Float64
γ_q1::Float64
γ_d2::Float64
γ_q2::Float64
γ_qd::Float64
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 4-[states](@ref S) round-rotor synchronous machine with quadratic/exponential saturation:
IEEE Std 1110 §5.3.2 (Model 2.2). GENROU or GENROE model in PSSE and PSLF
# Arguments
- `R::Float64`: Armature resistance, validation range: `(0, nothing)`
- `Td0_p::Float64`: Time constant of transient d-axis voltage, validation range: `(0, nothing)`
- `Td0_pp::Float64`: Time constant of sub-transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_p::Float64`: Time constant of transient q-axis voltage, validation range: `(0, nothing)`
- `Tq0_pp::Float64`: Time constant of sub-transient q-axis voltage, validation range: `(0, nothing)`
- `Xd::Float64`: Reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq::Float64`: Reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_p::Float64`: Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_p::Float64`: Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_pp::Float64`: Sub-Transient reactance after EMF in d-axis per unit. Note: Xd_pp = Xq_pp, validation range: `(0, nothing)`
- `Xl::Float64`: Stator leakage reactance, validation range: `(0, nothing)`
- `Se::Tuple{Float64, Float64}`: Saturation factor at 1 and 1.2 pu flux: S(1.0) = B(|ψ_pp|-A)^2
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `γ_d1::Float64`: (**Do not modify.**) γ_d1 parameter
- `γ_q1::Float64`: (**Do not modify.**) γ_q1 parameter
- `γ_d2::Float64`: (**Do not modify.**) γ_d2 parameter
- `γ_q2::Float64`: (**Do not modify.**) γ_q2 parameter
- `γ_qd::Float64`: (**Do not modify.**) γ_qd parameter
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
eq_p: q-axis generator voltage behind the transient reactance,
ed_p: d-axis generator voltage behind the transient reactance,
ψ_kd: flux linkage in the first equivalent damping circuit in the d-axis,
ψ_kq: flux linkage in the first equivalent damping circuit in the d-axis
- `n_states::Int`: (**Do not modify.**) RoundRotorMachine has 4 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct RoundRotorMachine <: Machine
"Armature resistance"
R::Float64
"Time constant of transient d-axis voltage"
Td0_p::Float64
"Time constant of sub-transient d-axis voltage"
Td0_pp::Float64
"Time constant of transient q-axis voltage"
Tq0_p::Float64
"Time constant of sub-transient q-axis voltage"
Tq0_pp::Float64
"Reactance after EMF in d-axis per unit"
Xd::Float64
"Reactance after EMF in q-axis per unit"
Xq::Float64
"Transient reactance after EMF in d-axis per unit"
Xd_p::Float64
"Transient reactance after EMF in q-axis per unit"
Xq_p::Float64
"Sub-Transient reactance after EMF in d-axis per unit. Note: Xd_pp = Xq_pp"
Xd_pp::Float64
"Stator leakage reactance"
Xl::Float64
"Saturation factor at 1 and 1.2 pu flux: S(1.0) = B(|ψ_pp|-A)^2"
Se::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) γ_d1 parameter"
γ_d1::Float64
"(**Do not modify.**) γ_q1 parameter"
γ_q1::Float64
"(**Do not modify.**) γ_d2 parameter"
γ_d2::Float64
"(**Do not modify.**) γ_q2 parameter"
γ_q2::Float64
"(**Do not modify.**) γ_qd parameter"
γ_qd::Float64
"(**Do not modify.**) The [states](@ref S) are:
eq_p: q-axis generator voltage behind the transient reactance,
ed_p: d-axis generator voltage behind the transient reactance,
ψ_kd: flux linkage in the first equivalent damping circuit in the d-axis,
ψ_kq: flux linkage in the first equivalent damping circuit in the d-axis"
states::Vector{Symbol}
"(**Do not modify.**) RoundRotorMachine has 4 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function RoundRotorMachine(R, Td0_p, Td0_pp, Tq0_p, Tq0_pp, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xl, Se, ext=Dict{String, Any}(), )
RoundRotorMachine(R, Td0_p, Td0_pp, Tq0_p, Tq0_pp, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xl, Se, ext, (Xd_pp - Xl) / (Xd_p - Xl), (Xd_pp - Xl) / (Xq_p - Xl), (Xd_p - Xd_pp) / (Xd_p - Xl)^2, (Xq_p - Xd_pp) / (Xq_p - Xl)^2, (Xq - Xl) / (Xd - Xl), [:eq_p, :ed_p, :ψ_kd, :ψ_kq], 4, InfrastructureSystemsInternal(), )
end
function RoundRotorMachine(; R, Td0_p, Td0_pp, Tq0_p, Tq0_pp, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xl, Se, ext=Dict{String, Any}(), γ_d1=(Xd_pp - Xl) / (Xd_p - Xl), γ_q1=(Xd_pp - Xl) / (Xq_p - Xl), γ_d2=(Xd_p - Xd_pp) / (Xd_p - Xl)^2, γ_q2=(Xq_p - Xd_pp) / (Xq_p - Xl)^2, γ_qd=(Xq - Xl) / (Xd - Xl), states=[:eq_p, :ed_p, :ψ_kd, :ψ_kq], n_states=4, internal=InfrastructureSystemsInternal(), )
RoundRotorMachine(R, Td0_p, Td0_pp, Tq0_p, Tq0_pp, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xl, Se, ext, γ_d1, γ_q1, γ_d2, γ_q2, γ_qd, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function RoundRotorMachine(::Nothing)
RoundRotorMachine(;
R=0,
Td0_p=0,
Td0_pp=0,
Tq0_p=0,
Tq0_pp=0,
Xd=0,
Xq=0,
Xd_p=0,
Xq_p=0,
Xd_pp=0,
Xl=0,
Se=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`RoundRotorMachine`](@ref) `R`."""
get_R(value::RoundRotorMachine) = value.R
"""Get [`RoundRotorMachine`](@ref) `Td0_p`."""
get_Td0_p(value::RoundRotorMachine) = value.Td0_p
"""Get [`RoundRotorMachine`](@ref) `Td0_pp`."""
get_Td0_pp(value::RoundRotorMachine) = value.Td0_pp
"""Get [`RoundRotorMachine`](@ref) `Tq0_p`."""
get_Tq0_p(value::RoundRotorMachine) = value.Tq0_p
"""Get [`RoundRotorMachine`](@ref) `Tq0_pp`."""
get_Tq0_pp(value::RoundRotorMachine) = value.Tq0_pp
"""Get [`RoundRotorMachine`](@ref) `Xd`."""
get_Xd(value::RoundRotorMachine) = value.Xd
"""Get [`RoundRotorMachine`](@ref) `Xq`."""
get_Xq(value::RoundRotorMachine) = value.Xq
"""Get [`RoundRotorMachine`](@ref) `Xd_p`."""
get_Xd_p(value::RoundRotorMachine) = value.Xd_p
"""Get [`RoundRotorMachine`](@ref) `Xq_p`."""
get_Xq_p(value::RoundRotorMachine) = value.Xq_p
"""Get [`RoundRotorMachine`](@ref) `Xd_pp`."""
get_Xd_pp(value::RoundRotorMachine) = value.Xd_pp
"""Get [`RoundRotorMachine`](@ref) `Xl`."""
get_Xl(value::RoundRotorMachine) = value.Xl
"""Get [`RoundRotorMachine`](@ref) `Se`."""
get_Se(value::RoundRotorMachine) = value.Se
"""Get [`RoundRotorMachine`](@ref) `ext`."""
get_ext(value::RoundRotorMachine) = value.ext
"""Get [`RoundRotorMachine`](@ref) `γ_d1`."""
get_γ_d1(value::RoundRotorMachine) = value.γ_d1
"""Get [`RoundRotorMachine`](@ref) `γ_q1`."""
get_γ_q1(value::RoundRotorMachine) = value.γ_q1
"""Get [`RoundRotorMachine`](@ref) `γ_d2`."""
get_γ_d2(value::RoundRotorMachine) = value.γ_d2
"""Get [`RoundRotorMachine`](@ref) `γ_q2`."""
get_γ_q2(value::RoundRotorMachine) = value.γ_q2
"""Get [`RoundRotorMachine`](@ref) `γ_qd`."""
get_γ_qd(value::RoundRotorMachine) = value.γ_qd
"""Get [`RoundRotorMachine`](@ref) `states`."""
get_states(value::RoundRotorMachine) = value.states
"""Get [`RoundRotorMachine`](@ref) `n_states`."""
get_n_states(value::RoundRotorMachine) = value.n_states
"""Get [`RoundRotorMachine`](@ref) `internal`."""
get_internal(value::RoundRotorMachine) = value.internal
"""Set [`RoundRotorMachine`](@ref) `R`."""
set_R!(value::RoundRotorMachine, val) = value.R = val
"""Set [`RoundRotorMachine`](@ref) `Td0_p`."""
set_Td0_p!(value::RoundRotorMachine, val) = value.Td0_p = val
"""Set [`RoundRotorMachine`](@ref) `Td0_pp`."""
set_Td0_pp!(value::RoundRotorMachine, val) = value.Td0_pp = val
"""Set [`RoundRotorMachine`](@ref) `Tq0_p`."""
set_Tq0_p!(value::RoundRotorMachine, val) = value.Tq0_p = val
"""Set [`RoundRotorMachine`](@ref) `Tq0_pp`."""
set_Tq0_pp!(value::RoundRotorMachine, val) = value.Tq0_pp = val
"""Set [`RoundRotorMachine`](@ref) `Xd`."""
set_Xd!(value::RoundRotorMachine, val) = value.Xd = val
"""Set [`RoundRotorMachine`](@ref) `Xq`."""
set_Xq!(value::RoundRotorMachine, val) = value.Xq = val
"""Set [`RoundRotorMachine`](@ref) `Xd_p`."""
set_Xd_p!(value::RoundRotorMachine, val) = value.Xd_p = val
"""Set [`RoundRotorMachine`](@ref) `Xq_p`."""
set_Xq_p!(value::RoundRotorMachine, val) = value.Xq_p = val
"""Set [`RoundRotorMachine`](@ref) `Xd_pp`."""
set_Xd_pp!(value::RoundRotorMachine, val) = value.Xd_pp = val
"""Set [`RoundRotorMachine`](@ref) `Xl`."""
set_Xl!(value::RoundRotorMachine, val) = value.Xl = val
"""Set [`RoundRotorMachine`](@ref) `Se`."""
set_Se!(value::RoundRotorMachine, val) = value.Se = val
"""Set [`RoundRotorMachine`](@ref) `ext`."""
set_ext!(value::RoundRotorMachine, val) = value.ext = val
"""Set [`RoundRotorMachine`](@ref) `γ_d1`."""
set_γ_d1!(value::RoundRotorMachine, val) = value.γ_d1 = val
"""Set [`RoundRotorMachine`](@ref) `γ_q1`."""
set_γ_q1!(value::RoundRotorMachine, val) = value.γ_q1 = val
"""Set [`RoundRotorMachine`](@ref) `γ_d2`."""
set_γ_d2!(value::RoundRotorMachine, val) = value.γ_d2 = val
"""Set [`RoundRotorMachine`](@ref) `γ_q2`."""
set_γ_q2!(value::RoundRotorMachine, val) = value.γ_q2 = val
"""Set [`RoundRotorMachine`](@ref) `γ_qd`."""
set_γ_qd!(value::RoundRotorMachine, val) = value.γ_qd = val
================================================
FILE: src/models/generated/SCRX.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SCRX <: AVR
Ta_Tb::Float64
Tb::Float64
K::Float64
Te::Float64
Efd_lim::MinMax
switch::Int
rc_rfd::Float64
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
This exciter is based on an IEEE type SCRX solid state exciter. The output field voltage is varied by a control system to maintain the system voltage at Vref. Please note that this exciter model has no initialization capabilities - this means that it will respond to whatever inputs it receives regardless of the state of the machine model
# Arguments
- `Ta_Tb::Float64`: Lead input constant ratio, validation range: `(0.05, 0.3)`
- `Tb::Float64`: Lag input constant in s, validation range: `(5, 20)`
- `K::Float64`: Regulator Gain, validation range: `(20, 100)`
- `Te::Float64`: Regulator Time Constant, validation range: `(0, 1)`
- `Efd_lim::MinMax`: Field Voltage regulator limits (regulator output) (Efd_min, Efd_max)
- `switch::Int`: Switch, validation range: `(0, 1)`
- `rc_rfd::Float64`: Field current capability. Set = 0 for negative current capability. Typical value 10, validation range: `(0, 10)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vr1: First integrator,
Vr2: Second integrator
- `n_states::Int`: (**Do not modify.**) SCRX has 2 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) SCRX has 2 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SCRX <: AVR
"Lead input constant ratio"
Ta_Tb::Float64
"Lag input constant in s"
Tb::Float64
"Regulator Gain"
K::Float64
"Regulator Time Constant"
Te::Float64
"Field Voltage regulator limits (regulator output) (Efd_min, Efd_max)"
Efd_lim::MinMax
"Switch"
switch::Int
"Field current capability. Set = 0 for negative current capability. Typical value 10"
rc_rfd::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vr1: First integrator,
Vr2: Second integrator"
states::Vector{Symbol}
"(**Do not modify.**) SCRX has 2 states"
n_states::Int
"(**Do not modify.**) SCRX has 2 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SCRX(Ta_Tb, Tb, K, Te, Efd_lim, switch, rc_rfd, V_ref=1.0, ext=Dict{String, Any}(), )
SCRX(Ta_Tb, Tb, K, Te, Efd_lim, switch, rc_rfd, V_ref, ext, [:Vr1, :Vr2], 2, [StateTypes.Differential, StateTypes.Hybrid], InfrastructureSystemsInternal(), )
end
function SCRX(; Ta_Tb, Tb, K, Te, Efd_lim, switch, rc_rfd, V_ref=1.0, ext=Dict{String, Any}(), states=[:Vr1, :Vr2], n_states=2, states_types=[StateTypes.Differential, StateTypes.Hybrid], internal=InfrastructureSystemsInternal(), )
SCRX(Ta_Tb, Tb, K, Te, Efd_lim, switch, rc_rfd, V_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function SCRX(::Nothing)
SCRX(;
Ta_Tb=0,
Tb=0,
K=0,
Te=0,
Efd_lim=(min=0.0, max=0.0),
switch=0,
rc_rfd=0,
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`SCRX`](@ref) `Ta_Tb`."""
get_Ta_Tb(value::SCRX) = value.Ta_Tb
"""Get [`SCRX`](@ref) `Tb`."""
get_Tb(value::SCRX) = value.Tb
"""Get [`SCRX`](@ref) `K`."""
get_K(value::SCRX) = value.K
"""Get [`SCRX`](@ref) `Te`."""
get_Te(value::SCRX) = value.Te
"""Get [`SCRX`](@ref) `Efd_lim`."""
get_Efd_lim(value::SCRX) = value.Efd_lim
"""Get [`SCRX`](@ref) `switch`."""
get_switch(value::SCRX) = value.switch
"""Get [`SCRX`](@ref) `rc_rfd`."""
get_rc_rfd(value::SCRX) = value.rc_rfd
"""Get [`SCRX`](@ref) `V_ref`."""
get_V_ref(value::SCRX) = value.V_ref
"""Get [`SCRX`](@ref) `ext`."""
get_ext(value::SCRX) = value.ext
"""Get [`SCRX`](@ref) `states`."""
get_states(value::SCRX) = value.states
"""Get [`SCRX`](@ref) `n_states`."""
get_n_states(value::SCRX) = value.n_states
"""Get [`SCRX`](@ref) `states_types`."""
get_states_types(value::SCRX) = value.states_types
"""Get [`SCRX`](@ref) `internal`."""
get_internal(value::SCRX) = value.internal
"""Set [`SCRX`](@ref) `Ta_Tb`."""
set_Ta_Tb!(value::SCRX, val) = value.Ta_Tb = val
"""Set [`SCRX`](@ref) `Tb`."""
set_Tb!(value::SCRX, val) = value.Tb = val
"""Set [`SCRX`](@ref) `K`."""
set_K!(value::SCRX, val) = value.K = val
"""Set [`SCRX`](@ref) `Te`."""
set_Te!(value::SCRX, val) = value.Te = val
"""Set [`SCRX`](@ref) `Efd_lim`."""
set_Efd_lim!(value::SCRX, val) = value.Efd_lim = val
"""Set [`SCRX`](@ref) `switch`."""
set_switch!(value::SCRX, val) = value.switch = val
"""Set [`SCRX`](@ref) `rc_rfd`."""
set_rc_rfd!(value::SCRX, val) = value.rc_rfd = val
"""Set [`SCRX`](@ref) `V_ref`."""
set_V_ref!(value::SCRX, val) = value.V_ref = val
"""Set [`SCRX`](@ref) `ext`."""
set_ext!(value::SCRX, val) = value.ext = val
"""Set [`SCRX`](@ref) `states_types`."""
set_states_types!(value::SCRX, val) = value.states_types = val
================================================
FILE: src/models/generated/SEXS.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SEXS <: AVR
Ta_Tb::Float64
Tb::Float64
K::Float64
Te::Float64
V_lim::MinMax
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Parameters of Simplified Excitation System Model - SEXS in PSSE
# Arguments
- `Ta_Tb::Float64`: Ratio of lead and lag time constants, validation range: `(0, nothing)`
- `Tb::Float64`: Lag time constant, validation range: `(eps(), nothing)`
- `K::Float64`: Gain, validation range: `(0, nothing)`
- `Te::Float64`: Field circuit time constant in s, validation range: `(0, nothing)`
- `V_lim::MinMax`: Field voltage limits
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are: Vf: Voltage field, Vr: Lead-lag state
- `n_states::Int`: (**Do not modify.**) SEXS has 2 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) SEXS has 2 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SEXS <: AVR
"Ratio of lead and lag time constants"
Ta_Tb::Float64
"Lag time constant"
Tb::Float64
"Gain"
K::Float64
"Field circuit time constant in s"
Te::Float64
"Field voltage limits"
V_lim::MinMax
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are: Vf: Voltage field, Vr: Lead-lag state"
states::Vector{Symbol}
"(**Do not modify.**) SEXS has 2 states"
n_states::Int
"(**Do not modify.**) SEXS has 2 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SEXS(Ta_Tb, Tb, K, Te, V_lim, V_ref=1.0, ext=Dict{String, Any}(), )
SEXS(Ta_Tb, Tb, K, Te, V_lim, V_ref, ext, [:Vf, :Vr], 2, [StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function SEXS(; Ta_Tb, Tb, K, Te, V_lim, V_ref=1.0, ext=Dict{String, Any}(), states=[:Vf, :Vr], n_states=2, states_types=[StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
SEXS(Ta_Tb, Tb, K, Te, V_lim, V_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function SEXS(::Nothing)
SEXS(;
Ta_Tb=0,
Tb=0,
K=0,
Te=0,
V_lim=(min=0.0, max=0.0),
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`SEXS`](@ref) `Ta_Tb`."""
get_Ta_Tb(value::SEXS) = value.Ta_Tb
"""Get [`SEXS`](@ref) `Tb`."""
get_Tb(value::SEXS) = value.Tb
"""Get [`SEXS`](@ref) `K`."""
get_K(value::SEXS) = value.K
"""Get [`SEXS`](@ref) `Te`."""
get_Te(value::SEXS) = value.Te
"""Get [`SEXS`](@ref) `V_lim`."""
get_V_lim(value::SEXS) = value.V_lim
"""Get [`SEXS`](@ref) `V_ref`."""
get_V_ref(value::SEXS) = value.V_ref
"""Get [`SEXS`](@ref) `ext`."""
get_ext(value::SEXS) = value.ext
"""Get [`SEXS`](@ref) `states`."""
get_states(value::SEXS) = value.states
"""Get [`SEXS`](@ref) `n_states`."""
get_n_states(value::SEXS) = value.n_states
"""Get [`SEXS`](@ref) `states_types`."""
get_states_types(value::SEXS) = value.states_types
"""Get [`SEXS`](@ref) `internal`."""
get_internal(value::SEXS) = value.internal
"""Set [`SEXS`](@ref) `Ta_Tb`."""
set_Ta_Tb!(value::SEXS, val) = value.Ta_Tb = val
"""Set [`SEXS`](@ref) `Tb`."""
set_Tb!(value::SEXS, val) = value.Tb = val
"""Set [`SEXS`](@ref) `K`."""
set_K!(value::SEXS, val) = value.K = val
"""Set [`SEXS`](@ref) `Te`."""
set_Te!(value::SEXS, val) = value.Te = val
"""Set [`SEXS`](@ref) `V_lim`."""
set_V_lim!(value::SEXS, val) = value.V_lim = val
"""Set [`SEXS`](@ref) `V_ref`."""
set_V_ref!(value::SEXS, val) = value.V_ref = val
"""Set [`SEXS`](@ref) `ext`."""
set_ext!(value::SEXS, val) = value.ext = val
"""Set [`SEXS`](@ref) `states_types`."""
set_states_types!(value::SEXS, val) = value.states_types = val
================================================
FILE: src/models/generated/ST6B.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ST6B <: AVR
OEL_Flag::Int
Tr::Float64
K_pa::Float64
K_ia::Float64
K_da::Float64
T_da::Float64
Va_lim::MinMax
K_ff::Float64
K_m::Float64
K_ci::Float64
K_lr::Float64
I_lr::Float64
Vr_lim::MinMax
Kg::Float64
Tg::Float64
V_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
In these excitation systems, voltage (and also current in compounded systems) is transformed to an appropriate level. Rectifiers, either controlled or non-controlled, provide the necessary direct current for the generator field.
Parameters of IEEE Std 421.5 Type ST6B Excitacion System. ST6B in PSSE and PSLF
# Arguments
- `OEL_Flag::Int`: OEL Flag for ST6B: 1: before HV gate, 2: after HV gate, validation range: `(0, 2)`
- `Tr::Float64`: Regulator input filter time constant in s, validation range: `(0, nothing)`
- `K_pa::Float64`: Regulator proportional gain, validation range: `(0, nothing)`
- `K_ia::Float64`: Regulator integral gain, validation range: `(0, nothing)`
- `K_da::Float64`: Regulator derivative gain, validation range: `(0, nothing)`
- `T_da::Float64`: Voltage regulator derivative channel time constant in s, validation range: `(0, nothing)`
- `Va_lim::MinMax`: Regulator output limits (Vi_min, Vi_max)
- `K_ff::Float64`: Pre-control gain of the inner loop field regulator, validation range: `(0, nothing)`
- `K_m::Float64`: Forward gain of the inner loop field regulator, validation range: `(0, nothing)`
- `K_ci::Float64`: Exciter output current limit adjustment gain, validation range: `(0, nothing)`
- `K_lr::Float64`: Exciter output current limiter gain, validation range: `(0, nothing)`
- `I_lr::Float64`: Exciter current limiter reference, validation range: `(0, nothing)`
- `Vr_lim::MinMax`: Voltage regulator limits (Vi_min, Vi_max)
- `Kg::Float64`: Feedback gain constant of the inner loop field regulator, validation range: `(0, nothing)`
- `Tg::Float64`: Feedback time constant of the inner loop field voltage regulator in s, validation range: `(0, nothing)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
x_i: Regulator Integrator,
x_d: Regulator Derivative,
Vg: Regulator Feedback
- `n_states::Int`: (**Do not modify.**) ST6B has 4 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) ST6B has 4 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ST6B <: AVR
"OEL Flag for ST6B: 1: before HV gate, 2: after HV gate"
OEL_Flag::Int
"Regulator input filter time constant in s"
Tr::Float64
"Regulator proportional gain"
K_pa::Float64
"Regulator integral gain"
K_ia::Float64
"Regulator derivative gain"
K_da::Float64
"Voltage regulator derivative channel time constant in s"
T_da::Float64
"Regulator output limits (Vi_min, Vi_max)"
Va_lim::MinMax
"Pre-control gain of the inner loop field regulator"
K_ff::Float64
"Forward gain of the inner loop field regulator"
K_m::Float64
"Exciter output current limit adjustment gain"
K_ci::Float64
"Exciter output current limiter gain"
K_lr::Float64
"Exciter current limiter reference"
I_lr::Float64
"Voltage regulator limits (Vi_min, Vi_max)"
Vr_lim::MinMax
"Feedback gain constant of the inner loop field regulator"
Kg::Float64
"Feedback time constant of the inner loop field voltage regulator in s"
Tg::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
x_i: Regulator Integrator,
x_d: Regulator Derivative,
Vg: Regulator Feedback"
states::Vector{Symbol}
"(**Do not modify.**) ST6B has 4 states"
n_states::Int
"(**Do not modify.**) ST6B has 4 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ST6B(OEL_Flag, Tr, K_pa, K_ia, K_da, T_da, Va_lim, K_ff, K_m, K_ci, K_lr, I_lr, Vr_lim, Kg, Tg, V_ref=1.0, ext=Dict{String, Any}(), )
ST6B(OEL_Flag, Tr, K_pa, K_ia, K_da, T_da, Va_lim, K_ff, K_m, K_ci, K_lr, I_lr, Vr_lim, Kg, Tg, V_ref, ext, [:Vm, :x_i, :x_d, :Vg], 4, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], InfrastructureSystemsInternal(), )
end
function ST6B(; OEL_Flag, Tr, K_pa, K_ia, K_da, T_da, Va_lim, K_ff, K_m, K_ci, K_lr, I_lr, Vr_lim, Kg, Tg, V_ref=1.0, ext=Dict{String, Any}(), states=[:Vm, :x_i, :x_d, :Vg], n_states=4, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], internal=InfrastructureSystemsInternal(), )
ST6B(OEL_Flag, Tr, K_pa, K_ia, K_da, T_da, Va_lim, K_ff, K_m, K_ci, K_lr, I_lr, Vr_lim, Kg, Tg, V_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function ST6B(::Nothing)
ST6B(;
OEL_Flag=0,
Tr=0,
K_pa=0,
K_ia=0,
K_da=0,
T_da=0,
Va_lim=(min=0.0, max=0.0),
K_ff=0,
K_m=0,
K_ci=0,
K_lr=0,
I_lr=0,
Vr_lim=(min=0.0, max=0.0),
Kg=0,
Tg=0,
V_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ST6B`](@ref) `OEL_Flag`."""
get_OEL_Flag(value::ST6B) = value.OEL_Flag
"""Get [`ST6B`](@ref) `Tr`."""
get_Tr(value::ST6B) = value.Tr
"""Get [`ST6B`](@ref) `K_pa`."""
get_K_pa(value::ST6B) = value.K_pa
"""Get [`ST6B`](@ref) `K_ia`."""
get_K_ia(value::ST6B) = value.K_ia
"""Get [`ST6B`](@ref) `K_da`."""
get_K_da(value::ST6B) = value.K_da
"""Get [`ST6B`](@ref) `T_da`."""
get_T_da(value::ST6B) = value.T_da
"""Get [`ST6B`](@ref) `Va_lim`."""
get_Va_lim(value::ST6B) = value.Va_lim
"""Get [`ST6B`](@ref) `K_ff`."""
get_K_ff(value::ST6B) = value.K_ff
"""Get [`ST6B`](@ref) `K_m`."""
get_K_m(value::ST6B) = value.K_m
"""Get [`ST6B`](@ref) `K_ci`."""
get_K_ci(value::ST6B) = value.K_ci
"""Get [`ST6B`](@ref) `K_lr`."""
get_K_lr(value::ST6B) = value.K_lr
"""Get [`ST6B`](@ref) `I_lr`."""
get_I_lr(value::ST6B) = value.I_lr
"""Get [`ST6B`](@ref) `Vr_lim`."""
get_Vr_lim(value::ST6B) = value.Vr_lim
"""Get [`ST6B`](@ref) `Kg`."""
get_Kg(value::ST6B) = value.Kg
"""Get [`ST6B`](@ref) `Tg`."""
get_Tg(value::ST6B) = value.Tg
"""Get [`ST6B`](@ref) `V_ref`."""
get_V_ref(value::ST6B) = value.V_ref
"""Get [`ST6B`](@ref) `ext`."""
get_ext(value::ST6B) = value.ext
"""Get [`ST6B`](@ref) `states`."""
get_states(value::ST6B) = value.states
"""Get [`ST6B`](@ref) `n_states`."""
get_n_states(value::ST6B) = value.n_states
"""Get [`ST6B`](@ref) `states_types`."""
get_states_types(value::ST6B) = value.states_types
"""Get [`ST6B`](@ref) `internal`."""
get_internal(value::ST6B) = value.internal
"""Set [`ST6B`](@ref) `OEL_Flag`."""
set_OEL_Flag!(value::ST6B, val) = value.OEL_Flag = val
"""Set [`ST6B`](@ref) `Tr`."""
set_Tr!(value::ST6B, val) = value.Tr = val
"""Set [`ST6B`](@ref) `K_pa`."""
set_K_pa!(value::ST6B, val) = value.K_pa = val
"""Set [`ST6B`](@ref) `K_ia`."""
set_K_ia!(value::ST6B, val) = value.K_ia = val
"""Set [`ST6B`](@ref) `K_da`."""
set_K_da!(value::ST6B, val) = value.K_da = val
"""Set [`ST6B`](@ref) `T_da`."""
set_T_da!(value::ST6B, val) = value.T_da = val
"""Set [`ST6B`](@ref) `Va_lim`."""
set_Va_lim!(value::ST6B, val) = value.Va_lim = val
"""Set [`ST6B`](@ref) `K_ff`."""
set_K_ff!(value::ST6B, val) = value.K_ff = val
"""Set [`ST6B`](@ref) `K_m`."""
set_K_m!(value::ST6B, val) = value.K_m = val
"""Set [`ST6B`](@ref) `K_ci`."""
set_K_ci!(value::ST6B, val) = value.K_ci = val
"""Set [`ST6B`](@ref) `K_lr`."""
set_K_lr!(value::ST6B, val) = value.K_lr = val
"""Set [`ST6B`](@ref) `I_lr`."""
set_I_lr!(value::ST6B, val) = value.I_lr = val
"""Set [`ST6B`](@ref) `Vr_lim`."""
set_Vr_lim!(value::ST6B, val) = value.Vr_lim = val
"""Set [`ST6B`](@ref) `Kg`."""
set_Kg!(value::ST6B, val) = value.Kg = val
"""Set [`ST6B`](@ref) `Tg`."""
set_Tg!(value::ST6B, val) = value.Tg = val
"""Set [`ST6B`](@ref) `V_ref`."""
set_V_ref!(value::ST6B, val) = value.V_ref = val
"""Set [`ST6B`](@ref) `ext`."""
set_ext!(value::ST6B, val) = value.ext = val
"""Set [`ST6B`](@ref) `states_types`."""
set_states_types!(value::ST6B, val) = value.states_types = val
================================================
FILE: src/models/generated/ST8C.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ST8C <: AVR
OEL_Flag::Int
UEL_Flag::Int
SCL_Flag::Int
SW1_Flag::Int
Tr::Float64
K_pr::Float64
K_ir::Float64
Vpi_lim::MinMax
K_pa::Float64
K_ia::Float64
Va_lim::MinMax
K_a::Float64
T_a::Float64
Vr_lim::MinMax
K_f::Float64
T_f::Float64
K_c1::Float64
K_p::Float64
K_i1::Float64
X_l::Float64
θ_p::Float64
VB1_max::Float64
K_c2::Float64
K_i2::Float64
VB2_max::Float64
V_ref::Float64
Ifd_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
In these excitation systems, voltage (and also current in compounded systems) is transformed to an appropriate level. Rectifiers, either controlled or non-controlled, provide the necessary direct current for the generator field.
Parameters of IEEE Std 421.5 Type ST8C Excitacion System. ST8C in PSSE and PSLF
# Arguments
- `OEL_Flag::Int`: OEL Flag for ST8C: <2: Summation at Voltage Error, 2: OEL takeover at gate, validation range: `(0, 2)`
- `UEL_Flag::Int`: UEL Flag for ST8C: <2: Summation at Voltage Error, 2: UEL takeover at gate, validation range: `(0, 2)`
- `SCL_Flag::Int`: SCL Flag for ST8C: <2: Summation at Voltage Error, 2: SCL Takeover at UEL and OEL gates, validation range: `(0, 2)`
- `SW1_Flag::Int`: SW1 Flag for Power Source Selector for ST8C: <2: Source from generator terminal voltage, 2: Independent power source, validation range: `(0, 2)`
- `Tr::Float64`: Regulator input filter time constant in seconds, validation range: `(0, nothing)`
- `K_pr::Float64`: Regulator proportional gain (pu), validation range: `(0, nothing)`
- `K_ir::Float64`: Regulator integral gain (pu), validation range: `(0, nothing)`
- `Vpi_lim::MinMax`: Regulator input limits (Vpi_min, Vpi_max)
- `K_pa::Float64`: Field current regulator proportional gain (pu), validation range: `(0, nothing)`
- `K_ia::Float64`: Field current regulator integral gain (pu), validation range: `(0, nothing)`
- `Va_lim::MinMax`: Field current regulator output limits (Va_min, Va_max)
- `K_a::Float64`: Field current regulator proportional gain (pu), validation range: `(0, nothing)`
- `T_a::Float64`: Controlled rectifier bridge equivalent time constant in seconds, validation range: `(0, nothing)`
- `Vr_lim::MinMax`: Voltage regulator limits (Vr_min, Vr_max)
- `K_f::Float64`: Exciter field current feedback gain (pu), validation range: `(0, nothing)`
- `T_f::Float64`: Field current feedback time constant in seconds, validation range: `(0, nothing)`
- `K_c1::Float64`: Rectifier loading factor proportional to commutating reactance (pu), validation range: `(0, nothing)`
- `K_p::Float64`: Potential circuit (voltage) gain coefficient (pu), validation range: `(0, nothing)`
- `K_i1::Float64`: Potential circuit (current) gain coefficient (pu), validation range: `(0, nothing)`
- `X_l::Float64`: Reactance associated with potential source (pu), validation range: `(0, nothing)`
- `θ_p::Float64`: Potential circuit phase angle (degrees), validation range: `(0, nothing)`
- `VB1_max::Float64`: Maximum available exciter voltage (pu), validation range: `(0, nothing)`
- `K_c2::Float64`: Rectifier loading factor proportional to commutating reactance (pu), validation range: `(0, nothing)`
- `K_i2::Float64`: Potential circuit (current) gain coefficient (pu), validation range: `(0, nothing)`
- `VB2_max::Float64`: Maximum available exciter voltage (pu), validation range: `(0, nothing)`
- `V_ref::Float64`: (default: `1.0`) Reference Voltage Set-point (pu), validation range: `(0, nothing)`
- `Ifd_ref::Float64`: (default: `1.0`) Reference Field Current Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
x_a1: Regulator Integrator state,
x_a2: Field Current regulator state,
x_a3: Controller rectifier bridge state,
x_a4: Regulator Feedback state
- `n_states::Int`: (**Do not modify.**) ST8C has 5 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) ST8C has 5 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ST8C <: AVR
"OEL Flag for ST8C: <2: Summation at Voltage Error, 2: OEL takeover at gate"
OEL_Flag::Int
"UEL Flag for ST8C: <2: Summation at Voltage Error, 2: UEL takeover at gate"
UEL_Flag::Int
"SCL Flag for ST8C: <2: Summation at Voltage Error, 2: SCL Takeover at UEL and OEL gates"
SCL_Flag::Int
"SW1 Flag for Power Source Selector for ST8C: <2: Source from generator terminal voltage, 2: Independent power source"
SW1_Flag::Int
"Regulator input filter time constant in seconds"
Tr::Float64
"Regulator proportional gain (pu)"
K_pr::Float64
"Regulator integral gain (pu)"
K_ir::Float64
"Regulator input limits (Vpi_min, Vpi_max)"
Vpi_lim::MinMax
"Field current regulator proportional gain (pu)"
K_pa::Float64
"Field current regulator integral gain (pu)"
K_ia::Float64
"Field current regulator output limits (Va_min, Va_max)"
Va_lim::MinMax
"Field current regulator proportional gain (pu)"
K_a::Float64
"Controlled rectifier bridge equivalent time constant in seconds"
T_a::Float64
"Voltage regulator limits (Vr_min, Vr_max)"
Vr_lim::MinMax
"Exciter field current feedback gain (pu)"
K_f::Float64
"Field current feedback time constant in seconds"
T_f::Float64
"Rectifier loading factor proportional to commutating reactance (pu)"
K_c1::Float64
"Potential circuit (voltage) gain coefficient (pu)"
K_p::Float64
"Potential circuit (current) gain coefficient (pu)"
K_i1::Float64
"Reactance associated with potential source (pu)"
X_l::Float64
"Potential circuit phase angle (degrees)"
θ_p::Float64
"Maximum available exciter voltage (pu)"
VB1_max::Float64
"Rectifier loading factor proportional to commutating reactance (pu)"
K_c2::Float64
"Potential circuit (current) gain coefficient (pu)"
K_i2::Float64
"Maximum available exciter voltage (pu)"
VB2_max::Float64
"Reference Voltage Set-point (pu)"
V_ref::Float64
"Reference Field Current Set-point (pu)"
Ifd_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
Vm: Sensed terminal voltage,
x_a1: Regulator Integrator state,
x_a2: Field Current regulator state,
x_a3: Controller rectifier bridge state,
x_a4: Regulator Feedback state"
states::Vector{Symbol}
"(**Do not modify.**) ST8C has 5 states"
n_states::Int
"(**Do not modify.**) ST8C has 5 states"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ST8C(OEL_Flag, UEL_Flag, SCL_Flag, SW1_Flag, Tr, K_pr, K_ir, Vpi_lim, K_pa, K_ia, Va_lim, K_a, T_a, Vr_lim, K_f, T_f, K_c1, K_p, K_i1, X_l, θ_p, VB1_max, K_c2, K_i2, VB2_max, V_ref=1.0, Ifd_ref=1.0, ext=Dict{String, Any}(), )
ST8C(OEL_Flag, UEL_Flag, SCL_Flag, SW1_Flag, Tr, K_pr, K_ir, Vpi_lim, K_pa, K_ia, Va_lim, K_a, T_a, Vr_lim, K_f, T_f, K_c1, K_p, K_i1, X_l, θ_p, VB1_max, K_c2, K_i2, VB2_max, V_ref, Ifd_ref, ext, [:Vm, :x_a1, :x_a2, :x_a3, :x_a4], 5, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], InfrastructureSystemsInternal(), )
end
function ST8C(; OEL_Flag, UEL_Flag, SCL_Flag, SW1_Flag, Tr, K_pr, K_ir, Vpi_lim, K_pa, K_ia, Va_lim, K_a, T_a, Vr_lim, K_f, T_f, K_c1, K_p, K_i1, X_l, θ_p, VB1_max, K_c2, K_i2, VB2_max, V_ref=1.0, Ifd_ref=1.0, ext=Dict{String, Any}(), states=[:Vm, :x_a1, :x_a2, :x_a3, :x_a4], n_states=5, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], internal=InfrastructureSystemsInternal(), )
ST8C(OEL_Flag, UEL_Flag, SCL_Flag, SW1_Flag, Tr, K_pr, K_ir, Vpi_lim, K_pa, K_ia, Va_lim, K_a, T_a, Vr_lim, K_f, T_f, K_c1, K_p, K_i1, X_l, θ_p, VB1_max, K_c2, K_i2, VB2_max, V_ref, Ifd_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function ST8C(::Nothing)
ST8C(;
OEL_Flag=0,
UEL_Flag=0,
SCL_Flag=0,
SW1_Flag=0,
Tr=0,
K_pr=0,
K_ir=0,
Vpi_lim=(min=0.0, max=0.0),
K_pa=0,
K_ia=0,
Va_lim=(min=0.0, max=0.0),
K_a=0,
T_a=0,
Vr_lim=(min=0.0, max=0.0),
K_f=0,
T_f=0,
K_c1=0,
K_p=0,
K_i1=0,
X_l=0,
θ_p=0,
VB1_max=0,
K_c2=0,
K_i2=0,
VB2_max=0,
V_ref=0,
Ifd_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ST8C`](@ref) `OEL_Flag`."""
get_OEL_Flag(value::ST8C) = value.OEL_Flag
"""Get [`ST8C`](@ref) `UEL_Flag`."""
get_UEL_Flag(value::ST8C) = value.UEL_Flag
"""Get [`ST8C`](@ref) `SCL_Flag`."""
get_SCL_Flag(value::ST8C) = value.SCL_Flag
"""Get [`ST8C`](@ref) `SW1_Flag`."""
get_SW1_Flag(value::ST8C) = value.SW1_Flag
"""Get [`ST8C`](@ref) `Tr`."""
get_Tr(value::ST8C) = value.Tr
"""Get [`ST8C`](@ref) `K_pr`."""
get_K_pr(value::ST8C) = value.K_pr
"""Get [`ST8C`](@ref) `K_ir`."""
get_K_ir(value::ST8C) = value.K_ir
"""Get [`ST8C`](@ref) `Vpi_lim`."""
get_Vpi_lim(value::ST8C) = value.Vpi_lim
"""Get [`ST8C`](@ref) `K_pa`."""
get_K_pa(value::ST8C) = value.K_pa
"""Get [`ST8C`](@ref) `K_ia`."""
get_K_ia(value::ST8C) = value.K_ia
"""Get [`ST8C`](@ref) `Va_lim`."""
get_Va_lim(value::ST8C) = value.Va_lim
"""Get [`ST8C`](@ref) `K_a`."""
get_K_a(value::ST8C) = value.K_a
"""Get [`ST8C`](@ref) `T_a`."""
get_T_a(value::ST8C) = value.T_a
"""Get [`ST8C`](@ref) `Vr_lim`."""
get_Vr_lim(value::ST8C) = value.Vr_lim
"""Get [`ST8C`](@ref) `K_f`."""
get_K_f(value::ST8C) = value.K_f
"""Get [`ST8C`](@ref) `T_f`."""
get_T_f(value::ST8C) = value.T_f
"""Get [`ST8C`](@ref) `K_c1`."""
get_K_c1(value::ST8C) = value.K_c1
"""Get [`ST8C`](@ref) `K_p`."""
get_K_p(value::ST8C) = value.K_p
"""Get [`ST8C`](@ref) `K_i1`."""
get_K_i1(value::ST8C) = value.K_i1
"""Get [`ST8C`](@ref) `X_l`."""
get_X_l(value::ST8C) = value.X_l
"""Get [`ST8C`](@ref) `θ_p`."""
get_θ_p(value::ST8C) = value.θ_p
"""Get [`ST8C`](@ref) `VB1_max`."""
get_VB1_max(value::ST8C) = value.VB1_max
"""Get [`ST8C`](@ref) `K_c2`."""
get_K_c2(value::ST8C) = value.K_c2
"""Get [`ST8C`](@ref) `K_i2`."""
get_K_i2(value::ST8C) = value.K_i2
"""Get [`ST8C`](@ref) `VB2_max`."""
get_VB2_max(value::ST8C) = value.VB2_max
"""Get [`ST8C`](@ref) `V_ref`."""
get_V_ref(value::ST8C) = value.V_ref
"""Get [`ST8C`](@ref) `Ifd_ref`."""
get_Ifd_ref(value::ST8C) = value.Ifd_ref
"""Get [`ST8C`](@ref) `ext`."""
get_ext(value::ST8C) = value.ext
"""Get [`ST8C`](@ref) `states`."""
get_states(value::ST8C) = value.states
"""Get [`ST8C`](@ref) `n_states`."""
get_n_states(value::ST8C) = value.n_states
"""Get [`ST8C`](@ref) `states_types`."""
get_states_types(value::ST8C) = value.states_types
"""Get [`ST8C`](@ref) `internal`."""
get_internal(value::ST8C) = value.internal
"""Set [`ST8C`](@ref) `OEL_Flag`."""
set_OEL_Flag!(value::ST8C, val) = value.OEL_Flag = val
"""Set [`ST8C`](@ref) `UEL_Flag`."""
set_UEL_Flag!(value::ST8C, val) = value.UEL_Flag = val
"""Set [`ST8C`](@ref) `SCL_Flag`."""
set_SCL_Flag!(value::ST8C, val) = value.SCL_Flag = val
"""Set [`ST8C`](@ref) `SW1_Flag`."""
set_SW1_Flag!(value::ST8C, val) = value.SW1_Flag = val
"""Set [`ST8C`](@ref) `Tr`."""
set_Tr!(value::ST8C, val) = value.Tr = val
"""Set [`ST8C`](@ref) `K_pr`."""
set_K_pr!(value::ST8C, val) = value.K_pr = val
"""Set [`ST8C`](@ref) `K_ir`."""
set_K_ir!(value::ST8C, val) = value.K_ir = val
"""Set [`ST8C`](@ref) `Vpi_lim`."""
set_Vpi_lim!(value::ST8C, val) = value.Vpi_lim = val
"""Set [`ST8C`](@ref) `K_pa`."""
set_K_pa!(value::ST8C, val) = value.K_pa = val
"""Set [`ST8C`](@ref) `K_ia`."""
set_K_ia!(value::ST8C, val) = value.K_ia = val
"""Set [`ST8C`](@ref) `Va_lim`."""
set_Va_lim!(value::ST8C, val) = value.Va_lim = val
"""Set [`ST8C`](@ref) `K_a`."""
set_K_a!(value::ST8C, val) = value.K_a = val
"""Set [`ST8C`](@ref) `T_a`."""
set_T_a!(value::ST8C, val) = value.T_a = val
"""Set [`ST8C`](@ref) `Vr_lim`."""
set_Vr_lim!(value::ST8C, val) = value.Vr_lim = val
"""Set [`ST8C`](@ref) `K_f`."""
set_K_f!(value::ST8C, val) = value.K_f = val
"""Set [`ST8C`](@ref) `T_f`."""
set_T_f!(value::ST8C, val) = value.T_f = val
"""Set [`ST8C`](@ref) `K_c1`."""
set_K_c1!(value::ST8C, val) = value.K_c1 = val
"""Set [`ST8C`](@ref) `K_p`."""
set_K_p!(value::ST8C, val) = value.K_p = val
"""Set [`ST8C`](@ref) `K_i1`."""
set_K_i1!(value::ST8C, val) = value.K_i1 = val
"""Set [`ST8C`](@ref) `X_l`."""
set_X_l!(value::ST8C, val) = value.X_l = val
"""Set [`ST8C`](@ref) `θ_p`."""
set_θ_p!(value::ST8C, val) = value.θ_p = val
"""Set [`ST8C`](@ref) `VB1_max`."""
set_VB1_max!(value::ST8C, val) = value.VB1_max = val
"""Set [`ST8C`](@ref) `K_c2`."""
set_K_c2!(value::ST8C, val) = value.K_c2 = val
"""Set [`ST8C`](@ref) `K_i2`."""
set_K_i2!(value::ST8C, val) = value.K_i2 = val
"""Set [`ST8C`](@ref) `VB2_max`."""
set_VB2_max!(value::ST8C, val) = value.VB2_max = val
"""Set [`ST8C`](@ref) `V_ref`."""
set_V_ref!(value::ST8C, val) = value.V_ref = val
"""Set [`ST8C`](@ref) `Ifd_ref`."""
set_Ifd_ref!(value::ST8C, val) = value.Ifd_ref = val
"""Set [`ST8C`](@ref) `ext`."""
set_ext!(value::ST8C, val) = value.ext = val
"""Set [`ST8C`](@ref) `states_types`."""
set_states_types!(value::ST8C, val) = value.states_types = val
================================================
FILE: src/models/generated/STAB1.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct STAB1 <: PSS
KT::Float64
T::Float64
T1T3::Float64
T3::Float64
T2T4::Float64
T4::Float64
H_lim::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Speed-Sensitive Stabilizing Model
# Arguments
- `KT::Float64`: K/T for washout filter, validation range: `(0, nothing)`
- `T::Float64`: Time constant for washout filter, validation range: `(0.01, nothing)`
- `T1T3::Float64`: Time constant division T1/T3, validation range: `(0, nothing)`
- `T3::Float64`: Time constant, validation range: `(0.01, nothing)`
- `T2T4::Float64`: Time constant division T2/T4, validation range: `(0, nothing)`
- `T4::Float64`: Time constant, validation range: `(0.01, nothing)`
- `H_lim::Float64`: PSS output limit, validation range: `(0, 0.5)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
x_p1: washout filter,
x_p2: T1/T3 lead-lag block,
x_p3: T2/T4 lead-lag block,
- `n_states::Int`: (**Do not modify.**) STAB1 has 3 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) STAB1 has 3 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct STAB1 <: PSS
"K/T for washout filter"
KT::Float64
"Time constant for washout filter"
T::Float64
"Time constant division T1/T3"
T1T3::Float64
"Time constant"
T3::Float64
"Time constant division T2/T4"
T2T4::Float64
"Time constant"
T4::Float64
"PSS output limit"
H_lim::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
x_p1: washout filter,
x_p2: T1/T3 lead-lag block,
x_p3: T2/T4 lead-lag block,"
states::Vector{Symbol}
"(**Do not modify.**) STAB1 has 3 states"
n_states::Int
"(**Do not modify.**) STAB1 has 3 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function STAB1(KT, T, T1T3, T3, T2T4, T4, H_lim, ext=Dict{String, Any}(), )
STAB1(KT, T, T1T3, T3, T2T4, T4, H_lim, ext, [:x_p1, :x_p2, :x_p3], 3, [StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function STAB1(; KT, T, T1T3, T3, T2T4, T4, H_lim, ext=Dict{String, Any}(), states=[:x_p1, :x_p2, :x_p3], n_states=3, states_types=[StateTypes.Differential, StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
STAB1(KT, T, T1T3, T3, T2T4, T4, H_lim, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function STAB1(::Nothing)
STAB1(;
KT=0,
T=0.01,
T1T3=0,
T3=0.01,
T2T4=0,
T4=0.01,
H_lim=0,
ext=Dict{String, Any}(),
)
end
"""Get [`STAB1`](@ref) `KT`."""
get_KT(value::STAB1) = value.KT
"""Get [`STAB1`](@ref) `T`."""
get_T(value::STAB1) = value.T
"""Get [`STAB1`](@ref) `T1T3`."""
get_T1T3(value::STAB1) = value.T1T3
"""Get [`STAB1`](@ref) `T3`."""
get_T3(value::STAB1) = value.T3
"""Get [`STAB1`](@ref) `T2T4`."""
get_T2T4(value::STAB1) = value.T2T4
"""Get [`STAB1`](@ref) `T4`."""
get_T4(value::STAB1) = value.T4
"""Get [`STAB1`](@ref) `H_lim`."""
get_H_lim(value::STAB1) = value.H_lim
"""Get [`STAB1`](@ref) `ext`."""
get_ext(value::STAB1) = value.ext
"""Get [`STAB1`](@ref) `states`."""
get_states(value::STAB1) = value.states
"""Get [`STAB1`](@ref) `n_states`."""
get_n_states(value::STAB1) = value.n_states
"""Get [`STAB1`](@ref) `states_types`."""
get_states_types(value::STAB1) = value.states_types
"""Get [`STAB1`](@ref) `internal`."""
get_internal(value::STAB1) = value.internal
"""Set [`STAB1`](@ref) `KT`."""
set_KT!(value::STAB1, val) = value.KT = val
"""Set [`STAB1`](@ref) `T`."""
set_T!(value::STAB1, val) = value.T = val
"""Set [`STAB1`](@ref) `T1T3`."""
set_T1T3!(value::STAB1, val) = value.T1T3 = val
"""Set [`STAB1`](@ref) `T3`."""
set_T3!(value::STAB1, val) = value.T3 = val
"""Set [`STAB1`](@ref) `T2T4`."""
set_T2T4!(value::STAB1, val) = value.T2T4 = val
"""Set [`STAB1`](@ref) `T4`."""
set_T4!(value::STAB1, val) = value.T4 = val
"""Set [`STAB1`](@ref) `H_lim`."""
set_H_lim!(value::STAB1, val) = value.H_lim = val
"""Set [`STAB1`](@ref) `ext`."""
set_ext!(value::STAB1, val) = value.ext = val
"""Set [`STAB1`](@ref) `states_types`."""
set_states_types!(value::STAB1, val) = value.states_types = val
================================================
FILE: src/models/generated/SalientPoleMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SalientPoleMachine <: Machine
R::Float64
Td0_p::Float64
Td0_pp::Float64
Tq0_pp::Float64
Xd::Float64
Xq::Float64
Xd_p::Float64
Xd_pp::Float64
Xl::Float64
Se::Tuple{Float64, Float64}
ext::Dict{String, Any}
γ_d1::Float64
γ_q1::Float64
γ_d2::Float64
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 3-[states](@ref S) salient-pole synchronous machine with quadratic/exponential saturation:
IEEE Std 1110 §5.3.1 (Model 2.1). GENSAL or GENSAE model in PSSE and PSLF
# Arguments
- `R::Float64`: Armature resistance, validation range: `(0, nothing)`
- `Td0_p::Float64`: Time constant of transient d-axis voltage, validation range: `(0, nothing)`
- `Td0_pp::Float64`: Time constant of sub-transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_pp::Float64`: Time constant of sub-transient q-axis voltage, validation range: `(0, nothing)`
- `Xd::Float64`: Reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq::Float64`: Reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_p::Float64`: Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xd_pp::Float64`: Sub-Transient reactance after EMF in d-axis per unit. Note: Xd_pp = Xq_pp, validation range: `(0, nothing)`
- `Xl::Float64`: Stator leakage reactance, validation range: `(0, nothing)`
- `Se::Tuple{Float64, Float64}`: Saturation factor at 1 and 1.2 pu flux: Se(eq_p) = B(eq_p-A)^2
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `γ_d1::Float64`: (**Do not modify.**) γ_d1 parameter
- `γ_q1::Float64`: (**Do not modify.**) γ_q1 parameter
- `γ_d2::Float64`: (**Do not modify.**) γ_d2 parameter
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
eq_p: q-axis generator voltage behind the transient reactance,
ψ_kd: flux linkage in the first equivalent damping circuit in the d-axis,
ψq_pp: phasonf of the subtransient flux linkage in the q-axis
- `n_states::Int`: (**Do not modify.**) SalientPoleMachine has 3 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SalientPoleMachine <: Machine
"Armature resistance"
R::Float64
"Time constant of transient d-axis voltage"
Td0_p::Float64
"Time constant of sub-transient d-axis voltage"
Td0_pp::Float64
"Time constant of sub-transient q-axis voltage"
Tq0_pp::Float64
"Reactance after EMF in d-axis per unit"
Xd::Float64
"Reactance after EMF in q-axis per unit"
Xq::Float64
"Transient reactance after EMF in d-axis per unit"
Xd_p::Float64
"Sub-Transient reactance after EMF in d-axis per unit. Note: Xd_pp = Xq_pp"
Xd_pp::Float64
"Stator leakage reactance"
Xl::Float64
"Saturation factor at 1 and 1.2 pu flux: Se(eq_p) = B(eq_p-A)^2"
Se::Tuple{Float64, Float64}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) γ_d1 parameter"
γ_d1::Float64
"(**Do not modify.**) γ_q1 parameter"
γ_q1::Float64
"(**Do not modify.**) γ_d2 parameter"
γ_d2::Float64
"(**Do not modify.**) The [states](@ref S) are:
eq_p: q-axis generator voltage behind the transient reactance,
ψ_kd: flux linkage in the first equivalent damping circuit in the d-axis,
ψq_pp: phasonf of the subtransient flux linkage in the q-axis"
states::Vector{Symbol}
"(**Do not modify.**) SalientPoleMachine has 3 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SalientPoleMachine(R, Td0_p, Td0_pp, Tq0_pp, Xd, Xq, Xd_p, Xd_pp, Xl, Se, ext=Dict{String, Any}(), )
SalientPoleMachine(R, Td0_p, Td0_pp, Tq0_pp, Xd, Xq, Xd_p, Xd_pp, Xl, Se, ext, (Xd_pp - Xl) / (Xd_p - Xl), (Xd_p - Xd_pp) / (Xd_p - Xl), (Xd_p - Xd_pp) / (Xd_p - Xl)^2, [:eq_p, :ψ_kd, :ψq_pp], 3, InfrastructureSystemsInternal(), )
end
function SalientPoleMachine(; R, Td0_p, Td0_pp, Tq0_pp, Xd, Xq, Xd_p, Xd_pp, Xl, Se, ext=Dict{String, Any}(), γ_d1=(Xd_pp - Xl) / (Xd_p - Xl), γ_q1=(Xd_p - Xd_pp) / (Xd_p - Xl), γ_d2=(Xd_p - Xd_pp) / (Xd_p - Xl)^2, states=[:eq_p, :ψ_kd, :ψq_pp], n_states=3, internal=InfrastructureSystemsInternal(), )
SalientPoleMachine(R, Td0_p, Td0_pp, Tq0_pp, Xd, Xq, Xd_p, Xd_pp, Xl, Se, ext, γ_d1, γ_q1, γ_d2, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function SalientPoleMachine(::Nothing)
SalientPoleMachine(;
R=0,
Td0_p=0,
Td0_pp=0,
Tq0_pp=0,
Xd=0,
Xq=0,
Xd_p=0,
Xd_pp=0,
Xl=0,
Se=(0.0, 0.0),
ext=Dict{String, Any}(),
)
end
"""Get [`SalientPoleMachine`](@ref) `R`."""
get_R(value::SalientPoleMachine) = value.R
"""Get [`SalientPoleMachine`](@ref) `Td0_p`."""
get_Td0_p(value::SalientPoleMachine) = value.Td0_p
"""Get [`SalientPoleMachine`](@ref) `Td0_pp`."""
get_Td0_pp(value::SalientPoleMachine) = value.Td0_pp
"""Get [`SalientPoleMachine`](@ref) `Tq0_pp`."""
get_Tq0_pp(value::SalientPoleMachine) = value.Tq0_pp
"""Get [`SalientPoleMachine`](@ref) `Xd`."""
get_Xd(value::SalientPoleMachine) = value.Xd
"""Get [`SalientPoleMachine`](@ref) `Xq`."""
get_Xq(value::SalientPoleMachine) = value.Xq
"""Get [`SalientPoleMachine`](@ref) `Xd_p`."""
get_Xd_p(value::SalientPoleMachine) = value.Xd_p
"""Get [`SalientPoleMachine`](@ref) `Xd_pp`."""
get_Xd_pp(value::SalientPoleMachine) = value.Xd_pp
"""Get [`SalientPoleMachine`](@ref) `Xl`."""
get_Xl(value::SalientPoleMachine) = value.Xl
"""Get [`SalientPoleMachine`](@ref) `Se`."""
get_Se(value::SalientPoleMachine) = value.Se
"""Get [`SalientPoleMachine`](@ref) `ext`."""
get_ext(value::SalientPoleMachine) = value.ext
"""Get [`SalientPoleMachine`](@ref) `γ_d1`."""
get_γ_d1(value::SalientPoleMachine) = value.γ_d1
"""Get [`SalientPoleMachine`](@ref) `γ_q1`."""
get_γ_q1(value::SalientPoleMachine) = value.γ_q1
"""Get [`SalientPoleMachine`](@ref) `γ_d2`."""
get_γ_d2(value::SalientPoleMachine) = value.γ_d2
"""Get [`SalientPoleMachine`](@ref) `states`."""
get_states(value::SalientPoleMachine) = value.states
"""Get [`SalientPoleMachine`](@ref) `n_states`."""
get_n_states(value::SalientPoleMachine) = value.n_states
"""Get [`SalientPoleMachine`](@ref) `internal`."""
get_internal(value::SalientPoleMachine) = value.internal
"""Set [`SalientPoleMachine`](@ref) `R`."""
set_R!(value::SalientPoleMachine, val) = value.R = val
"""Set [`SalientPoleMachine`](@ref) `Td0_p`."""
set_Td0_p!(value::SalientPoleMachine, val) = value.Td0_p = val
"""Set [`SalientPoleMachine`](@ref) `Td0_pp`."""
set_Td0_pp!(value::SalientPoleMachine, val) = value.Td0_pp = val
"""Set [`SalientPoleMachine`](@ref) `Tq0_pp`."""
set_Tq0_pp!(value::SalientPoleMachine, val) = value.Tq0_pp = val
"""Set [`SalientPoleMachine`](@ref) `Xd`."""
set_Xd!(value::SalientPoleMachine, val) = value.Xd = val
"""Set [`SalientPoleMachine`](@ref) `Xq`."""
set_Xq!(value::SalientPoleMachine, val) = value.Xq = val
"""Set [`SalientPoleMachine`](@ref) `Xd_p`."""
set_Xd_p!(value::SalientPoleMachine, val) = value.Xd_p = val
"""Set [`SalientPoleMachine`](@ref) `Xd_pp`."""
set_Xd_pp!(value::SalientPoleMachine, val) = value.Xd_pp = val
"""Set [`SalientPoleMachine`](@ref) `Xl`."""
set_Xl!(value::SalientPoleMachine, val) = value.Xl = val
"""Set [`SalientPoleMachine`](@ref) `Se`."""
set_Se!(value::SalientPoleMachine, val) = value.Se = val
"""Set [`SalientPoleMachine`](@ref) `ext`."""
set_ext!(value::SalientPoleMachine, val) = value.ext = val
"""Set [`SalientPoleMachine`](@ref) `γ_d1`."""
set_γ_d1!(value::SalientPoleMachine, val) = value.γ_d1 = val
"""Set [`SalientPoleMachine`](@ref) `γ_q1`."""
set_γ_q1!(value::SalientPoleMachine, val) = value.γ_q1 = val
"""Set [`SalientPoleMachine`](@ref) `γ_d2`."""
set_γ_d2!(value::SalientPoleMachine, val) = value.γ_d2 = val
================================================
FILE: src/models/generated/SaturationOutputCurrentLimiter.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SaturationOutputCurrentLimiter <: OutputCurrentLimiter
I_max::Float64
kw::Float64
ext::Dict{String, Any}
end
Parameters of Saturation Current Controller Limiter. Regulates the magnitude of the inverter output current, and applies a closed loop feedback regulated by a static gain which provides ant-windup
# Arguments
- `I_max::Float64`: Maximum limit on current controller input current (device base), validation range: `(0, nothing)`
- `kw::Float64`: Defined feedback gain, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`)
"""
mutable struct SaturationOutputCurrentLimiter <: OutputCurrentLimiter
"Maximum limit on current controller input current (device base)"
I_max::Float64
"Defined feedback gain"
kw::Float64
ext::Dict{String, Any}
end
function SaturationOutputCurrentLimiter(; I_max, kw, ext=Dict{String, Any}(), )
SaturationOutputCurrentLimiter(I_max, kw, ext, )
end
# Constructor for demo purposes; non-functional.
function SaturationOutputCurrentLimiter(::Nothing)
SaturationOutputCurrentLimiter(;
I_max=0,
kw=0,
ext=Dict{String, Any}(),
)
end
"""Get [`SaturationOutputCurrentLimiter`](@ref) `I_max`."""
get_I_max(value::SaturationOutputCurrentLimiter) = value.I_max
"""Get [`SaturationOutputCurrentLimiter`](@ref) `kw`."""
get_kw(value::SaturationOutputCurrentLimiter) = value.kw
"""Get [`SaturationOutputCurrentLimiter`](@ref) `ext`."""
get_ext(value::SaturationOutputCurrentLimiter) = value.ext
"""Set [`SaturationOutputCurrentLimiter`](@ref) `I_max`."""
set_I_max!(value::SaturationOutputCurrentLimiter, val) = value.I_max = val
"""Set [`SaturationOutputCurrentLimiter`](@ref) `kw`."""
set_kw!(value::SaturationOutputCurrentLimiter, val) = value.kw = val
"""Set [`SaturationOutputCurrentLimiter`](@ref) `ext`."""
set_ext!(value::SaturationOutputCurrentLimiter, val) = value.ext = val
================================================
FILE: src/models/generated/SauerPaiMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SauerPaiMachine <: Machine
R::Float64
Xd::Float64
Xq::Float64
Xd_p::Float64
Xq_p::Float64
Xd_pp::Float64
Xq_pp::Float64
Xl::Float64
Td0_p::Float64
Tq0_p::Float64
Td0_pp::Float64
Tq0_pp::Float64
ext::Dict{String, Any}
γ_d1::Float64
γ_q1::Float64
γ_d2::Float64
γ_q2::Float64
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of synchronous machine: Sauer Pai model
# Arguments
- `R::Float64`: Resistance after EMF in machine per unit, validation range: `(0, nothing)`
- `Xd::Float64`: Reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq::Float64`: Reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_p::Float64`: Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_p::Float64`: Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_pp::Float64`: Sub-Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_pp::Float64`: Sub-Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xl::Float64`: Stator Leakage Reactance, validation range: `(0, nothing)`
- `Td0_p::Float64`: Time constant of transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_p::Float64`: Time constant of transient q-axis voltage, validation range: `(0, nothing)`
- `Td0_pp::Float64`: Time constant of sub-transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_pp::Float64`: Time constant of sub-transient q-axis voltage, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `γ_d1::Float64`: (**Do not modify.**) Internal equation
- `γ_q1::Float64`: (**Do not modify.**) Internal equation
- `γ_d2::Float64`: (**Do not modify.**) Internal equation
- `γ_q2::Float64`: (**Do not modify.**) Internal equation
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
ψq: q-axis stator flux,
ψd: d-axis stator flux,
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage
ψd_pp: subtransient flux linkage in the d-axis
ψq_pp: subtransient flux linkage in the q-axis
- `n_states::Int`: (**Do not modify.**) SauerPaiMachine has 6 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SauerPaiMachine <: Machine
"Resistance after EMF in machine per unit"
R::Float64
"Reactance after EMF in d-axis per unit"
Xd::Float64
"Reactance after EMF in q-axis per unit"
Xq::Float64
"Transient reactance after EMF in d-axis per unit"
Xd_p::Float64
"Transient reactance after EMF in q-axis per unit"
Xq_p::Float64
"Sub-Transient reactance after EMF in d-axis per unit"
Xd_pp::Float64
"Sub-Transient reactance after EMF in q-axis per unit"
Xq_pp::Float64
"Stator Leakage Reactance"
Xl::Float64
"Time constant of transient d-axis voltage"
Td0_p::Float64
"Time constant of transient q-axis voltage"
Tq0_p::Float64
"Time constant of sub-transient d-axis voltage"
Td0_pp::Float64
"Time constant of sub-transient q-axis voltage"
Tq0_pp::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) Internal equation"
γ_d1::Float64
"(**Do not modify.**) Internal equation"
γ_q1::Float64
"(**Do not modify.**) Internal equation"
γ_d2::Float64
"(**Do not modify.**) Internal equation"
γ_q2::Float64
"(**Do not modify.**) The [states](@ref S) are:
ψq: q-axis stator flux,
ψd: d-axis stator flux,
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage
ψd_pp: subtransient flux linkage in the d-axis
ψq_pp: subtransient flux linkage in the q-axis"
states::Vector{Symbol}
"(**Do not modify.**) SauerPaiMachine has 6 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SauerPaiMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Xl, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext=Dict{String, Any}(), )
SauerPaiMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Xl, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext, (Xd_pp-Xl)/(Xd_p-Xl), (Xq_pp-Xl)/(Xq_p-Xl), (Xd_p - Xd_pp) / (Xd_p - Xl)^2, (Xq_p - Xq_pp) / (Xq_p - Xl)^2, [:ψq, :ψd, :eq_p, :ed_p, :ψd_pp, :ψq_pp], 6, InfrastructureSystemsInternal(), )
end
function SauerPaiMachine(; R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Xl, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext=Dict{String, Any}(), γ_d1=(Xd_pp-Xl)/(Xd_p-Xl), γ_q1=(Xq_pp-Xl)/(Xq_p-Xl), γ_d2=(Xd_p - Xd_pp) / (Xd_p - Xl)^2, γ_q2=(Xq_p - Xq_pp) / (Xq_p - Xl)^2, states=[:ψq, :ψd, :eq_p, :ed_p, :ψd_pp, :ψq_pp], n_states=6, internal=InfrastructureSystemsInternal(), )
SauerPaiMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Xl, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext, γ_d1, γ_q1, γ_d2, γ_q2, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function SauerPaiMachine(::Nothing)
SauerPaiMachine(;
R=0,
Xd=0,
Xq=0,
Xd_p=0,
Xq_p=0,
Xd_pp=0,
Xq_pp=0,
Xl=0,
Td0_p=0,
Tq0_p=0,
Td0_pp=0,
Tq0_pp=0,
ext=Dict{String, Any}(),
)
end
"""Get [`SauerPaiMachine`](@ref) `R`."""
get_R(value::SauerPaiMachine) = value.R
"""Get [`SauerPaiMachine`](@ref) `Xd`."""
get_Xd(value::SauerPaiMachine) = value.Xd
"""Get [`SauerPaiMachine`](@ref) `Xq`."""
get_Xq(value::SauerPaiMachine) = value.Xq
"""Get [`SauerPaiMachine`](@ref) `Xd_p`."""
get_Xd_p(value::SauerPaiMachine) = value.Xd_p
"""Get [`SauerPaiMachine`](@ref) `Xq_p`."""
get_Xq_p(value::SauerPaiMachine) = value.Xq_p
"""Get [`SauerPaiMachine`](@ref) `Xd_pp`."""
get_Xd_pp(value::SauerPaiMachine) = value.Xd_pp
"""Get [`SauerPaiMachine`](@ref) `Xq_pp`."""
get_Xq_pp(value::SauerPaiMachine) = value.Xq_pp
"""Get [`SauerPaiMachine`](@ref) `Xl`."""
get_Xl(value::SauerPaiMachine) = value.Xl
"""Get [`SauerPaiMachine`](@ref) `Td0_p`."""
get_Td0_p(value::SauerPaiMachine) = value.Td0_p
"""Get [`SauerPaiMachine`](@ref) `Tq0_p`."""
get_Tq0_p(value::SauerPaiMachine) = value.Tq0_p
"""Get [`SauerPaiMachine`](@ref) `Td0_pp`."""
get_Td0_pp(value::SauerPaiMachine) = value.Td0_pp
"""Get [`SauerPaiMachine`](@ref) `Tq0_pp`."""
get_Tq0_pp(value::SauerPaiMachine) = value.Tq0_pp
"""Get [`SauerPaiMachine`](@ref) `ext`."""
get_ext(value::SauerPaiMachine) = value.ext
"""Get [`SauerPaiMachine`](@ref) `γ_d1`."""
get_γ_d1(value::SauerPaiMachine) = value.γ_d1
"""Get [`SauerPaiMachine`](@ref) `γ_q1`."""
get_γ_q1(value::SauerPaiMachine) = value.γ_q1
"""Get [`SauerPaiMachine`](@ref) `γ_d2`."""
get_γ_d2(value::SauerPaiMachine) = value.γ_d2
"""Get [`SauerPaiMachine`](@ref) `γ_q2`."""
get_γ_q2(value::SauerPaiMachine) = value.γ_q2
"""Get [`SauerPaiMachine`](@ref) `states`."""
get_states(value::SauerPaiMachine) = value.states
"""Get [`SauerPaiMachine`](@ref) `n_states`."""
get_n_states(value::SauerPaiMachine) = value.n_states
"""Get [`SauerPaiMachine`](@ref) `internal`."""
get_internal(value::SauerPaiMachine) = value.internal
"""Set [`SauerPaiMachine`](@ref) `R`."""
set_R!(value::SauerPaiMachine, val) = value.R = val
"""Set [`SauerPaiMachine`](@ref) `Xd`."""
set_Xd!(value::SauerPaiMachine, val) = value.Xd = val
"""Set [`SauerPaiMachine`](@ref) `Xq`."""
set_Xq!(value::SauerPaiMachine, val) = value.Xq = val
"""Set [`SauerPaiMachine`](@ref) `Xd_p`."""
set_Xd_p!(value::SauerPaiMachine, val) = value.Xd_p = val
"""Set [`SauerPaiMachine`](@ref) `Xq_p`."""
set_Xq_p!(value::SauerPaiMachine, val) = value.Xq_p = val
"""Set [`SauerPaiMachine`](@ref) `Xd_pp`."""
set_Xd_pp!(value::SauerPaiMachine, val) = value.Xd_pp = val
"""Set [`SauerPaiMachine`](@ref) `Xq_pp`."""
set_Xq_pp!(value::SauerPaiMachine, val) = value.Xq_pp = val
"""Set [`SauerPaiMachine`](@ref) `Xl`."""
set_Xl!(value::SauerPaiMachine, val) = value.Xl = val
"""Set [`SauerPaiMachine`](@ref) `Td0_p`."""
set_Td0_p!(value::SauerPaiMachine, val) = value.Td0_p = val
"""Set [`SauerPaiMachine`](@ref) `Tq0_p`."""
set_Tq0_p!(value::SauerPaiMachine, val) = value.Tq0_p = val
"""Set [`SauerPaiMachine`](@ref) `Td0_pp`."""
set_Td0_pp!(value::SauerPaiMachine, val) = value.Td0_pp = val
"""Set [`SauerPaiMachine`](@ref) `Tq0_pp`."""
set_Tq0_pp!(value::SauerPaiMachine, val) = value.Tq0_pp = val
"""Set [`SauerPaiMachine`](@ref) `ext`."""
set_ext!(value::SauerPaiMachine, val) = value.ext = val
"""Set [`SauerPaiMachine`](@ref) `γ_d1`."""
set_γ_d1!(value::SauerPaiMachine, val) = value.γ_d1 = val
"""Set [`SauerPaiMachine`](@ref) `γ_q1`."""
set_γ_q1!(value::SauerPaiMachine, val) = value.γ_q1 = val
"""Set [`SauerPaiMachine`](@ref) `γ_d2`."""
set_γ_d2!(value::SauerPaiMachine, val) = value.γ_d2 = val
"""Set [`SauerPaiMachine`](@ref) `γ_q2`."""
set_γ_q2!(value::SauerPaiMachine, val) = value.γ_q2 = val
================================================
FILE: src/models/generated/ShiftablePowerLoad.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ShiftablePowerLoad <: ControllableLoad
name::String
available::Bool
bus::ACBus
active_power::Float64
active_power_limits::MinMax
reactive_power::Float64
max_active_power::Float64
max_reactive_power::Float64
base_power::Float64
load_balance_time_horizon::Int
operation_cost::Union{LoadCost, MarketBidCost}
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A [static](@ref S) power load that can be partially or completed shifted to later time periods.
These loads are used to model demand response. This load has a target demand profile (set by a [`max_active_power` time series](@ref ts_data) for an operational simulation). Load in the profile can be shifted to later time periods to aid in satisfying other system needs; however, any shifted load must be served within a designated time horizon (e.g., 24 hours), which is set by `load_balance_time_horizon`.
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial steady state active power demand (MW)
- `active_power_limits::MinMax`: Minimum and maximum stable active power levels (MW)
- `reactive_power::Float64`: Initial steady state reactive power demand (MVAR)
- `max_active_power::Float64`: Maximum active power (MW) that this load can demand
- `max_reactive_power::Float64`: Maximum reactive power (MVAR) that this load can demand
- `base_power::Float64`: Base power (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `load_balance_time_horizon::Int`: Number of time periods over which load must be balanced, validation range: `(1, nothing)`
- `operation_cost::Union{LoadCost, MarketBidCost}`: [`OperationalCost`](@ref) of interrupting load
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ShiftablePowerLoad <: ControllableLoad
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial steady state active power demand (MW)"
active_power::Float64
"Minimum and maximum stable active power levels (MW)"
active_power_limits::MinMax
"Initial steady state reactive power demand (MVAR)"
reactive_power::Float64
"Maximum active power (MW) that this load can demand"
max_active_power::Float64
"Maximum reactive power (MVAR) that this load can demand"
max_reactive_power::Float64
"Base power (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Number of time periods over which load must be balanced"
load_balance_time_horizon::Int
"[`OperationalCost`](@ref) of interrupting load"
operation_cost::Union{LoadCost, MarketBidCost}
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ShiftablePowerLoad(name, available, bus, active_power, active_power_limits, reactive_power, max_active_power, max_reactive_power, base_power, load_balance_time_horizon, operation_cost, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
ShiftablePowerLoad(name, available, bus, active_power, active_power_limits, reactive_power, max_active_power, max_reactive_power, base_power, load_balance_time_horizon, operation_cost, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function ShiftablePowerLoad(; name, available, bus, active_power, active_power_limits, reactive_power, max_active_power, max_reactive_power, base_power, load_balance_time_horizon, operation_cost, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
ShiftablePowerLoad(name, available, bus, active_power, active_power_limits, reactive_power, max_active_power, max_reactive_power, base_power, load_balance_time_horizon, operation_cost, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function ShiftablePowerLoad(::Nothing)
ShiftablePowerLoad(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
active_power_limits=(min=0.0, max=0.0),
reactive_power=0.0,
max_active_power=0.0,
max_reactive_power=0.0,
base_power=100.0,
load_balance_time_horizon=1,
operation_cost=LoadCost(nothing),
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`ShiftablePowerLoad`](@ref) `name`."""
get_name(value::ShiftablePowerLoad) = value.name
"""Get [`ShiftablePowerLoad`](@ref) `available`."""
get_available(value::ShiftablePowerLoad) = value.available
"""Get [`ShiftablePowerLoad`](@ref) `bus`."""
get_bus(value::ShiftablePowerLoad) = value.bus
"""Get [`ShiftablePowerLoad`](@ref) `active_power`."""
get_active_power(value::ShiftablePowerLoad) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`ShiftablePowerLoad`](@ref) `active_power_limits`."""
get_active_power_limits(value::ShiftablePowerLoad) = get_value(value, Val(:active_power_limits), Val(:mva))
"""Get [`ShiftablePowerLoad`](@ref) `reactive_power`."""
get_reactive_power(value::ShiftablePowerLoad) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`ShiftablePowerLoad`](@ref) `max_active_power`."""
get_max_active_power(value::ShiftablePowerLoad) = get_value(value, Val(:max_active_power), Val(:mva))
"""Get [`ShiftablePowerLoad`](@ref) `max_reactive_power`."""
get_max_reactive_power(value::ShiftablePowerLoad) = get_value(value, Val(:max_reactive_power), Val(:mva))
"""Get [`ShiftablePowerLoad`](@ref) `base_power`."""
get_base_power(value::ShiftablePowerLoad) = value.base_power
"""Get [`ShiftablePowerLoad`](@ref) `load_balance_time_horizon`."""
get_load_balance_time_horizon(value::ShiftablePowerLoad) = value.load_balance_time_horizon
"""Get [`ShiftablePowerLoad`](@ref) `operation_cost`."""
get_operation_cost(value::ShiftablePowerLoad) = value.operation_cost
"""Get [`ShiftablePowerLoad`](@ref) `services`."""
get_services(value::ShiftablePowerLoad) = value.services
"""Get [`ShiftablePowerLoad`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::ShiftablePowerLoad) = value.dynamic_injector
"""Get [`ShiftablePowerLoad`](@ref) `ext`."""
get_ext(value::ShiftablePowerLoad) = value.ext
"""Get [`ShiftablePowerLoad`](@ref) `internal`."""
get_internal(value::ShiftablePowerLoad) = value.internal
"""Set [`ShiftablePowerLoad`](@ref) `available`."""
set_available!(value::ShiftablePowerLoad, val) = value.available = val
"""Set [`ShiftablePowerLoad`](@ref) `bus`."""
set_bus!(value::ShiftablePowerLoad, val) = value.bus = val
"""Set [`ShiftablePowerLoad`](@ref) `active_power`."""
set_active_power!(value::ShiftablePowerLoad, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`ShiftablePowerLoad`](@ref) `active_power_limits`."""
set_active_power_limits!(value::ShiftablePowerLoad, val) = value.active_power_limits = set_value(value, Val(:active_power_limits), val, Val(:mva))
"""Set [`ShiftablePowerLoad`](@ref) `reactive_power`."""
set_reactive_power!(value::ShiftablePowerLoad, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`ShiftablePowerLoad`](@ref) `max_active_power`."""
set_max_active_power!(value::ShiftablePowerLoad, val) = value.max_active_power = set_value(value, Val(:max_active_power), val, Val(:mva))
"""Set [`ShiftablePowerLoad`](@ref) `max_reactive_power`."""
set_max_reactive_power!(value::ShiftablePowerLoad, val) = value.max_reactive_power = set_value(value, Val(:max_reactive_power), val, Val(:mva))
"""Set [`ShiftablePowerLoad`](@ref) `base_power`."""
set_base_power!(value::ShiftablePowerLoad, val) = value.base_power = val
"""Set [`ShiftablePowerLoad`](@ref) `load_balance_time_horizon`."""
set_load_balance_time_horizon!(value::ShiftablePowerLoad, val) = value.load_balance_time_horizon = val
"""Set [`ShiftablePowerLoad`](@ref) `operation_cost`."""
set_operation_cost!(value::ShiftablePowerLoad, val) = value.operation_cost = val
"""Set [`ShiftablePowerLoad`](@ref) `services`."""
set_services!(value::ShiftablePowerLoad, val) = value.services = val
"""Set [`ShiftablePowerLoad`](@ref) `ext`."""
set_ext!(value::ShiftablePowerLoad, val) = value.ext = val
================================================
FILE: src/models/generated/SimpleAFMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SimpleAFMachine <: Machine
R::Float64
Xd::Float64
Xq::Float64
Xd_p::Float64
Xq_p::Float64
Xd_pp::Float64
Xq_pp::Float64
Td0_p::Float64
Tq0_p::Float64
Td0_pp::Float64
Tq0_pp::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 4-[states](@ref S) simplified Anderson-Fouad (SimpleAFMachine) model.
The derivative of stator fluxes (ψd and ψq) is neglected and ωψd = ψd and
ωψq = ψq is assumed (i.e. ω=1.0). This is standard when transmission network
dynamics is neglected.
If transmission dynamics is considered use the full order Anderson Fouad model
# Arguments
- `R::Float64`: Resistance after EMF in machine per unit, validation range: `(0, nothing)`
- `Xd::Float64`: Reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq::Float64`: Reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_p::Float64`: Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_p::Float64`: Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_pp::Float64`: Sub-Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_pp::Float64`: Sub-Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Td0_p::Float64`: Time constant of transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_p::Float64`: Time constant of transient q-axis voltage, validation range: `(0, nothing)`
- `Td0_pp::Float64`: Time constant of sub-transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_pp::Float64`: Time constant of sub-transient q-axis voltage, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage,
eq_pp: q-axis subtransient voltage,
ed_pp: d-axis subtransient voltage
- `n_states::Int`: (**Do not modify.**) SimpleAFMachine has 4 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SimpleAFMachine <: Machine
"Resistance after EMF in machine per unit"
R::Float64
"Reactance after EMF in d-axis per unit"
Xd::Float64
"Reactance after EMF in q-axis per unit"
Xq::Float64
"Transient reactance after EMF in d-axis per unit"
Xd_p::Float64
"Transient reactance after EMF in q-axis per unit"
Xq_p::Float64
"Sub-Transient reactance after EMF in d-axis per unit"
Xd_pp::Float64
"Sub-Transient reactance after EMF in q-axis per unit"
Xq_pp::Float64
"Time constant of transient d-axis voltage"
Td0_p::Float64
"Time constant of transient q-axis voltage"
Tq0_p::Float64
"Time constant of sub-transient d-axis voltage"
Td0_pp::Float64
"Time constant of sub-transient q-axis voltage"
Tq0_pp::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage,
eq_pp: q-axis subtransient voltage,
ed_pp: d-axis subtransient voltage"
states::Vector{Symbol}
"(**Do not modify.**) SimpleAFMachine has 4 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SimpleAFMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext=Dict{String, Any}(), )
SimpleAFMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext, [:eq_p, :ed_p, :eq_pp, :ed_pp], 4, InfrastructureSystemsInternal(), )
end
function SimpleAFMachine(; R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext=Dict{String, Any}(), states=[:eq_p, :ed_p, :eq_pp, :ed_pp], n_states=4, internal=InfrastructureSystemsInternal(), )
SimpleAFMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function SimpleAFMachine(::Nothing)
SimpleAFMachine(;
R=0,
Xd=0,
Xq=0,
Xd_p=0,
Xq_p=0,
Xd_pp=0,
Xq_pp=0,
Td0_p=0,
Tq0_p=0,
Td0_pp=0,
Tq0_pp=0,
ext=Dict{String, Any}(),
)
end
"""Get [`SimpleAFMachine`](@ref) `R`."""
get_R(value::SimpleAFMachine) = value.R
"""Get [`SimpleAFMachine`](@ref) `Xd`."""
get_Xd(value::SimpleAFMachine) = value.Xd
"""Get [`SimpleAFMachine`](@ref) `Xq`."""
get_Xq(value::SimpleAFMachine) = value.Xq
"""Get [`SimpleAFMachine`](@ref) `Xd_p`."""
get_Xd_p(value::SimpleAFMachine) = value.Xd_p
"""Get [`SimpleAFMachine`](@ref) `Xq_p`."""
get_Xq_p(value::SimpleAFMachine) = value.Xq_p
"""Get [`SimpleAFMachine`](@ref) `Xd_pp`."""
get_Xd_pp(value::SimpleAFMachine) = value.Xd_pp
"""Get [`SimpleAFMachine`](@ref) `Xq_pp`."""
get_Xq_pp(value::SimpleAFMachine) = value.Xq_pp
"""Get [`SimpleAFMachine`](@ref) `Td0_p`."""
get_Td0_p(value::SimpleAFMachine) = value.Td0_p
"""Get [`SimpleAFMachine`](@ref) `Tq0_p`."""
get_Tq0_p(value::SimpleAFMachine) = value.Tq0_p
"""Get [`SimpleAFMachine`](@ref) `Td0_pp`."""
get_Td0_pp(value::SimpleAFMachine) = value.Td0_pp
"""Get [`SimpleAFMachine`](@ref) `Tq0_pp`."""
get_Tq0_pp(value::SimpleAFMachine) = value.Tq0_pp
"""Get [`SimpleAFMachine`](@ref) `ext`."""
get_ext(value::SimpleAFMachine) = value.ext
"""Get [`SimpleAFMachine`](@ref) `states`."""
get_states(value::SimpleAFMachine) = value.states
"""Get [`SimpleAFMachine`](@ref) `n_states`."""
get_n_states(value::SimpleAFMachine) = value.n_states
"""Get [`SimpleAFMachine`](@ref) `internal`."""
get_internal(value::SimpleAFMachine) = value.internal
"""Set [`SimpleAFMachine`](@ref) `R`."""
set_R!(value::SimpleAFMachine, val) = value.R = val
"""Set [`SimpleAFMachine`](@ref) `Xd`."""
set_Xd!(value::SimpleAFMachine, val) = value.Xd = val
"""Set [`SimpleAFMachine`](@ref) `Xq`."""
set_Xq!(value::SimpleAFMachine, val) = value.Xq = val
"""Set [`SimpleAFMachine`](@ref) `Xd_p`."""
set_Xd_p!(value::SimpleAFMachine, val) = value.Xd_p = val
"""Set [`SimpleAFMachine`](@ref) `Xq_p`."""
set_Xq_p!(value::SimpleAFMachine, val) = value.Xq_p = val
"""Set [`SimpleAFMachine`](@ref) `Xd_pp`."""
set_Xd_pp!(value::SimpleAFMachine, val) = value.Xd_pp = val
"""Set [`SimpleAFMachine`](@ref) `Xq_pp`."""
set_Xq_pp!(value::SimpleAFMachine, val) = value.Xq_pp = val
"""Set [`SimpleAFMachine`](@ref) `Td0_p`."""
set_Td0_p!(value::SimpleAFMachine, val) = value.Td0_p = val
"""Set [`SimpleAFMachine`](@ref) `Tq0_p`."""
set_Tq0_p!(value::SimpleAFMachine, val) = value.Tq0_p = val
"""Set [`SimpleAFMachine`](@ref) `Td0_pp`."""
set_Td0_pp!(value::SimpleAFMachine, val) = value.Td0_pp = val
"""Set [`SimpleAFMachine`](@ref) `Tq0_pp`."""
set_Tq0_pp!(value::SimpleAFMachine, val) = value.Tq0_pp = val
"""Set [`SimpleAFMachine`](@ref) `ext`."""
set_ext!(value::SimpleAFMachine, val) = value.ext = val
================================================
FILE: src/models/generated/SimpleFullMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SimpleFullMachine <: Machine
R::Float64
R_f::Float64
R_1d::Float64
R_1q::Float64
L_d::Float64
L_q::Float64
L_ad::Float64
L_aq::Float64
L_f1d::Float64
L_ff::Float64
L_1d::Float64
L_1q::Float64
ext::Dict{String, Any}
inv_d_fluxlink::Array{Float64,2}
inv_q_fluxlink::Array{Float64,2}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameter of a full order flux stator-rotor model without zero sequence flux in the stator.
The derivative of stator fluxes (ψd and ψq) is neglected. This is standard when
transmission network dynamics is neglected. Only one q-axis damping circuit
is considered. All per unit are in machine per unit.
Refer to Chapter 3 of Power System Stability and Control by P. Kundur or Chapter 11 of Power System Dynamics: Stability and Control, by J. Machowski, J. Bialek and J. Bumby, for more details.
Note that the models are somewhat different (but equivalent) due to the different Park Transformation used in both books
# Arguments
- `R::Float64`: Resistance after EMF in machine per unit, validation range: `(0, nothing)`
- `R_f::Float64`: Field rotor winding resistance in per unit, validation range: `(0, nothing)`
- `R_1d::Float64`: Damping rotor winding resistance on d-axis in per unit. This value is denoted as RD in Machowski, validation range: `(0, nothing)`
- `R_1q::Float64`: Damping rotor winding resistance on q-axis in per unit. This value is denoted as RQ in Machowski, validation range: `(0, nothing)`
- `L_d::Float64`: Inductance of fictitious damping that represent the effect of the three-phase stator winding in the d-axis of the rotor, in per unit. This value is denoted as L_ad + L_l in Kundur (and Ld in Machowski), validation range: `(0, nothing)`
- `L_q::Float64`: Inductance of fictitious damping that represent the effect of the three-phase stator winding in the q-axis of the rotor, in per unit. This value is denoted as L_aq + L_l in Kundur, validation range: `(0, nothing)`
- `L_ad::Float64`: Mutual inductance between stator winding and rotor field (and damping) winding inductance on d-axis, in per unit, validation range: `(0, nothing)`
- `L_aq::Float64`: Mutual inductance between stator winding and rotor damping winding inductance on q-axis, in per unit, validation range: `(0, nothing)`
- `L_f1d::Float64`: Mutual inductance between rotor field winding and rotor damping winding inductance on d-axis, in per unit, validation range: `(0, nothing)`
- `L_ff::Float64`: Field rotor winding inductance, in per unit, validation range: `(0, nothing)`
- `L_1d::Float64`: Inductance of the d-axis rotor damping circuit, in per unit, validation range: `(0, nothing)`
- `L_1q::Float64`: Inductance of the q-axis rotor damping circuit, in per unit, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `inv_d_fluxlink::Array{Float64,2}`: (**Do not modify.**) Equations 3.127, 3.130, 3.131 From Kundur
- `inv_q_fluxlink::Array{Float64,2}`: (**Do not modify.**) Equations 3.128, 3.132 From Kundur
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
ψf: field rotor flux,
ψ1d: d-axis rotor damping flux,
ψ1q: q-axis rotor damping flux
- `n_states::Int`: (**Do not modify.**) SimpleFullMachine has 3 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SimpleFullMachine <: Machine
"Resistance after EMF in machine per unit"
R::Float64
"Field rotor winding resistance in per unit"
R_f::Float64
" Damping rotor winding resistance on d-axis in per unit. This value is denoted as RD in Machowski"
R_1d::Float64
"Damping rotor winding resistance on q-axis in per unit. This value is denoted as RQ in Machowski"
R_1q::Float64
"Inductance of fictitious damping that represent the effect of the three-phase stator winding in the d-axis of the rotor, in per unit. This value is denoted as L_ad + L_l in Kundur (and Ld in Machowski)"
L_d::Float64
"Inductance of fictitious damping that represent the effect of the three-phase stator winding in the q-axis of the rotor, in per unit. This value is denoted as L_aq + L_l in Kundur"
L_q::Float64
"Mutual inductance between stator winding and rotor field (and damping) winding inductance on d-axis, in per unit"
L_ad::Float64
"Mutual inductance between stator winding and rotor damping winding inductance on q-axis, in per unit"
L_aq::Float64
"Mutual inductance between rotor field winding and rotor damping winding inductance on d-axis, in per unit"
L_f1d::Float64
"Field rotor winding inductance, in per unit"
L_ff::Float64
"Inductance of the d-axis rotor damping circuit, in per unit"
L_1d::Float64
"Inductance of the q-axis rotor damping circuit, in per unit"
L_1q::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) Equations 3.127, 3.130, 3.131 From Kundur"
inv_d_fluxlink::Array{Float64,2}
"(**Do not modify.**) Equations 3.128, 3.132 From Kundur"
inv_q_fluxlink::Array{Float64,2}
"(**Do not modify.**) The [states](@ref S) are:
ψf: field rotor flux,
ψ1d: d-axis rotor damping flux,
ψ1q: q-axis rotor damping flux"
states::Vector{Symbol}
"(**Do not modify.**) SimpleFullMachine has 3 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SimpleFullMachine(R, R_f, R_1d, R_1q, L_d, L_q, L_ad, L_aq, L_f1d, L_ff, L_1d, L_1q, ext=Dict{String, Any}(), )
SimpleFullMachine(R, R_f, R_1d, R_1q, L_d, L_q, L_ad, L_aq, L_f1d, L_ff, L_1d, L_1q, ext, inv([[-L_d L_ad L_ad]; [-L_ad L_ff L_f1d]; [-L_ad L_f1d L_1d]]), inv([[-L_q L_aq]; [-L_aq L_1q]]), [:ψf, :ψ1d, :ψ1q], 3, InfrastructureSystemsInternal(), )
end
function SimpleFullMachine(; R, R_f, R_1d, R_1q, L_d, L_q, L_ad, L_aq, L_f1d, L_ff, L_1d, L_1q, ext=Dict{String, Any}(), inv_d_fluxlink=inv([[-L_d L_ad L_ad]; [-L_ad L_ff L_f1d]; [-L_ad L_f1d L_1d]]), inv_q_fluxlink=inv([[-L_q L_aq]; [-L_aq L_1q]]), states=[:ψf, :ψ1d, :ψ1q], n_states=3, internal=InfrastructureSystemsInternal(), )
SimpleFullMachine(R, R_f, R_1d, R_1q, L_d, L_q, L_ad, L_aq, L_f1d, L_ff, L_1d, L_1q, ext, inv_d_fluxlink, inv_q_fluxlink, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function SimpleFullMachine(::Nothing)
SimpleFullMachine(;
R=0,
R_f=0,
R_1d=0,
R_1q=0,
L_d=1,
L_q=1,
L_ad=2,
L_aq=1,
L_f1d=1,
L_ff=2,
L_1d=1,
L_1q=2,
ext=Dict{String, Any}(),
)
end
"""Get [`SimpleFullMachine`](@ref) `R`."""
get_R(value::SimpleFullMachine) = value.R
"""Get [`SimpleFullMachine`](@ref) `R_f`."""
get_R_f(value::SimpleFullMachine) = value.R_f
"""Get [`SimpleFullMachine`](@ref) `R_1d`."""
get_R_1d(value::SimpleFullMachine) = value.R_1d
"""Get [`SimpleFullMachine`](@ref) `R_1q`."""
get_R_1q(value::SimpleFullMachine) = value.R_1q
"""Get [`SimpleFullMachine`](@ref) `L_d`."""
get_L_d(value::SimpleFullMachine) = value.L_d
"""Get [`SimpleFullMachine`](@ref) `L_q`."""
get_L_q(value::SimpleFullMachine) = value.L_q
"""Get [`SimpleFullMachine`](@ref) `L_ad`."""
get_L_ad(value::SimpleFullMachine) = value.L_ad
"""Get [`SimpleFullMachine`](@ref) `L_aq`."""
get_L_aq(value::SimpleFullMachine) = value.L_aq
"""Get [`SimpleFullMachine`](@ref) `L_f1d`."""
get_L_f1d(value::SimpleFullMachine) = value.L_f1d
"""Get [`SimpleFullMachine`](@ref) `L_ff`."""
get_L_ff(value::SimpleFullMachine) = value.L_ff
"""Get [`SimpleFullMachine`](@ref) `L_1d`."""
get_L_1d(value::SimpleFullMachine) = value.L_1d
"""Get [`SimpleFullMachine`](@ref) `L_1q`."""
get_L_1q(value::SimpleFullMachine) = value.L_1q
"""Get [`SimpleFullMachine`](@ref) `ext`."""
get_ext(value::SimpleFullMachine) = value.ext
"""Get [`SimpleFullMachine`](@ref) `inv_d_fluxlink`."""
get_inv_d_fluxlink(value::SimpleFullMachine) = value.inv_d_fluxlink
"""Get [`SimpleFullMachine`](@ref) `inv_q_fluxlink`."""
get_inv_q_fluxlink(value::SimpleFullMachine) = value.inv_q_fluxlink
"""Get [`SimpleFullMachine`](@ref) `states`."""
get_states(value::SimpleFullMachine) = value.states
"""Get [`SimpleFullMachine`](@ref) `n_states`."""
get_n_states(value::SimpleFullMachine) = value.n_states
"""Get [`SimpleFullMachine`](@ref) `internal`."""
get_internal(value::SimpleFullMachine) = value.internal
"""Set [`SimpleFullMachine`](@ref) `R`."""
set_R!(value::SimpleFullMachine, val) = value.R = val
"""Set [`SimpleFullMachine`](@ref) `R_f`."""
set_R_f!(value::SimpleFullMachine, val) = value.R_f = val
"""Set [`SimpleFullMachine`](@ref) `R_1d`."""
set_R_1d!(value::SimpleFullMachine, val) = value.R_1d = val
"""Set [`SimpleFullMachine`](@ref) `R_1q`."""
set_R_1q!(value::SimpleFullMachine, val) = value.R_1q = val
"""Set [`SimpleFullMachine`](@ref) `L_d`."""
set_L_d!(value::SimpleFullMachine, val) = value.L_d = val
"""Set [`SimpleFullMachine`](@ref) `L_q`."""
set_L_q!(value::SimpleFullMachine, val) = value.L_q = val
"""Set [`SimpleFullMachine`](@ref) `L_ad`."""
set_L_ad!(value::SimpleFullMachine, val) = value.L_ad = val
"""Set [`SimpleFullMachine`](@ref) `L_aq`."""
set_L_aq!(value::SimpleFullMachine, val) = value.L_aq = val
"""Set [`SimpleFullMachine`](@ref) `L_f1d`."""
set_L_f1d!(value::SimpleFullMachine, val) = value.L_f1d = val
"""Set [`SimpleFullMachine`](@ref) `L_ff`."""
set_L_ff!(value::SimpleFullMachine, val) = value.L_ff = val
"""Set [`SimpleFullMachine`](@ref) `L_1d`."""
set_L_1d!(value::SimpleFullMachine, val) = value.L_1d = val
"""Set [`SimpleFullMachine`](@ref) `L_1q`."""
set_L_1q!(value::SimpleFullMachine, val) = value.L_1q = val
"""Set [`SimpleFullMachine`](@ref) `ext`."""
set_ext!(value::SimpleFullMachine, val) = value.ext = val
"""Set [`SimpleFullMachine`](@ref) `inv_d_fluxlink`."""
set_inv_d_fluxlink!(value::SimpleFullMachine, val) = value.inv_d_fluxlink = val
"""Set [`SimpleFullMachine`](@ref) `inv_q_fluxlink`."""
set_inv_q_fluxlink!(value::SimpleFullMachine, val) = value.inv_q_fluxlink = val
================================================
FILE: src/models/generated/SimpleMarconatoMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SimpleMarconatoMachine <: Machine
R::Float64
Xd::Float64
Xq::Float64
Xd_p::Float64
Xq_p::Float64
Xd_pp::Float64
Xq_pp::Float64
Td0_p::Float64
Tq0_p::Float64
Td0_pp::Float64
Tq0_pp::Float64
T_AA::Float64
ext::Dict{String, Any}
γd::Float64
γq::Float64
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 4-[states](@ref S) synchronous machine: Simplified Marconato model
The derivative of stator fluxes (ψd and ψq) is neglected and ωψd = ψd and
ωψq = ψq is assumed (i.e. ω=1.0). This is standard when transmission network
dynamics is neglected
# Arguments
- `R::Float64`: Resistance after EMF in machine per unit, validation range: `(0, nothing)`
- `Xd::Float64`: Reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq::Float64`: Reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_p::Float64`: Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_p::Float64`: Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Xd_pp::Float64`: Sub-Transient reactance after EMF in d-axis per unit, validation range: `(0, nothing)`
- `Xq_pp::Float64`: Sub-Transient reactance after EMF in q-axis per unit, validation range: `(0, nothing)`
- `Td0_p::Float64`: Time constant of transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_p::Float64`: Time constant of transient q-axis voltage, validation range: `(0, nothing)`
- `Td0_pp::Float64`: Time constant of sub-transient d-axis voltage, validation range: `(0, nothing)`
- `Tq0_pp::Float64`: Time constant of sub-transient q-axis voltage, validation range: `(0, nothing)`
- `T_AA::Float64`: Time constant of d-axis additional leakage, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `γd::Float64`: (**Do not modify.**) Internal equation
- `γq::Float64`: (**Do not modify.**) Internal equation
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage,
eq_pp: q-axis subtransient voltage,
ed_pp: d-axis subtransient voltage
- `n_states::Int`: (**Do not modify.**) SimpleMarconatoMachine has 4 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SimpleMarconatoMachine <: Machine
"Resistance after EMF in machine per unit"
R::Float64
"Reactance after EMF in d-axis per unit"
Xd::Float64
"Reactance after EMF in q-axis per unit"
Xq::Float64
"Transient reactance after EMF in d-axis per unit"
Xd_p::Float64
"Transient reactance after EMF in q-axis per unit"
Xq_p::Float64
"Sub-Transient reactance after EMF in d-axis per unit"
Xd_pp::Float64
"Sub-Transient reactance after EMF in q-axis per unit"
Xq_pp::Float64
"Time constant of transient d-axis voltage"
Td0_p::Float64
"Time constant of transient q-axis voltage"
Tq0_p::Float64
"Time constant of sub-transient d-axis voltage"
Td0_pp::Float64
"Time constant of sub-transient q-axis voltage"
Tq0_pp::Float64
"Time constant of d-axis additional leakage"
T_AA::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) Internal equation"
γd::Float64
"(**Do not modify.**) Internal equation"
γq::Float64
"(**Do not modify.**) The [states](@ref S) are:
eq_p: q-axis transient voltage,
ed_p: d-axis transient voltage,
eq_pp: q-axis subtransient voltage,
ed_pp: d-axis subtransient voltage"
states::Vector{Symbol}
"(**Do not modify.**) SimpleMarconatoMachine has 4 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SimpleMarconatoMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, T_AA, ext=Dict{String, Any}(), )
SimpleMarconatoMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, T_AA, ext, ((Td0_pp*Xd_pp)/(Td0_p*Xd_p) )*(Xd-Xd_p), ((Tq0_pp*Xq_pp)/(Tq0_p*Xq_p) )*(Xq-Xq_p), [:eq_p, :ed_p, :eq_pp, :ed_pp], 4, InfrastructureSystemsInternal(), )
end
function SimpleMarconatoMachine(; R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, T_AA, ext=Dict{String, Any}(), γd=((Td0_pp*Xd_pp)/(Td0_p*Xd_p) )*(Xd-Xd_p), γq=((Tq0_pp*Xq_pp)/(Tq0_p*Xq_p) )*(Xq-Xq_p), states=[:eq_p, :ed_p, :eq_pp, :ed_pp], n_states=4, internal=InfrastructureSystemsInternal(), )
SimpleMarconatoMachine(R, Xd, Xq, Xd_p, Xq_p, Xd_pp, Xq_pp, Td0_p, Tq0_p, Td0_pp, Tq0_pp, T_AA, ext, γd, γq, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function SimpleMarconatoMachine(::Nothing)
SimpleMarconatoMachine(;
R=0,
Xd=0,
Xq=0,
Xd_p=0,
Xq_p=0,
Xd_pp=0,
Xq_pp=0,
Td0_p=0,
Tq0_p=0,
Td0_pp=0,
Tq0_pp=0,
T_AA=0,
ext=Dict{String, Any}(),
)
end
"""Get [`SimpleMarconatoMachine`](@ref) `R`."""
get_R(value::SimpleMarconatoMachine) = value.R
"""Get [`SimpleMarconatoMachine`](@ref) `Xd`."""
get_Xd(value::SimpleMarconatoMachine) = value.Xd
"""Get [`SimpleMarconatoMachine`](@ref) `Xq`."""
get_Xq(value::SimpleMarconatoMachine) = value.Xq
"""Get [`SimpleMarconatoMachine`](@ref) `Xd_p`."""
get_Xd_p(value::SimpleMarconatoMachine) = value.Xd_p
"""Get [`SimpleMarconatoMachine`](@ref) `Xq_p`."""
get_Xq_p(value::SimpleMarconatoMachine) = value.Xq_p
"""Get [`SimpleMarconatoMachine`](@ref) `Xd_pp`."""
get_Xd_pp(value::SimpleMarconatoMachine) = value.Xd_pp
"""Get [`SimpleMarconatoMachine`](@ref) `Xq_pp`."""
get_Xq_pp(value::SimpleMarconatoMachine) = value.Xq_pp
"""Get [`SimpleMarconatoMachine`](@ref) `Td0_p`."""
get_Td0_p(value::SimpleMarconatoMachine) = value.Td0_p
"""Get [`SimpleMarconatoMachine`](@ref) `Tq0_p`."""
get_Tq0_p(value::SimpleMarconatoMachine) = value.Tq0_p
"""Get [`SimpleMarconatoMachine`](@ref) `Td0_pp`."""
get_Td0_pp(value::SimpleMarconatoMachine) = value.Td0_pp
"""Get [`SimpleMarconatoMachine`](@ref) `Tq0_pp`."""
get_Tq0_pp(value::SimpleMarconatoMachine) = value.Tq0_pp
"""Get [`SimpleMarconatoMachine`](@ref) `T_AA`."""
get_T_AA(value::SimpleMarconatoMachine) = value.T_AA
"""Get [`SimpleMarconatoMachine`](@ref) `ext`."""
get_ext(value::SimpleMarconatoMachine) = value.ext
"""Get [`SimpleMarconatoMachine`](@ref) `γd`."""
get_γd(value::SimpleMarconatoMachine) = value.γd
"""Get [`SimpleMarconatoMachine`](@ref) `γq`."""
get_γq(value::SimpleMarconatoMachine) = value.γq
"""Get [`SimpleMarconatoMachine`](@ref) `states`."""
get_states(value::SimpleMarconatoMachine) = value.states
"""Get [`SimpleMarconatoMachine`](@ref) `n_states`."""
get_n_states(value::SimpleMarconatoMachine) = value.n_states
"""Get [`SimpleMarconatoMachine`](@ref) `internal`."""
get_internal(value::SimpleMarconatoMachine) = value.internal
"""Set [`SimpleMarconatoMachine`](@ref) `R`."""
set_R!(value::SimpleMarconatoMachine, val) = value.R = val
"""Set [`SimpleMarconatoMachine`](@ref) `Xd`."""
set_Xd!(value::SimpleMarconatoMachine, val) = value.Xd = val
"""Set [`SimpleMarconatoMachine`](@ref) `Xq`."""
set_Xq!(value::SimpleMarconatoMachine, val) = value.Xq = val
"""Set [`SimpleMarconatoMachine`](@ref) `Xd_p`."""
set_Xd_p!(value::SimpleMarconatoMachine, val) = value.Xd_p = val
"""Set [`SimpleMarconatoMachine`](@ref) `Xq_p`."""
set_Xq_p!(value::SimpleMarconatoMachine, val) = value.Xq_p = val
"""Set [`SimpleMarconatoMachine`](@ref) `Xd_pp`."""
set_Xd_pp!(value::SimpleMarconatoMachine, val) = value.Xd_pp = val
"""Set [`SimpleMarconatoMachine`](@ref) `Xq_pp`."""
set_Xq_pp!(value::SimpleMarconatoMachine, val) = value.Xq_pp = val
"""Set [`SimpleMarconatoMachine`](@ref) `Td0_p`."""
set_Td0_p!(value::SimpleMarconatoMachine, val) = value.Td0_p = val
"""Set [`SimpleMarconatoMachine`](@ref) `Tq0_p`."""
set_Tq0_p!(value::SimpleMarconatoMachine, val) = value.Tq0_p = val
"""Set [`SimpleMarconatoMachine`](@ref) `Td0_pp`."""
set_Td0_pp!(value::SimpleMarconatoMachine, val) = value.Td0_pp = val
"""Set [`SimpleMarconatoMachine`](@ref) `Tq0_pp`."""
set_Tq0_pp!(value::SimpleMarconatoMachine, val) = value.Tq0_pp = val
"""Set [`SimpleMarconatoMachine`](@ref) `T_AA`."""
set_T_AA!(value::SimpleMarconatoMachine, val) = value.T_AA = val
"""Set [`SimpleMarconatoMachine`](@ref) `ext`."""
set_ext!(value::SimpleMarconatoMachine, val) = value.ext = val
"""Set [`SimpleMarconatoMachine`](@ref) `γd`."""
set_γd!(value::SimpleMarconatoMachine, val) = value.γd = val
"""Set [`SimpleMarconatoMachine`](@ref) `γq`."""
set_γq!(value::SimpleMarconatoMachine, val) = value.γq = val
================================================
FILE: src/models/generated/SimplifiedSingleCageInductionMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SimplifiedSingleCageInductionMachine <: DynamicInjection
name::String
R_s::Float64
R_r::Float64
X_ls::Float64
X_lr::Float64
X_m::Float64
H::Float64
A::Float64
B::Float64
base_power::Float64
ext::Dict{String, Any}
C::Float64
τ_ref::Float64
B_shunt::Float64
X_ss::Float64
X_rr::Float64
X_p::Float64
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 3-states three-phase single cage induction machine with quadratic torque-speed relationship
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `R_s::Float64`: Armature stator resistance, validation range: `(0, nothing)`
- `R_r::Float64`: Rotor resistance, validation range: `(0, nothing)`
- `X_ls::Float64`: Stator Leakage Reactance, validation range: `(0, nothing)`
- `X_lr::Float64`: Rotor Leakage Reactance, validation range: `(0, nothing)`
- `X_m::Float64`: Stator-Rotor Mutual Reactance, validation range: `(0, nothing)`
- `H::Float64`: Motor Inertia Constant [s], validation range: `(0, nothing)`
- `A::Float64`: Torque-Speed Quadratic Term, validation range: `(0, 1)`
- `B::Float64`: Torque-Speed Linear Term, validation range: `(0, 1)`
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `C::Float64`: (**Do not modify.**) Torque-Speed Constant Term
- `τ_ref::Float64`: Reference torque parameter
- `B_shunt::Float64`: Susceptance Initialization Corrector Term
- `X_ss::Float64`: (**Do not modify.**) Stator self reactance
- `X_rr::Float64`: (**Do not modify.**) Rotor self reactance
- `X_p::Float64`: (**Do not modify.**) Transient reactance
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
ψ_qr: rotor flux in the q-axis,
ψ_dr: rotor flux in the d-axis,
ωr: Rotor speed [pu],
- `n_states::Int`: (**Do not modify.**) SimplifiedSingleCageInductionMachine has 3 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SimplifiedSingleCageInductionMachine <: DynamicInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Armature stator resistance"
R_s::Float64
"Rotor resistance"
R_r::Float64
"Stator Leakage Reactance"
X_ls::Float64
"Rotor Leakage Reactance"
X_lr::Float64
"Stator-Rotor Mutual Reactance"
X_m::Float64
"Motor Inertia Constant [s]"
H::Float64
"Torque-Speed Quadratic Term"
A::Float64
"Torque-Speed Linear Term"
B::Float64
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) Torque-Speed Constant Term"
C::Float64
"Reference torque parameter"
τ_ref::Float64
"Susceptance Initialization Corrector Term"
B_shunt::Float64
"(**Do not modify.**) Stator self reactance"
X_ss::Float64
"(**Do not modify.**) Rotor self reactance"
X_rr::Float64
"(**Do not modify.**) Transient reactance"
X_p::Float64
"(**Do not modify.**) The [states](@ref S) are:
ψ_qr: rotor flux in the q-axis,
ψ_dr: rotor flux in the d-axis,
ωr: Rotor speed [pu],"
states::Vector{Symbol}
"(**Do not modify.**) SimplifiedSingleCageInductionMachine has 3 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SimplifiedSingleCageInductionMachine(name, R_s, R_r, X_ls, X_lr, X_m, H, A, B, base_power, ext=Dict{String, Any}(), )
SimplifiedSingleCageInductionMachine(name, R_s, R_r, X_ls, X_lr, X_m, H, A, B, base_power, ext, PowerSystems.calculate_IM_torque_params(A, B), 1.0, 0.0, X_ls + X_m, X_lr + X_m, X_ss - X_m^2 / X_rr, [:ψ_qr, :ψ_dr, :ωr], 3, InfrastructureSystemsInternal(), )
end
function SimplifiedSingleCageInductionMachine(; name, R_s, R_r, X_ls, X_lr, X_m, H, A, B, base_power, ext=Dict{String, Any}(), C=PowerSystems.calculate_IM_torque_params(A, B), τ_ref=1.0, B_shunt=0.0, X_ss=X_ls + X_m, X_rr=X_lr + X_m, X_p=X_ss - X_m^2 / X_rr, states=[:ψ_qr, :ψ_dr, :ωr], n_states=3, internal=InfrastructureSystemsInternal(), )
SimplifiedSingleCageInductionMachine(name, R_s, R_r, X_ls, X_lr, X_m, H, A, B, base_power, ext, C, τ_ref, B_shunt, X_ss, X_rr, X_p, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function SimplifiedSingleCageInductionMachine(::Nothing)
SimplifiedSingleCageInductionMachine(;
name="init",
R_s=0,
R_r=0,
X_ls=0,
X_lr=0,
X_m=0,
H=0,
A=0.0,
B=0.0,
base_power=100,
ext=Dict{String, Any}(),
)
end
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `name`."""
get_name(value::SimplifiedSingleCageInductionMachine) = value.name
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `R_s`."""
get_R_s(value::SimplifiedSingleCageInductionMachine) = value.R_s
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `R_r`."""
get_R_r(value::SimplifiedSingleCageInductionMachine) = value.R_r
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `X_ls`."""
get_X_ls(value::SimplifiedSingleCageInductionMachine) = value.X_ls
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `X_lr`."""
get_X_lr(value::SimplifiedSingleCageInductionMachine) = value.X_lr
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `X_m`."""
get_X_m(value::SimplifiedSingleCageInductionMachine) = value.X_m
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `H`."""
get_H(value::SimplifiedSingleCageInductionMachine) = value.H
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `A`."""
get_A(value::SimplifiedSingleCageInductionMachine) = value.A
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `B`."""
get_B(value::SimplifiedSingleCageInductionMachine) = value.B
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `base_power`."""
get_base_power(value::SimplifiedSingleCageInductionMachine) = value.base_power
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `ext`."""
get_ext(value::SimplifiedSingleCageInductionMachine) = value.ext
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `C`."""
get_C(value::SimplifiedSingleCageInductionMachine) = value.C
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `τ_ref`."""
get_τ_ref(value::SimplifiedSingleCageInductionMachine) = value.τ_ref
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `B_shunt`."""
get_B_shunt(value::SimplifiedSingleCageInductionMachine) = value.B_shunt
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `X_ss`."""
get_X_ss(value::SimplifiedSingleCageInductionMachine) = value.X_ss
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `X_rr`."""
get_X_rr(value::SimplifiedSingleCageInductionMachine) = value.X_rr
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `X_p`."""
get_X_p(value::SimplifiedSingleCageInductionMachine) = value.X_p
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `states`."""
get_states(value::SimplifiedSingleCageInductionMachine) = value.states
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `n_states`."""
get_n_states(value::SimplifiedSingleCageInductionMachine) = value.n_states
"""Get [`SimplifiedSingleCageInductionMachine`](@ref) `internal`."""
get_internal(value::SimplifiedSingleCageInductionMachine) = value.internal
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `R_s`."""
set_R_s!(value::SimplifiedSingleCageInductionMachine, val) = value.R_s = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `R_r`."""
set_R_r!(value::SimplifiedSingleCageInductionMachine, val) = value.R_r = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `X_ls`."""
set_X_ls!(value::SimplifiedSingleCageInductionMachine, val) = value.X_ls = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `X_lr`."""
set_X_lr!(value::SimplifiedSingleCageInductionMachine, val) = value.X_lr = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `X_m`."""
set_X_m!(value::SimplifiedSingleCageInductionMachine, val) = value.X_m = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `H`."""
set_H!(value::SimplifiedSingleCageInductionMachine, val) = value.H = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `A`."""
set_A!(value::SimplifiedSingleCageInductionMachine, val) = value.A = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `B`."""
set_B!(value::SimplifiedSingleCageInductionMachine, val) = value.B = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `base_power`."""
set_base_power!(value::SimplifiedSingleCageInductionMachine, val) = value.base_power = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `ext`."""
set_ext!(value::SimplifiedSingleCageInductionMachine, val) = value.ext = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `C`."""
set_C!(value::SimplifiedSingleCageInductionMachine, val) = value.C = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `τ_ref`."""
set_τ_ref!(value::SimplifiedSingleCageInductionMachine, val) = value.τ_ref = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `B_shunt`."""
set_B_shunt!(value::SimplifiedSingleCageInductionMachine, val) = value.B_shunt = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `X_ss`."""
set_X_ss!(value::SimplifiedSingleCageInductionMachine, val) = value.X_ss = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `X_rr`."""
set_X_rr!(value::SimplifiedSingleCageInductionMachine, val) = value.X_rr = val
"""Set [`SimplifiedSingleCageInductionMachine`](@ref) `X_p`."""
set_X_p!(value::SimplifiedSingleCageInductionMachine, val) = value.X_p = val
================================================
FILE: src/models/generated/SingleCageInductionMachine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SingleCageInductionMachine <: DynamicInjection
name::String
R_s::Float64
R_r::Float64
X_ls::Float64
X_lr::Float64
X_m::Float64
H::Float64
A::Float64
B::Float64
base_power::Float64
ext::Dict{String, Any}
C::Float64
τ_ref::Float64
B_shunt::Float64
X_ad::Float64
X_aq::Float64
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of 5-states three-phase single cage induction machine with quadratic torque-speed relationship
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `R_s::Float64`: Armature stator resistance, validation range: `(0, nothing)`
- `R_r::Float64`: Rotor resistance, validation range: `(0, nothing)`
- `X_ls::Float64`: Stator Leakage Reactance, validation range: `(0, nothing)`
- `X_lr::Float64`: Rotor Leakage Reactance, validation range: `(0, nothing)`
- `X_m::Float64`: Stator-Rotor Mutual Reactance, validation range: `(0, nothing)`
- `H::Float64`: Motor Inertia Constant [s], validation range: `(0, nothing)`
- `A::Float64`: Torque-Speed Quadratic Term, validation range: `(0, 1)`
- `B::Float64`: Torque-Speed Linear Term, validation range: `(0, 1)`
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `C::Float64`: (**Do not modify.**) Torque-Speed Constant Term
- `τ_ref::Float64`: Reference torque parameter
- `B_shunt::Float64`: Susceptance Initialization Corrector Term
- `X_ad::Float64`: (**Do not modify.**) Equivalent d-axis reactance
- `X_aq::Float64`: (**Do not modify.**) Equivalent q-axis reactance
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
ψ_qs: stator flux in the q-axis,
ψ_ds: stator flux in the d-axis,
ψ_qr: rotor flux in the q-axis,
ψ_dr: rotor flux in the d-axis,
ωr: Rotor speed [pu],
- `n_states::Int`: (**Do not modify.**) SingleCageInductionMachine has 5 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SingleCageInductionMachine <: DynamicInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Armature stator resistance"
R_s::Float64
"Rotor resistance"
R_r::Float64
"Stator Leakage Reactance"
X_ls::Float64
"Rotor Leakage Reactance"
X_lr::Float64
"Stator-Rotor Mutual Reactance"
X_m::Float64
"Motor Inertia Constant [s]"
H::Float64
"Torque-Speed Quadratic Term"
A::Float64
"Torque-Speed Linear Term"
B::Float64
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) Torque-Speed Constant Term"
C::Float64
"Reference torque parameter"
τ_ref::Float64
"Susceptance Initialization Corrector Term"
B_shunt::Float64
"(**Do not modify.**) Equivalent d-axis reactance"
X_ad::Float64
"(**Do not modify.**) Equivalent q-axis reactance"
X_aq::Float64
"(**Do not modify.**) The [states](@ref S) are:
ψ_qs: stator flux in the q-axis,
ψ_ds: stator flux in the d-axis,
ψ_qr: rotor flux in the q-axis,
ψ_dr: rotor flux in the d-axis,
ωr: Rotor speed [pu],"
states::Vector{Symbol}
"(**Do not modify.**) SingleCageInductionMachine has 5 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SingleCageInductionMachine(name, R_s, R_r, X_ls, X_lr, X_m, H, A, B, base_power, ext=Dict{String, Any}(), )
SingleCageInductionMachine(name, R_s, R_r, X_ls, X_lr, X_m, H, A, B, base_power, ext, PowerSystems.calculate_IM_torque_params(A, B), 1.0, 0.0, (1.0 / X_m + 1.0 / X_ls + 1.0 / X_lr)^(-1), X_ad, [:ψ_qs, :ψ_ds, :ψ_qr, :ψ_dr, :ωr], 5, InfrastructureSystemsInternal(), )
end
function SingleCageInductionMachine(; name, R_s, R_r, X_ls, X_lr, X_m, H, A, B, base_power, ext=Dict{String, Any}(), C=PowerSystems.calculate_IM_torque_params(A, B), τ_ref=1.0, B_shunt=0.0, X_ad=(1.0 / X_m + 1.0 / X_ls + 1.0 / X_lr)^(-1), X_aq=X_ad, states=[:ψ_qs, :ψ_ds, :ψ_qr, :ψ_dr, :ωr], n_states=5, internal=InfrastructureSystemsInternal(), )
SingleCageInductionMachine(name, R_s, R_r, X_ls, X_lr, X_m, H, A, B, base_power, ext, C, τ_ref, B_shunt, X_ad, X_aq, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function SingleCageInductionMachine(::Nothing)
SingleCageInductionMachine(;
name="init",
R_s=0,
R_r=0,
X_ls=0,
X_lr=0,
X_m=0,
H=0,
A=0.0,
B=0.0,
base_power=100,
ext=Dict{String, Any}(),
)
end
"""Get [`SingleCageInductionMachine`](@ref) `name`."""
get_name(value::SingleCageInductionMachine) = value.name
"""Get [`SingleCageInductionMachine`](@ref) `R_s`."""
get_R_s(value::SingleCageInductionMachine) = value.R_s
"""Get [`SingleCageInductionMachine`](@ref) `R_r`."""
get_R_r(value::SingleCageInductionMachine) = value.R_r
"""Get [`SingleCageInductionMachine`](@ref) `X_ls`."""
get_X_ls(value::SingleCageInductionMachine) = value.X_ls
"""Get [`SingleCageInductionMachine`](@ref) `X_lr`."""
get_X_lr(value::SingleCageInductionMachine) = value.X_lr
"""Get [`SingleCageInductionMachine`](@ref) `X_m`."""
get_X_m(value::SingleCageInductionMachine) = value.X_m
"""Get [`SingleCageInductionMachine`](@ref) `H`."""
get_H(value::SingleCageInductionMachine) = value.H
"""Get [`SingleCageInductionMachine`](@ref) `A`."""
get_A(value::SingleCageInductionMachine) = value.A
"""Get [`SingleCageInductionMachine`](@ref) `B`."""
get_B(value::SingleCageInductionMachine) = value.B
"""Get [`SingleCageInductionMachine`](@ref) `base_power`."""
get_base_power(value::SingleCageInductionMachine) = value.base_power
"""Get [`SingleCageInductionMachine`](@ref) `ext`."""
get_ext(value::SingleCageInductionMachine) = value.ext
"""Get [`SingleCageInductionMachine`](@ref) `C`."""
get_C(value::SingleCageInductionMachine) = value.C
"""Get [`SingleCageInductionMachine`](@ref) `τ_ref`."""
get_τ_ref(value::SingleCageInductionMachine) = value.τ_ref
"""Get [`SingleCageInductionMachine`](@ref) `B_shunt`."""
get_B_shunt(value::SingleCageInductionMachine) = value.B_shunt
"""Get [`SingleCageInductionMachine`](@ref) `X_ad`."""
get_X_ad(value::SingleCageInductionMachine) = value.X_ad
"""Get [`SingleCageInductionMachine`](@ref) `X_aq`."""
get_X_aq(value::SingleCageInductionMachine) = value.X_aq
"""Get [`SingleCageInductionMachine`](@ref) `states`."""
get_states(value::SingleCageInductionMachine) = value.states
"""Get [`SingleCageInductionMachine`](@ref) `n_states`."""
get_n_states(value::SingleCageInductionMachine) = value.n_states
"""Get [`SingleCageInductionMachine`](@ref) `internal`."""
get_internal(value::SingleCageInductionMachine) = value.internal
"""Set [`SingleCageInductionMachine`](@ref) `R_s`."""
set_R_s!(value::SingleCageInductionMachine, val) = value.R_s = val
"""Set [`SingleCageInductionMachine`](@ref) `R_r`."""
set_R_r!(value::SingleCageInductionMachine, val) = value.R_r = val
"""Set [`SingleCageInductionMachine`](@ref) `X_ls`."""
set_X_ls!(value::SingleCageInductionMachine, val) = value.X_ls = val
"""Set [`SingleCageInductionMachine`](@ref) `X_lr`."""
set_X_lr!(value::SingleCageInductionMachine, val) = value.X_lr = val
"""Set [`SingleCageInductionMachine`](@ref) `X_m`."""
set_X_m!(value::SingleCageInductionMachine, val) = value.X_m = val
"""Set [`SingleCageInductionMachine`](@ref) `H`."""
set_H!(value::SingleCageInductionMachine, val) = value.H = val
"""Set [`SingleCageInductionMachine`](@ref) `A`."""
set_A!(value::SingleCageInductionMachine, val) = value.A = val
"""Set [`SingleCageInductionMachine`](@ref) `B`."""
set_B!(value::SingleCageInductionMachine, val) = value.B = val
"""Set [`SingleCageInductionMachine`](@ref) `base_power`."""
set_base_power!(value::SingleCageInductionMachine, val) = value.base_power = val
"""Set [`SingleCageInductionMachine`](@ref) `ext`."""
set_ext!(value::SingleCageInductionMachine, val) = value.ext = val
"""Set [`SingleCageInductionMachine`](@ref) `C`."""
set_C!(value::SingleCageInductionMachine, val) = value.C = val
"""Set [`SingleCageInductionMachine`](@ref) `τ_ref`."""
set_τ_ref!(value::SingleCageInductionMachine, val) = value.τ_ref = val
"""Set [`SingleCageInductionMachine`](@ref) `B_shunt`."""
set_B_shunt!(value::SingleCageInductionMachine, val) = value.B_shunt = val
"""Set [`SingleCageInductionMachine`](@ref) `X_ad`."""
set_X_ad!(value::SingleCageInductionMachine, val) = value.X_ad = val
"""Set [`SingleCageInductionMachine`](@ref) `X_aq`."""
set_X_aq!(value::SingleCageInductionMachine, val) = value.X_aq = val
================================================
FILE: src/models/generated/SingleMass.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SingleMass <: Shaft
H::Float64
D::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of single mass shaft model. Typically represents the rotor mass
# Arguments
- `H::Float64`: Rotor inertia constant in MWs/MVA, validation range: `(0, nothing)`
- `D::Float64`: Rotor natural damping in pu, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) are:
δ: rotor angle,
ω: rotor speed
- `n_states::Int`: (**Do not modify.**) SingleMass has 1 state
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SingleMass <: Shaft
"Rotor inertia constant in MWs/MVA"
H::Float64
"Rotor natural damping in pu"
D::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) are:
δ: rotor angle,
ω: rotor speed"
states::Vector{Symbol}
"(**Do not modify.**) SingleMass has 1 state"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SingleMass(H, D, ext=Dict{String, Any}(), )
SingleMass(H, D, ext, [:δ, :ω], 2, InfrastructureSystemsInternal(), )
end
function SingleMass(; H, D, ext=Dict{String, Any}(), states=[:δ, :ω], n_states=2, internal=InfrastructureSystemsInternal(), )
SingleMass(H, D, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function SingleMass(::Nothing)
SingleMass(;
H=0,
D=0,
ext=Dict{String, Any}(),
)
end
"""Get [`SingleMass`](@ref) `H`."""
get_H(value::SingleMass) = value.H
"""Get [`SingleMass`](@ref) `D`."""
get_D(value::SingleMass) = value.D
"""Get [`SingleMass`](@ref) `ext`."""
get_ext(value::SingleMass) = value.ext
"""Get [`SingleMass`](@ref) `states`."""
get_states(value::SingleMass) = value.states
"""Get [`SingleMass`](@ref) `n_states`."""
get_n_states(value::SingleMass) = value.n_states
"""Get [`SingleMass`](@ref) `internal`."""
get_internal(value::SingleMass) = value.internal
"""Set [`SingleMass`](@ref) `H`."""
set_H!(value::SingleMass, val) = value.H = val
"""Set [`SingleMass`](@ref) `D`."""
set_D!(value::SingleMass, val) = value.D = val
"""Set [`SingleMass`](@ref) `ext`."""
set_ext!(value::SingleMass, val) = value.ext = val
================================================
FILE: src/models/generated/Source.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct Source <: StaticInjection
name::String
available::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
active_power_limits::MinMax
reactive_power_limits::Union{Nothing, MinMax}
R_th::Float64
X_th::Float64
internal_voltage::Float64
internal_angle::Float64
base_power::Float64
operation_cost::ImportExportCost
dynamic_injector::Union{Nothing, DynamicInjection}
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
An infinite bus with a constant voltage output.
Commonly used in dynamics simulations to represent a very large machine on a single bus or for the representation of import/exports in operational simulations
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: (default: `0.0`) Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used
- `reactive_power::Float64`: (default: `0.0`) Initial reactive power set point of the unit (MVAR)
- `active_power_limits::MinMax`: (default: `(min=0.0, max=0.0)`) Minimum and maximum stable active power levels (MW)
- `reactive_power_limits::Union{Nothing, MinMax}`: (default: `(min=0.0, max=0.0)`) Minimum and maximum reactive power limits. Set to `Nothing` if not applicable
- `R_th::Float64`: (default: `0.0`) Source Thevenin resistance. [See here:](https://en.wikipedia.org/wiki/Thevenins_theorem), validation range: `(0, nothing)`
- `X_th::Float64`: (default: `0.0`) Source Thevenin reactance. [See here:](https://en.wikipedia.org/wiki/Thevenins_theorem), validation range: `(0, nothing)`
- `internal_voltage::Float64`: (default: `1.0`) Internal Voltage (pu), validation range: `(0, nothing)`
- `internal_angle::Float64`: (default: `0.0`) Internal Angle
- `base_power::Float64`: (default: `100.0`) Base Power in MVA
- `operation_cost::ImportExportCost`: (default: `ImportExportCost(nothing)`) [`ImportExportCost`](@ref) of the source.
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct Source <: StaticInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used"
active_power::Float64
"Initial reactive power set point of the unit (MVAR)"
reactive_power::Float64
"Minimum and maximum stable active power levels (MW)"
active_power_limits::MinMax
"Minimum and maximum reactive power limits. Set to `Nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
"Source Thevenin resistance. [See here:](https://en.wikipedia.org/wiki/Thevenins_theorem)"
R_th::Float64
"Source Thevenin reactance. [See here:](https://en.wikipedia.org/wiki/Thevenins_theorem)"
X_th::Float64
"Internal Voltage (pu)"
internal_voltage::Float64
"Internal Angle"
internal_angle::Float64
"Base Power in MVA"
base_power::Float64
"[`ImportExportCost`](@ref) of the source."
operation_cost::ImportExportCost
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function Source(name, available, bus, active_power=0.0, reactive_power=0.0, active_power_limits=(min=0.0, max=0.0), reactive_power_limits=(min=0.0, max=0.0), R_th=0.0, X_th=0.0, internal_voltage=1.0, internal_angle=0.0, base_power=100.0, operation_cost=ImportExportCost(nothing), dynamic_injector=nothing, services=Device[], ext=Dict{String, Any}(), )
Source(name, available, bus, active_power, reactive_power, active_power_limits, reactive_power_limits, R_th, X_th, internal_voltage, internal_angle, base_power, operation_cost, dynamic_injector, services, ext, InfrastructureSystemsInternal(), )
end
function Source(; name, available, bus, active_power=0.0, reactive_power=0.0, active_power_limits=(min=0.0, max=0.0), reactive_power_limits=(min=0.0, max=0.0), R_th=0.0, X_th=0.0, internal_voltage=1.0, internal_angle=0.0, base_power=100.0, operation_cost=ImportExportCost(nothing), dynamic_injector=nothing, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
Source(name, available, bus, active_power, reactive_power, active_power_limits, reactive_power_limits, R_th, X_th, internal_voltage, internal_angle, base_power, operation_cost, dynamic_injector, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function Source(::Nothing)
Source(;
name="init",
available=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
active_power_limits=(min=0.0, max=0.0),
reactive_power_limits=nothing,
R_th=0,
X_th=0,
internal_voltage=0,
internal_angle=0,
base_power=0,
operation_cost=ImportExportCost(nothing),
dynamic_injector=nothing,
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`Source`](@ref) `name`."""
get_name(value::Source) = value.name
"""Get [`Source`](@ref) `available`."""
get_available(value::Source) = value.available
"""Get [`Source`](@ref) `bus`."""
get_bus(value::Source) = value.bus
"""Get [`Source`](@ref) `active_power`."""
get_active_power(value::Source) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`Source`](@ref) `reactive_power`."""
get_reactive_power(value::Source) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`Source`](@ref) `active_power_limits`."""
get_active_power_limits(value::Source) = get_value(value, Val(:active_power_limits), Val(:mva))
"""Get [`Source`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::Source) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`Source`](@ref) `R_th`."""
get_R_th(value::Source) = value.R_th
"""Get [`Source`](@ref) `X_th`."""
get_X_th(value::Source) = value.X_th
"""Get [`Source`](@ref) `internal_voltage`."""
get_internal_voltage(value::Source) = value.internal_voltage
"""Get [`Source`](@ref) `internal_angle`."""
get_internal_angle(value::Source) = value.internal_angle
"""Get [`Source`](@ref) `base_power`."""
get_base_power(value::Source) = value.base_power
"""Get [`Source`](@ref) `operation_cost`."""
get_operation_cost(value::Source) = value.operation_cost
"""Get [`Source`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::Source) = value.dynamic_injector
"""Get [`Source`](@ref) `services`."""
get_services(value::Source) = value.services
"""Get [`Source`](@ref) `ext`."""
get_ext(value::Source) = value.ext
"""Get [`Source`](@ref) `internal`."""
get_internal(value::Source) = value.internal
"""Set [`Source`](@ref) `available`."""
set_available!(value::Source, val) = value.available = val
"""Set [`Source`](@ref) `bus`."""
set_bus!(value::Source, val) = value.bus = val
"""Set [`Source`](@ref) `active_power`."""
set_active_power!(value::Source, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`Source`](@ref) `reactive_power`."""
set_reactive_power!(value::Source, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`Source`](@ref) `active_power_limits`."""
set_active_power_limits!(value::Source, val) = value.active_power_limits = set_value(value, Val(:active_power_limits), val, Val(:mva))
"""Set [`Source`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::Source, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`Source`](@ref) `R_th`."""
set_R_th!(value::Source, val) = value.R_th = val
"""Set [`Source`](@ref) `X_th`."""
set_X_th!(value::Source, val) = value.X_th = val
"""Set [`Source`](@ref) `internal_voltage`."""
set_internal_voltage!(value::Source, val) = value.internal_voltage = val
"""Set [`Source`](@ref) `internal_angle`."""
set_internal_angle!(value::Source, val) = value.internal_angle = val
"""Set [`Source`](@ref) `base_power`."""
set_base_power!(value::Source, val) = value.base_power = val
"""Set [`Source`](@ref) `operation_cost`."""
set_operation_cost!(value::Source, val) = value.operation_cost = val
"""Set [`Source`](@ref) `services`."""
set_services!(value::Source, val) = value.services = val
"""Set [`Source`](@ref) `ext`."""
set_ext!(value::Source, val) = value.ext = val
================================================
FILE: src/models/generated/StandardLoad.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct StandardLoad <: StaticLoad
name::String
available::Bool
bus::ACBus
base_power::Float64
constant_active_power::Float64
constant_reactive_power::Float64
impedance_active_power::Float64
impedance_reactive_power::Float64
current_active_power::Float64
current_reactive_power::Float64
max_constant_active_power::Float64
max_constant_reactive_power::Float64
max_impedance_active_power::Float64
max_impedance_reactive_power::Float64
max_current_active_power::Float64
max_current_reactive_power::Float64
conformity::LoadConformity
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A voltage-dependent [ZIP load](@ref Z), most commonly used for dynamics modeling.
A `StandardLoad` breaks the ZIP into three pieces: Z (constant impedance), I (constant current), and P (constant power), according to `P = P_P * V^0 + P_I * V^1 + P_Z * V^2` for active power and `Q = Q_P * V^0 + Q_I * V^1 + Q_Z * V^2` for reactive power. (Voltage V is in per unit.)
For an alternative exponential formulation of the ZIP model, see [`ExponentialLoad`](@ref). For a simpler load model with no voltage dependency, see [`PowerLoad`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `base_power::Float64`: Base power of the load (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `constant_active_power::Float64`: (default: `0.0`) Constant active power demand in MW (P_P)
- `constant_reactive_power::Float64`: (default: `0.0`) Constant reactive power demand in MVAR (Q_P)
- `impedance_active_power::Float64`: (default: `0.0`) Active power coefficient in MW for constant impedance load (P_Z)
- `impedance_reactive_power::Float64`: (default: `0.0`) Reactive power coefficient in MVAR for constant impedance load (Q_Z)
- `current_active_power::Float64`: (default: `0.0`) Active power coefficient in MW for constant current load (P_I)
- `current_reactive_power::Float64`: (default: `0.0`) Reactive power coefficient in MVAR for constant current load (Q_I)
- `max_constant_active_power::Float64`: (default: `0.0`) Maximum active power (MW) drawn by constant power load
- `max_constant_reactive_power::Float64`: (default: `0.0`) Maximum reactive power (MVAR) drawn by constant power load
- `max_impedance_active_power::Float64`: (default: `0.0`) Maximum active power (MW) drawn by constant impedance load
- `max_impedance_reactive_power::Float64`: (default: `0.0`) Maximum reactive power (MVAR) drawn by constant impedance load
- `max_current_active_power::Float64`: (default: `0.0`) Maximum active power (MW) drawn by constant current load
- `max_current_reactive_power::Float64`: (default: `0.0`) Maximum reactive power (MVAR) drawn by constant current load
- `conformity::LoadConformity`: (default: `LoadConformity.UNDEFINED`) Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list).
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct StandardLoad <: StaticLoad
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Base power of the load (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Constant active power demand in MW (P_P)"
constant_active_power::Float64
"Constant reactive power demand in MVAR (Q_P)"
constant_reactive_power::Float64
"Active power coefficient in MW for constant impedance load (P_Z)"
impedance_active_power::Float64
"Reactive power coefficient in MVAR for constant impedance load (Q_Z)"
impedance_reactive_power::Float64
"Active power coefficient in MW for constant current load (P_I)"
current_active_power::Float64
"Reactive power coefficient in MVAR for constant current load (Q_I)"
current_reactive_power::Float64
"Maximum active power (MW) drawn by constant power load"
max_constant_active_power::Float64
"Maximum reactive power (MVAR) drawn by constant power load"
max_constant_reactive_power::Float64
"Maximum active power (MW) drawn by constant impedance load"
max_impedance_active_power::Float64
"Maximum reactive power (MVAR) drawn by constant impedance load"
max_impedance_reactive_power::Float64
"Maximum active power (MW) drawn by constant current load"
max_current_active_power::Float64
"Maximum reactive power (MVAR) drawn by constant current load"
max_current_reactive_power::Float64
"Indicates whether the specified load is conforming or non-conforming. Options are [listed here](@ref loadconform_list)."
conformity::LoadConformity
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function StandardLoad(name, available, bus, base_power, constant_active_power=0.0, constant_reactive_power=0.0, impedance_active_power=0.0, impedance_reactive_power=0.0, current_active_power=0.0, current_reactive_power=0.0, max_constant_active_power=0.0, max_constant_reactive_power=0.0, max_impedance_active_power=0.0, max_impedance_reactive_power=0.0, max_current_active_power=0.0, max_current_reactive_power=0.0, conformity=LoadConformity.UNDEFINED, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
StandardLoad(name, available, bus, base_power, constant_active_power, constant_reactive_power, impedance_active_power, impedance_reactive_power, current_active_power, current_reactive_power, max_constant_active_power, max_constant_reactive_power, max_impedance_active_power, max_impedance_reactive_power, max_current_active_power, max_current_reactive_power, conformity, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function StandardLoad(; name, available, bus, base_power, constant_active_power=0.0, constant_reactive_power=0.0, impedance_active_power=0.0, impedance_reactive_power=0.0, current_active_power=0.0, current_reactive_power=0.0, max_constant_active_power=0.0, max_constant_reactive_power=0.0, max_impedance_active_power=0.0, max_impedance_reactive_power=0.0, max_current_active_power=0.0, max_current_reactive_power=0.0, conformity=LoadConformity.UNDEFINED, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
StandardLoad(name, available, bus, base_power, constant_active_power, constant_reactive_power, impedance_active_power, impedance_reactive_power, current_active_power, current_reactive_power, max_constant_active_power, max_constant_reactive_power, max_impedance_active_power, max_impedance_reactive_power, max_current_active_power, max_current_reactive_power, conformity, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function StandardLoad(::Nothing)
StandardLoad(;
name="init",
available=false,
bus=ACBus(nothing),
base_power=100.0,
constant_active_power=0.0,
constant_reactive_power=0.0,
impedance_active_power=0.0,
impedance_reactive_power=0.0,
current_active_power=0.0,
current_reactive_power=0.0,
max_constant_active_power=0.0,
max_constant_reactive_power=0.0,
max_impedance_active_power=0.0,
max_impedance_reactive_power=0.0,
max_current_active_power=0.0,
max_current_reactive_power=0.0,
conformity=LoadConformity.UNDEFINED,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`StandardLoad`](@ref) `name`."""
get_name(value::StandardLoad) = value.name
"""Get [`StandardLoad`](@ref) `available`."""
get_available(value::StandardLoad) = value.available
"""Get [`StandardLoad`](@ref) `bus`."""
get_bus(value::StandardLoad) = value.bus
"""Get [`StandardLoad`](@ref) `base_power`."""
get_base_power(value::StandardLoad) = value.base_power
"""Get [`StandardLoad`](@ref) `constant_active_power`."""
get_constant_active_power(value::StandardLoad) = get_value(value, Val(:constant_active_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `constant_reactive_power`."""
get_constant_reactive_power(value::StandardLoad) = get_value(value, Val(:constant_reactive_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `impedance_active_power`."""
get_impedance_active_power(value::StandardLoad) = get_value(value, Val(:impedance_active_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `impedance_reactive_power`."""
get_impedance_reactive_power(value::StandardLoad) = get_value(value, Val(:impedance_reactive_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `current_active_power`."""
get_current_active_power(value::StandardLoad) = get_value(value, Val(:current_active_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `current_reactive_power`."""
get_current_reactive_power(value::StandardLoad) = get_value(value, Val(:current_reactive_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `max_constant_active_power`."""
get_max_constant_active_power(value::StandardLoad) = get_value(value, Val(:max_constant_active_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `max_constant_reactive_power`."""
get_max_constant_reactive_power(value::StandardLoad) = get_value(value, Val(:max_constant_reactive_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `max_impedance_active_power`."""
get_max_impedance_active_power(value::StandardLoad) = get_value(value, Val(:max_impedance_active_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `max_impedance_reactive_power`."""
get_max_impedance_reactive_power(value::StandardLoad) = get_value(value, Val(:max_impedance_reactive_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `max_current_active_power`."""
get_max_current_active_power(value::StandardLoad) = get_value(value, Val(:max_current_active_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `max_current_reactive_power`."""
get_max_current_reactive_power(value::StandardLoad) = get_value(value, Val(:max_current_reactive_power), Val(:mva))
"""Get [`StandardLoad`](@ref) `conformity`."""
get_conformity(value::StandardLoad) = value.conformity
"""Get [`StandardLoad`](@ref) `services`."""
get_services(value::StandardLoad) = value.services
"""Get [`StandardLoad`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::StandardLoad) = value.dynamic_injector
"""Get [`StandardLoad`](@ref) `ext`."""
get_ext(value::StandardLoad) = value.ext
"""Get [`StandardLoad`](@ref) `internal`."""
get_internal(value::StandardLoad) = value.internal
"""Set [`StandardLoad`](@ref) `available`."""
set_available!(value::StandardLoad, val) = value.available = val
"""Set [`StandardLoad`](@ref) `bus`."""
set_bus!(value::StandardLoad, val) = value.bus = val
"""Set [`StandardLoad`](@ref) `base_power`."""
set_base_power!(value::StandardLoad, val) = value.base_power = val
"""Set [`StandardLoad`](@ref) `constant_active_power`."""
set_constant_active_power!(value::StandardLoad, val) = value.constant_active_power = set_value(value, Val(:constant_active_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `constant_reactive_power`."""
set_constant_reactive_power!(value::StandardLoad, val) = value.constant_reactive_power = set_value(value, Val(:constant_reactive_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `impedance_active_power`."""
set_impedance_active_power!(value::StandardLoad, val) = value.impedance_active_power = set_value(value, Val(:impedance_active_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `impedance_reactive_power`."""
set_impedance_reactive_power!(value::StandardLoad, val) = value.impedance_reactive_power = set_value(value, Val(:impedance_reactive_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `current_active_power`."""
set_current_active_power!(value::StandardLoad, val) = value.current_active_power = set_value(value, Val(:current_active_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `current_reactive_power`."""
set_current_reactive_power!(value::StandardLoad, val) = value.current_reactive_power = set_value(value, Val(:current_reactive_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `max_constant_active_power`."""
set_max_constant_active_power!(value::StandardLoad, val) = value.max_constant_active_power = set_value(value, Val(:max_constant_active_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `max_constant_reactive_power`."""
set_max_constant_reactive_power!(value::StandardLoad, val) = value.max_constant_reactive_power = set_value(value, Val(:max_constant_reactive_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `max_impedance_active_power`."""
set_max_impedance_active_power!(value::StandardLoad, val) = value.max_impedance_active_power = set_value(value, Val(:max_impedance_active_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `max_impedance_reactive_power`."""
set_max_impedance_reactive_power!(value::StandardLoad, val) = value.max_impedance_reactive_power = set_value(value, Val(:max_impedance_reactive_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `max_current_active_power`."""
set_max_current_active_power!(value::StandardLoad, val) = value.max_current_active_power = set_value(value, Val(:max_current_active_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `max_current_reactive_power`."""
set_max_current_reactive_power!(value::StandardLoad, val) = value.max_current_reactive_power = set_value(value, Val(:max_current_reactive_power), val, Val(:mva))
"""Set [`StandardLoad`](@ref) `conformity`."""
set_conformity!(value::StandardLoad, val) = value.conformity = val
"""Set [`StandardLoad`](@ref) `services`."""
set_services!(value::StandardLoad, val) = value.services = val
"""Set [`StandardLoad`](@ref) `ext`."""
set_ext!(value::StandardLoad, val) = value.ext = val
================================================
FILE: src/models/generated/SteamTurbineGov1.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SteamTurbineGov1 <: TurbineGov
R::Float64
T1::Float64
valve_position_limits::MinMax
T2::Float64
T3::Float64
D_T::Float64
DB_h::Float64
DB_l::Float64
T_rate::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Steam Turbine-Governor. This model considers both TGOV1 or TGOV1DU in PSS/E
# Arguments
- `R::Float64`: Droop parameter, validation range: `(0, 0.1)`
- `T1::Float64`: Governor time constant, validation range: `(eps(), 0.5)`
- `valve_position_limits::MinMax`: Valve position limits
- `T2::Float64`: Lead Lag Lead Time constant , validation range: `(0, nothing)`
- `T3::Float64`: Lead Lag Lag Time constant , validation range: `(eps(), 10)`
- `D_T::Float64`: Turbine Damping, validation range: `(0, 0.5)`
- `DB_h::Float64`: Deadband for overspeed, validation range: `(0, nothing)`
- `DB_l::Float64`: Deadband for underspeed, validation range: `(nothing, 0)`
- `T_rate::Float64`: Turbine Rate (MW). If zero, generator base is used, validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the SteamTurbineGov1 model are:
x_g1: Valve Opening,
x_g2: Lead-lag state
- `n_states::Int`: (**Do not modify.**) TGOV1 has 2 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) TGOV1 has 2 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SteamTurbineGov1 <: TurbineGov
"Droop parameter"
R::Float64
"Governor time constant"
T1::Float64
"Valve position limits"
valve_position_limits::MinMax
"Lead Lag Lead Time constant "
T2::Float64
"Lead Lag Lag Time constant "
T3::Float64
"Turbine Damping"
D_T::Float64
"Deadband for overspeed"
DB_h::Float64
"Deadband for underspeed"
DB_l::Float64
"Turbine Rate (MW). If zero, generator base is used"
T_rate::Float64
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the SteamTurbineGov1 model are:
x_g1: Valve Opening,
x_g2: Lead-lag state"
states::Vector{Symbol}
"(**Do not modify.**) TGOV1 has 2 states"
n_states::Int
"(**Do not modify.**) TGOV1 has 2 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SteamTurbineGov1(R, T1, valve_position_limits, T2, T3, D_T, DB_h, DB_l, T_rate, P_ref=1.0, ext=Dict{String, Any}(), )
SteamTurbineGov1(R, T1, valve_position_limits, T2, T3, D_T, DB_h, DB_l, T_rate, P_ref, ext, [:x_g1, :x_g2], 2, [StateTypes.Differential, StateTypes.Differential], InfrastructureSystemsInternal(), )
end
function SteamTurbineGov1(; R, T1, valve_position_limits, T2, T3, D_T, DB_h, DB_l, T_rate, P_ref=1.0, ext=Dict{String, Any}(), states=[:x_g1, :x_g2], n_states=2, states_types=[StateTypes.Differential, StateTypes.Differential], internal=InfrastructureSystemsInternal(), )
SteamTurbineGov1(R, T1, valve_position_limits, T2, T3, D_T, DB_h, DB_l, T_rate, P_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function SteamTurbineGov1(::Nothing)
SteamTurbineGov1(;
R=0,
T1=0,
valve_position_limits=(min=0.0, max=0.0),
T2=0,
T3=0,
D_T=0,
DB_h=0,
DB_l=0,
T_rate=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`SteamTurbineGov1`](@ref) `R`."""
get_R(value::SteamTurbineGov1) = value.R
"""Get [`SteamTurbineGov1`](@ref) `T1`."""
get_T1(value::SteamTurbineGov1) = value.T1
"""Get [`SteamTurbineGov1`](@ref) `valve_position_limits`."""
get_valve_position_limits(value::SteamTurbineGov1) = value.valve_position_limits
"""Get [`SteamTurbineGov1`](@ref) `T2`."""
get_T2(value::SteamTurbineGov1) = value.T2
"""Get [`SteamTurbineGov1`](@ref) `T3`."""
get_T3(value::SteamTurbineGov1) = value.T3
"""Get [`SteamTurbineGov1`](@ref) `D_T`."""
get_D_T(value::SteamTurbineGov1) = value.D_T
"""Get [`SteamTurbineGov1`](@ref) `DB_h`."""
get_DB_h(value::SteamTurbineGov1) = value.DB_h
"""Get [`SteamTurbineGov1`](@ref) `DB_l`."""
get_DB_l(value::SteamTurbineGov1) = value.DB_l
"""Get [`SteamTurbineGov1`](@ref) `T_rate`."""
get_T_rate(value::SteamTurbineGov1) = value.T_rate
"""Get [`SteamTurbineGov1`](@ref) `P_ref`."""
get_P_ref(value::SteamTurbineGov1) = value.P_ref
"""Get [`SteamTurbineGov1`](@ref) `ext`."""
get_ext(value::SteamTurbineGov1) = value.ext
"""Get [`SteamTurbineGov1`](@ref) `states`."""
get_states(value::SteamTurbineGov1) = value.states
"""Get [`SteamTurbineGov1`](@ref) `n_states`."""
get_n_states(value::SteamTurbineGov1) = value.n_states
"""Get [`SteamTurbineGov1`](@ref) `states_types`."""
get_states_types(value::SteamTurbineGov1) = value.states_types
"""Get [`SteamTurbineGov1`](@ref) `internal`."""
get_internal(value::SteamTurbineGov1) = value.internal
"""Set [`SteamTurbineGov1`](@ref) `R`."""
set_R!(value::SteamTurbineGov1, val) = value.R = val
"""Set [`SteamTurbineGov1`](@ref) `T1`."""
set_T1!(value::SteamTurbineGov1, val) = value.T1 = val
"""Set [`SteamTurbineGov1`](@ref) `valve_position_limits`."""
set_valve_position_limits!(value::SteamTurbineGov1, val) = value.valve_position_limits = val
"""Set [`SteamTurbineGov1`](@ref) `T2`."""
set_T2!(value::SteamTurbineGov1, val) = value.T2 = val
"""Set [`SteamTurbineGov1`](@ref) `T3`."""
set_T3!(value::SteamTurbineGov1, val) = value.T3 = val
"""Set [`SteamTurbineGov1`](@ref) `D_T`."""
set_D_T!(value::SteamTurbineGov1, val) = value.D_T = val
"""Set [`SteamTurbineGov1`](@ref) `DB_h`."""
set_DB_h!(value::SteamTurbineGov1, val) = value.DB_h = val
"""Set [`SteamTurbineGov1`](@ref) `DB_l`."""
set_DB_l!(value::SteamTurbineGov1, val) = value.DB_l = val
"""Set [`SteamTurbineGov1`](@ref) `T_rate`."""
set_T_rate!(value::SteamTurbineGov1, val) = value.T_rate = val
"""Set [`SteamTurbineGov1`](@ref) `P_ref`."""
set_P_ref!(value::SteamTurbineGov1, val) = value.P_ref = val
"""Set [`SteamTurbineGov1`](@ref) `ext`."""
set_ext!(value::SteamTurbineGov1, val) = value.ext = val
"""Set [`SteamTurbineGov1`](@ref) `states_types`."""
set_states_types!(value::SteamTurbineGov1, val) = value.states_types = val
================================================
FILE: src/models/generated/SwitchedAdmittance.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SwitchedAdmittance <: ElectricLoad
name::String
available::Bool
bus::ACBus
Y::Complex{Float64}
initial_status::Vector{Int}
number_of_steps::Vector{Int}
Y_increase::Vector{Complex{Float64}}
admittance_limits::MinMax
dynamic_injector::Union{Nothing, DynamicInjection}
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A switched admittance, with discrete steps to adjust the admittance.
Most often used in power flow studies, iterating over the steps to see impacts of admittance on the results. Total admittance is calculated as: `Y` + `number_of_steps` * `Y_increase`
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `Y::Complex{Float64}`: Initial admittance at N = 0
- `initial_status::Vector{Int}`: (default: `Int[]`) Vector of initial switched shunt status, one for in-service and zero for out-of-service for block i (1 through 8)
- `number_of_steps::Vector{Int}`: (default: `Int[]`) Vector with number of steps for each adjustable shunt block. For example, `number_of_steps[2]` are the number of available steps for admittance increment at block 2.
- `Y_increase::Vector{Complex{Float64}}`: (default: `Complex{Float64}[]`) Vector with admittance increment step for each adjustable shunt block. For example, `Y_increase[2]` is the complex admittance increment for each step at block 2.
- `admittance_limits::MinMax`: (default: `(min=1.0, max=1.0)`) Shunt admittance limits for switched shunt model
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection model for admittance
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SwitchedAdmittance <: ElectricLoad
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial admittance at N = 0"
Y::Complex{Float64}
"Vector of initial switched shunt status, one for in-service and zero for out-of-service for block i (1 through 8)"
initial_status::Vector{Int}
"Vector with number of steps for each adjustable shunt block. For example, `number_of_steps[2]` are the number of available steps for admittance increment at block 2."
number_of_steps::Vector{Int}
"Vector with admittance increment step for each adjustable shunt block. For example, `Y_increase[2]` is the complex admittance increment for each step at block 2."
Y_increase::Vector{Complex{Float64}}
"Shunt admittance limits for switched shunt model"
admittance_limits::MinMax
"corresponding dynamic injection model for admittance"
dynamic_injector::Union{Nothing, DynamicInjection}
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SwitchedAdmittance(name, available, bus, Y, initial_status=Int[], number_of_steps=Int[], Y_increase=Complex{Float64}[], admittance_limits=(min=1.0, max=1.0), dynamic_injector=nothing, services=Device[], ext=Dict{String, Any}(), )
SwitchedAdmittance(name, available, bus, Y, initial_status, number_of_steps, Y_increase, admittance_limits, dynamic_injector, services, ext, InfrastructureSystemsInternal(), )
end
function SwitchedAdmittance(; name, available, bus, Y, initial_status=Int[], number_of_steps=Int[], Y_increase=Complex{Float64}[], admittance_limits=(min=1.0, max=1.0), dynamic_injector=nothing, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
SwitchedAdmittance(name, available, bus, Y, initial_status, number_of_steps, Y_increase, admittance_limits, dynamic_injector, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function SwitchedAdmittance(::Nothing)
SwitchedAdmittance(;
name="init",
available=false,
bus=ACBus(nothing),
Y=0.0 + 0.0im,
initial_status=Int[],
number_of_steps=Int[],
Y_increase=Complex{Float64}[],
admittance_limits=(min=0.0, max=0.0),
dynamic_injector=nothing,
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`SwitchedAdmittance`](@ref) `name`."""
get_name(value::SwitchedAdmittance) = value.name
"""Get [`SwitchedAdmittance`](@ref) `available`."""
get_available(value::SwitchedAdmittance) = value.available
"""Get [`SwitchedAdmittance`](@ref) `bus`."""
get_bus(value::SwitchedAdmittance) = value.bus
"""Get [`SwitchedAdmittance`](@ref) `Y`."""
get_Y(value::SwitchedAdmittance) = value.Y
"""Get [`SwitchedAdmittance`](@ref) `initial_status`."""
get_initial_status(value::SwitchedAdmittance) = value.initial_status
"""Get [`SwitchedAdmittance`](@ref) `number_of_steps`."""
get_number_of_steps(value::SwitchedAdmittance) = value.number_of_steps
"""Get [`SwitchedAdmittance`](@ref) `Y_increase`."""
get_Y_increase(value::SwitchedAdmittance) = value.Y_increase
"""Get [`SwitchedAdmittance`](@ref) `admittance_limits`."""
get_admittance_limits(value::SwitchedAdmittance) = value.admittance_limits
"""Get [`SwitchedAdmittance`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::SwitchedAdmittance) = value.dynamic_injector
"""Get [`SwitchedAdmittance`](@ref) `services`."""
get_services(value::SwitchedAdmittance) = value.services
"""Get [`SwitchedAdmittance`](@ref) `ext`."""
get_ext(value::SwitchedAdmittance) = value.ext
"""Get [`SwitchedAdmittance`](@ref) `internal`."""
get_internal(value::SwitchedAdmittance) = value.internal
"""Set [`SwitchedAdmittance`](@ref) `available`."""
set_available!(value::SwitchedAdmittance, val) = value.available = val
"""Set [`SwitchedAdmittance`](@ref) `bus`."""
set_bus!(value::SwitchedAdmittance, val) = value.bus = val
"""Set [`SwitchedAdmittance`](@ref) `Y`."""
set_Y!(value::SwitchedAdmittance, val) = value.Y = val
"""Set [`SwitchedAdmittance`](@ref) `initial_status`."""
set_initial_status!(value::SwitchedAdmittance, val) = value.initial_status = val
"""Set [`SwitchedAdmittance`](@ref) `number_of_steps`."""
set_number_of_steps!(value::SwitchedAdmittance, val) = value.number_of_steps = val
"""Set [`SwitchedAdmittance`](@ref) `Y_increase`."""
set_Y_increase!(value::SwitchedAdmittance, val) = value.Y_increase = val
"""Set [`SwitchedAdmittance`](@ref) `admittance_limits`."""
set_admittance_limits!(value::SwitchedAdmittance, val) = value.admittance_limits = val
"""Set [`SwitchedAdmittance`](@ref) `services`."""
set_services!(value::SwitchedAdmittance, val) = value.services = val
"""Set [`SwitchedAdmittance`](@ref) `ext`."""
set_ext!(value::SwitchedAdmittance, val) = value.ext = val
================================================
FILE: src/models/generated/SynchronousCondenser.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct SynchronousCondenser <: StaticInjection
name::String
available::Bool
bus::ACBus
reactive_power::Float64
rating::Float64
reactive_power_limits::Union{Nothing, MinMax}
base_power::Float64
active_power_losses::Float64
services::Vector{Service}
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A Synchronous Machine connected to the system to provide inertia or reactive power support
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `bus::ACBus`: Bus that this component is connected to
- `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR), validation range: `reactive_power_limits`
- `rating::Float64`: Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power, validation range: `(0, nothing)`
- `reactive_power_limits::Union{Nothing, MinMax}`: Minimum and maximum reactive power limits. Set to `Nothing` if not applicable
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `active_power_losses::Float64`: (default: `0.0`) Active Power Loss incurred by having the unit online., validation range: `(0, nothing)`
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct SynchronousCondenser <: StaticInjection
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial reactive power set point of the unit (MVAR)"
reactive_power::Float64
"Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power"
rating::Float64
"Minimum and maximum reactive power limits. Set to `Nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Active Power Loss incurred by having the unit online."
active_power_losses::Float64
"Services that this device contributes to"
services::Vector{Service}
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function SynchronousCondenser(name, available, bus, reactive_power, rating, reactive_power_limits, base_power, active_power_losses=0.0, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), )
SynchronousCondenser(name, available, bus, reactive_power, rating, reactive_power_limits, base_power, active_power_losses, services, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function SynchronousCondenser(; name, available, bus, reactive_power, rating, reactive_power_limits, base_power, active_power_losses=0.0, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
SynchronousCondenser(name, available, bus, reactive_power, rating, reactive_power_limits, base_power, active_power_losses, services, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function SynchronousCondenser(::Nothing)
SynchronousCondenser(;
name="init",
available=false,
bus=ACBus(nothing),
reactive_power=0.0,
rating=0.0,
reactive_power_limits=nothing,
base_power=100.0,
active_power_losses=0.0,
services=Device[],
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`SynchronousCondenser`](@ref) `name`."""
get_name(value::SynchronousCondenser) = value.name
"""Get [`SynchronousCondenser`](@ref) `available`."""
get_available(value::SynchronousCondenser) = value.available
"""Get [`SynchronousCondenser`](@ref) `bus`."""
get_bus(value::SynchronousCondenser) = value.bus
"""Get [`SynchronousCondenser`](@ref) `reactive_power`."""
get_reactive_power(value::SynchronousCondenser) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`SynchronousCondenser`](@ref) `rating`."""
get_rating(value::SynchronousCondenser) = get_value(value, Val(:rating), Val(:mva))
"""Get [`SynchronousCondenser`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::SynchronousCondenser) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`SynchronousCondenser`](@ref) `base_power`."""
get_base_power(value::SynchronousCondenser) = value.base_power
"""Get [`SynchronousCondenser`](@ref) `active_power_losses`."""
get_active_power_losses(value::SynchronousCondenser) = get_value(value, Val(:active_power_losses), Val(:mva))
"""Get [`SynchronousCondenser`](@ref) `services`."""
get_services(value::SynchronousCondenser) = value.services
"""Get [`SynchronousCondenser`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::SynchronousCondenser) = value.dynamic_injector
"""Get [`SynchronousCondenser`](@ref) `ext`."""
get_ext(value::SynchronousCondenser) = value.ext
"""Get [`SynchronousCondenser`](@ref) `internal`."""
get_internal(value::SynchronousCondenser) = value.internal
"""Set [`SynchronousCondenser`](@ref) `available`."""
set_available!(value::SynchronousCondenser, val) = value.available = val
"""Set [`SynchronousCondenser`](@ref) `bus`."""
set_bus!(value::SynchronousCondenser, val) = value.bus = val
"""Set [`SynchronousCondenser`](@ref) `reactive_power`."""
set_reactive_power!(value::SynchronousCondenser, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`SynchronousCondenser`](@ref) `rating`."""
set_rating!(value::SynchronousCondenser, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`SynchronousCondenser`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::SynchronousCondenser, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`SynchronousCondenser`](@ref) `base_power`."""
set_base_power!(value::SynchronousCondenser, val) = value.base_power = val
"""Set [`SynchronousCondenser`](@ref) `active_power_losses`."""
set_active_power_losses!(value::SynchronousCondenser, val) = value.active_power_losses = set_value(value, Val(:active_power_losses), val, Val(:mva))
"""Set [`SynchronousCondenser`](@ref) `services`."""
set_services!(value::SynchronousCondenser, val) = value.services = val
"""Set [`SynchronousCondenser`](@ref) `ext`."""
set_ext!(value::SynchronousCondenser, val) = value.ext = val
================================================
FILE: src/models/generated/TGFixed.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct TGFixed <: TurbineGov
efficiency::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of a fixed Turbine Governor that returns a fixed mechanical torque
given by the product of P_ref*efficiency
# Arguments
- `efficiency::Float64`: Efficiency factor that multiplies `P_ref`, validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) TGFixed has no [states](@ref S)
- `n_states::Int`: (**Do not modify.**) TGFixed has no states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct TGFixed <: TurbineGov
"Efficiency factor that multiplies `P_ref`"
efficiency::Float64
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) TGFixed has no [states](@ref S)"
states::Vector{Symbol}
"(**Do not modify.**) TGFixed has no states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function TGFixed(efficiency, P_ref=1.0, ext=Dict{String, Any}(), )
TGFixed(efficiency, P_ref, ext, Vector{Symbol}(), 0, InfrastructureSystemsInternal(), )
end
function TGFixed(; efficiency, P_ref=1.0, ext=Dict{String, Any}(), states=Vector{Symbol}(), n_states=0, internal=InfrastructureSystemsInternal(), )
TGFixed(efficiency, P_ref, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function TGFixed(::Nothing)
TGFixed(;
efficiency=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`TGFixed`](@ref) `efficiency`."""
get_efficiency(value::TGFixed) = value.efficiency
"""Get [`TGFixed`](@ref) `P_ref`."""
get_P_ref(value::TGFixed) = value.P_ref
"""Get [`TGFixed`](@ref) `ext`."""
get_ext(value::TGFixed) = value.ext
"""Get [`TGFixed`](@ref) `states`."""
get_states(value::TGFixed) = value.states
"""Get [`TGFixed`](@ref) `n_states`."""
get_n_states(value::TGFixed) = value.n_states
"""Get [`TGFixed`](@ref) `internal`."""
get_internal(value::TGFixed) = value.internal
"""Set [`TGFixed`](@ref) `efficiency`."""
set_efficiency!(value::TGFixed, val) = value.efficiency = val
"""Set [`TGFixed`](@ref) `P_ref`."""
set_P_ref!(value::TGFixed, val) = value.P_ref = val
"""Set [`TGFixed`](@ref) `ext`."""
set_ext!(value::TGFixed, val) = value.ext = val
================================================
FILE: src/models/generated/TGSimple.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct TGSimple <: TurbineGov
d_t::Float64
Tm::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of a Simple one-state Turbine Governor
# Arguments
- `d_t::Float64`: Inverse Droop parameter, validation range: `(0, nothing)`
- `Tm::Float64`: Turbine Governor Low-Pass Time Constant [s], validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the TGSimple model are:
τm: mechanical torque
- `n_states::Int`: (**Do not modify.**) TGSimple has 1 state
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct TGSimple <: TurbineGov
"Inverse Droop parameter"
d_t::Float64
"Turbine Governor Low-Pass Time Constant [s]"
Tm::Float64
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the TGSimple model are:
τm: mechanical torque"
states::Vector{Symbol}
"(**Do not modify.**) TGSimple has 1 state"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function TGSimple(d_t, Tm, P_ref=1.0, ext=Dict{String, Any}(), )
TGSimple(d_t, Tm, P_ref, ext, [:τm], 1, InfrastructureSystemsInternal(), )
end
function TGSimple(; d_t, Tm, P_ref=1.0, ext=Dict{String, Any}(), states=[:τm], n_states=1, internal=InfrastructureSystemsInternal(), )
TGSimple(d_t, Tm, P_ref, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function TGSimple(::Nothing)
TGSimple(;
d_t=0,
Tm=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`TGSimple`](@ref) `d_t`."""
get_d_t(value::TGSimple) = value.d_t
"""Get [`TGSimple`](@ref) `Tm`."""
get_Tm(value::TGSimple) = value.Tm
"""Get [`TGSimple`](@ref) `P_ref`."""
get_P_ref(value::TGSimple) = value.P_ref
"""Get [`TGSimple`](@ref) `ext`."""
get_ext(value::TGSimple) = value.ext
"""Get [`TGSimple`](@ref) `states`."""
get_states(value::TGSimple) = value.states
"""Get [`TGSimple`](@ref) `n_states`."""
get_n_states(value::TGSimple) = value.n_states
"""Get [`TGSimple`](@ref) `internal`."""
get_internal(value::TGSimple) = value.internal
"""Set [`TGSimple`](@ref) `d_t`."""
set_d_t!(value::TGSimple, val) = value.d_t = val
"""Set [`TGSimple`](@ref) `Tm`."""
set_Tm!(value::TGSimple, val) = value.Tm = val
"""Set [`TGSimple`](@ref) `P_ref`."""
set_P_ref!(value::TGSimple, val) = value.P_ref = val
"""Set [`TGSimple`](@ref) `ext`."""
set_ext!(value::TGSimple, val) = value.ext = val
================================================
FILE: src/models/generated/TGTypeI.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct TGTypeI <: TurbineGov
R::Float64
Ts::Float64
Tc::Float64
T3::Float64
T4::Float64
T5::Float64
valve_position_limits::MinMax
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of a Turbine Governor Type I
# Arguments
- `R::Float64`: Droop parameter, validation range: `(0, nothing)`
- `Ts::Float64`: Governor time constant, validation range: `(0, nothing)`
- `Tc::Float64`: Servo time constant, validation range: `(0, nothing)`
- `T3::Float64`: Transient gain time constant, validation range: `(0, nothing)`
- `T4::Float64`: Power fraction time constant, validation range: `(0, nothing)`
- `T5::Float64`: Reheat time constant, validation range: `(0, nothing)`
- `valve_position_limits::MinMax`: Valve position limits in MW
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the TGTypeI model are:
x_g1: Governor state,
x_g2: Servo state,
x_g3: Reheat state
- `n_states::Int`: (**Do not modify.**) TGTypeI has 3 states
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct TGTypeI <: TurbineGov
"Droop parameter"
R::Float64
"Governor time constant"
Ts::Float64
"Servo time constant"
Tc::Float64
"Transient gain time constant"
T3::Float64
"Power fraction time constant"
T4::Float64
"Reheat time constant"
T5::Float64
"Valve position limits in MW"
valve_position_limits::MinMax
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the TGTypeI model are:
x_g1: Governor state,
x_g2: Servo state,
x_g3: Reheat state"
states::Vector{Symbol}
"(**Do not modify.**) TGTypeI has 3 states"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function TGTypeI(R, Ts, Tc, T3, T4, T5, valve_position_limits, P_ref=1.0, ext=Dict{String, Any}(), )
TGTypeI(R, Ts, Tc, T3, T4, T5, valve_position_limits, P_ref, ext, [:x_g1, :x_g2, :x_g3], 3, InfrastructureSystemsInternal(), )
end
function TGTypeI(; R, Ts, Tc, T3, T4, T5, valve_position_limits, P_ref=1.0, ext=Dict{String, Any}(), states=[:x_g1, :x_g2, :x_g3], n_states=3, internal=InfrastructureSystemsInternal(), )
TGTypeI(R, Ts, Tc, T3, T4, T5, valve_position_limits, P_ref, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function TGTypeI(::Nothing)
TGTypeI(;
R=0,
Ts=0,
Tc=0,
T3=0,
T4=0,
T5=0,
valve_position_limits=(min=0.0, max=0.0),
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`TGTypeI`](@ref) `R`."""
get_R(value::TGTypeI) = value.R
"""Get [`TGTypeI`](@ref) `Ts`."""
get_Ts(value::TGTypeI) = value.Ts
"""Get [`TGTypeI`](@ref) `Tc`."""
get_Tc(value::TGTypeI) = value.Tc
"""Get [`TGTypeI`](@ref) `T3`."""
get_T3(value::TGTypeI) = value.T3
"""Get [`TGTypeI`](@ref) `T4`."""
get_T4(value::TGTypeI) = value.T4
"""Get [`TGTypeI`](@ref) `T5`."""
get_T5(value::TGTypeI) = value.T5
"""Get [`TGTypeI`](@ref) `valve_position_limits`."""
get_valve_position_limits(value::TGTypeI) = value.valve_position_limits
"""Get [`TGTypeI`](@ref) `P_ref`."""
get_P_ref(value::TGTypeI) = value.P_ref
"""Get [`TGTypeI`](@ref) `ext`."""
get_ext(value::TGTypeI) = value.ext
"""Get [`TGTypeI`](@ref) `states`."""
get_states(value::TGTypeI) = value.states
"""Get [`TGTypeI`](@ref) `n_states`."""
get_n_states(value::TGTypeI) = value.n_states
"""Get [`TGTypeI`](@ref) `internal`."""
get_internal(value::TGTypeI) = value.internal
"""Set [`TGTypeI`](@ref) `R`."""
set_R!(value::TGTypeI, val) = value.R = val
"""Set [`TGTypeI`](@ref) `Ts`."""
set_Ts!(value::TGTypeI, val) = value.Ts = val
"""Set [`TGTypeI`](@ref) `Tc`."""
set_Tc!(value::TGTypeI, val) = value.Tc = val
"""Set [`TGTypeI`](@ref) `T3`."""
set_T3!(value::TGTypeI, val) = value.T3 = val
"""Set [`TGTypeI`](@ref) `T4`."""
set_T4!(value::TGTypeI, val) = value.T4 = val
"""Set [`TGTypeI`](@ref) `T5`."""
set_T5!(value::TGTypeI, val) = value.T5 = val
"""Set [`TGTypeI`](@ref) `valve_position_limits`."""
set_valve_position_limits!(value::TGTypeI, val) = value.valve_position_limits = val
"""Set [`TGTypeI`](@ref) `P_ref`."""
set_P_ref!(value::TGTypeI, val) = value.P_ref = val
"""Set [`TGTypeI`](@ref) `ext`."""
set_ext!(value::TGTypeI, val) = value.ext = val
================================================
FILE: src/models/generated/TGTypeII.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct TGTypeII <: TurbineGov
R::Float64
T1::Float64
T2::Float64
τ_limits::MinMax
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
internal::InfrastructureSystemsInternal
end
Parameters of a Turbine Governor Type II
# Arguments
- `R::Float64`: Droop parameter, validation range: `(0, nothing)`
- `T1::Float64`: Transient gain time constant, validation range: `(0, nothing)`
- `T2::Float64`: Power fraction time constant, validation range: `(0, nothing)`
- `τ_limits::MinMax`: Power into the governor limits
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the TGTypeI model are:
x_g1: lead-lag state
- `n_states::Int`: (**Do not modify.**) TGTypeII has 1 state
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct TGTypeII <: TurbineGov
"Droop parameter"
R::Float64
"Transient gain time constant"
T1::Float64
"Power fraction time constant"
T2::Float64
"Power into the governor limits"
τ_limits::MinMax
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the TGTypeI model are:
x_g1: lead-lag state"
states::Vector{Symbol}
"(**Do not modify.**) TGTypeII has 1 state"
n_states::Int
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function TGTypeII(R, T1, T2, τ_limits, P_ref=1.0, ext=Dict{String, Any}(), )
TGTypeII(R, T1, T2, τ_limits, P_ref, ext, [:xg], 1, InfrastructureSystemsInternal(), )
end
function TGTypeII(; R, T1, T2, τ_limits, P_ref=1.0, ext=Dict{String, Any}(), states=[:xg], n_states=1, internal=InfrastructureSystemsInternal(), )
TGTypeII(R, T1, T2, τ_limits, P_ref, ext, states, n_states, internal, )
end
# Constructor for demo purposes; non-functional.
function TGTypeII(::Nothing)
TGTypeII(;
R=0,
T1=0,
T2=0,
τ_limits=(min=0.0, max=0.0),
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`TGTypeII`](@ref) `R`."""
get_R(value::TGTypeII) = value.R
"""Get [`TGTypeII`](@ref) `T1`."""
get_T1(value::TGTypeII) = value.T1
"""Get [`TGTypeII`](@ref) `T2`."""
get_T2(value::TGTypeII) = value.T2
"""Get [`TGTypeII`](@ref) `τ_limits`."""
get_τ_limits(value::TGTypeII) = value.τ_limits
"""Get [`TGTypeII`](@ref) `P_ref`."""
get_P_ref(value::TGTypeII) = value.P_ref
"""Get [`TGTypeII`](@ref) `ext`."""
get_ext(value::TGTypeII) = value.ext
"""Get [`TGTypeII`](@ref) `states`."""
get_states(value::TGTypeII) = value.states
"""Get [`TGTypeII`](@ref) `n_states`."""
get_n_states(value::TGTypeII) = value.n_states
"""Get [`TGTypeII`](@ref) `internal`."""
get_internal(value::TGTypeII) = value.internal
"""Set [`TGTypeII`](@ref) `R`."""
set_R!(value::TGTypeII, val) = value.R = val
"""Set [`TGTypeII`](@ref) `T1`."""
set_T1!(value::TGTypeII, val) = value.T1 = val
"""Set [`TGTypeII`](@ref) `T2`."""
set_T2!(value::TGTypeII, val) = value.T2 = val
"""Set [`TGTypeII`](@ref) `τ_limits`."""
set_τ_limits!(value::TGTypeII, val) = value.τ_limits = val
"""Set [`TGTypeII`](@ref) `P_ref`."""
set_P_ref!(value::TGTypeII, val) = value.P_ref = val
"""Set [`TGTypeII`](@ref) `ext`."""
set_ext!(value::TGTypeII, val) = value.ext = val
================================================
FILE: src/models/generated/TModelHVDCLine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct TModelHVDCLine <: DCBranch
name::String
available::Bool
active_power_flow::Float64
arc::Arc
r::Float64
l::Float64
c::Float64
active_power_limits_from::MinMax
active_power_limits_to::MinMax
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A High Voltage DC transmission line for modeling DC transmission networks.
This line must be connected to a [`DCBus`](@ref) on each end. It uses a T-Model of the line impedance. This is suitable for operational simulations with a multi-terminal DC network
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow::Float64`: Initial condition of active power flow on the line (MW)
- `arc::Arc`: An [`Arc`](@ref) defining this line `from` a bus `to` another bus
- `r::Float64`: Total series Resistance in p.u. ([`SYSTEM_BASE`](@ref per_unit)), split equally on both sides of the shunt capacitance
- `l::Float64`: Total series Inductance in p.u. ([`SYSTEM_BASE`](@ref per_unit)), split equally on both sides of the shunt capacitance
- `c::Float64`: Shunt capacitance in p.u. ([`SYSTEM_BASE`](@ref per_unit))
- `active_power_limits_from::MinMax`: Minimum and maximum active power flows to the FROM node (MW)
- `active_power_limits_to::MinMax`: Minimum and maximum active power flows to the TO node (MW)
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct TModelHVDCLine <: DCBranch
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial condition of active power flow on the line (MW)"
active_power_flow::Float64
"An [`Arc`](@ref) defining this line `from` a bus `to` another bus"
arc::Arc
"Total series Resistance in p.u. ([`SYSTEM_BASE`](@ref per_unit)), split equally on both sides of the shunt capacitance"
r::Float64
"Total series Inductance in p.u. ([`SYSTEM_BASE`](@ref per_unit)), split equally on both sides of the shunt capacitance"
l::Float64
"Shunt capacitance in p.u. ([`SYSTEM_BASE`](@ref per_unit))"
c::Float64
"Minimum and maximum active power flows to the FROM node (MW)"
active_power_limits_from::MinMax
"Minimum and maximum active power flows to the TO node (MW)"
active_power_limits_to::MinMax
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function TModelHVDCLine(name, available, active_power_flow, arc, r, l, c, active_power_limits_from, active_power_limits_to, services=Device[], ext=Dict{String, Any}(), )
TModelHVDCLine(name, available, active_power_flow, arc, r, l, c, active_power_limits_from, active_power_limits_to, services, ext, InfrastructureSystemsInternal(), )
end
function TModelHVDCLine(; name, available, active_power_flow, arc, r, l, c, active_power_limits_from, active_power_limits_to, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
TModelHVDCLine(name, available, active_power_flow, arc, r, l, c, active_power_limits_from, active_power_limits_to, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function TModelHVDCLine(::Nothing)
TModelHVDCLine(;
name="init",
available=false,
active_power_flow=0.0,
arc=Arc(DCBus(nothing), DCBus(nothing)),
r=0.0,
l=0.0,
c=0.0,
active_power_limits_from=(min=0.0, max=0.0),
active_power_limits_to=(min=0.0, max=0.0),
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`TModelHVDCLine`](@ref) `name`."""
get_name(value::TModelHVDCLine) = value.name
"""Get [`TModelHVDCLine`](@ref) `available`."""
get_available(value::TModelHVDCLine) = value.available
"""Get [`TModelHVDCLine`](@ref) `active_power_flow`."""
get_active_power_flow(value::TModelHVDCLine) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`TModelHVDCLine`](@ref) `arc`."""
get_arc(value::TModelHVDCLine) = value.arc
"""Get [`TModelHVDCLine`](@ref) `r`."""
get_r(value::TModelHVDCLine) = value.r
"""Get [`TModelHVDCLine`](@ref) `l`."""
get_l(value::TModelHVDCLine) = value.l
"""Get [`TModelHVDCLine`](@ref) `c`."""
get_c(value::TModelHVDCLine) = value.c
"""Get [`TModelHVDCLine`](@ref) `active_power_limits_from`."""
get_active_power_limits_from(value::TModelHVDCLine) = get_value(value, Val(:active_power_limits_from), Val(:mva))
"""Get [`TModelHVDCLine`](@ref) `active_power_limits_to`."""
get_active_power_limits_to(value::TModelHVDCLine) = get_value(value, Val(:active_power_limits_to), Val(:mva))
"""Get [`TModelHVDCLine`](@ref) `services`."""
get_services(value::TModelHVDCLine) = value.services
"""Get [`TModelHVDCLine`](@ref) `ext`."""
get_ext(value::TModelHVDCLine) = value.ext
"""Get [`TModelHVDCLine`](@ref) `internal`."""
get_internal(value::TModelHVDCLine) = value.internal
"""Set [`TModelHVDCLine`](@ref) `available`."""
set_available!(value::TModelHVDCLine, val) = value.available = val
"""Set [`TModelHVDCLine`](@ref) `active_power_flow`."""
set_active_power_flow!(value::TModelHVDCLine, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`TModelHVDCLine`](@ref) `arc`."""
set_arc!(value::TModelHVDCLine, val) = value.arc = val
"""Set [`TModelHVDCLine`](@ref) `r`."""
set_r!(value::TModelHVDCLine, val) = value.r = val
"""Set [`TModelHVDCLine`](@ref) `l`."""
set_l!(value::TModelHVDCLine, val) = value.l = val
"""Set [`TModelHVDCLine`](@ref) `c`."""
set_c!(value::TModelHVDCLine, val) = value.c = val
"""Set [`TModelHVDCLine`](@ref) `active_power_limits_from`."""
set_active_power_limits_from!(value::TModelHVDCLine, val) = value.active_power_limits_from = set_value(value, Val(:active_power_limits_from), val, Val(:mva))
"""Set [`TModelHVDCLine`](@ref) `active_power_limits_to`."""
set_active_power_limits_to!(value::TModelHVDCLine, val) = value.active_power_limits_to = set_value(value, Val(:active_power_limits_to), val, Val(:mva))
"""Set [`TModelHVDCLine`](@ref) `services`."""
set_services!(value::TModelHVDCLine, val) = value.services = val
"""Set [`TModelHVDCLine`](@ref) `ext`."""
set_ext!(value::TModelHVDCLine, val) = value.ext = val
================================================
FILE: src/models/generated/TapTransformer.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct TapTransformer <: TwoWindingTransformer
name::String
available::Bool
active_power_flow::Float64
reactive_power_flow::Float64
arc::Arc
r::Float64
x::Float64
primary_shunt::Complex{Float64}
tap::Float64
rating::Union{Nothing, Float64}
base_power::Float64
base_voltage_primary::Union{Nothing, Float64}
base_voltage_secondary::Union{Nothing, Float64}
rating_b::Union{Nothing, Float64}
rating_c::Union{Nothing, Float64}
winding_group_number::WindingGroupNumber
control_objective::TransformerControlObjective
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A 2-winding transformer, with a tap changer for variable turns ratio.
The model uses an equivalent circuit assuming the impedance is on the High Voltage Side of the transformer. The model allocates the iron losses and magnetizing susceptance to the primary side
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow::Float64`: Initial condition of active power flow through the transformer (MW)
- `reactive_power_flow::Float64`: Initial condition of reactive power flow through the transformer (MVAR)
- `arc::Arc`: An [`Arc`](@ref) defining this transformer `from` a bus `to` another bus
- `r::Float64`: Resistance in p.u. ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(-2, 2)`
- `x::Float64`: Reactance in p.u. ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(-2, 4)`
- `primary_shunt::Complex{Float64}`: Primary shunt admittance in pu ([`SYSTEM_BASE`](@ref per_unit))
- `tap::Float64`: Normalized tap changer position for voltage control, varying between 0 and 2, with 1 centered at the nominal voltage, validation range: `(0, 2)`
- `rating::Union{Nothing, Float64}`: Thermal rating (MVA). Flow through the transformer must be between -`rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to, validation range: `(0, nothing)`
- `base_power::Float64`: Base power (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `base_voltage_primary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_from(arc))`) Primary base voltage in kV, validation range: `(0, nothing)`
- `base_voltage_secondary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_to(arc))`) Secondary base voltage in kV, validation range: `(0, nothing)`
- `rating_b::Union{Nothing, Float64}`: (default: `nothing`) Second current rating; entered in MVA.
- `rating_c::Union{Nothing, Float64}`: (default: `nothing`) Third current rating; entered in MVA.
- `winding_group_number::WindingGroupNumber`: (default: `WindingGroupNumber.UNDEFINED`) Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration
- `control_objective::TransformerControlObjective`: (default: `TransformerControlObjective.UNDEFINED`) Control objective for the tap changer for power flow calculations. See [`TransformerControlObjective`](@ref xtf_crtl)
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct TapTransformer <: TwoWindingTransformer
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial condition of active power flow through the transformer (MW)"
active_power_flow::Float64
"Initial condition of reactive power flow through the transformer (MVAR)"
reactive_power_flow::Float64
"An [`Arc`](@ref) defining this transformer `from` a bus `to` another bus"
arc::Arc
"Resistance in p.u. ([`SYSTEM_BASE`](@ref per_unit))"
r::Float64
"Reactance in p.u. ([`SYSTEM_BASE`](@ref per_unit))"
x::Float64
"Primary shunt admittance in pu ([`SYSTEM_BASE`](@ref per_unit))"
primary_shunt::Complex{Float64}
"Normalized tap changer position for voltage control, varying between 0 and 2, with 1 centered at the nominal voltage"
tap::Float64
"Thermal rating (MVA). Flow through the transformer must be between -`rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to"
rating::Union{Nothing, Float64}
"Base power (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Primary base voltage in kV"
base_voltage_primary::Union{Nothing, Float64}
"Secondary base voltage in kV"
base_voltage_secondary::Union{Nothing, Float64}
"Second current rating; entered in MVA."
rating_b::Union{Nothing, Float64}
"Third current rating; entered in MVA."
rating_c::Union{Nothing, Float64}
"Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration"
winding_group_number::WindingGroupNumber
"Control objective for the tap changer for power flow calculations. See [`TransformerControlObjective`](@ref xtf_crtl)"
control_objective::TransformerControlObjective
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function TapTransformer(name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, tap, rating, base_power, base_voltage_primary=get_base_voltage(get_from(arc)), base_voltage_secondary=get_base_voltage(get_to(arc)), rating_b=nothing, rating_c=nothing, winding_group_number=WindingGroupNumber.UNDEFINED, control_objective=TransformerControlObjective.UNDEFINED, services=Device[], ext=Dict{String, Any}(), )
TapTransformer(name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, tap, rating, base_power, base_voltage_primary, base_voltage_secondary, rating_b, rating_c, winding_group_number, control_objective, services, ext, InfrastructureSystemsInternal(), )
end
function TapTransformer(; name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, tap, rating, base_power, base_voltage_primary=get_base_voltage(get_from(arc)), base_voltage_secondary=get_base_voltage(get_to(arc)), rating_b=nothing, rating_c=nothing, winding_group_number=WindingGroupNumber.UNDEFINED, control_objective=TransformerControlObjective.UNDEFINED, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
TapTransformer(name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, tap, rating, base_power, base_voltage_primary, base_voltage_secondary, rating_b, rating_c, winding_group_number, control_objective, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function TapTransformer(::Nothing)
TapTransformer(;
name="init",
available=false,
active_power_flow=0.0,
reactive_power_flow=0.0,
arc=Arc(ACBus(nothing), ACBus(nothing)),
r=0.0,
x=0.0,
primary_shunt=0.0,
tap=1.0,
rating=0.0,
base_power=100.0,
base_voltage_primary=nothing,
base_voltage_secondary=nothing,
rating_b=0.0,
rating_c=0.0,
winding_group_number=WindingGroupNumber.UNDEFINED,
control_objective=TransformerControlObjective.UNDEFINED,
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`TapTransformer`](@ref) `name`."""
get_name(value::TapTransformer) = value.name
"""Get [`TapTransformer`](@ref) `available`."""
get_available(value::TapTransformer) = value.available
"""Get [`TapTransformer`](@ref) `active_power_flow`."""
get_active_power_flow(value::TapTransformer) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`TapTransformer`](@ref) `reactive_power_flow`."""
get_reactive_power_flow(value::TapTransformer) = get_value(value, Val(:reactive_power_flow), Val(:mva))
"""Get [`TapTransformer`](@ref) `arc`."""
get_arc(value::TapTransformer) = value.arc
"""Get [`TapTransformer`](@ref) `r`."""
get_r(value::TapTransformer) = get_value(value, Val(:r), Val(:ohm))
"""Get [`TapTransformer`](@ref) `x`."""
get_x(value::TapTransformer) = get_value(value, Val(:x), Val(:ohm))
"""Get [`TapTransformer`](@ref) `primary_shunt`."""
get_primary_shunt(value::TapTransformer) = get_value(value, Val(:primary_shunt), Val(:siemens))
"""Get [`TapTransformer`](@ref) `tap`."""
get_tap(value::TapTransformer) = value.tap
"""Get [`TapTransformer`](@ref) `rating`."""
get_rating(value::TapTransformer) = get_value(value, Val(:rating), Val(:mva))
"""Get [`TapTransformer`](@ref) `base_power`."""
get_base_power(value::TapTransformer) = value.base_power
"""Get [`TapTransformer`](@ref) `base_voltage_primary`."""
get_base_voltage_primary(value::TapTransformer) = value.base_voltage_primary
"""Get [`TapTransformer`](@ref) `base_voltage_secondary`."""
get_base_voltage_secondary(value::TapTransformer) = value.base_voltage_secondary
"""Get [`TapTransformer`](@ref) `rating_b`."""
get_rating_b(value::TapTransformer) = get_value(value, Val(:rating_b), Val(:mva))
"""Get [`TapTransformer`](@ref) `rating_c`."""
get_rating_c(value::TapTransformer) = get_value(value, Val(:rating_c), Val(:mva))
"""Get [`TapTransformer`](@ref) `winding_group_number`."""
get_winding_group_number(value::TapTransformer) = value.winding_group_number
"""Get [`TapTransformer`](@ref) `control_objective`."""
get_control_objective(value::TapTransformer) = value.control_objective
"""Get [`TapTransformer`](@ref) `services`."""
get_services(value::TapTransformer) = value.services
"""Get [`TapTransformer`](@ref) `ext`."""
get_ext(value::TapTransformer) = value.ext
"""Get [`TapTransformer`](@ref) `internal`."""
get_internal(value::TapTransformer) = value.internal
"""Set [`TapTransformer`](@ref) `available`."""
set_available!(value::TapTransformer, val) = value.available = val
"""Set [`TapTransformer`](@ref) `active_power_flow`."""
set_active_power_flow!(value::TapTransformer, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`TapTransformer`](@ref) `reactive_power_flow`."""
set_reactive_power_flow!(value::TapTransformer, val) = value.reactive_power_flow = set_value(value, Val(:reactive_power_flow), val, Val(:mva))
"""Set [`TapTransformer`](@ref) `arc`."""
set_arc!(value::TapTransformer, val) = value.arc = val
"""Set [`TapTransformer`](@ref) `r`."""
set_r!(value::TapTransformer, val) = value.r = set_value(value, Val(:r), val, Val(:ohm))
"""Set [`TapTransformer`](@ref) `x`."""
set_x!(value::TapTransformer, val) = value.x = set_value(value, Val(:x), val, Val(:ohm))
"""Set [`TapTransformer`](@ref) `primary_shunt`."""
set_primary_shunt!(value::TapTransformer, val) = value.primary_shunt = set_value(value, Val(:primary_shunt), val, Val(:siemens))
"""Set [`TapTransformer`](@ref) `tap`."""
set_tap!(value::TapTransformer, val) = value.tap = val
"""Set [`TapTransformer`](@ref) `rating`."""
set_rating!(value::TapTransformer, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`TapTransformer`](@ref) `base_power`."""
set_base_power!(value::TapTransformer, val) = value.base_power = val
"""Set [`TapTransformer`](@ref) `base_voltage_primary`."""
set_base_voltage_primary!(value::TapTransformer, val) = value.base_voltage_primary = val
"""Set [`TapTransformer`](@ref) `base_voltage_secondary`."""
set_base_voltage_secondary!(value::TapTransformer, val) = value.base_voltage_secondary = val
"""Set [`TapTransformer`](@ref) `rating_b`."""
set_rating_b!(value::TapTransformer, val) = value.rating_b = set_value(value, Val(:rating_b), val, Val(:mva))
"""Set [`TapTransformer`](@ref) `rating_c`."""
set_rating_c!(value::TapTransformer, val) = value.rating_c = set_value(value, Val(:rating_c), val, Val(:mva))
"""Set [`TapTransformer`](@ref) `winding_group_number`."""
set_winding_group_number!(value::TapTransformer, val) = value.winding_group_number = val
"""Set [`TapTransformer`](@ref) `control_objective`."""
set_control_objective!(value::TapTransformer, val) = value.control_objective = val
"""Set [`TapTransformer`](@ref) `services`."""
set_services!(value::TapTransformer, val) = value.services = val
"""Set [`TapTransformer`](@ref) `ext`."""
set_ext!(value::TapTransformer, val) = value.ext = val
================================================
FILE: src/models/generated/ThermalMultiStart.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ThermalMultiStart <: ThermalGen
name::String
available::Bool
status::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
rating::Float64
prime_mover_type::PrimeMovers
fuel::ThermalFuels
active_power_limits::MinMax
reactive_power_limits::Union{Nothing, MinMax}
ramp_limits::Union{Nothing, UpDown}
power_trajectory::Union{Nothing, StartUpShutDown}
time_limits::Union{Nothing, UpDown}
start_time_limits::Union{Nothing, StartUpStages}
start_types::Int
operation_cost::Union{ThermalGenerationCost, MarketBidCost}
base_power::Float64
services::Vector{Service}
time_at_status::Float64
must_run::Bool
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A thermal generator, such as a fossil fuel or nuclear generator, that can start-up again from a *hot*, *warm*, or *cold* state.
`ThermalMultiStart` has a detailed representation of the start-up process based on the time elapsed since the last shut down, as well as a detailed shut-down process. The model is based on ["Tight and Compact MILP Formulation for the Thermal Unit Commitment Problem."](https://doi.org/10.1109/TPWRS.2013.2251373). For a simplified representation of the start-up and shut-down processes, see [`ThermalStandard`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `status::Bool`: Initial commitment condition at the start of a simulation (`true` = on or `false` = off)
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used, validation range: `active_power_limits`
- `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR), validation range: `reactive_power_limits`
- `rating::Float64`: Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power, validation range: `(0, nothing)`
- `prime_mover_type::PrimeMovers`: Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)
- `fuel::ThermalFuels`: Prime mover fuel according to EIA 923. Options are listed [here](@ref tf_list)
- `active_power_limits::MinMax`: Minimum and maximum stable active power levels (MW)
- `reactive_power_limits::Union{Nothing, MinMax}`: Minimum and maximum reactive power limits. Set to `Nothing` if not applicable
- `ramp_limits::Union{Nothing, UpDown}`:, validation range: `(0, nothing)`
- `power_trajectory::Union{Nothing, StartUpShutDown}`: Power trajectory the unit will take during the start-up and shut-down ramp process, validation range: `(0, nothing)`
- `time_limits::Union{Nothing, UpDown}`: Minimum up and Minimum down time limits in hours, validation range: `(0, nothing)`
- `start_time_limits::Union{Nothing, StartUpStages}`: Time limits for start-up based on turbine temperature in hours
- `start_types::Int`: Number of start-up based on turbine temperature, where `1` = *hot*, `2` = *warm*, and `3` = *cold*, validation range: `(1, 3)`
- `operation_cost::Union{ThermalGenerationCost, MarketBidCost}`: [`OperationalCost`](@ref) of generation
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `time_at_status::Float64`: (default: `INFINITE_TIME`) Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`
- `must_run::Bool`: (default: `false`) Set to `true` if the unit is must run
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ThermalMultiStart <: ThermalGen
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial commitment condition at the start of a simulation (`true` = on or `false` = off)"
status::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used"
active_power::Float64
"Initial reactive power set point of the unit (MVAR)"
reactive_power::Float64
"Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power"
rating::Float64
"Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)"
prime_mover_type::PrimeMovers
"Prime mover fuel according to EIA 923. Options are listed [here](@ref tf_list)"
fuel::ThermalFuels
"Minimum and maximum stable active power levels (MW)"
active_power_limits::MinMax
"Minimum and maximum reactive power limits. Set to `Nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
ramp_limits::Union{Nothing, UpDown}
"Power trajectory the unit will take during the start-up and shut-down ramp process"
power_trajectory::Union{Nothing, StartUpShutDown}
"Minimum up and Minimum down time limits in hours"
time_limits::Union{Nothing, UpDown}
"Time limits for start-up based on turbine temperature in hours"
start_time_limits::Union{Nothing, StartUpStages}
"Number of start-up based on turbine temperature, where `1` = *hot*, `2` = *warm*, and `3` = *cold*"
start_types::Int
"[`OperationalCost`](@ref) of generation"
operation_cost::Union{ThermalGenerationCost, MarketBidCost}
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Services that this device contributes to"
services::Vector{Service}
"Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`"
time_at_status::Float64
"Set to `true` if the unit is must run"
must_run::Bool
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ThermalMultiStart(name, available, status, bus, active_power, reactive_power, rating, prime_mover_type, fuel, active_power_limits, reactive_power_limits, ramp_limits, power_trajectory, time_limits, start_time_limits, start_types, operation_cost, base_power, services=Device[], time_at_status=INFINITE_TIME, must_run=false, dynamic_injector=nothing, ext=Dict{String, Any}(), )
ThermalMultiStart(name, available, status, bus, active_power, reactive_power, rating, prime_mover_type, fuel, active_power_limits, reactive_power_limits, ramp_limits, power_trajectory, time_limits, start_time_limits, start_types, operation_cost, base_power, services, time_at_status, must_run, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function ThermalMultiStart(; name, available, status, bus, active_power, reactive_power, rating, prime_mover_type, fuel, active_power_limits, reactive_power_limits, ramp_limits, power_trajectory, time_limits, start_time_limits, start_types, operation_cost, base_power, services=Device[], time_at_status=INFINITE_TIME, must_run=false, dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
ThermalMultiStart(name, available, status, bus, active_power, reactive_power, rating, prime_mover_type, fuel, active_power_limits, reactive_power_limits, ramp_limits, power_trajectory, time_limits, start_time_limits, start_types, operation_cost, base_power, services, time_at_status, must_run, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function ThermalMultiStart(::Nothing)
ThermalMultiStart(;
name="init",
available=false,
status=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
rating=0.0,
prime_mover_type=PrimeMovers.OT,
fuel=ThermalFuels.OTHER,
active_power_limits=(min=0.0, max=0.0),
reactive_power_limits=nothing,
ramp_limits=nothing,
power_trajectory=nothing,
time_limits=nothing,
start_time_limits=nothing,
start_types=1,
operation_cost=ThermalGenerationCost(nothing),
base_power=100.0,
services=Device[],
time_at_status=INFINITE_TIME,
must_run=false,
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`ThermalMultiStart`](@ref) `name`."""
get_name(value::ThermalMultiStart) = value.name
"""Get [`ThermalMultiStart`](@ref) `available`."""
get_available(value::ThermalMultiStart) = value.available
"""Get [`ThermalMultiStart`](@ref) `status`."""
get_status(value::ThermalMultiStart) = value.status
"""Get [`ThermalMultiStart`](@ref) `bus`."""
get_bus(value::ThermalMultiStart) = value.bus
"""Get [`ThermalMultiStart`](@ref) `active_power`."""
get_active_power(value::ThermalMultiStart) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`ThermalMultiStart`](@ref) `reactive_power`."""
get_reactive_power(value::ThermalMultiStart) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`ThermalMultiStart`](@ref) `rating`."""
get_rating(value::ThermalMultiStart) = get_value(value, Val(:rating), Val(:mva))
"""Get [`ThermalMultiStart`](@ref) `prime_mover_type`."""
get_prime_mover_type(value::ThermalMultiStart) = value.prime_mover_type
"""Get [`ThermalMultiStart`](@ref) `fuel`."""
get_fuel(value::ThermalMultiStart) = value.fuel
"""Get [`ThermalMultiStart`](@ref) `active_power_limits`."""
get_active_power_limits(value::ThermalMultiStart) = get_value(value, Val(:active_power_limits), Val(:mva))
"""Get [`ThermalMultiStart`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::ThermalMultiStart) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`ThermalMultiStart`](@ref) `ramp_limits`."""
get_ramp_limits(value::ThermalMultiStart) = get_value(value, Val(:ramp_limits), Val(:mva))
"""Get [`ThermalMultiStart`](@ref) `power_trajectory`."""
get_power_trajectory(value::ThermalMultiStart) = get_value(value, Val(:power_trajectory), Val(:mva))
"""Get [`ThermalMultiStart`](@ref) `time_limits`."""
get_time_limits(value::ThermalMultiStart) = value.time_limits
"""Get [`ThermalMultiStart`](@ref) `start_time_limits`."""
get_start_time_limits(value::ThermalMultiStart) = value.start_time_limits
"""Get [`ThermalMultiStart`](@ref) `start_types`."""
get_start_types(value::ThermalMultiStart) = value.start_types
"""Get [`ThermalMultiStart`](@ref) `operation_cost`."""
get_operation_cost(value::ThermalMultiStart) = value.operation_cost
"""Get [`ThermalMultiStart`](@ref) `base_power`."""
get_base_power(value::ThermalMultiStart) = value.base_power
"""Get [`ThermalMultiStart`](@ref) `services`."""
get_services(value::ThermalMultiStart) = value.services
"""Get [`ThermalMultiStart`](@ref) `time_at_status`."""
get_time_at_status(value::ThermalMultiStart) = value.time_at_status
"""Get [`ThermalMultiStart`](@ref) `must_run`."""
get_must_run(value::ThermalMultiStart) = value.must_run
"""Get [`ThermalMultiStart`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::ThermalMultiStart) = value.dynamic_injector
"""Get [`ThermalMultiStart`](@ref) `ext`."""
get_ext(value::ThermalMultiStart) = value.ext
"""Get [`ThermalMultiStart`](@ref) `internal`."""
get_internal(value::ThermalMultiStart) = value.internal
"""Set [`ThermalMultiStart`](@ref) `available`."""
set_available!(value::ThermalMultiStart, val) = value.available = val
"""Set [`ThermalMultiStart`](@ref) `status`."""
set_status!(value::ThermalMultiStart, val) = value.status = val
"""Set [`ThermalMultiStart`](@ref) `bus`."""
set_bus!(value::ThermalMultiStart, val) = value.bus = val
"""Set [`ThermalMultiStart`](@ref) `active_power`."""
set_active_power!(value::ThermalMultiStart, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`ThermalMultiStart`](@ref) `reactive_power`."""
set_reactive_power!(value::ThermalMultiStart, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`ThermalMultiStart`](@ref) `rating`."""
set_rating!(value::ThermalMultiStart, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`ThermalMultiStart`](@ref) `prime_mover_type`."""
set_prime_mover_type!(value::ThermalMultiStart, val) = value.prime_mover_type = val
"""Set [`ThermalMultiStart`](@ref) `fuel`."""
set_fuel!(value::ThermalMultiStart, val) = value.fuel = val
"""Set [`ThermalMultiStart`](@ref) `active_power_limits`."""
set_active_power_limits!(value::ThermalMultiStart, val) = value.active_power_limits = set_value(value, Val(:active_power_limits), val, Val(:mva))
"""Set [`ThermalMultiStart`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::ThermalMultiStart, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`ThermalMultiStart`](@ref) `ramp_limits`."""
set_ramp_limits!(value::ThermalMultiStart, val) = value.ramp_limits = set_value(value, Val(:ramp_limits), val, Val(:mva))
"""Set [`ThermalMultiStart`](@ref) `power_trajectory`."""
set_power_trajectory!(value::ThermalMultiStart, val) = value.power_trajectory = set_value(value, Val(:power_trajectory), val, Val(:mva))
"""Set [`ThermalMultiStart`](@ref) `time_limits`."""
set_time_limits!(value::ThermalMultiStart, val) = value.time_limits = val
"""Set [`ThermalMultiStart`](@ref) `start_time_limits`."""
set_start_time_limits!(value::ThermalMultiStart, val) = value.start_time_limits = val
"""Set [`ThermalMultiStart`](@ref) `start_types`."""
set_start_types!(value::ThermalMultiStart, val) = value.start_types = val
"""Set [`ThermalMultiStart`](@ref) `operation_cost`."""
set_operation_cost!(value::ThermalMultiStart, val) = value.operation_cost = val
"""Set [`ThermalMultiStart`](@ref) `base_power`."""
set_base_power!(value::ThermalMultiStart, val) = value.base_power = val
"""Set [`ThermalMultiStart`](@ref) `services`."""
set_services!(value::ThermalMultiStart, val) = value.services = val
"""Set [`ThermalMultiStart`](@ref) `time_at_status`."""
set_time_at_status!(value::ThermalMultiStart, val) = value.time_at_status = val
"""Set [`ThermalMultiStart`](@ref) `must_run`."""
set_must_run!(value::ThermalMultiStart, val) = value.must_run = val
"""Set [`ThermalMultiStart`](@ref) `ext`."""
set_ext!(value::ThermalMultiStart, val) = value.ext = val
================================================
FILE: src/models/generated/ThermalStandard.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ThermalStandard <: ThermalGen
name::String
available::Bool
status::Bool
bus::ACBus
active_power::Float64
reactive_power::Float64
rating::Float64
active_power_limits::MinMax
reactive_power_limits::Union{Nothing, MinMax}
ramp_limits::Union{Nothing, UpDown}
operation_cost::Union{ThermalGenerationCost, MarketBidCost}
base_power::Float64
time_limits::Union{Nothing, UpDown}
must_run::Bool
prime_mover_type::PrimeMovers
fuel::ThermalFuels
services::Vector{Service}
time_at_status::Float64
dynamic_injector::Union{Nothing, DynamicInjection}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A thermal generator, such as a fossil fuel and nuclear generator.
This is a standard representation with options to include a minimum up time, minimum down time, and ramp limits. For a more detailed representation the start-up and shut-down processes, including hot starts, see [`ThermalMultiStart`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `status::Bool`: Initial commitment condition at the start of a simulation (`true` = on or `false` = off)
- `bus::ACBus`: Bus that this component is connected to
- `active_power::Float64`: Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used, validation range: `active_power_limits`
- `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR), validation range: `reactive_power_limits`
- `rating::Float64`: Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power, validation range: `(0, nothing)`
- `active_power_limits::MinMax`: Minimum and maximum stable active power levels (MW), validation range: `(0, nothing)`
- `reactive_power_limits::Union{Nothing, MinMax}`: Minimum and maximum reactive power limits. Set to `Nothing` if not applicable
- `ramp_limits::Union{Nothing, UpDown}`: ramp up and ramp down limits in MW/min, validation range: `(0, nothing)`
- `operation_cost::Union{ThermalGenerationCost, MarketBidCost}`: [`OperationalCost`](@ref) of generation
- `base_power::Float64`: Base power of the unit (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `time_limits::Union{Nothing, UpDown}`: (default: `nothing`) Minimum up and Minimum down time limits in hours, validation range: `(0, nothing)`
- `must_run::Bool`: (default: `false`) Set to `true` if the unit is must run
- `prime_mover_type::PrimeMovers`: (default: `PrimeMovers.OT`) Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)
- `fuel::ThermalFuels`: (default: `ThermalFuels.OTHER`) Prime mover fuel according to EIA 923. Options are listed [here](@ref tf_list)
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `time_at_status::Float64`: (default: `INFINITE_TIME`) Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`
- `dynamic_injector::Union{Nothing, DynamicInjection}`: (default: `nothing`) corresponding dynamic injection device
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct ThermalStandard <: ThermalGen
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial commitment condition at the start of a simulation (`true` = on or `false` = off)"
status::Bool
"Bus that this component is connected to"
bus::ACBus
"Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used"
active_power::Float64
"Initial reactive power set point of the unit (MVAR)"
reactive_power::Float64
"Maximum AC side output power rating of the unit. Stored in per unit of the device and not to be confused with base_power"
rating::Float64
"Minimum and maximum stable active power levels (MW)"
active_power_limits::MinMax
"Minimum and maximum reactive power limits. Set to `Nothing` if not applicable"
reactive_power_limits::Union{Nothing, MinMax}
"ramp up and ramp down limits in MW/min"
ramp_limits::Union{Nothing, UpDown}
"[`OperationalCost`](@ref) of generation"
operation_cost::Union{ThermalGenerationCost, MarketBidCost}
"Base power of the unit (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Minimum up and Minimum down time limits in hours"
time_limits::Union{Nothing, UpDown}
"Set to `true` if the unit is must run"
must_run::Bool
"Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list)"
prime_mover_type::PrimeMovers
"Prime mover fuel according to EIA 923. Options are listed [here](@ref tf_list)"
fuel::ThermalFuels
"Services that this device contributes to"
services::Vector{Service}
"Time (e.g., `Hours(6)`) the generator has been on or off, as indicated by `status`"
time_at_status::Float64
"corresponding dynamic injection device"
dynamic_injector::Union{Nothing, DynamicInjection}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function ThermalStandard(name, available, status, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, ramp_limits, operation_cost, base_power, time_limits=nothing, must_run=false, prime_mover_type=PrimeMovers.OT, fuel=ThermalFuels.OTHER, services=Device[], time_at_status=INFINITE_TIME, dynamic_injector=nothing, ext=Dict{String, Any}(), )
ThermalStandard(name, available, status, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, ramp_limits, operation_cost, base_power, time_limits, must_run, prime_mover_type, fuel, services, time_at_status, dynamic_injector, ext, InfrastructureSystemsInternal(), )
end
function ThermalStandard(; name, available, status, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, ramp_limits, operation_cost, base_power, time_limits=nothing, must_run=false, prime_mover_type=PrimeMovers.OT, fuel=ThermalFuels.OTHER, services=Device[], time_at_status=INFINITE_TIME, dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
ThermalStandard(name, available, status, bus, active_power, reactive_power, rating, active_power_limits, reactive_power_limits, ramp_limits, operation_cost, base_power, time_limits, must_run, prime_mover_type, fuel, services, time_at_status, dynamic_injector, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function ThermalStandard(::Nothing)
ThermalStandard(;
name="init",
available=false,
status=false,
bus=ACBus(nothing),
active_power=0.0,
reactive_power=0.0,
rating=0.0,
active_power_limits=(min=0.0, max=0.0),
reactive_power_limits=nothing,
ramp_limits=nothing,
operation_cost=ThermalGenerationCost(nothing),
base_power=100.0,
time_limits=nothing,
must_run=false,
prime_mover_type=PrimeMovers.OT,
fuel=ThermalFuels.OTHER,
services=Device[],
time_at_status=INFINITE_TIME,
dynamic_injector=nothing,
ext=Dict{String, Any}(),
)
end
"""Get [`ThermalStandard`](@ref) `name`."""
get_name(value::ThermalStandard) = value.name
"""Get [`ThermalStandard`](@ref) `available`."""
get_available(value::ThermalStandard) = value.available
"""Get [`ThermalStandard`](@ref) `status`."""
get_status(value::ThermalStandard) = value.status
"""Get [`ThermalStandard`](@ref) `bus`."""
get_bus(value::ThermalStandard) = value.bus
"""Get [`ThermalStandard`](@ref) `active_power`."""
get_active_power(value::ThermalStandard) = get_value(value, Val(:active_power), Val(:mva))
"""Get [`ThermalStandard`](@ref) `reactive_power`."""
get_reactive_power(value::ThermalStandard) = get_value(value, Val(:reactive_power), Val(:mva))
"""Get [`ThermalStandard`](@ref) `rating`."""
get_rating(value::ThermalStandard) = get_value(value, Val(:rating), Val(:mva))
"""Get [`ThermalStandard`](@ref) `active_power_limits`."""
get_active_power_limits(value::ThermalStandard) = get_value(value, Val(:active_power_limits), Val(:mva))
"""Get [`ThermalStandard`](@ref) `reactive_power_limits`."""
get_reactive_power_limits(value::ThermalStandard) = get_value(value, Val(:reactive_power_limits), Val(:mva))
"""Get [`ThermalStandard`](@ref) `ramp_limits`."""
get_ramp_limits(value::ThermalStandard) = get_value(value, Val(:ramp_limits), Val(:mva))
"""Get [`ThermalStandard`](@ref) `operation_cost`."""
get_operation_cost(value::ThermalStandard) = value.operation_cost
"""Get [`ThermalStandard`](@ref) `base_power`."""
get_base_power(value::ThermalStandard) = value.base_power
"""Get [`ThermalStandard`](@ref) `time_limits`."""
get_time_limits(value::ThermalStandard) = value.time_limits
"""Get [`ThermalStandard`](@ref) `must_run`."""
get_must_run(value::ThermalStandard) = value.must_run
"""Get [`ThermalStandard`](@ref) `prime_mover_type`."""
get_prime_mover_type(value::ThermalStandard) = value.prime_mover_type
"""Get [`ThermalStandard`](@ref) `fuel`."""
get_fuel(value::ThermalStandard) = value.fuel
"""Get [`ThermalStandard`](@ref) `services`."""
get_services(value::ThermalStandard) = value.services
"""Get [`ThermalStandard`](@ref) `time_at_status`."""
get_time_at_status(value::ThermalStandard) = value.time_at_status
"""Get [`ThermalStandard`](@ref) `dynamic_injector`."""
get_dynamic_injector(value::ThermalStandard) = value.dynamic_injector
"""Get [`ThermalStandard`](@ref) `ext`."""
get_ext(value::ThermalStandard) = value.ext
"""Get [`ThermalStandard`](@ref) `internal`."""
get_internal(value::ThermalStandard) = value.internal
"""Set [`ThermalStandard`](@ref) `available`."""
set_available!(value::ThermalStandard, val) = value.available = val
"""Set [`ThermalStandard`](@ref) `status`."""
set_status!(value::ThermalStandard, val) = value.status = val
"""Set [`ThermalStandard`](@ref) `bus`."""
set_bus!(value::ThermalStandard, val) = value.bus = val
"""Set [`ThermalStandard`](@ref) `active_power`."""
set_active_power!(value::ThermalStandard, val) = value.active_power = set_value(value, Val(:active_power), val, Val(:mva))
"""Set [`ThermalStandard`](@ref) `reactive_power`."""
set_reactive_power!(value::ThermalStandard, val) = value.reactive_power = set_value(value, Val(:reactive_power), val, Val(:mva))
"""Set [`ThermalStandard`](@ref) `rating`."""
set_rating!(value::ThermalStandard, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`ThermalStandard`](@ref) `active_power_limits`."""
set_active_power_limits!(value::ThermalStandard, val) = value.active_power_limits = set_value(value, Val(:active_power_limits), val, Val(:mva))
"""Set [`ThermalStandard`](@ref) `reactive_power_limits`."""
set_reactive_power_limits!(value::ThermalStandard, val) = value.reactive_power_limits = set_value(value, Val(:reactive_power_limits), val, Val(:mva))
"""Set [`ThermalStandard`](@ref) `ramp_limits`."""
set_ramp_limits!(value::ThermalStandard, val) = value.ramp_limits = set_value(value, Val(:ramp_limits), val, Val(:mva))
"""Set [`ThermalStandard`](@ref) `operation_cost`."""
set_operation_cost!(value::ThermalStandard, val) = value.operation_cost = val
"""Set [`ThermalStandard`](@ref) `base_power`."""
set_base_power!(value::ThermalStandard, val) = value.base_power = val
"""Set [`ThermalStandard`](@ref) `time_limits`."""
set_time_limits!(value::ThermalStandard, val) = value.time_limits = val
"""Set [`ThermalStandard`](@ref) `must_run`."""
set_must_run!(value::ThermalStandard, val) = value.must_run = val
"""Set [`ThermalStandard`](@ref) `prime_mover_type`."""
set_prime_mover_type!(value::ThermalStandard, val) = value.prime_mover_type = val
"""Set [`ThermalStandard`](@ref) `fuel`."""
set_fuel!(value::ThermalStandard, val) = value.fuel = val
"""Set [`ThermalStandard`](@ref) `services`."""
set_services!(value::ThermalStandard, val) = value.services = val
"""Set [`ThermalStandard`](@ref) `time_at_status`."""
set_time_at_status!(value::ThermalStandard, val) = value.time_at_status = val
"""Set [`ThermalStandard`](@ref) `ext`."""
set_ext!(value::ThermalStandard, val) = value.ext = val
================================================
FILE: src/models/generated/Transformer2W.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct Transformer2W <: TwoWindingTransformer
name::String
available::Bool
active_power_flow::Float64
reactive_power_flow::Float64
arc::Arc
r::Float64
x::Float64
primary_shunt::Complex{Float64}
rating::Union{Nothing, Float64}
base_power::Float64
base_voltage_primary::Union{Nothing, Float64}
base_voltage_secondary::Union{Nothing, Float64}
rating_b::Union{Nothing, Float64}
rating_c::Union{Nothing, Float64}
winding_group_number::WindingGroupNumber
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A basic 2-winding transformer.
The model uses an equivalent circuit assuming the impedance is on the High Voltage Side of the transformer. The model allocates the iron losses and magnetizing susceptance to the primary side
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow::Float64`: Initial condition of active power flow through the transformer (MW)
- `reactive_power_flow::Float64`: Initial condition of reactive power flow through the transformer (MVAR)
- `arc::Arc`: An [`Arc`](@ref) defining this transformer `from` a bus `to` another bus
- `r::Float64`: Resistance in pu ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(-2, 4)`
- `x::Float64`: Reactance in pu ([`SYSTEM_BASE`](@ref per_unit)), validation range: `(-2, 4)`
- `primary_shunt::Complex{Float64}`: Primary shunt admittance in pu ([`SYSTEM_BASE`](@ref per_unit))
- `rating::Union{Nothing, Float64}`: Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to, validation range: `(0, nothing)`
- `base_power::Float64`: Base power (MVA) for [per unitization](@ref per_unit), validation range: `(0.0001, nothing)`
- `base_voltage_primary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_from(arc))`) Primary base voltage in kV, validation range: `(0, nothing)`
- `base_voltage_secondary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_to(arc))`) Secondary base voltage in kV, validation range: `(0, nothing)`
- `rating_b::Union{Nothing, Float64}`: (default: `nothing`) Second current rating; entered in MVA.
- `rating_c::Union{Nothing, Float64}`: (default: `nothing`) Third current rating; entered in MVA.
- `winding_group_number::WindingGroupNumber`: (default: `WindingGroupNumber.UNDEFINED`) Vector group number ('clock number') indicating phase shift (radians) between the `from` and `to` buses
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct Transformer2W <: TwoWindingTransformer
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial condition of active power flow through the transformer (MW)"
active_power_flow::Float64
"Initial condition of reactive power flow through the transformer (MVAR)"
reactive_power_flow::Float64
"An [`Arc`](@ref) defining this transformer `from` a bus `to` another bus"
arc::Arc
"Resistance in pu ([`SYSTEM_BASE`](@ref per_unit))"
r::Float64
"Reactance in pu ([`SYSTEM_BASE`](@ref per_unit))"
x::Float64
"Primary shunt admittance in pu ([`SYSTEM_BASE`](@ref per_unit))"
primary_shunt::Complex{Float64}
"Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to"
rating::Union{Nothing, Float64}
"Base power (MVA) for [per unitization](@ref per_unit)"
base_power::Float64
"Primary base voltage in kV"
base_voltage_primary::Union{Nothing, Float64}
"Secondary base voltage in kV"
base_voltage_secondary::Union{Nothing, Float64}
"Second current rating; entered in MVA."
rating_b::Union{Nothing, Float64}
"Third current rating; entered in MVA."
rating_c::Union{Nothing, Float64}
"Vector group number ('clock number') indicating phase shift (radians) between the `from` and `to` buses"
winding_group_number::WindingGroupNumber
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function Transformer2W(name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, rating, base_power, base_voltage_primary=get_base_voltage(get_from(arc)), base_voltage_secondary=get_base_voltage(get_to(arc)), rating_b=nothing, rating_c=nothing, winding_group_number=WindingGroupNumber.UNDEFINED, services=Device[], ext=Dict{String, Any}(), )
Transformer2W(name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, rating, base_power, base_voltage_primary, base_voltage_secondary, rating_b, rating_c, winding_group_number, services, ext, InfrastructureSystemsInternal(), )
end
function Transformer2W(; name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, rating, base_power, base_voltage_primary=get_base_voltage(get_from(arc)), base_voltage_secondary=get_base_voltage(get_to(arc)), rating_b=nothing, rating_c=nothing, winding_group_number=WindingGroupNumber.UNDEFINED, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
Transformer2W(name, available, active_power_flow, reactive_power_flow, arc, r, x, primary_shunt, rating, base_power, base_voltage_primary, base_voltage_secondary, rating_b, rating_c, winding_group_number, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function Transformer2W(::Nothing)
Transformer2W(;
name="init",
available=false,
active_power_flow=0.0,
reactive_power_flow=0.0,
arc=Arc(ACBus(nothing), ACBus(nothing)),
r=0.0,
x=0.0,
primary_shunt=0.0,
rating=nothing,
base_power=100.0,
base_voltage_primary=nothing,
base_voltage_secondary=nothing,
rating_b=0.0,
rating_c=0.0,
winding_group_number=WindingGroupNumber.UNDEFINED,
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`Transformer2W`](@ref) `name`."""
get_name(value::Transformer2W) = value.name
"""Get [`Transformer2W`](@ref) `available`."""
get_available(value::Transformer2W) = value.available
"""Get [`Transformer2W`](@ref) `active_power_flow`."""
get_active_power_flow(value::Transformer2W) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`Transformer2W`](@ref) `reactive_power_flow`."""
get_reactive_power_flow(value::Transformer2W) = get_value(value, Val(:reactive_power_flow), Val(:mva))
"""Get [`Transformer2W`](@ref) `arc`."""
get_arc(value::Transformer2W) = value.arc
"""Get [`Transformer2W`](@ref) `r`."""
get_r(value::Transformer2W) = get_value(value, Val(:r), Val(:ohm))
"""Get [`Transformer2W`](@ref) `x`."""
get_x(value::Transformer2W) = get_value(value, Val(:x), Val(:ohm))
"""Get [`Transformer2W`](@ref) `primary_shunt`."""
get_primary_shunt(value::Transformer2W) = get_value(value, Val(:primary_shunt), Val(:siemens))
"""Get [`Transformer2W`](@ref) `rating`."""
get_rating(value::Transformer2W) = get_value(value, Val(:rating), Val(:mva))
"""Get [`Transformer2W`](@ref) `base_power`."""
get_base_power(value::Transformer2W) = value.base_power
"""Get [`Transformer2W`](@ref) `base_voltage_primary`."""
get_base_voltage_primary(value::Transformer2W) = value.base_voltage_primary
"""Get [`Transformer2W`](@ref) `base_voltage_secondary`."""
get_base_voltage_secondary(value::Transformer2W) = value.base_voltage_secondary
"""Get [`Transformer2W`](@ref) `rating_b`."""
get_rating_b(value::Transformer2W) = get_value(value, Val(:rating_b), Val(:mva))
"""Get [`Transformer2W`](@ref) `rating_c`."""
get_rating_c(value::Transformer2W) = get_value(value, Val(:rating_c), Val(:mva))
"""Get [`Transformer2W`](@ref) `winding_group_number`."""
get_winding_group_number(value::Transformer2W) = value.winding_group_number
"""Get [`Transformer2W`](@ref) `services`."""
get_services(value::Transformer2W) = value.services
"""Get [`Transformer2W`](@ref) `ext`."""
get_ext(value::Transformer2W) = value.ext
"""Get [`Transformer2W`](@ref) `internal`."""
get_internal(value::Transformer2W) = value.internal
"""Set [`Transformer2W`](@ref) `available`."""
set_available!(value::Transformer2W, val) = value.available = val
"""Set [`Transformer2W`](@ref) `active_power_flow`."""
set_active_power_flow!(value::Transformer2W, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`Transformer2W`](@ref) `reactive_power_flow`."""
set_reactive_power_flow!(value::Transformer2W, val) = value.reactive_power_flow = set_value(value, Val(:reactive_power_flow), val, Val(:mva))
"""Set [`Transformer2W`](@ref) `arc`."""
set_arc!(value::Transformer2W, val) = value.arc = val
"""Set [`Transformer2W`](@ref) `r`."""
set_r!(value::Transformer2W, val) = value.r = set_value(value, Val(:r), val, Val(:ohm))
"""Set [`Transformer2W`](@ref) `x`."""
set_x!(value::Transformer2W, val) = value.x = set_value(value, Val(:x), val, Val(:ohm))
"""Set [`Transformer2W`](@ref) `primary_shunt`."""
set_primary_shunt!(value::Transformer2W, val) = value.primary_shunt = set_value(value, Val(:primary_shunt), val, Val(:siemens))
"""Set [`Transformer2W`](@ref) `rating`."""
set_rating!(value::Transformer2W, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`Transformer2W`](@ref) `base_power`."""
set_base_power!(value::Transformer2W, val) = value.base_power = val
"""Set [`Transformer2W`](@ref) `base_voltage_primary`."""
set_base_voltage_primary!(value::Transformer2W, val) = value.base_voltage_primary = val
"""Set [`Transformer2W`](@ref) `base_voltage_secondary`."""
set_base_voltage_secondary!(value::Transformer2W, val) = value.base_voltage_secondary = val
"""Set [`Transformer2W`](@ref) `rating_b`."""
set_rating_b!(value::Transformer2W, val) = value.rating_b = set_value(value, Val(:rating_b), val, Val(:mva))
"""Set [`Transformer2W`](@ref) `rating_c`."""
set_rating_c!(value::Transformer2W, val) = value.rating_c = set_value(value, Val(:rating_c), val, Val(:mva))
"""Set [`Transformer2W`](@ref) `winding_group_number`."""
set_winding_group_number!(value::Transformer2W, val) = value.winding_group_number = val
"""Set [`Transformer2W`](@ref) `services`."""
set_services!(value::Transformer2W, val) = value.services = val
"""Set [`Transformer2W`](@ref) `ext`."""
set_ext!(value::Transformer2W, val) = value.ext = val
================================================
FILE: src/models/generated/Transformer3W.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct Transformer3W <: ThreeWindingTransformer
name::String
available::Bool
primary_star_arc::Arc
secondary_star_arc::Arc
tertiary_star_arc::Arc
star_bus::ACBus
active_power_flow_primary::Float64
reactive_power_flow_primary::Float64
active_power_flow_secondary::Float64
reactive_power_flow_secondary::Float64
active_power_flow_tertiary::Float64
reactive_power_flow_tertiary::Float64
r_primary::Float64
x_primary::Float64
r_secondary::Float64
x_secondary::Float64
r_tertiary::Float64
x_tertiary::Float64
rating::Union{Nothing, Float64}
r_12::Float64
x_12::Float64
r_23::Float64
x_23::Float64
r_13::Float64
x_13::Float64
base_power_12::Float64
base_power_23::Float64
base_power_13::Float64
base_voltage_primary::Union{Nothing, Float64}
base_voltage_secondary::Union{Nothing, Float64}
base_voltage_tertiary::Union{Nothing, Float64}
g::Float64
b::Float64
primary_turns_ratio::Float64
secondary_turns_ratio::Float64
tertiary_turns_ratio::Float64
available_primary::Bool
available_secondary::Bool
available_tertiary::Bool
rating_primary::Float64
rating_secondary::Float64
rating_tertiary::Float64
primary_group_number::WindingGroupNumber
secondary_group_number::WindingGroupNumber
tertiary_group_number::WindingGroupNumber
control_objective_primary::TransformerControlObjective
control_objective_secondary::TransformerControlObjective
control_objective_tertiary::TransformerControlObjective
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A 3-winding transformer.
The model uses an equivalent star model with a star (hidden) bus. The user must transform the data to use `CW = CZ = CM = 1` and `COD1 = COD2 = COD3 = 0` (no voltage control) if taken from a PSS/E 3W transformer model. Three equivalent impedances (connecting each side to the star bus) are required to define the model. Shunt conductance (iron losses) and magnetizing susceptance can be considered from the star bus to ground. The model is described in Chapter 3.6 in J.D. Glover, M.S. Sarma and T. Overbye: Power Systems Analysis and Design.
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `primary_star_arc::Arc`: An [`Arc`](@ref) defining this transformer `from` a primary bus `to` the star bus
- `secondary_star_arc::Arc`: An [`Arc`](@ref) defining this transformer `from` a secondary bus `to` the star bus
- `tertiary_star_arc::Arc`: An [`Arc`](@ref) defining this transformer `from` a tertiary bus `to` the star bus
- `star_bus::ACBus`: Star (hidden) Bus that this component (equivalent model) is connected to
- `active_power_flow_primary::Float64`: Initial condition of active power flow through the transformer primary side to star (hidden) bus (MW)
- `reactive_power_flow_primary::Float64`: Initial condition of reactive power flow through the transformer primary side to star (hidden) bus (MW)
- `active_power_flow_secondary::Float64`: Initial condition of active power flow through the transformer secondary side to star (hidden) bus (MW)
- `reactive_power_flow_secondary::Float64`: Initial condition of reactive power flow through the transformer secondary side to star (hidden) bus (MW)
- `active_power_flow_tertiary::Float64`: Initial condition of active power flow through the transformer tertiary side to star (hidden) bus (MW)
- `reactive_power_flow_tertiary::Float64`: Initial condition of reactive power flow through the transformer tertiary side to star (hidden) bus (MW)
- `r_primary::Float64`: Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus., validation range: `(-2, 4)`
- `x_primary::Float64`: Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus., validation range: `(-2, 4)`
- `r_secondary::Float64`: Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus., validation range: `(-2, 4)`
- `x_secondary::Float64`: Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus., validation range: `(-2, 4)`
- `r_tertiary::Float64`: Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus., validation range: `(-2, 4)`
- `x_tertiary::Float64`: Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus., validation range: `(-2, 4)`
- `rating::Union{Nothing, Float64}`: Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to, validation range: `(0, nothing)`
- `r_12::Float64`: Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (R1-2 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `x_12::Float64`: Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (X1-2 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `r_23::Float64`: Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (R2-3 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `x_23::Float64`: Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (X2-3 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `r_13::Float64`: Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (R1-3 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `x_13::Float64`: Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (X1-3 with CZ = 1 in PSS/E)., validation range: `(0, 4)`
- `base_power_12::Float64`: Base power (MVA) for [per unitization](@ref per_unit) for primary-secondary windings., validation range: `(0, nothing)`
- `base_power_23::Float64`: Base power (MVA) for [per unitization](@ref per_unit) for secondary-tertiary windings., validation range: `(0, nothing)`
- `base_power_13::Float64`: Base power (MVA) for [per unitization](@ref per_unit) for primary-tertiary windings., validation range: `(0, nothing)`
- `base_voltage_primary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_from(primary_star_arc))`) Primary base voltage in kV, validation range: `(0, nothing)`
- `base_voltage_secondary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_from(secondary_star_arc))`) Secondary base voltage in kV, validation range: `(0, nothing)`
- `base_voltage_tertiary::Union{Nothing, Float64}`: (default: `get_base_voltage(get_from(tertiary_star_arc))`) Tertiary base voltage in kV, validation range: `(0, nothing)`
- `g::Float64`: (default: `0.0`) Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG1 in PSS/E).
- `b::Float64`: (default: `0.0`) Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG2 in PSS/E).
- `primary_turns_ratio::Float64`: (default: `1.0`) Primary side off-nominal turns ratio in p.u. with respect to connected primary bus (WINDV1 with CW = 1 in PSS/E).
- `secondary_turns_ratio::Float64`: (default: `1.0`) Secondary side off-nominal turns ratio in p.u. with respect to connected secondary bus (WINDV2 with CW = 1 in PSS/E).
- `tertiary_turns_ratio::Float64`: (default: `1.0`) Tertiary side off-nominal turns ratio in p.u. with respect to connected tertiary bus (WINDV3 with CW = 1 in PSS/E).
- `available_primary::Bool`: (default: `true`) Status if primary winding is available or not.
- `available_secondary::Bool`: (default: `true`) Status if primary winding is available or not.
- `available_tertiary::Bool`: (default: `true`) Status if primary winding is available or not.
- `rating_primary::Float64`: (default: `0.0`) Rating (in MVA) for primary winding.
- `rating_secondary::Float64`: (default: `0.0`) Rating (in MVA) for secondary winding.
- `rating_tertiary::Float64`: (default: `0.0`) Rating (in MVA) for tertiary winding.
- `primary_group_number::WindingGroupNumber`: (default: `WindingGroupNumber.UNDEFINED`) Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration
- `secondary_group_number::WindingGroupNumber`: (default: `WindingGroupNumber.UNDEFINED`) Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration
- `tertiary_group_number::WindingGroupNumber`: (default: `WindingGroupNumber.UNDEFINED`) Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration
- `control_objective_primary::TransformerControlObjective`: (default: `TransformerControlObjective.UNDEFINED`) Control objective for the tap changer for winding 1. See [`TransformerControlObjective`](@ref xtf_crtl)
- `control_objective_secondary::TransformerControlObjective`: (default: `TransformerControlObjective.UNDEFINED`) Control objective for the tap changer for winding 2. See [`TransformerControlObjective`](@ref xtf_crtl)
- `control_objective_tertiary::TransformerControlObjective`: (default: `TransformerControlObjective.UNDEFINED`) Control objective for the tap changer for winding 3. See [`TransformerControlObjective`](@ref xtf_crtl)
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct Transformer3W <: ThreeWindingTransformer
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"An [`Arc`](@ref) defining this transformer `from` a primary bus `to` the star bus"
primary_star_arc::Arc
"An [`Arc`](@ref) defining this transformer `from` a secondary bus `to` the star bus"
secondary_star_arc::Arc
"An [`Arc`](@ref) defining this transformer `from` a tertiary bus `to` the star bus"
tertiary_star_arc::Arc
"Star (hidden) Bus that this component (equivalent model) is connected to"
star_bus::ACBus
"Initial condition of active power flow through the transformer primary side to star (hidden) bus (MW)"
active_power_flow_primary::Float64
"Initial condition of reactive power flow through the transformer primary side to star (hidden) bus (MW)"
reactive_power_flow_primary::Float64
"Initial condition of active power flow through the transformer secondary side to star (hidden) bus (MW)"
active_power_flow_secondary::Float64
"Initial condition of reactive power flow through the transformer secondary side to star (hidden) bus (MW)"
reactive_power_flow_secondary::Float64
"Initial condition of active power flow through the transformer tertiary side to star (hidden) bus (MW)"
active_power_flow_tertiary::Float64
"Initial condition of reactive power flow through the transformer tertiary side to star (hidden) bus (MW)"
reactive_power_flow_tertiary::Float64
"Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus."
r_primary::Float64
"Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to star (hidden) bus."
x_primary::Float64
"Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus."
r_secondary::Float64
"Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to star (hidden) bus."
x_secondary::Float64
"Equivalent resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus."
r_tertiary::Float64
"Equivalent reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from tertiary to star (hidden) bus."
x_tertiary::Float64
"Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a transformer before it is attached to a `System`, `rating` must be in pu ([`SYSTEM_BASE`](@ref per_unit)) using the base power of the `System` it will be attached to"
rating::Union{Nothing, Float64}
"Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (R1-2 with CZ = 1 in PSS/E)."
r_12::Float64
"Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to secondary windings (X1-2 with CZ = 1 in PSS/E)."
x_12::Float64
"Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (R2-3 with CZ = 1 in PSS/E)."
r_23::Float64
"Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from secondary to tertiary windings (X2-3 with CZ = 1 in PSS/E)."
x_23::Float64
"Measured resistance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (R1-3 with CZ = 1 in PSS/E)."
r_13::Float64
"Measured reactance in pu ([`SYSTEM_BASE`](@ref per_unit)) from primary to tertiary windings (X1-3 with CZ = 1 in PSS/E)."
x_13::Float64
"Base power (MVA) for [per unitization](@ref per_unit) for primary-secondary windings."
base_power_12::Float64
"Base power (MVA) for [per unitization](@ref per_unit) for secondary-tertiary windings."
base_power_23::Float64
"Base power (MVA) for [per unitization](@ref per_unit) for primary-tertiary windings."
base_power_13::Float64
"Primary base voltage in kV"
base_voltage_primary::Union{Nothing, Float64}
"Secondary base voltage in kV"
base_voltage_secondary::Union{Nothing, Float64}
"Tertiary base voltage in kV"
base_voltage_tertiary::Union{Nothing, Float64}
"Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG1 in PSS/E)."
g::Float64
"Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)) from star (hidden) bus to ground (MAG2 in PSS/E)."
b::Float64
"Primary side off-nominal turns ratio in p.u. with respect to connected primary bus (WINDV1 with CW = 1 in PSS/E)."
primary_turns_ratio::Float64
"Secondary side off-nominal turns ratio in p.u. with respect to connected secondary bus (WINDV2 with CW = 1 in PSS/E)."
secondary_turns_ratio::Float64
"Tertiary side off-nominal turns ratio in p.u. with respect to connected tertiary bus (WINDV3 with CW = 1 in PSS/E)."
tertiary_turns_ratio::Float64
"Status if primary winding is available or not."
available_primary::Bool
"Status if primary winding is available or not."
available_secondary::Bool
"Status if primary winding is available or not."
available_tertiary::Bool
"Rating (in MVA) for primary winding."
rating_primary::Float64
"Rating (in MVA) for secondary winding."
rating_secondary::Float64
"Rating (in MVA) for tertiary winding."
rating_tertiary::Float64
"Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration"
primary_group_number::WindingGroupNumber
"Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration"
secondary_group_number::WindingGroupNumber
"Vector group number ('clock number') indicating fixed phase shift (radians) between the `from` and `to` buses due to the connection group configuration"
tertiary_group_number::WindingGroupNumber
"Control objective for the tap changer for winding 1. See [`TransformerControlObjective`](@ref xtf_crtl)"
control_objective_primary::TransformerControlObjective
"Control objective for the tap changer for winding 2. See [`TransformerControlObjective`](@ref xtf_crtl)"
control_objective_secondary::TransformerControlObjective
"Control objective for the tap changer for winding 3. See [`TransformerControlObjective`](@ref xtf_crtl)"
control_objective_tertiary::TransformerControlObjective
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function Transformer3W(name, available, primary_star_arc, secondary_star_arc, tertiary_star_arc, star_bus, active_power_flow_primary, reactive_power_flow_primary, active_power_flow_secondary, reactive_power_flow_secondary, active_power_flow_tertiary, reactive_power_flow_tertiary, r_primary, x_primary, r_secondary, x_secondary, r_tertiary, x_tertiary, rating, r_12, x_12, r_23, x_23, r_13, x_13, base_power_12, base_power_23, base_power_13, base_voltage_primary=get_base_voltage(get_from(primary_star_arc)), base_voltage_secondary=get_base_voltage(get_from(secondary_star_arc)), base_voltage_tertiary=get_base_voltage(get_from(tertiary_star_arc)), g=0.0, b=0.0, primary_turns_ratio=1.0, secondary_turns_ratio=1.0, tertiary_turns_ratio=1.0, available_primary=true, available_secondary=true, available_tertiary=true, rating_primary=0.0, rating_secondary=0.0, rating_tertiary=0.0, primary_group_number=WindingGroupNumber.UNDEFINED, secondary_group_number=WindingGroupNumber.UNDEFINED, tertiary_group_number=WindingGroupNumber.UNDEFINED, control_objective_primary=TransformerControlObjective.UNDEFINED, control_objective_secondary=TransformerControlObjective.UNDEFINED, control_objective_tertiary=TransformerControlObjective.UNDEFINED, services=Device[], ext=Dict{String, Any}(), )
Transformer3W(name, available, primary_star_arc, secondary_star_arc, tertiary_star_arc, star_bus, active_power_flow_primary, reactive_power_flow_primary, active_power_flow_secondary, reactive_power_flow_secondary, active_power_flow_tertiary, reactive_power_flow_tertiary, r_primary, x_primary, r_secondary, x_secondary, r_tertiary, x_tertiary, rating, r_12, x_12, r_23, x_23, r_13, x_13, base_power_12, base_power_23, base_power_13, base_voltage_primary, base_voltage_secondary, base_voltage_tertiary, g, b, primary_turns_ratio, secondary_turns_ratio, tertiary_turns_ratio, available_primary, available_secondary, available_tertiary, rating_primary, rating_secondary, rating_tertiary, primary_group_number, secondary_group_number, tertiary_group_number, control_objective_primary, control_objective_secondary, control_objective_tertiary, services, ext, InfrastructureSystemsInternal(), )
end
function Transformer3W(; name, available, primary_star_arc, secondary_star_arc, tertiary_star_arc, star_bus, active_power_flow_primary, reactive_power_flow_primary, active_power_flow_secondary, reactive_power_flow_secondary, active_power_flow_tertiary, reactive_power_flow_tertiary, r_primary, x_primary, r_secondary, x_secondary, r_tertiary, x_tertiary, rating, r_12, x_12, r_23, x_23, r_13, x_13, base_power_12, base_power_23, base_power_13, base_voltage_primary=get_base_voltage(get_from(primary_star_arc)), base_voltage_secondary=get_base_voltage(get_from(secondary_star_arc)), base_voltage_tertiary=get_base_voltage(get_from(tertiary_star_arc)), g=0.0, b=0.0, primary_turns_ratio=1.0, secondary_turns_ratio=1.0, tertiary_turns_ratio=1.0, available_primary=true, available_secondary=true, available_tertiary=true, rating_primary=0.0, rating_secondary=0.0, rating_tertiary=0.0, primary_group_number=WindingGroupNumber.UNDEFINED, secondary_group_number=WindingGroupNumber.UNDEFINED, tertiary_group_number=WindingGroupNumber.UNDEFINED, control_objective_primary=TransformerControlObjective.UNDEFINED, control_objective_secondary=TransformerControlObjective.UNDEFINED, control_objective_tertiary=TransformerControlObjective.UNDEFINED, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
Transformer3W(name, available, primary_star_arc, secondary_star_arc, tertiary_star_arc, star_bus, active_power_flow_primary, reactive_power_flow_primary, active_power_flow_secondary, reactive_power_flow_secondary, active_power_flow_tertiary, reactive_power_flow_tertiary, r_primary, x_primary, r_secondary, x_secondary, r_tertiary, x_tertiary, rating, r_12, x_12, r_23, x_23, r_13, x_13, base_power_12, base_power_23, base_power_13, base_voltage_primary, base_voltage_secondary, base_voltage_tertiary, g, b, primary_turns_ratio, secondary_turns_ratio, tertiary_turns_ratio, available_primary, available_secondary, available_tertiary, rating_primary, rating_secondary, rating_tertiary, primary_group_number, secondary_group_number, tertiary_group_number, control_objective_primary, control_objective_secondary, control_objective_tertiary, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function Transformer3W(::Nothing)
Transformer3W(;
name="init",
available=false,
primary_star_arc=Arc(ACBus(nothing), ACBus(nothing)),
secondary_star_arc=Arc(ACBus(nothing), ACBus(nothing)),
tertiary_star_arc=Arc(ACBus(nothing), ACBus(nothing)),
star_bus=ACBus(nothing),
active_power_flow_primary=0.0,
reactive_power_flow_primary=0.0,
active_power_flow_secondary=0.0,
reactive_power_flow_secondary=0.0,
active_power_flow_tertiary=0.0,
reactive_power_flow_tertiary=0.0,
r_primary=0.0,
x_primary=0.0,
r_secondary=0.0,
x_secondary=0.0,
r_tertiary=0.0,
x_tertiary=0.0,
rating=nothing,
r_12=0.0,
x_12=0.0,
r_23=0.0,
x_23=0.0,
r_13=0.0,
x_13=0.0,
base_power_12=0.0,
base_power_23=0.0,
base_power_13=0.0,
base_voltage_primary=nothing,
base_voltage_secondary=nothing,
base_voltage_tertiary=nothing,
g=0.0,
b=0.0,
primary_turns_ratio=0.0,
secondary_turns_ratio=0.0,
tertiary_turns_ratio=0.0,
available_primary=false,
available_secondary=false,
available_tertiary=false,
rating_primary=0.0,
rating_secondary=0.0,
rating_tertiary=0.0,
primary_group_number=WindingGroupNumber.UNDEFINED,
secondary_group_number=WindingGroupNumber.UNDEFINED,
tertiary_group_number=WindingGroupNumber.UNDEFINED,
control_objective_primary=TransformerControlObjective.UNDEFINED,
control_objective_secondary=TransformerControlObjective.UNDEFINED,
control_objective_tertiary=TransformerControlObjective.UNDEFINED,
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`Transformer3W`](@ref) `name`."""
get_name(value::Transformer3W) = value.name
"""Get [`Transformer3W`](@ref) `available`."""
get_available(value::Transformer3W) = value.available
"""Get [`Transformer3W`](@ref) `primary_star_arc`."""
get_primary_star_arc(value::Transformer3W) = value.primary_star_arc
"""Get [`Transformer3W`](@ref) `secondary_star_arc`."""
get_secondary_star_arc(value::Transformer3W) = value.secondary_star_arc
"""Get [`Transformer3W`](@ref) `tertiary_star_arc`."""
get_tertiary_star_arc(value::Transformer3W) = value.tertiary_star_arc
"""Get [`Transformer3W`](@ref) `star_bus`."""
get_star_bus(value::Transformer3W) = value.star_bus
"""Get [`Transformer3W`](@ref) `active_power_flow_primary`."""
get_active_power_flow_primary(value::Transformer3W) = get_value(value, Val(:active_power_flow_primary), Val(:mva))
"""Get [`Transformer3W`](@ref) `reactive_power_flow_primary`."""
get_reactive_power_flow_primary(value::Transformer3W) = get_value(value, Val(:reactive_power_flow_primary), Val(:mva))
"""Get [`Transformer3W`](@ref) `active_power_flow_secondary`."""
get_active_power_flow_secondary(value::Transformer3W) = get_value(value, Val(:active_power_flow_secondary), Val(:mva))
"""Get [`Transformer3W`](@ref) `reactive_power_flow_secondary`."""
get_reactive_power_flow_secondary(value::Transformer3W) = get_value(value, Val(:reactive_power_flow_secondary), Val(:mva))
"""Get [`Transformer3W`](@ref) `active_power_flow_tertiary`."""
get_active_power_flow_tertiary(value::Transformer3W) = get_value(value, Val(:active_power_flow_tertiary), Val(:mva))
"""Get [`Transformer3W`](@ref) `reactive_power_flow_tertiary`."""
get_reactive_power_flow_tertiary(value::Transformer3W) = get_value(value, Val(:reactive_power_flow_tertiary), Val(:mva))
"""Get [`Transformer3W`](@ref) `r_primary`."""
get_r_primary(value::Transformer3W) = get_value(value, Val(:r_primary), Val(:ohm))
"""Get [`Transformer3W`](@ref) `x_primary`."""
get_x_primary(value::Transformer3W) = get_value(value, Val(:x_primary), Val(:ohm))
"""Get [`Transformer3W`](@ref) `r_secondary`."""
get_r_secondary(value::Transformer3W) = get_value(value, Val(:r_secondary), Val(:ohm))
"""Get [`Transformer3W`](@ref) `x_secondary`."""
get_x_secondary(value::Transformer3W) = get_value(value, Val(:x_secondary), Val(:ohm))
"""Get [`Transformer3W`](@ref) `r_tertiary`."""
get_r_tertiary(value::Transformer3W) = get_value(value, Val(:r_tertiary), Val(:ohm))
"""Get [`Transformer3W`](@ref) `x_tertiary`."""
get_x_tertiary(value::Transformer3W) = get_value(value, Val(:x_tertiary), Val(:ohm))
"""Get [`Transformer3W`](@ref) `rating`."""
get_rating(value::Transformer3W) = get_value(value, Val(:rating), Val(:mva))
"""Get [`Transformer3W`](@ref) `r_12`."""
get_r_12(value::Transformer3W) = get_value(value, Val(:r_12), Val(:ohm))
"""Get [`Transformer3W`](@ref) `x_12`."""
get_x_12(value::Transformer3W) = get_value(value, Val(:x_12), Val(:ohm))
"""Get [`Transformer3W`](@ref) `r_23`."""
get_r_23(value::Transformer3W) = get_value(value, Val(:r_23), Val(:ohm))
"""Get [`Transformer3W`](@ref) `x_23`."""
get_x_23(value::Transformer3W) = get_value(value, Val(:x_23), Val(:ohm))
"""Get [`Transformer3W`](@ref) `r_13`."""
get_r_13(value::Transformer3W) = get_value(value, Val(:r_13), Val(:ohm))
"""Get [`Transformer3W`](@ref) `x_13`."""
get_x_13(value::Transformer3W) = get_value(value, Val(:x_13), Val(:ohm))
"""Get [`Transformer3W`](@ref) `base_power_12`."""
get_base_power_12(value::Transformer3W) = value.base_power_12
"""Get [`Transformer3W`](@ref) `base_power_23`."""
get_base_power_23(value::Transformer3W) = value.base_power_23
"""Get [`Transformer3W`](@ref) `base_power_13`."""
get_base_power_13(value::Transformer3W) = value.base_power_13
"""Get [`Transformer3W`](@ref) `base_voltage_primary`."""
get_base_voltage_primary(value::Transformer3W) = value.base_voltage_primary
"""Get [`Transformer3W`](@ref) `base_voltage_secondary`."""
get_base_voltage_secondary(value::Transformer3W) = value.base_voltage_secondary
"""Get [`Transformer3W`](@ref) `base_voltage_tertiary`."""
get_base_voltage_tertiary(value::Transformer3W) = value.base_voltage_tertiary
"""Get [`Transformer3W`](@ref) `g`."""
get_g(value::Transformer3W) = get_value(value, Val(:g), Val(:siemens))
"""Get [`Transformer3W`](@ref) `b`."""
get_b(value::Transformer3W) = get_value(value, Val(:b), Val(:siemens))
"""Get [`Transformer3W`](@ref) `primary_turns_ratio`."""
get_primary_turns_ratio(value::Transformer3W) = value.primary_turns_ratio
"""Get [`Transformer3W`](@ref) `secondary_turns_ratio`."""
get_secondary_turns_ratio(value::Transformer3W) = value.secondary_turns_ratio
"""Get [`Transformer3W`](@ref) `tertiary_turns_ratio`."""
get_tertiary_turns_ratio(value::Transformer3W) = value.tertiary_turns_ratio
"""Get [`Transformer3W`](@ref) `available_primary`."""
get_available_primary(value::Transformer3W) = value.available_primary
"""Get [`Transformer3W`](@ref) `available_secondary`."""
get_available_secondary(value::Transformer3W) = value.available_secondary
"""Get [`Transformer3W`](@ref) `available_tertiary`."""
get_available_tertiary(value::Transformer3W) = value.available_tertiary
"""Get [`Transformer3W`](@ref) `rating_primary`."""
get_rating_primary(value::Transformer3W) = get_value(value, Val(:rating_primary), Val(:mva))
"""Get [`Transformer3W`](@ref) `rating_secondary`."""
get_rating_secondary(value::Transformer3W) = get_value(value, Val(:rating_secondary), Val(:mva))
"""Get [`Transformer3W`](@ref) `rating_tertiary`."""
get_rating_tertiary(value::Transformer3W) = get_value(value, Val(:rating_tertiary), Val(:mva))
"""Get [`Transformer3W`](@ref) `primary_group_number`."""
get_primary_group_number(value::Transformer3W) = value.primary_group_number
"""Get [`Transformer3W`](@ref) `secondary_group_number`."""
get_secondary_group_number(value::Transformer3W) = value.secondary_group_number
"""Get [`Transformer3W`](@ref) `tertiary_group_number`."""
get_tertiary_group_number(value::Transformer3W) = value.tertiary_group_number
"""Get [`Transformer3W`](@ref) `control_objective_primary`."""
get_control_objective_primary(value::Transformer3W) = value.control_objective_primary
"""Get [`Transformer3W`](@ref) `control_objective_secondary`."""
get_control_objective_secondary(value::Transformer3W) = value.control_objective_secondary
"""Get [`Transformer3W`](@ref) `control_objective_tertiary`."""
get_control_objective_tertiary(value::Transformer3W) = value.control_objective_tertiary
"""Get [`Transformer3W`](@ref) `services`."""
get_services(value::Transformer3W) = value.services
"""Get [`Transformer3W`](@ref) `ext`."""
get_ext(value::Transformer3W) = value.ext
"""Get [`Transformer3W`](@ref) `internal`."""
get_internal(value::Transformer3W) = value.internal
"""Set [`Transformer3W`](@ref) `available`."""
set_available!(value::Transformer3W, val) = value.available = val
"""Set [`Transformer3W`](@ref) `primary_star_arc`."""
set_primary_star_arc!(value::Transformer3W, val) = value.primary_star_arc = val
"""Set [`Transformer3W`](@ref) `secondary_star_arc`."""
set_secondary_star_arc!(value::Transformer3W, val) = value.secondary_star_arc = val
"""Set [`Transformer3W`](@ref) `tertiary_star_arc`."""
set_tertiary_star_arc!(value::Transformer3W, val) = value.tertiary_star_arc = val
"""Set [`Transformer3W`](@ref) `star_bus`."""
set_star_bus!(value::Transformer3W, val) = value.star_bus = val
"""Set [`Transformer3W`](@ref) `active_power_flow_primary`."""
set_active_power_flow_primary!(value::Transformer3W, val) = value.active_power_flow_primary = set_value(value, Val(:active_power_flow_primary), val, Val(:mva))
"""Set [`Transformer3W`](@ref) `reactive_power_flow_primary`."""
set_reactive_power_flow_primary!(value::Transformer3W, val) = value.reactive_power_flow_primary = set_value(value, Val(:reactive_power_flow_primary), val, Val(:mva))
"""Set [`Transformer3W`](@ref) `active_power_flow_secondary`."""
set_active_power_flow_secondary!(value::Transformer3W, val) = value.active_power_flow_secondary = set_value(value, Val(:active_power_flow_secondary), val, Val(:mva))
"""Set [`Transformer3W`](@ref) `reactive_power_flow_secondary`."""
set_reactive_power_flow_secondary!(value::Transformer3W, val) = value.reactive_power_flow_secondary = set_value(value, Val(:reactive_power_flow_secondary), val, Val(:mva))
"""Set [`Transformer3W`](@ref) `active_power_flow_tertiary`."""
set_active_power_flow_tertiary!(value::Transformer3W, val) = value.active_power_flow_tertiary = set_value(value, Val(:active_power_flow_tertiary), val, Val(:mva))
"""Set [`Transformer3W`](@ref) `reactive_power_flow_tertiary`."""
set_reactive_power_flow_tertiary!(value::Transformer3W, val) = value.reactive_power_flow_tertiary = set_value(value, Val(:reactive_power_flow_tertiary), val, Val(:mva))
"""Set [`Transformer3W`](@ref) `r_primary`."""
set_r_primary!(value::Transformer3W, val) = value.r_primary = set_value(value, Val(:r_primary), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `x_primary`."""
set_x_primary!(value::Transformer3W, val) = value.x_primary = set_value(value, Val(:x_primary), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `r_secondary`."""
set_r_secondary!(value::Transformer3W, val) = value.r_secondary = set_value(value, Val(:r_secondary), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `x_secondary`."""
set_x_secondary!(value::Transformer3W, val) = value.x_secondary = set_value(value, Val(:x_secondary), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `r_tertiary`."""
set_r_tertiary!(value::Transformer3W, val) = value.r_tertiary = set_value(value, Val(:r_tertiary), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `x_tertiary`."""
set_x_tertiary!(value::Transformer3W, val) = value.x_tertiary = set_value(value, Val(:x_tertiary), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `rating`."""
set_rating!(value::Transformer3W, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`Transformer3W`](@ref) `r_12`."""
set_r_12!(value::Transformer3W, val) = value.r_12 = set_value(value, Val(:r_12), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `x_12`."""
set_x_12!(value::Transformer3W, val) = value.x_12 = set_value(value, Val(:x_12), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `r_23`."""
set_r_23!(value::Transformer3W, val) = value.r_23 = set_value(value, Val(:r_23), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `x_23`."""
set_x_23!(value::Transformer3W, val) = value.x_23 = set_value(value, Val(:x_23), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `r_13`."""
set_r_13!(value::Transformer3W, val) = value.r_13 = set_value(value, Val(:r_13), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `x_13`."""
set_x_13!(value::Transformer3W, val) = value.x_13 = set_value(value, Val(:x_13), val, Val(:ohm))
"""Set [`Transformer3W`](@ref) `base_power_12`."""
set_base_power_12!(value::Transformer3W, val) = value.base_power_12 = val
"""Set [`Transformer3W`](@ref) `base_power_23`."""
set_base_power_23!(value::Transformer3W, val) = value.base_power_23 = val
"""Set [`Transformer3W`](@ref) `base_power_13`."""
set_base_power_13!(value::Transformer3W, val) = value.base_power_13 = val
"""Set [`Transformer3W`](@ref) `base_voltage_primary`."""
set_base_voltage_primary!(value::Transformer3W, val) = value.base_voltage_primary = val
"""Set [`Transformer3W`](@ref) `base_voltage_secondary`."""
set_base_voltage_secondary!(value::Transformer3W, val) = value.base_voltage_secondary = val
"""Set [`Transformer3W`](@ref) `base_voltage_tertiary`."""
set_base_voltage_tertiary!(value::Transformer3W, val) = value.base_voltage_tertiary = val
"""Set [`Transformer3W`](@ref) `g`."""
set_g!(value::Transformer3W, val) = value.g = set_value(value, Val(:g), val, Val(:siemens))
"""Set [`Transformer3W`](@ref) `b`."""
set_b!(value::Transformer3W, val) = value.b = set_value(value, Val(:b), val, Val(:siemens))
"""Set [`Transformer3W`](@ref) `primary_turns_ratio`."""
set_primary_turns_ratio!(value::Transformer3W, val) = value.primary_turns_ratio = val
"""Set [`Transformer3W`](@ref) `secondary_turns_ratio`."""
set_secondary_turns_ratio!(value::Transformer3W, val) = value.secondary_turns_ratio = val
"""Set [`Transformer3W`](@ref) `tertiary_turns_ratio`."""
set_tertiary_turns_ratio!(value::Transformer3W, val) = value.tertiary_turns_ratio = val
"""Set [`Transformer3W`](@ref) `available_primary`."""
set_available_primary!(value::Transformer3W, val) = value.available_primary = val
"""Set [`Transformer3W`](@ref) `available_secondary`."""
set_available_secondary!(value::Transformer3W, val) = value.available_secondary = val
"""Set [`Transformer3W`](@ref) `available_tertiary`."""
set_available_tertiary!(value::Transformer3W, val) = value.available_tertiary = val
"""Set [`Transformer3W`](@ref) `rating_primary`."""
set_rating_primary!(value::Transformer3W, val) = value.rating_primary = set_value(value, Val(:rating_primary), val, Val(:mva))
"""Set [`Transformer3W`](@ref) `rating_secondary`."""
set_rating_secondary!(value::Transformer3W, val) = value.rating_secondary = set_value(value, Val(:rating_secondary), val, Val(:mva))
"""Set [`Transformer3W`](@ref) `rating_tertiary`."""
set_rating_tertiary!(value::Transformer3W, val) = value.rating_tertiary = set_value(value, Val(:rating_tertiary), val, Val(:mva))
"""Set [`Transformer3W`](@ref) `primary_group_number`."""
set_primary_group_number!(value::Transformer3W, val) = value.primary_group_number = val
"""Set [`Transformer3W`](@ref) `secondary_group_number`."""
set_secondary_group_number!(value::Transformer3W, val) = value.secondary_group_number = val
"""Set [`Transformer3W`](@ref) `tertiary_group_number`."""
set_tertiary_group_number!(value::Transformer3W, val) = value.tertiary_group_number = val
"""Set [`Transformer3W`](@ref) `control_objective_primary`."""
set_control_objective_primary!(value::Transformer3W, val) = value.control_objective_primary = val
"""Set [`Transformer3W`](@ref) `control_objective_secondary`."""
set_control_objective_secondary!(value::Transformer3W, val) = value.control_objective_secondary = val
"""Set [`Transformer3W`](@ref) `control_objective_tertiary`."""
set_control_objective_tertiary!(value::Transformer3W, val) = value.control_objective_tertiary = val
"""Set [`Transformer3W`](@ref) `services`."""
set_services!(value::Transformer3W, val) = value.services = val
"""Set [`Transformer3W`](@ref) `ext`."""
set_ext!(value::Transformer3W, val) = value.ext = val
================================================
FILE: src/models/generated/TransmissionInterface.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct TransmissionInterface <: Service
name::String
available::Bool
active_power_flow_limits::MinMax
violation_penalty::Float64
direction_mapping::Dict{String, Int}
internal::InfrastructureSystemsInternal
end
A collection of branches that make up an interface or corridor for the transfer of power, such as between different [`Areas`](@ref Area) or [`LoadZones`](@ref LoadZone).
The interface can be used to constrain the power flow across it
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow_limits::MinMax`: Minimum and maximum active power flow limits on the interface (MW)
- `violation_penalty::Float64`: (default: `INFINITE_COST`) Penalty cost for violating the flow limits in the interface
- `direction_mapping::Dict{String, Int}`: (default: `Dict{String, Int}()`) Dictionary of the line `name`s in the interface and their direction of flow (1 or -1) relative to the flow of the interface
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct TransmissionInterface <: Service
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Minimum and maximum active power flow limits on the interface (MW)"
active_power_flow_limits::MinMax
"Penalty cost for violating the flow limits in the interface"
violation_penalty::Float64
"Dictionary of the line `name`s in the interface and their direction of flow (1 or -1) relative to the flow of the interface"
direction_mapping::Dict{String, Int}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function TransmissionInterface(name, available, active_power_flow_limits, violation_penalty=INFINITE_COST, direction_mapping=Dict{String, Int}(), )
TransmissionInterface(name, available, active_power_flow_limits, violation_penalty, direction_mapping, InfrastructureSystemsInternal(), )
end
function TransmissionInterface(; name, available, active_power_flow_limits, violation_penalty=INFINITE_COST, direction_mapping=Dict{String, Int}(), internal=InfrastructureSystemsInternal(), )
TransmissionInterface(name, available, active_power_flow_limits, violation_penalty, direction_mapping, internal, )
end
# Constructor for demo purposes; non-functional.
function TransmissionInterface(::Nothing)
TransmissionInterface(;
name="init",
available=false,
active_power_flow_limits=(min=0.0, max=0.0),
violation_penalty=0.0,
direction_mapping=Dict{String, Int}(),
)
end
"""Get [`TransmissionInterface`](@ref) `name`."""
get_name(value::TransmissionInterface) = value.name
"""Get [`TransmissionInterface`](@ref) `available`."""
get_available(value::TransmissionInterface) = value.available
"""Get [`TransmissionInterface`](@ref) `active_power_flow_limits`."""
get_active_power_flow_limits(value::TransmissionInterface) = get_value(value, Val(:active_power_flow_limits), Val(:mva))
"""Get [`TransmissionInterface`](@ref) `violation_penalty`."""
get_violation_penalty(value::TransmissionInterface) = value.violation_penalty
"""Get [`TransmissionInterface`](@ref) `direction_mapping`."""
get_direction_mapping(value::TransmissionInterface) = value.direction_mapping
"""Get [`TransmissionInterface`](@ref) `internal`."""
get_internal(value::TransmissionInterface) = value.internal
"""Set [`TransmissionInterface`](@ref) `available`."""
set_available!(value::TransmissionInterface, val) = value.available = val
"""Set [`TransmissionInterface`](@ref) `active_power_flow_limits`."""
set_active_power_flow_limits!(value::TransmissionInterface, val) = value.active_power_flow_limits = set_value(value, Val(:active_power_flow_limits), val, Val(:mva))
"""Set [`TransmissionInterface`](@ref) `violation_penalty`."""
set_violation_penalty!(value::TransmissionInterface, val) = value.violation_penalty = val
"""Set [`TransmissionInterface`](@ref) `direction_mapping`."""
set_direction_mapping!(value::TransmissionInterface, val) = value.direction_mapping = val
================================================
FILE: src/models/generated/TwoTerminalGenericHVDCLine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct TwoTerminalGenericHVDCLine <: TwoTerminalHVDC
name::String
available::Bool
active_power_flow::Float64
arc::Arc
active_power_limits_from::MinMax
active_power_limits_to::MinMax
reactive_power_limits_from::MinMax
reactive_power_limits_to::MinMax
loss::Union{LinearCurve, PiecewiseIncrementalCurve}
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A High Voltage DC line, which must be connected to an [`ACBus`](@ref) on each end.
This model is appropriate for operational simulations with a linearized DC power flow approximation with losses proportional to the power flow. For modeling a DC network, see [`TModelHVDCLine`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `active_power_flow::Float64`: Initial condition of active power flow on the line (MW)
- `arc::Arc`: An [`Arc`](@ref) defining this line `from` a bus `to` another bus
- `active_power_limits_from::MinMax`: Minimum and maximum active power flows to the FROM node (MW)
- `active_power_limits_to::MinMax`: Minimum and maximum active power flows to the TO node (MW)
- `reactive_power_limits_from::MinMax`: Minimum and maximum reactive power limits to the FROM node (MVAR)
- `reactive_power_limits_to::MinMax`: Minimum and maximum reactive power limits to the TO node (MVAR)
- `loss::Union{LinearCurve, PiecewiseIncrementalCurve}`: (default: `LinearCurve(0.0)`) Loss model coefficients. It accepts a linear model with a constant loss (MW) and a proportional loss rate (MW of loss per MW of flow). It also accepts a Piecewise loss, with N segments to specify different proportional losses for different segments.
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct TwoTerminalGenericHVDCLine <: TwoTerminalHVDC
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"Initial condition of active power flow on the line (MW)"
active_power_flow::Float64
"An [`Arc`](@ref) defining this line `from` a bus `to` another bus"
arc::Arc
"Minimum and maximum active power flows to the FROM node (MW)"
active_power_limits_from::MinMax
"Minimum and maximum active power flows to the TO node (MW)"
active_power_limits_to::MinMax
"Minimum and maximum reactive power limits to the FROM node (MVAR)"
reactive_power_limits_from::MinMax
"Minimum and maximum reactive power limits to the TO node (MVAR)"
reactive_power_limits_to::MinMax
"Loss model coefficients. It accepts a linear model with a constant loss (MW) and a proportional loss rate (MW of loss per MW of flow). It also accepts a Piecewise loss, with N segments to specify different proportional losses for different segments."
loss::Union{LinearCurve, PiecewiseIncrementalCurve}
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function TwoTerminalGenericHVDCLine(name, available, active_power_flow, arc, active_power_limits_from, active_power_limits_to, reactive_power_limits_from, reactive_power_limits_to, loss=LinearCurve(0.0), services=Device[], ext=Dict{String, Any}(), )
TwoTerminalGenericHVDCLine(name, available, active_power_flow, arc, active_power_limits_from, active_power_limits_to, reactive_power_limits_from, reactive_power_limits_to, loss, services, ext, InfrastructureSystemsInternal(), )
end
function TwoTerminalGenericHVDCLine(; name, available, active_power_flow, arc, active_power_limits_from, active_power_limits_to, reactive_power_limits_from, reactive_power_limits_to, loss=LinearCurve(0.0), services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
TwoTerminalGenericHVDCLine(name, available, active_power_flow, arc, active_power_limits_from, active_power_limits_to, reactive_power_limits_from, reactive_power_limits_to, loss, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function TwoTerminalGenericHVDCLine(::Nothing)
TwoTerminalGenericHVDCLine(;
name="init",
available=false,
active_power_flow=0.0,
arc=Arc(ACBus(nothing), ACBus(nothing)),
active_power_limits_from=(min=0.0, max=0.0),
active_power_limits_to=(min=0.0, max=0.0),
reactive_power_limits_from=(min=0.0, max=0.0),
reactive_power_limits_to=(min=0.0, max=0.0),
loss=LinearCurve(0.0),
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `name`."""
get_name(value::TwoTerminalGenericHVDCLine) = value.name
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `available`."""
get_available(value::TwoTerminalGenericHVDCLine) = value.available
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `active_power_flow`."""
get_active_power_flow(value::TwoTerminalGenericHVDCLine) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `arc`."""
get_arc(value::TwoTerminalGenericHVDCLine) = value.arc
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `active_power_limits_from`."""
get_active_power_limits_from(value::TwoTerminalGenericHVDCLine) = get_value(value, Val(:active_power_limits_from), Val(:mva))
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `active_power_limits_to`."""
get_active_power_limits_to(value::TwoTerminalGenericHVDCLine) = get_value(value, Val(:active_power_limits_to), Val(:mva))
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `reactive_power_limits_from`."""
get_reactive_power_limits_from(value::TwoTerminalGenericHVDCLine) = get_value(value, Val(:reactive_power_limits_from), Val(:mva))
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `reactive_power_limits_to`."""
get_reactive_power_limits_to(value::TwoTerminalGenericHVDCLine) = get_value(value, Val(:reactive_power_limits_to), Val(:mva))
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `loss`."""
get_loss(value::TwoTerminalGenericHVDCLine) = value.loss
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `services`."""
get_services(value::TwoTerminalGenericHVDCLine) = value.services
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `ext`."""
get_ext(value::TwoTerminalGenericHVDCLine) = value.ext
"""Get [`TwoTerminalGenericHVDCLine`](@ref) `internal`."""
get_internal(value::TwoTerminalGenericHVDCLine) = value.internal
"""Set [`TwoTerminalGenericHVDCLine`](@ref) `available`."""
set_available!(value::TwoTerminalGenericHVDCLine, val) = value.available = val
"""Set [`TwoTerminalGenericHVDCLine`](@ref) `active_power_flow`."""
set_active_power_flow!(value::TwoTerminalGenericHVDCLine, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`TwoTerminalGenericHVDCLine`](@ref) `arc`."""
set_arc!(value::TwoTerminalGenericHVDCLine, val) = value.arc = val
"""Set [`TwoTerminalGenericHVDCLine`](@ref) `active_power_limits_from`."""
set_active_power_limits_from!(value::TwoTerminalGenericHVDCLine, val) = value.active_power_limits_from = set_value(value, Val(:active_power_limits_from), val, Val(:mva))
"""Set [`TwoTerminalGenericHVDCLine`](@ref) `active_power_limits_to`."""
set_active_power_limits_to!(value::TwoTerminalGenericHVDCLine, val) = value.active_power_limits_to = set_value(value, Val(:active_power_limits_to), val, Val(:mva))
"""Set [`TwoTerminalGenericHVDCLine`](@ref) `reactive_power_limits_from`."""
set_reactive_power_limits_from!(value::TwoTerminalGenericHVDCLine, val) = value.reactive_power_limits_from = set_value(value, Val(:reactive_power_limits_from), val, Val(:mva))
"""Set [`TwoTerminalGenericHVDCLine`](@ref) `reactive_power_limits_to`."""
set_reactive_power_limits_to!(value::TwoTerminalGenericHVDCLine, val) = value.reactive_power_limits_to = set_value(value, Val(:reactive_power_limits_to), val, Val(:mva))
"""Set [`TwoTerminalGenericHVDCLine`](@ref) `loss`."""
set_loss!(value::TwoTerminalGenericHVDCLine, val) = value.loss = val
"""Set [`TwoTerminalGenericHVDCLine`](@ref) `services`."""
set_services!(value::TwoTerminalGenericHVDCLine, val) = value.services = val
"""Set [`TwoTerminalGenericHVDCLine`](@ref) `ext`."""
set_ext!(value::TwoTerminalGenericHVDCLine, val) = value.ext = val
================================================
FILE: src/models/generated/TwoTerminalLCCLine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct TwoTerminalLCCLine <: TwoTerminalHVDC
name::String
available::Bool
arc::Arc
active_power_flow::Float64
r::Float64
transfer_setpoint::Float64
scheduled_dc_voltage::Float64
rectifier_bridges::Int
rectifier_delay_angle_limits::MinMax
rectifier_rc::Float64
rectifier_xc::Float64
rectifier_base_voltage::Float64
inverter_bridges::Int
inverter_extinction_angle_limits::MinMax
inverter_rc::Float64
inverter_xc::Float64
inverter_base_voltage::Float64
power_mode::Bool
switch_mode_voltage::Float64
compounding_resistance::Float64
min_compounding_voltage::Float64
rectifier_transformer_ratio::Float64
rectifier_tap_setting::Float64
rectifier_tap_limits::MinMax
rectifier_tap_step::Float64
rectifier_delay_angle::Float64
rectifier_capacitor_reactance::Float64
inverter_transformer_ratio::Float64
inverter_tap_setting::Float64
inverter_tap_limits::MinMax
inverter_tap_step::Float64
inverter_extinction_angle::Float64
inverter_capacitor_reactance::Float64
active_power_limits_from::MinMax
active_power_limits_to::MinMax
reactive_power_limits_from::MinMax
reactive_power_limits_to::MinMax
loss::Union{LinearCurve, PiecewiseIncrementalCurve}
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A Non-Capacitor Line Commutated Converter (LCC)-HVDC transmission line.
As implemented in PSS/E.
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `arc::Arc`: An [`Arc`](@ref) defining this line `from` a rectifier bus `to` an inverter bus. The rectifier bus must be specified in the `from` bus and inverter bus in the `to` bus.
- `active_power_flow::Float64`: Initial condition of active power flow on the line (MW)
- `r::Float64`: Series resistance of the DC line in pu ([`SYSTEM_BASE`](@ref per_unit))
- `transfer_setpoint::Float64`: Desired set-point of power. If `power_mode = true` this value is in MW units, and if `power_mode = false` is in Amperes units. This parameter must not be specified in per-unit. A positive value represents the desired consumed power at the rectifier bus, while a negative value represents the desired power at the inverter bus (i.e. the absolute value of `transfer_setpoint` is the generated power at the inverter bus).
- `scheduled_dc_voltage::Float64`: Scheduled compounded DC voltage in kV. By default this parameter is the scheduled DC voltage in the inverter bus This parameter must not be specified in per-unit.
- `rectifier_bridges::Int`: Number of bridges in series in the rectifier side.
- `rectifier_delay_angle_limits::MinMax`: Minimum and maximum rectifier firing delay angle (α) (radians)
- `rectifier_rc::Float64`: Rectifier commutating transformer resistance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))
- `rectifier_xc::Float64`: Rectifier commutating transformer reactance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))
- `rectifier_base_voltage::Float64`: Rectifier primary base AC voltage in kV, entered in kV.
- `inverter_bridges::Int`: Number of bridges in series in the inverter side.
- `inverter_extinction_angle_limits::MinMax`: Minimum and maximum inverter extinction angle (γ) (radians)
- `inverter_rc::Float64`: Inverter commutating transformer resistance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))
- `inverter_xc::Float64`: Inverter commutating transformer reactance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))
- `inverter_base_voltage::Float64`: Inverter primary base AC voltage in kV, entered in kV.
- `power_mode::Bool`: (default: `true`) Boolean flag to identify if the LCC line is in power mode or current mode. If `power_mode = true`, setpoint values must be specified in MW, and if `power_mode = false` setpoint values must be specified in Amperes.
- `switch_mode_voltage::Float64`: (default: `0.0`) Mode switch DC voltage, in kV. This parameter must not be added in per-unit. If LCC line is in power mode control, and DC voltage falls below this value, the line switch to current mode control.
- `compounding_resistance::Float64`: (default: `0.0`) Compounding Resistance, in ohms. This parameter is for control of the DC voltage in the rectifier or inverter end. For inverter DC voltage control, the paremeter is set to zero; for rectifier DC voltage control, the paremeter is set to the DC line resistance; otherwise, set to a fraction of the DC line resistance.
- `min_compounding_voltage::Float64`: (default: `0.0`) Minimum compounded voltage, in kV. This parameter must not be added in per-unit. Only used in constant gamma operation (γ_min = γ_max), and the AC transformer is used to control the DC voltage.
- `rectifier_transformer_ratio::Float64`: (default: `1.0`) Rectifier transformer ratio between the primary and secondary side AC voltages.
- `rectifier_tap_setting::Float64`: (default: `1.0`) Rectifier transformer tap setting.
- `rectifier_tap_limits::MinMax`: (default: `(min=0.51, max=1.5)`) Minimum and maximum rectifier tap limits as a ratio between the primary and secondary side AC voltages.
- `rectifier_tap_step::Float64`: (default: `0.00625`) Rectifier transformer tap step value
- `rectifier_delay_angle::Float64`: (default: `0.0`) Rectifier firing delay angle (α).
- `rectifier_capacitor_reactance::Float64`: (default: `0.0`) Commutating rectifier capacitor reactance magnitude per bridge, in system p.u. ([`SYSTEM_BASE`](@ref per_unit)).
- `inverter_transformer_ratio::Float64`: (default: `1.0`) Inverter transformer ratio between the primary and secondary side AC voltages.
- `inverter_tap_setting::Float64`: (default: `1.0`) Inverter transformer tap setting.
- `inverter_tap_limits::MinMax`: (default: `(min=0.51, max=1.5)`) Minimum and maximum inverter tap limits as a ratio between the primary and secondary side AC voltages.
- `inverter_tap_step::Float64`: (default: `0.00625`) Inverter transformer tap step value.
- `inverter_extinction_angle::Float64`: (default: `0.0`) Inverter extinction angle (γ).
- `inverter_capacitor_reactance::Float64`: (default: `0.0`) Commutating inverter capacitor reactance magnitude per bridge, in system p.u. ([`SYSTEM_BASE`](@ref per_unit)).
- `active_power_limits_from::MinMax`: (default: `(min=0.0, max=0.0)`) Minimum and maximum active power flows to the FROM node (MW)
- `active_power_limits_to::MinMax`: (default: `(min=0.0, max=0.0)`) Minimum and maximum active power flows to the TO node (MW)
- `reactive_power_limits_from::MinMax`: (default: `(min=0.0, max=0.0)`) Minimum and maximum reactive power limits to the FROM node (MVAR)
- `reactive_power_limits_to::MinMax`: (default: `(min=0.0, max=0.0)`) Minimum and maximum reactive power limits to the TO node (MVAR)
- `loss::Union{LinearCurve, PiecewiseIncrementalCurve}`: (default: `LinearCurve(0.0)`) A generic loss model coefficients. It accepts a linear model with a constant loss (MW) and a proportional loss rate (MW of loss per MW of flow). It also accepts a Piecewise loss, with N segments to specify different proportional losses for different segments.
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct TwoTerminalLCCLine <: TwoTerminalHVDC
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"An [`Arc`](@ref) defining this line `from` a rectifier bus `to` an inverter bus. The rectifier bus must be specified in the `from` bus and inverter bus in the `to` bus."
arc::Arc
"Initial condition of active power flow on the line (MW)"
active_power_flow::Float64
"Series resistance of the DC line in pu ([`SYSTEM_BASE`](@ref per_unit))"
r::Float64
"Desired set-point of power. If `power_mode = true` this value is in MW units, and if `power_mode = false` is in Amperes units. This parameter must not be specified in per-unit. A positive value represents the desired consumed power at the rectifier bus, while a negative value represents the desired power at the inverter bus (i.e. the absolute value of `transfer_setpoint` is the generated power at the inverter bus)."
transfer_setpoint::Float64
"Scheduled compounded DC voltage in kV. By default this parameter is the scheduled DC voltage in the inverter bus This parameter must not be specified in per-unit."
scheduled_dc_voltage::Float64
"Number of bridges in series in the rectifier side."
rectifier_bridges::Int
"Minimum and maximum rectifier firing delay angle (α) (radians)"
rectifier_delay_angle_limits::MinMax
"Rectifier commutating transformer resistance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))"
rectifier_rc::Float64
"Rectifier commutating transformer reactance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))"
rectifier_xc::Float64
"Rectifier primary base AC voltage in kV, entered in kV."
rectifier_base_voltage::Float64
"Number of bridges in series in the inverter side."
inverter_bridges::Int
"Minimum and maximum inverter extinction angle (γ) (radians)"
inverter_extinction_angle_limits::MinMax
"Inverter commutating transformer resistance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))"
inverter_rc::Float64
"Inverter commutating transformer reactance per bridge in system p.u. ([`SYSTEM_BASE`](@ref per_unit))"
inverter_xc::Float64
"Inverter primary base AC voltage in kV, entered in kV."
inverter_base_voltage::Float64
"Boolean flag to identify if the LCC line is in power mode or current mode. If `power_mode = true`, setpoint values must be specified in MW, and if `power_mode = false` setpoint values must be specified in Amperes."
power_mode::Bool
"Mode switch DC voltage, in kV. This parameter must not be added in per-unit. If LCC line is in power mode control, and DC voltage falls below this value, the line switch to current mode control."
switch_mode_voltage::Float64
"Compounding Resistance, in ohms. This parameter is for control of the DC voltage in the rectifier or inverter end. For inverter DC voltage control, the paremeter is set to zero; for rectifier DC voltage control, the paremeter is set to the DC line resistance; otherwise, set to a fraction of the DC line resistance."
compounding_resistance::Float64
"Minimum compounded voltage, in kV. This parameter must not be added in per-unit. Only used in constant gamma operation (γ_min = γ_max), and the AC transformer is used to control the DC voltage."
min_compounding_voltage::Float64
"Rectifier transformer ratio between the primary and secondary side AC voltages."
rectifier_transformer_ratio::Float64
"Rectifier transformer tap setting."
rectifier_tap_setting::Float64
"Minimum and maximum rectifier tap limits as a ratio between the primary and secondary side AC voltages."
rectifier_tap_limits::MinMax
"Rectifier transformer tap step value"
rectifier_tap_step::Float64
"Rectifier firing delay angle (α)."
rectifier_delay_angle::Float64
"Commutating rectifier capacitor reactance magnitude per bridge, in system p.u. ([`SYSTEM_BASE`](@ref per_unit))."
rectifier_capacitor_reactance::Float64
"Inverter transformer ratio between the primary and secondary side AC voltages."
inverter_transformer_ratio::Float64
"Inverter transformer tap setting."
inverter_tap_setting::Float64
"Minimum and maximum inverter tap limits as a ratio between the primary and secondary side AC voltages."
inverter_tap_limits::MinMax
"Inverter transformer tap step value."
inverter_tap_step::Float64
"Inverter extinction angle (γ)."
inverter_extinction_angle::Float64
"Commutating inverter capacitor reactance magnitude per bridge, in system p.u. ([`SYSTEM_BASE`](@ref per_unit))."
inverter_capacitor_reactance::Float64
"Minimum and maximum active power flows to the FROM node (MW)"
active_power_limits_from::MinMax
"Minimum and maximum active power flows to the TO node (MW)"
active_power_limits_to::MinMax
"Minimum and maximum reactive power limits to the FROM node (MVAR)"
reactive_power_limits_from::MinMax
"Minimum and maximum reactive power limits to the TO node (MVAR)"
reactive_power_limits_to::MinMax
"A generic loss model coefficients. It accepts a linear model with a constant loss (MW) and a proportional loss rate (MW of loss per MW of flow). It also accepts a Piecewise loss, with N segments to specify different proportional losses for different segments."
loss::Union{LinearCurve, PiecewiseIncrementalCurve}
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function TwoTerminalLCCLine(name, available, arc, active_power_flow, r, transfer_setpoint, scheduled_dc_voltage, rectifier_bridges, rectifier_delay_angle_limits, rectifier_rc, rectifier_xc, rectifier_base_voltage, inverter_bridges, inverter_extinction_angle_limits, inverter_rc, inverter_xc, inverter_base_voltage, power_mode=true, switch_mode_voltage=0.0, compounding_resistance=0.0, min_compounding_voltage=0.0, rectifier_transformer_ratio=1.0, rectifier_tap_setting=1.0, rectifier_tap_limits=(min=0.51, max=1.5), rectifier_tap_step=0.00625, rectifier_delay_angle=0.0, rectifier_capacitor_reactance=0.0, inverter_transformer_ratio=1.0, inverter_tap_setting=1.0, inverter_tap_limits=(min=0.51, max=1.5), inverter_tap_step=0.00625, inverter_extinction_angle=0.0, inverter_capacitor_reactance=0.0, active_power_limits_from=(min=0.0, max=0.0), active_power_limits_to=(min=0.0, max=0.0), reactive_power_limits_from=(min=0.0, max=0.0), reactive_power_limits_to=(min=0.0, max=0.0), loss=LinearCurve(0.0), services=Device[], ext=Dict{String, Any}(), )
TwoTerminalLCCLine(name, available, arc, active_power_flow, r, transfer_setpoint, scheduled_dc_voltage, rectifier_bridges, rectifier_delay_angle_limits, rectifier_rc, rectifier_xc, rectifier_base_voltage, inverter_bridges, inverter_extinction_angle_limits, inverter_rc, inverter_xc, inverter_base_voltage, power_mode, switch_mode_voltage, compounding_resistance, min_compounding_voltage, rectifier_transformer_ratio, rectifier_tap_setting, rectifier_tap_limits, rectifier_tap_step, rectifier_delay_angle, rectifier_capacitor_reactance, inverter_transformer_ratio, inverter_tap_setting, inverter_tap_limits, inverter_tap_step, inverter_extinction_angle, inverter_capacitor_reactance, active_power_limits_from, active_power_limits_to, reactive_power_limits_from, reactive_power_limits_to, loss, services, ext, InfrastructureSystemsInternal(), )
end
function TwoTerminalLCCLine(; name, available, arc, active_power_flow, r, transfer_setpoint, scheduled_dc_voltage, rectifier_bridges, rectifier_delay_angle_limits, rectifier_rc, rectifier_xc, rectifier_base_voltage, inverter_bridges, inverter_extinction_angle_limits, inverter_rc, inverter_xc, inverter_base_voltage, power_mode=true, switch_mode_voltage=0.0, compounding_resistance=0.0, min_compounding_voltage=0.0, rectifier_transformer_ratio=1.0, rectifier_tap_setting=1.0, rectifier_tap_limits=(min=0.51, max=1.5), rectifier_tap_step=0.00625, rectifier_delay_angle=0.0, rectifier_capacitor_reactance=0.0, inverter_transformer_ratio=1.0, inverter_tap_setting=1.0, inverter_tap_limits=(min=0.51, max=1.5), inverter_tap_step=0.00625, inverter_extinction_angle=0.0, inverter_capacitor_reactance=0.0, active_power_limits_from=(min=0.0, max=0.0), active_power_limits_to=(min=0.0, max=0.0), reactive_power_limits_from=(min=0.0, max=0.0), reactive_power_limits_to=(min=0.0, max=0.0), loss=LinearCurve(0.0), services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
TwoTerminalLCCLine(name, available, arc, active_power_flow, r, transfer_setpoint, scheduled_dc_voltage, rectifier_bridges, rectifier_delay_angle_limits, rectifier_rc, rectifier_xc, rectifier_base_voltage, inverter_bridges, inverter_extinction_angle_limits, inverter_rc, inverter_xc, inverter_base_voltage, power_mode, switch_mode_voltage, compounding_resistance, min_compounding_voltage, rectifier_transformer_ratio, rectifier_tap_setting, rectifier_tap_limits, rectifier_tap_step, rectifier_delay_angle, rectifier_capacitor_reactance, inverter_transformer_ratio, inverter_tap_setting, inverter_tap_limits, inverter_tap_step, inverter_extinction_angle, inverter_capacitor_reactance, active_power_limits_from, active_power_limits_to, reactive_power_limits_from, reactive_power_limits_to, loss, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function TwoTerminalLCCLine(::Nothing)
TwoTerminalLCCLine(;
name="init",
available=false,
arc=Arc(ACBus(nothing), ACBus(nothing)),
active_power_flow=0.0,
r=0.0,
transfer_setpoint=0.0,
scheduled_dc_voltage=0.0,
rectifier_bridges=0,
rectifier_delay_angle_limits=(min=0.0, max=0.0),
rectifier_rc=0.0,
rectifier_xc=0.0,
rectifier_base_voltage=0.0,
inverter_bridges=0,
inverter_extinction_angle_limits=(min=0.0, max=0.0),
inverter_rc=0.0,
inverter_xc=0.0,
inverter_base_voltage=0.0,
power_mode=false,
switch_mode_voltage=0.0,
compounding_resistance=0.0,
min_compounding_voltage=0.0,
rectifier_transformer_ratio=0.0,
rectifier_tap_setting=0.0,
rectifier_tap_limits=(min=0.0, max=0.0),
rectifier_tap_step=0.0,
rectifier_delay_angle=0.0,
rectifier_capacitor_reactance=0.0,
inverter_transformer_ratio=0.0,
inverter_tap_setting=0.0,
inverter_tap_limits=(min=0.0, max=0.0),
inverter_tap_step=0.0,
inverter_extinction_angle=0.0,
inverter_capacitor_reactance=0.0,
active_power_limits_from=(min=0.0, max=0.0),
active_power_limits_to=(min=0.0, max=0.0),
reactive_power_limits_from=(min=0.0, max=0.0),
reactive_power_limits_to=(min=0.0, max=0.0),
loss=LinearCurve(0.0),
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`TwoTerminalLCCLine`](@ref) `name`."""
get_name(value::TwoTerminalLCCLine) = value.name
"""Get [`TwoTerminalLCCLine`](@ref) `available`."""
get_available(value::TwoTerminalLCCLine) = value.available
"""Get [`TwoTerminalLCCLine`](@ref) `arc`."""
get_arc(value::TwoTerminalLCCLine) = value.arc
"""Get [`TwoTerminalLCCLine`](@ref) `active_power_flow`."""
get_active_power_flow(value::TwoTerminalLCCLine) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`TwoTerminalLCCLine`](@ref) `r`."""
get_r(value::TwoTerminalLCCLine) = value.r
"""Get [`TwoTerminalLCCLine`](@ref) `transfer_setpoint`."""
get_transfer_setpoint(value::TwoTerminalLCCLine) = value.transfer_setpoint
"""Get [`TwoTerminalLCCLine`](@ref) `scheduled_dc_voltage`."""
get_scheduled_dc_voltage(value::TwoTerminalLCCLine) = value.scheduled_dc_voltage
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_bridges`."""
get_rectifier_bridges(value::TwoTerminalLCCLine) = value.rectifier_bridges
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_delay_angle_limits`."""
get_rectifier_delay_angle_limits(value::TwoTerminalLCCLine) = value.rectifier_delay_angle_limits
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_rc`."""
get_rectifier_rc(value::TwoTerminalLCCLine) = value.rectifier_rc
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_xc`."""
get_rectifier_xc(value::TwoTerminalLCCLine) = value.rectifier_xc
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_base_voltage`."""
get_rectifier_base_voltage(value::TwoTerminalLCCLine) = value.rectifier_base_voltage
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_bridges`."""
get_inverter_bridges(value::TwoTerminalLCCLine) = value.inverter_bridges
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_extinction_angle_limits`."""
get_inverter_extinction_angle_limits(value::TwoTerminalLCCLine) = value.inverter_extinction_angle_limits
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_rc`."""
get_inverter_rc(value::TwoTerminalLCCLine) = value.inverter_rc
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_xc`."""
get_inverter_xc(value::TwoTerminalLCCLine) = value.inverter_xc
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_base_voltage`."""
get_inverter_base_voltage(value::TwoTerminalLCCLine) = value.inverter_base_voltage
"""Get [`TwoTerminalLCCLine`](@ref) `power_mode`."""
get_power_mode(value::TwoTerminalLCCLine) = value.power_mode
"""Get [`TwoTerminalLCCLine`](@ref) `switch_mode_voltage`."""
get_switch_mode_voltage(value::TwoTerminalLCCLine) = value.switch_mode_voltage
"""Get [`TwoTerminalLCCLine`](@ref) `compounding_resistance`."""
get_compounding_resistance(value::TwoTerminalLCCLine) = value.compounding_resistance
"""Get [`TwoTerminalLCCLine`](@ref) `min_compounding_voltage`."""
get_min_compounding_voltage(value::TwoTerminalLCCLine) = value.min_compounding_voltage
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_transformer_ratio`."""
get_rectifier_transformer_ratio(value::TwoTerminalLCCLine) = value.rectifier_transformer_ratio
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_tap_setting`."""
get_rectifier_tap_setting(value::TwoTerminalLCCLine) = value.rectifier_tap_setting
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_tap_limits`."""
get_rectifier_tap_limits(value::TwoTerminalLCCLine) = value.rectifier_tap_limits
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_tap_step`."""
get_rectifier_tap_step(value::TwoTerminalLCCLine) = value.rectifier_tap_step
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_delay_angle`."""
get_rectifier_delay_angle(value::TwoTerminalLCCLine) = value.rectifier_delay_angle
"""Get [`TwoTerminalLCCLine`](@ref) `rectifier_capacitor_reactance`."""
get_rectifier_capacitor_reactance(value::TwoTerminalLCCLine) = value.rectifier_capacitor_reactance
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_transformer_ratio`."""
get_inverter_transformer_ratio(value::TwoTerminalLCCLine) = value.inverter_transformer_ratio
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_tap_setting`."""
get_inverter_tap_setting(value::TwoTerminalLCCLine) = value.inverter_tap_setting
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_tap_limits`."""
get_inverter_tap_limits(value::TwoTerminalLCCLine) = value.inverter_tap_limits
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_tap_step`."""
get_inverter_tap_step(value::TwoTerminalLCCLine) = value.inverter_tap_step
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_extinction_angle`."""
get_inverter_extinction_angle(value::TwoTerminalLCCLine) = value.inverter_extinction_angle
"""Get [`TwoTerminalLCCLine`](@ref) `inverter_capacitor_reactance`."""
get_inverter_capacitor_reactance(value::TwoTerminalLCCLine) = value.inverter_capacitor_reactance
"""Get [`TwoTerminalLCCLine`](@ref) `active_power_limits_from`."""
get_active_power_limits_from(value::TwoTerminalLCCLine) = get_value(value, Val(:active_power_limits_from), Val(:mva))
"""Get [`TwoTerminalLCCLine`](@ref) `active_power_limits_to`."""
get_active_power_limits_to(value::TwoTerminalLCCLine) = get_value(value, Val(:active_power_limits_to), Val(:mva))
"""Get [`TwoTerminalLCCLine`](@ref) `reactive_power_limits_from`."""
get_reactive_power_limits_from(value::TwoTerminalLCCLine) = get_value(value, Val(:reactive_power_limits_from), Val(:mva))
"""Get [`TwoTerminalLCCLine`](@ref) `reactive_power_limits_to`."""
get_reactive_power_limits_to(value::TwoTerminalLCCLine) = get_value(value, Val(:reactive_power_limits_to), Val(:mva))
"""Get [`TwoTerminalLCCLine`](@ref) `loss`."""
get_loss(value::TwoTerminalLCCLine) = value.loss
"""Get [`TwoTerminalLCCLine`](@ref) `services`."""
get_services(value::TwoTerminalLCCLine) = value.services
"""Get [`TwoTerminalLCCLine`](@ref) `ext`."""
get_ext(value::TwoTerminalLCCLine) = value.ext
"""Get [`TwoTerminalLCCLine`](@ref) `internal`."""
get_internal(value::TwoTerminalLCCLine) = value.internal
"""Set [`TwoTerminalLCCLine`](@ref) `available`."""
set_available!(value::TwoTerminalLCCLine, val) = value.available = val
"""Set [`TwoTerminalLCCLine`](@ref) `arc`."""
set_arc!(value::TwoTerminalLCCLine, val) = value.arc = val
"""Set [`TwoTerminalLCCLine`](@ref) `active_power_flow`."""
set_active_power_flow!(value::TwoTerminalLCCLine, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`TwoTerminalLCCLine`](@ref) `r`."""
set_r!(value::TwoTerminalLCCLine, val) = value.r = val
"""Set [`TwoTerminalLCCLine`](@ref) `transfer_setpoint`."""
set_transfer_setpoint!(value::TwoTerminalLCCLine, val) = value.transfer_setpoint = val
"""Set [`TwoTerminalLCCLine`](@ref) `scheduled_dc_voltage`."""
set_scheduled_dc_voltage!(value::TwoTerminalLCCLine, val) = value.scheduled_dc_voltage = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_bridges`."""
set_rectifier_bridges!(value::TwoTerminalLCCLine, val) = value.rectifier_bridges = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_delay_angle_limits`."""
set_rectifier_delay_angle_limits!(value::TwoTerminalLCCLine, val) = value.rectifier_delay_angle_limits = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_rc`."""
set_rectifier_rc!(value::TwoTerminalLCCLine, val) = value.rectifier_rc = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_xc`."""
set_rectifier_xc!(value::TwoTerminalLCCLine, val) = value.rectifier_xc = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_base_voltage`."""
set_rectifier_base_voltage!(value::TwoTerminalLCCLine, val) = value.rectifier_base_voltage = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_bridges`."""
set_inverter_bridges!(value::TwoTerminalLCCLine, val) = value.inverter_bridges = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_extinction_angle_limits`."""
set_inverter_extinction_angle_limits!(value::TwoTerminalLCCLine, val) = value.inverter_extinction_angle_limits = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_rc`."""
set_inverter_rc!(value::TwoTerminalLCCLine, val) = value.inverter_rc = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_xc`."""
set_inverter_xc!(value::TwoTerminalLCCLine, val) = value.inverter_xc = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_base_voltage`."""
set_inverter_base_voltage!(value::TwoTerminalLCCLine, val) = value.inverter_base_voltage = val
"""Set [`TwoTerminalLCCLine`](@ref) `power_mode`."""
set_power_mode!(value::TwoTerminalLCCLine, val) = value.power_mode = val
"""Set [`TwoTerminalLCCLine`](@ref) `switch_mode_voltage`."""
set_switch_mode_voltage!(value::TwoTerminalLCCLine, val) = value.switch_mode_voltage = val
"""Set [`TwoTerminalLCCLine`](@ref) `compounding_resistance`."""
set_compounding_resistance!(value::TwoTerminalLCCLine, val) = value.compounding_resistance = val
"""Set [`TwoTerminalLCCLine`](@ref) `min_compounding_voltage`."""
set_min_compounding_voltage!(value::TwoTerminalLCCLine, val) = value.min_compounding_voltage = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_transformer_ratio`."""
set_rectifier_transformer_ratio!(value::TwoTerminalLCCLine, val) = value.rectifier_transformer_ratio = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_tap_setting`."""
set_rectifier_tap_setting!(value::TwoTerminalLCCLine, val) = value.rectifier_tap_setting = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_tap_limits`."""
set_rectifier_tap_limits!(value::TwoTerminalLCCLine, val) = value.rectifier_tap_limits = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_tap_step`."""
set_rectifier_tap_step!(value::TwoTerminalLCCLine, val) = value.rectifier_tap_step = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_delay_angle`."""
set_rectifier_delay_angle!(value::TwoTerminalLCCLine, val) = value.rectifier_delay_angle = val
"""Set [`TwoTerminalLCCLine`](@ref) `rectifier_capacitor_reactance`."""
set_rectifier_capacitor_reactance!(value::TwoTerminalLCCLine, val) = value.rectifier_capacitor_reactance = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_transformer_ratio`."""
set_inverter_transformer_ratio!(value::TwoTerminalLCCLine, val) = value.inverter_transformer_ratio = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_tap_setting`."""
set_inverter_tap_setting!(value::TwoTerminalLCCLine, val) = value.inverter_tap_setting = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_tap_limits`."""
set_inverter_tap_limits!(value::TwoTerminalLCCLine, val) = value.inverter_tap_limits = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_tap_step`."""
set_inverter_tap_step!(value::TwoTerminalLCCLine, val) = value.inverter_tap_step = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_extinction_angle`."""
set_inverter_extinction_angle!(value::TwoTerminalLCCLine, val) = value.inverter_extinction_angle = val
"""Set [`TwoTerminalLCCLine`](@ref) `inverter_capacitor_reactance`."""
set_inverter_capacitor_reactance!(value::TwoTerminalLCCLine, val) = value.inverter_capacitor_reactance = val
"""Set [`TwoTerminalLCCLine`](@ref) `active_power_limits_from`."""
set_active_power_limits_from!(value::TwoTerminalLCCLine, val) = value.active_power_limits_from = set_value(value, Val(:active_power_limits_from), val, Val(:mva))
"""Set [`TwoTerminalLCCLine`](@ref) `active_power_limits_to`."""
set_active_power_limits_to!(value::TwoTerminalLCCLine, val) = value.active_power_limits_to = set_value(value, Val(:active_power_limits_to), val, Val(:mva))
"""Set [`TwoTerminalLCCLine`](@ref) `reactive_power_limits_from`."""
set_reactive_power_limits_from!(value::TwoTerminalLCCLine, val) = value.reactive_power_limits_from = set_value(value, Val(:reactive_power_limits_from), val, Val(:mva))
"""Set [`TwoTerminalLCCLine`](@ref) `reactive_power_limits_to`."""
set_reactive_power_limits_to!(value::TwoTerminalLCCLine, val) = value.reactive_power_limits_to = set_value(value, Val(:reactive_power_limits_to), val, Val(:mva))
"""Set [`TwoTerminalLCCLine`](@ref) `loss`."""
set_loss!(value::TwoTerminalLCCLine, val) = value.loss = val
"""Set [`TwoTerminalLCCLine`](@ref) `services`."""
set_services!(value::TwoTerminalLCCLine, val) = value.services = val
"""Set [`TwoTerminalLCCLine`](@ref) `ext`."""
set_ext!(value::TwoTerminalLCCLine, val) = value.ext = val
================================================
FILE: src/models/generated/TwoTerminalVSCLine.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct TwoTerminalVSCLine <: TwoTerminalHVDC
name::String
available::Bool
arc::Arc
active_power_flow::Float64
rating::Float64
active_power_limits_from::MinMax
active_power_limits_to::MinMax
g::Float64
dc_current::Float64
reactive_power_from::Float64
dc_voltage_control_from::Bool
ac_voltage_control_from::Bool
dc_setpoint_from::Float64
ac_setpoint_from::Float64
converter_loss_from::Union{LinearCurve, QuadraticCurve}
max_dc_current_from::Float64
rating_from::Float64
reactive_power_limits_from::MinMax
power_factor_weighting_fraction_from::Float64
voltage_limits_from::MinMax
reactive_power_to::Float64
dc_voltage_control_to::Bool
ac_voltage_control_to::Bool
dc_setpoint_to::Float64
ac_setpoint_to::Float64
converter_loss_to::Union{LinearCurve, QuadraticCurve}
max_dc_current_to::Float64
rating_to::Float64
reactive_power_limits_to::MinMax
power_factor_weighting_fraction_to::Float64
voltage_limits_to::MinMax
services::Vector{Service}
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A High Voltage Voltage-Source Converter DC line, which must be connected to an [`ACBus`](@ref) on each end.
This model is appropriate for operational simulations with a linearized DC power flow approximation with losses using a voltage-current model. For modeling a DC network, see [`TModelHVDCLine`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `arc::Arc`: An [`Arc`](@ref) defining this line `from` a bus `to` another bus
- `active_power_flow::Float64`: Initial condition of active power flowing from the from-bus to the to-bus in DC.
- `rating::Float64`: Maximum output power rating of the converter (MVA), validation range: `(0, nothing)`
- `active_power_limits_from::MinMax`: Minimum and maximum active power flows to the FROM node (MW)
- `active_power_limits_to::MinMax`: Minimum and maximum active power flows to the TO node (MW)
- `g::Float64`: (default: `0.0`) Series conductance of the DC line in pu ([`SYSTEM_BASE`](@ref per_unit))
- `dc_current::Float64`: (default: `0.0`) DC current (A) on the converter flowing in the DC line, from `from` bus to `to` bus.
- `reactive_power_from::Float64`: (default: `0.0`) Initial condition of reactive power flowing into the from-bus.
- `dc_voltage_control_from::Bool`: (default: `true`) Converter control type in the `from` bus converter. Set true for DC Voltage Control (set DC voltage on the DC side of the converter), and false for power demand in the converter.
- `ac_voltage_control_from::Bool`: (default: `true`) Converter control type in the `from` bus converter. Set true for AC Voltage Control (set AC voltage on the AC side of the converter), and false for fixed power AC factor.
- `dc_setpoint_from::Float64`: (default: `0.0`) Converter DC setpoint in the `from` bus converter. If `voltage_control_from = true` this number is the DC voltage on the DC side of the converter, entered in kV. If `voltage_control_from = false`, this value is the power demand in MW, if positive the converter is supplying power to the AC network at the `from` bus; if negative, the converter is withdrawing power from the AC network at the `from` bus.
- `ac_setpoint_from::Float64`: (default: `1.0`) Converter AC setpoint in the `from` bus converter. If `voltage_control_from = true` this number is the AC voltage on the AC side of the converter, entered in [per unit](@ref per_unit). If `voltage_control_from = false`, this value is the power factor setpoint.
- `converter_loss_from::Union{LinearCurve, QuadraticCurve}`: (default: `LinearCurve(0.0)`) Loss model coefficients in the `from` bus converter. It accepts a linear model or quadratic. Same converter data is used in both ends.
- `max_dc_current_from::Float64`: (default: `1e8`) Maximum stable dc current limits (A).
- `rating_from::Float64`: (default: `1e8`) Converter rating in MVA in the `from` bus.
- `reactive_power_limits_from::MinMax`: (default: `(min=0.0, max=0.0)`) Limits on the Reactive Power at the `from` side.
- `power_factor_weighting_fraction_from::Float64`: (default: `1.0`) Power weighting factor fraction used in reducing the active power order and either the reactive power order when the converter rating is violated. When is 0.0, only the active power is reduced; when is 1.0, only the reactive power is reduced; otherwise, a weighted reduction of both active and reactive power is applied., validation range: `(0, 1)`
- `voltage_limits_from::MinMax`: (default: `(min=0.0, max=999.9)`) Limits on the Voltage at the DC `from` Bus in [per unit](@ref per_unit.
- `reactive_power_to::Float64`: (default: `0.0`) Initial condition of reactive power flowing into the to-bus.
- `dc_voltage_control_to::Bool`: (default: `true`) Converter control type in the `to` bus converter. Set true for DC Voltage Control (set DC voltage on the DC side of the converter), and false for power demand in the converter.
- `ac_voltage_control_to::Bool`: (default: `true`) Converter control type in the `to` bus converter. Set true for AC Voltage Control (set AC voltage on the AC side of the converter), and false for fixed power AC factor.
- `dc_setpoint_to::Float64`: (default: `0.0`) Converter DC setpoint in the `to` bus converter. If `voltage_control_to = true` this number is the DC voltage on the DC side of the converter, entered in kV. If `voltage_control_to = false`, this value is the power demand in MW, if positive the converter is supplying power to the AC network at the `to` bus; if negative, the converter is withdrawing power from the AC network at the `to` bus.
- `ac_setpoint_to::Float64`: (default: `1.0`) Converter AC setpoint in the `to` bus converter. If `voltage_control_to = true` this number is the AC voltage on the AC side of the converter, entered in [per unit](@ref per_unit). If `voltage_control_to = false`, this value is the power factor setpoint.
- `converter_loss_to::Union{LinearCurve, QuadraticCurve}`: (default: `LinearCurve(0.0)`) Loss model coefficients in the `to` bus converter. It accepts a linear model or quadratic. Same converter data is used in both ends.
- `max_dc_current_to::Float64`: (default: `1e8`) Maximum stable dc current limits (A).
- `rating_to::Float64`: (default: `1e8`) Converter rating in MVA in the `to` bus.
- `reactive_power_limits_to::MinMax`: (default: `(min=0.0, max=0.0)`) Limits on the Reactive Power at the `to` side.
- `power_factor_weighting_fraction_to::Float64`: (default: `1.0`) Power weighting factor fraction used in reducing the active power order and either the reactive power order when the converter rating is violated. When is 0.0, only the active power is reduced; when is 1.0, only the reactive power is reduced; otherwise, a weighted reduction of both active and reactive power is applied., validation range: `(0, 1)`
- `voltage_limits_to::MinMax`: (default: `(min=0.0, max=999.9)`) Limits on the Voltage at the DC `to` Bus.
- `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct TwoTerminalVSCLine <: TwoTerminalHVDC
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"An [`Arc`](@ref) defining this line `from` a bus `to` another bus"
arc::Arc
"Initial condition of active power flowing from the from-bus to the to-bus in DC."
active_power_flow::Float64
"Maximum output power rating of the converter (MVA)"
rating::Float64
"Minimum and maximum active power flows to the FROM node (MW)"
active_power_limits_from::MinMax
"Minimum and maximum active power flows to the TO node (MW)"
active_power_limits_to::MinMax
"Series conductance of the DC line in pu ([`SYSTEM_BASE`](@ref per_unit))"
g::Float64
"DC current (A) on the converter flowing in the DC line, from `from` bus to `to` bus."
dc_current::Float64
"Initial condition of reactive power flowing into the from-bus."
reactive_power_from::Float64
"Converter control type in the `from` bus converter. Set true for DC Voltage Control (set DC voltage on the DC side of the converter), and false for power demand in the converter."
dc_voltage_control_from::Bool
"Converter control type in the `from` bus converter. Set true for AC Voltage Control (set AC voltage on the AC side of the converter), and false for fixed power AC factor."
ac_voltage_control_from::Bool
"Converter DC setpoint in the `from` bus converter. If `voltage_control_from = true` this number is the DC voltage on the DC side of the converter, entered in kV. If `voltage_control_from = false`, this value is the power demand in MW, if positive the converter is supplying power to the AC network at the `from` bus; if negative, the converter is withdrawing power from the AC network at the `from` bus."
dc_setpoint_from::Float64
"Converter AC setpoint in the `from` bus converter. If `voltage_control_from = true` this number is the AC voltage on the AC side of the converter, entered in [per unit](@ref per_unit). If `voltage_control_from = false`, this value is the power factor setpoint."
ac_setpoint_from::Float64
"Loss model coefficients in the `from` bus converter. It accepts a linear model or quadratic. Same converter data is used in both ends."
converter_loss_from::Union{LinearCurve, QuadraticCurve}
"Maximum stable dc current limits (A)."
max_dc_current_from::Float64
"Converter rating in MVA in the `from` bus."
rating_from::Float64
"Limits on the Reactive Power at the `from` side."
reactive_power_limits_from::MinMax
"Power weighting factor fraction used in reducing the active power order and either the reactive power order when the converter rating is violated. When is 0.0, only the active power is reduced; when is 1.0, only the reactive power is reduced; otherwise, a weighted reduction of both active and reactive power is applied."
power_factor_weighting_fraction_from::Float64
"Limits on the Voltage at the DC `from` Bus in [per unit](@ref per_unit."
voltage_limits_from::MinMax
"Initial condition of reactive power flowing into the to-bus."
reactive_power_to::Float64
"Converter control type in the `to` bus converter. Set true for DC Voltage Control (set DC voltage on the DC side of the converter), and false for power demand in the converter."
dc_voltage_control_to::Bool
"Converter control type in the `to` bus converter. Set true for AC Voltage Control (set AC voltage on the AC side of the converter), and false for fixed power AC factor."
ac_voltage_control_to::Bool
"Converter DC setpoint in the `to` bus converter. If `voltage_control_to = true` this number is the DC voltage on the DC side of the converter, entered in kV. If `voltage_control_to = false`, this value is the power demand in MW, if positive the converter is supplying power to the AC network at the `to` bus; if negative, the converter is withdrawing power from the AC network at the `to` bus."
dc_setpoint_to::Float64
"Converter AC setpoint in the `to` bus converter. If `voltage_control_to = true` this number is the AC voltage on the AC side of the converter, entered in [per unit](@ref per_unit). If `voltage_control_to = false`, this value is the power factor setpoint."
ac_setpoint_to::Float64
"Loss model coefficients in the `to` bus converter. It accepts a linear model or quadratic. Same converter data is used in both ends."
converter_loss_to::Union{LinearCurve, QuadraticCurve}
"Maximum stable dc current limits (A)."
max_dc_current_to::Float64
"Converter rating in MVA in the `to` bus."
rating_to::Float64
"Limits on the Reactive Power at the `to` side."
reactive_power_limits_to::MinMax
"Power weighting factor fraction used in reducing the active power order and either the reactive power order when the converter rating is violated. When is 0.0, only the active power is reduced; when is 1.0, only the reactive power is reduced; otherwise, a weighted reduction of both active and reactive power is applied."
power_factor_weighting_fraction_to::Float64
"Limits on the Voltage at the DC `to` Bus."
voltage_limits_to::MinMax
"Services that this device contributes to"
services::Vector{Service}
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function TwoTerminalVSCLine(name, available, arc, active_power_flow, rating, active_power_limits_from, active_power_limits_to, g=0.0, dc_current=0.0, reactive_power_from=0.0, dc_voltage_control_from=true, ac_voltage_control_from=true, dc_setpoint_from=0.0, ac_setpoint_from=1.0, converter_loss_from=LinearCurve(0.0), max_dc_current_from=1e8, rating_from=1e8, reactive_power_limits_from=(min=0.0, max=0.0), power_factor_weighting_fraction_from=1.0, voltage_limits_from=(min=0.0, max=999.9), reactive_power_to=0.0, dc_voltage_control_to=true, ac_voltage_control_to=true, dc_setpoint_to=0.0, ac_setpoint_to=1.0, converter_loss_to=LinearCurve(0.0), max_dc_current_to=1e8, rating_to=1e8, reactive_power_limits_to=(min=0.0, max=0.0), power_factor_weighting_fraction_to=1.0, voltage_limits_to=(min=0.0, max=999.9), services=Device[], ext=Dict{String, Any}(), )
TwoTerminalVSCLine(name, available, arc, active_power_flow, rating, active_power_limits_from, active_power_limits_to, g, dc_current, reactive_power_from, dc_voltage_control_from, ac_voltage_control_from, dc_setpoint_from, ac_setpoint_from, converter_loss_from, max_dc_current_from, rating_from, reactive_power_limits_from, power_factor_weighting_fraction_from, voltage_limits_from, reactive_power_to, dc_voltage_control_to, ac_voltage_control_to, dc_setpoint_to, ac_setpoint_to, converter_loss_to, max_dc_current_to, rating_to, reactive_power_limits_to, power_factor_weighting_fraction_to, voltage_limits_to, services, ext, InfrastructureSystemsInternal(), )
end
function TwoTerminalVSCLine(; name, available, arc, active_power_flow, rating, active_power_limits_from, active_power_limits_to, g=0.0, dc_current=0.0, reactive_power_from=0.0, dc_voltage_control_from=true, ac_voltage_control_from=true, dc_setpoint_from=0.0, ac_setpoint_from=1.0, converter_loss_from=LinearCurve(0.0), max_dc_current_from=1e8, rating_from=1e8, reactive_power_limits_from=(min=0.0, max=0.0), power_factor_weighting_fraction_from=1.0, voltage_limits_from=(min=0.0, max=999.9), reactive_power_to=0.0, dc_voltage_control_to=true, ac_voltage_control_to=true, dc_setpoint_to=0.0, ac_setpoint_to=1.0, converter_loss_to=LinearCurve(0.0), max_dc_current_to=1e8, rating_to=1e8, reactive_power_limits_to=(min=0.0, max=0.0), power_factor_weighting_fraction_to=1.0, voltage_limits_to=(min=0.0, max=999.9), services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
TwoTerminalVSCLine(name, available, arc, active_power_flow, rating, active_power_limits_from, active_power_limits_to, g, dc_current, reactive_power_from, dc_voltage_control_from, ac_voltage_control_from, dc_setpoint_from, ac_setpoint_from, converter_loss_from, max_dc_current_from, rating_from, reactive_power_limits_from, power_factor_weighting_fraction_from, voltage_limits_from, reactive_power_to, dc_voltage_control_to, ac_voltage_control_to, dc_setpoint_to, ac_setpoint_to, converter_loss_to, max_dc_current_to, rating_to, reactive_power_limits_to, power_factor_weighting_fraction_to, voltage_limits_to, services, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function TwoTerminalVSCLine(::Nothing)
TwoTerminalVSCLine(;
name="init",
available=false,
arc=Arc(ACBus(nothing), ACBus(nothing)),
active_power_flow=0.0,
rating=0.0,
active_power_limits_from=(min=0.0, max=0.0),
active_power_limits_to=(min=0.0, max=0.0),
g=0.0,
dc_current=0.0,
reactive_power_from=0.0,
dc_voltage_control_from=false,
ac_voltage_control_from=false,
dc_setpoint_from=0.0,
ac_setpoint_from=0.0,
converter_loss_from=LinearCurve(0.0),
max_dc_current_from=0.0,
rating_from=0.0,
reactive_power_limits_from=(min=0.0, max=0.0),
power_factor_weighting_fraction_from=0.0,
voltage_limits_from=(min=0.0, max=0.0),
reactive_power_to=0.0,
dc_voltage_control_to=false,
ac_voltage_control_to=false,
dc_setpoint_to=0.0,
ac_setpoint_to=0.0,
converter_loss_to=LinearCurve(0.0),
max_dc_current_to=0.0,
rating_to=0.0,
reactive_power_limits_to=(min=0.0, max=0.0),
power_factor_weighting_fraction_to=0.0,
voltage_limits_to=(min=0.0, max=0.0),
services=Device[],
ext=Dict{String, Any}(),
)
end
"""Get [`TwoTerminalVSCLine`](@ref) `name`."""
get_name(value::TwoTerminalVSCLine) = value.name
"""Get [`TwoTerminalVSCLine`](@ref) `available`."""
get_available(value::TwoTerminalVSCLine) = value.available
"""Get [`TwoTerminalVSCLine`](@ref) `arc`."""
get_arc(value::TwoTerminalVSCLine) = value.arc
"""Get [`TwoTerminalVSCLine`](@ref) `active_power_flow`."""
get_active_power_flow(value::TwoTerminalVSCLine) = get_value(value, Val(:active_power_flow), Val(:mva))
"""Get [`TwoTerminalVSCLine`](@ref) `rating`."""
get_rating(value::TwoTerminalVSCLine) = get_value(value, Val(:rating), Val(:mva))
"""Get [`TwoTerminalVSCLine`](@ref) `active_power_limits_from`."""
get_active_power_limits_from(value::TwoTerminalVSCLine) = get_value(value, Val(:active_power_limits_from), Val(:mva))
"""Get [`TwoTerminalVSCLine`](@ref) `active_power_limits_to`."""
get_active_power_limits_to(value::TwoTerminalVSCLine) = get_value(value, Val(:active_power_limits_to), Val(:mva))
"""Get [`TwoTerminalVSCLine`](@ref) `g`."""
get_g(value::TwoTerminalVSCLine) = value.g
"""Get [`TwoTerminalVSCLine`](@ref) `dc_current`."""
get_dc_current(value::TwoTerminalVSCLine) = value.dc_current
"""Get [`TwoTerminalVSCLine`](@ref) `reactive_power_from`."""
get_reactive_power_from(value::TwoTerminalVSCLine) = get_value(value, Val(:reactive_power_from), Val(:mva))
"""Get [`TwoTerminalVSCLine`](@ref) `dc_voltage_control_from`."""
get_dc_voltage_control_from(value::TwoTerminalVSCLine) = value.dc_voltage_control_from
"""Get [`TwoTerminalVSCLine`](@ref) `ac_voltage_control_from`."""
get_ac_voltage_control_from(value::TwoTerminalVSCLine) = value.ac_voltage_control_from
"""Get [`TwoTerminalVSCLine`](@ref) `dc_setpoint_from`."""
get_dc_setpoint_from(value::TwoTerminalVSCLine) = value.dc_setpoint_from
"""Get [`TwoTerminalVSCLine`](@ref) `ac_setpoint_from`."""
get_ac_setpoint_from(value::TwoTerminalVSCLine) = value.ac_setpoint_from
"""Get [`TwoTerminalVSCLine`](@ref) `converter_loss_from`."""
get_converter_loss_from(value::TwoTerminalVSCLine) = value.converter_loss_from
"""Get [`TwoTerminalVSCLine`](@ref) `max_dc_current_from`."""
get_max_dc_current_from(value::TwoTerminalVSCLine) = value.max_dc_current_from
"""Get [`TwoTerminalVSCLine`](@ref) `rating_from`."""
get_rating_from(value::TwoTerminalVSCLine) = get_value(value, Val(:rating_from), Val(:mva))
"""Get [`TwoTerminalVSCLine`](@ref) `reactive_power_limits_from`."""
get_reactive_power_limits_from(value::TwoTerminalVSCLine) = get_value(value, Val(:reactive_power_limits_from), Val(:mva))
"""Get [`TwoTerminalVSCLine`](@ref) `power_factor_weighting_fraction_from`."""
get_power_factor_weighting_fraction_from(value::TwoTerminalVSCLine) = value.power_factor_weighting_fraction_from
"""Get [`TwoTerminalVSCLine`](@ref) `voltage_limits_from`."""
get_voltage_limits_from(value::TwoTerminalVSCLine) = value.voltage_limits_from
"""Get [`TwoTerminalVSCLine`](@ref) `reactive_power_to`."""
get_reactive_power_to(value::TwoTerminalVSCLine) = get_value(value, Val(:reactive_power_to), Val(:mva))
"""Get [`TwoTerminalVSCLine`](@ref) `dc_voltage_control_to`."""
get_dc_voltage_control_to(value::TwoTerminalVSCLine) = value.dc_voltage_control_to
"""Get [`TwoTerminalVSCLine`](@ref) `ac_voltage_control_to`."""
get_ac_voltage_control_to(value::TwoTerminalVSCLine) = value.ac_voltage_control_to
"""Get [`TwoTerminalVSCLine`](@ref) `dc_setpoint_to`."""
get_dc_setpoint_to(value::TwoTerminalVSCLine) = value.dc_setpoint_to
"""Get [`TwoTerminalVSCLine`](@ref) `ac_setpoint_to`."""
get_ac_setpoint_to(value::TwoTerminalVSCLine) = value.ac_setpoint_to
"""Get [`TwoTerminalVSCLine`](@ref) `converter_loss_to`."""
get_converter_loss_to(value::TwoTerminalVSCLine) = value.converter_loss_to
"""Get [`TwoTerminalVSCLine`](@ref) `max_dc_current_to`."""
get_max_dc_current_to(value::TwoTerminalVSCLine) = value.max_dc_current_to
"""Get [`TwoTerminalVSCLine`](@ref) `rating_to`."""
get_rating_to(value::TwoTerminalVSCLine) = get_value(value, Val(:rating_to), Val(:mva))
"""Get [`TwoTerminalVSCLine`](@ref) `reactive_power_limits_to`."""
get_reactive_power_limits_to(value::TwoTerminalVSCLine) = get_value(value, Val(:reactive_power_limits_to), Val(:mva))
"""Get [`TwoTerminalVSCLine`](@ref) `power_factor_weighting_fraction_to`."""
get_power_factor_weighting_fraction_to(value::TwoTerminalVSCLine) = value.power_factor_weighting_fraction_to
"""Get [`TwoTerminalVSCLine`](@ref) `voltage_limits_to`."""
get_voltage_limits_to(value::TwoTerminalVSCLine) = value.voltage_limits_to
"""Get [`TwoTerminalVSCLine`](@ref) `services`."""
get_services(value::TwoTerminalVSCLine) = value.services
"""Get [`TwoTerminalVSCLine`](@ref) `ext`."""
get_ext(value::TwoTerminalVSCLine) = value.ext
"""Get [`TwoTerminalVSCLine`](@ref) `internal`."""
get_internal(value::TwoTerminalVSCLine) = value.internal
"""Set [`TwoTerminalVSCLine`](@ref) `available`."""
set_available!(value::TwoTerminalVSCLine, val) = value.available = val
"""Set [`TwoTerminalVSCLine`](@ref) `arc`."""
set_arc!(value::TwoTerminalVSCLine, val) = value.arc = val
"""Set [`TwoTerminalVSCLine`](@ref) `active_power_flow`."""
set_active_power_flow!(value::TwoTerminalVSCLine, val) = value.active_power_flow = set_value(value, Val(:active_power_flow), val, Val(:mva))
"""Set [`TwoTerminalVSCLine`](@ref) `rating`."""
set_rating!(value::TwoTerminalVSCLine, val) = value.rating = set_value(value, Val(:rating), val, Val(:mva))
"""Set [`TwoTerminalVSCLine`](@ref) `active_power_limits_from`."""
set_active_power_limits_from!(value::TwoTerminalVSCLine, val) = value.active_power_limits_from = set_value(value, Val(:active_power_limits_from), val, Val(:mva))
"""Set [`TwoTerminalVSCLine`](@ref) `active_power_limits_to`."""
set_active_power_limits_to!(value::TwoTerminalVSCLine, val) = value.active_power_limits_to = set_value(value, Val(:active_power_limits_to), val, Val(:mva))
"""Set [`TwoTerminalVSCLine`](@ref) `g`."""
set_g!(value::TwoTerminalVSCLine, val) = value.g = val
"""Set [`TwoTerminalVSCLine`](@ref) `dc_current`."""
set_dc_current!(value::TwoTerminalVSCLine, val) = value.dc_current = val
"""Set [`TwoTerminalVSCLine`](@ref) `reactive_power_from`."""
set_reactive_power_from!(value::TwoTerminalVSCLine, val) = value.reactive_power_from = set_value(value, Val(:reactive_power_from), val, Val(:mva))
"""Set [`TwoTerminalVSCLine`](@ref) `dc_voltage_control_from`."""
set_dc_voltage_control_from!(value::TwoTerminalVSCLine, val) = value.dc_voltage_control_from = val
"""Set [`TwoTerminalVSCLine`](@ref) `ac_voltage_control_from`."""
set_ac_voltage_control_from!(value::TwoTerminalVSCLine, val) = value.ac_voltage_control_from = val
"""Set [`TwoTerminalVSCLine`](@ref) `dc_setpoint_from`."""
set_dc_setpoint_from!(value::TwoTerminalVSCLine, val) = value.dc_setpoint_from = val
"""Set [`TwoTerminalVSCLine`](@ref) `ac_setpoint_from`."""
set_ac_setpoint_from!(value::TwoTerminalVSCLine, val) = value.ac_setpoint_from = val
"""Set [`TwoTerminalVSCLine`](@ref) `converter_loss_from`."""
set_converter_loss_from!(value::TwoTerminalVSCLine, val) = value.converter_loss_from = val
"""Set [`TwoTerminalVSCLine`](@ref) `max_dc_current_from`."""
set_max_dc_current_from!(value::TwoTerminalVSCLine, val) = value.max_dc_current_from = val
"""Set [`TwoTerminalVSCLine`](@ref) `rating_from`."""
set_rating_from!(value::TwoTerminalVSCLine, val) = value.rating_from = set_value(value, Val(:rating_from), val, Val(:mva))
"""Set [`TwoTerminalVSCLine`](@ref) `reactive_power_limits_from`."""
set_reactive_power_limits_from!(value::TwoTerminalVSCLine, val) = value.reactive_power_limits_from = set_value(value, Val(:reactive_power_limits_from), val, Val(:mva))
"""Set [`TwoTerminalVSCLine`](@ref) `power_factor_weighting_fraction_from`."""
set_power_factor_weighting_fraction_from!(value::TwoTerminalVSCLine, val) = value.power_factor_weighting_fraction_from = val
"""Set [`TwoTerminalVSCLine`](@ref) `voltage_limits_from`."""
set_voltage_limits_from!(value::TwoTerminalVSCLine, val) = value.voltage_limits_from = val
"""Set [`TwoTerminalVSCLine`](@ref) `reactive_power_to`."""
set_reactive_power_to!(value::TwoTerminalVSCLine, val) = value.reactive_power_to = set_value(value, Val(:reactive_power_to), val, Val(:mva))
"""Set [`TwoTerminalVSCLine`](@ref) `dc_voltage_control_to`."""
set_dc_voltage_control_to!(value::TwoTerminalVSCLine, val) = value.dc_voltage_control_to = val
"""Set [`TwoTerminalVSCLine`](@ref) `ac_voltage_control_to`."""
set_ac_voltage_control_to!(value::TwoTerminalVSCLine, val) = value.ac_voltage_control_to = val
"""Set [`TwoTerminalVSCLine`](@ref) `dc_setpoint_to`."""
set_dc_setpoint_to!(value::TwoTerminalVSCLine, val) = value.dc_setpoint_to = val
"""Set [`TwoTerminalVSCLine`](@ref) `ac_setpoint_to`."""
set_ac_setpoint_to!(value::TwoTerminalVSCLine, val) = value.ac_setpoint_to = val
"""Set [`TwoTerminalVSCLine`](@ref) `converter_loss_to`."""
set_converter_loss_to!(value::TwoTerminalVSCLine, val) = value.converter_loss_to = val
"""Set [`TwoTerminalVSCLine`](@ref) `max_dc_current_to`."""
set_max_dc_current_to!(value::TwoTerminalVSCLine, val) = value.max_dc_current_to = val
"""Set [`TwoTerminalVSCLine`](@ref) `rating_to`."""
set_rating_to!(value::TwoTerminalVSCLine, val) = value.rating_to = set_value(value, Val(:rating_to), val, Val(:mva))
"""Set [`TwoTerminalVSCLine`](@ref) `reactive_power_limits_to`."""
set_reactive_power_limits_to!(value::TwoTerminalVSCLine, val) = value.reactive_power_limits_to = set_value(value, Val(:reactive_power_limits_to), val, Val(:mva))
"""Set [`TwoTerminalVSCLine`](@ref) `power_factor_weighting_fraction_to`."""
set_power_factor_weighting_fraction_to!(value::TwoTerminalVSCLine, val) = value.power_factor_weighting_fraction_to = val
"""Set [`TwoTerminalVSCLine`](@ref) `voltage_limits_to`."""
set_voltage_limits_to!(value::TwoTerminalVSCLine, val) = value.voltage_limits_to = val
"""Set [`TwoTerminalVSCLine`](@ref) `services`."""
set_services!(value::TwoTerminalVSCLine, val) = value.services = val
"""Set [`TwoTerminalVSCLine`](@ref) `ext`."""
set_ext!(value::TwoTerminalVSCLine, val) = value.ext = val
================================================
FILE: src/models/generated/VariableReserve.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct VariableReserve{T <: ReserveDirection} <: Reserve{T}
name::String
available::Bool
time_frame::Float64
requirement::Float64
sustained_time::Float64
max_output_fraction::Float64
max_participation_factor::Float64
deployed_fraction::Float64
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A reserve product with a time-varying procurement requirement, such as a higher requirement during hours with an expected high load or high ramp.
This reserve product includes online generators that can respond right away after an unexpected contingency, such as a transmission line or generator outage. When defining the reserve, the `ReserveDirection` must be specified to define this as a [`ReserveUp`](@ref), [`ReserveDown`](@ref), or [`ReserveSymmetric`](@ref). To model the time varying requirement, a ["`requirement`" time series should be added](@ref ts_data) to this reserve
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `time_frame::Float64`: the saturation time_frame in minutes to provide reserve contribution, validation range: `(0, nothing)`
- `requirement::Float64`: the required quantity of the product should be scaled by a TimeSeriesData
- `sustained_time::Float64`: (default: `3600.0`) the time in seconds reserve contribution must sustained at a specified level, validation range: `(0, nothing)`
- `max_output_fraction::Float64`: (default: `1.0`) the maximum fraction of each device's output that can be assigned to the service, validation range: `(0, 1)`
- `max_participation_factor::Float64`: (default: `1.0`) the maximum portion [0, 1.0] of the reserve that can be contributed per device, validation range: `(0, 1)`
- `deployed_fraction::Float64`: (default: `0.0`) Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0, validation range: `(0, 1)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct VariableReserve{T <: ReserveDirection} <: Reserve{T}
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"the saturation time_frame in minutes to provide reserve contribution"
time_frame::Float64
"the required quantity of the product should be scaled by a TimeSeriesData"
requirement::Float64
"the time in seconds reserve contribution must sustained at a specified level"
sustained_time::Float64
"the maximum fraction of each device's output that can be assigned to the service"
max_output_fraction::Float64
"the maximum portion [0, 1.0] of the reserve that can be contributed per device"
max_participation_factor::Float64
"Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0"
deployed_fraction::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function VariableReserve{T}(name, available, time_frame, requirement, sustained_time=3600.0, max_output_fraction=1.0, max_participation_factor=1.0, deployed_fraction=0.0, ext=Dict{String, Any}(), ) where T <: ReserveDirection
VariableReserve{T}(name, available, time_frame, requirement, sustained_time, max_output_fraction, max_participation_factor, deployed_fraction, ext, InfrastructureSystemsInternal(), )
end
function VariableReserve{T}(; name, available, time_frame, requirement, sustained_time=3600.0, max_output_fraction=1.0, max_participation_factor=1.0, deployed_fraction=0.0, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), ) where T <: ReserveDirection
VariableReserve{T}(name, available, time_frame, requirement, sustained_time, max_output_fraction, max_participation_factor, deployed_fraction, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function VariableReserve{T}(::Nothing) where T <: ReserveDirection
VariableReserve{T}(;
name="init",
available=false,
time_frame=0.0,
requirement=0.0,
sustained_time=0.0,
max_output_fraction=1.0,
max_participation_factor=1.0,
deployed_fraction=0.0,
ext=Dict{String, Any}(),
)
end
"""Get [`VariableReserve`](@ref) `name`."""
get_name(value::VariableReserve) = value.name
"""Get [`VariableReserve`](@ref) `available`."""
get_available(value::VariableReserve) = value.available
"""Get [`VariableReserve`](@ref) `time_frame`."""
get_time_frame(value::VariableReserve) = value.time_frame
"""Get [`VariableReserve`](@ref) `requirement`."""
get_requirement(value::VariableReserve) = value.requirement
"""Get [`VariableReserve`](@ref) `sustained_time`."""
get_sustained_time(value::VariableReserve) = value.sustained_time
"""Get [`VariableReserve`](@ref) `max_output_fraction`."""
get_max_output_fraction(value::VariableReserve) = value.max_output_fraction
"""Get [`VariableReserve`](@ref) `max_participation_factor`."""
get_max_participation_factor(value::VariableReserve) = value.max_participation_factor
"""Get [`VariableReserve`](@ref) `deployed_fraction`."""
get_deployed_fraction(value::VariableReserve) = value.deployed_fraction
"""Get [`VariableReserve`](@ref) `ext`."""
get_ext(value::VariableReserve) = value.ext
"""Get [`VariableReserve`](@ref) `internal`."""
get_internal(value::VariableReserve) = value.internal
"""Set [`VariableReserve`](@ref) `available`."""
set_available!(value::VariableReserve, val) = value.available = val
"""Set [`VariableReserve`](@ref) `time_frame`."""
set_time_frame!(value::VariableReserve, val) = value.time_frame = val
"""Set [`VariableReserve`](@ref) `requirement`."""
set_requirement!(value::VariableReserve, val) = value.requirement = val
"""Set [`VariableReserve`](@ref) `sustained_time`."""
set_sustained_time!(value::VariableReserve, val) = value.sustained_time = val
"""Set [`VariableReserve`](@ref) `max_output_fraction`."""
set_max_output_fraction!(value::VariableReserve, val) = value.max_output_fraction = val
"""Set [`VariableReserve`](@ref) `max_participation_factor`."""
set_max_participation_factor!(value::VariableReserve, val) = value.max_participation_factor = val
"""Set [`VariableReserve`](@ref) `deployed_fraction`."""
set_deployed_fraction!(value::VariableReserve, val) = value.deployed_fraction = val
"""Set [`VariableReserve`](@ref) `ext`."""
set_ext!(value::VariableReserve, val) = value.ext = val
================================================
FILE: src/models/generated/VariableReserveNonSpinning.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct VariableReserveNonSpinning <: ReserveNonSpinning
name::String
available::Bool
time_frame::Float64
requirement::Float64
sustained_time::Float64
max_output_fraction::Float64
max_participation_factor::Float64
deployed_fraction::Float64
ext::Dict{String, Any}
internal::InfrastructureSystemsInternal
end
A non-spinning reserve product with a time-varying procurement requirement, such as a higher requirement during hours with an expected high load or high ramp.
This reserve product includes back-up generators that might not be currently synchronized with the power system, but can come online quickly after an unexpected contingency, such as a transmission line or generator outage. To model the time varying requirement, a ["`requirement`" time series should be added](@ref ts_data) to this reserve.
This is only an upwards reserve. For faster-responding upwards or downwards reserves from components already synchronized with the system, see [`VariableReserve`](@ref)
# Arguments
- `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name
- `available::Bool`: Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations
- `time_frame::Float64`: the saturation time_frame in minutes to provide reserve contribution, validation range: `(0, nothing)`
- `requirement::Float64`: the required quantity of the product should be scaled by a TimeSeriesData
- `sustained_time::Float64`: (default: `14400.0`) the time in seconds reserve contribution must sustained at a specified level, validation range: `(0, nothing)`
- `max_output_fraction::Float64`: (default: `1.0`) the maximum fraction of each device's output that can be assigned to the service, validation range: `(0, 1)`
- `max_participation_factor::Float64`: (default: `1.0`) the maximum portion [0, 1.0] of the reserve that can be contributed per device, validation range: `(0, 1)`
- `deployed_fraction::Float64`: (default: `0.0`) Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0, validation range: `(0, 1)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct VariableReserveNonSpinning <: ReserveNonSpinning
"Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name"
name::String
"Indicator of whether the component is connected and online (`true`) or disconnected, offline, or down (`false`). Unavailable components are excluded during simulations"
available::Bool
"the saturation time_frame in minutes to provide reserve contribution"
time_frame::Float64
"the required quantity of the product should be scaled by a TimeSeriesData"
requirement::Float64
"the time in seconds reserve contribution must sustained at a specified level"
sustained_time::Float64
"the maximum fraction of each device's output that can be assigned to the service"
max_output_fraction::Float64
"the maximum portion [0, 1.0] of the reserve that can be contributed per device"
max_participation_factor::Float64
"Fraction of service procurement that is assumed to be actually deployed. Most commonly, this is assumed to be either 0.0 or 1.0"
deployed_fraction::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function VariableReserveNonSpinning(name, available, time_frame, requirement, sustained_time=14400.0, max_output_fraction=1.0, max_participation_factor=1.0, deployed_fraction=0.0, ext=Dict{String, Any}(), )
VariableReserveNonSpinning(name, available, time_frame, requirement, sustained_time, max_output_fraction, max_participation_factor, deployed_fraction, ext, InfrastructureSystemsInternal(), )
end
function VariableReserveNonSpinning(; name, available, time_frame, requirement, sustained_time=14400.0, max_output_fraction=1.0, max_participation_factor=1.0, deployed_fraction=0.0, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), )
VariableReserveNonSpinning(name, available, time_frame, requirement, sustained_time, max_output_fraction, max_participation_factor, deployed_fraction, ext, internal, )
end
# Constructor for demo purposes; non-functional.
function VariableReserveNonSpinning(::Nothing)
VariableReserveNonSpinning(;
name="init",
available=false,
time_frame=0.0,
requirement=0.0,
sustained_time=0.0,
max_output_fraction=1.0,
max_participation_factor=1.0,
deployed_fraction=0.0,
ext=Dict{String, Any}(),
)
end
"""Get [`VariableReserveNonSpinning`](@ref) `name`."""
get_name(value::VariableReserveNonSpinning) = value.name
"""Get [`VariableReserveNonSpinning`](@ref) `available`."""
get_available(value::VariableReserveNonSpinning) = value.available
"""Get [`VariableReserveNonSpinning`](@ref) `time_frame`."""
get_time_frame(value::VariableReserveNonSpinning) = value.time_frame
"""Get [`VariableReserveNonSpinning`](@ref) `requirement`."""
get_requirement(value::VariableReserveNonSpinning) = get_value(value, Val(:requirement), Val(:mva))
"""Get [`VariableReserveNonSpinning`](@ref) `sustained_time`."""
get_sustained_time(value::VariableReserveNonSpinning) = value.sustained_time
"""Get [`VariableReserveNonSpinning`](@ref) `max_output_fraction`."""
get_max_output_fraction(value::VariableReserveNonSpinning) = value.max_output_fraction
"""Get [`VariableReserveNonSpinning`](@ref) `max_participation_factor`."""
get_max_participation_factor(value::VariableReserveNonSpinning) = value.max_participation_factor
"""Get [`VariableReserveNonSpinning`](@ref) `deployed_fraction`."""
get_deployed_fraction(value::VariableReserveNonSpinning) = value.deployed_fraction
"""Get [`VariableReserveNonSpinning`](@ref) `ext`."""
get_ext(value::VariableReserveNonSpinning) = value.ext
"""Get [`VariableReserveNonSpinning`](@ref) `internal`."""
get_internal(value::VariableReserveNonSpinning) = value.internal
"""Set [`VariableReserveNonSpinning`](@ref) `available`."""
set_available!(value::VariableReserveNonSpinning, val) = value.available = val
"""Set [`VariableReserveNonSpinning`](@ref) `time_frame`."""
set_time_frame!(value::VariableReserveNonSpinning, val) = value.time_frame = val
"""Set [`VariableReserveNonSpinning`](@ref) `requirement`."""
set_requirement!(value::VariableReserveNonSpinning, val) = value.requirement = set_value(value, Val(:requirement), val, Val(:mva))
"""Set [`VariableReserveNonSpinning`](@ref) `sustained_time`."""
set_sustained_time!(value::VariableReserveNonSpinning, val) = value.sustained_time = val
"""Set [`VariableReserveNonSpinning`](@ref) `max_output_fraction`."""
set_max_output_fraction!(value::VariableReserveNonSpinning, val) = value.max_output_fraction = val
"""Set [`VariableReserveNonSpinning`](@ref) `max_participation_factor`."""
set_max_participation_factor!(value::VariableReserveNonSpinning, val) = value.max_participation_factor = val
"""Set [`VariableReserveNonSpinning`](@ref) `deployed_fraction`."""
set_deployed_fraction!(value::VariableReserveNonSpinning, val) = value.deployed_fraction = val
"""Set [`VariableReserveNonSpinning`](@ref) `ext`."""
set_ext!(value::VariableReserveNonSpinning, val) = value.ext = val
================================================
FILE: src/models/generated/VirtualInertia.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct VirtualInertia <: ActivePowerControl
Ta::Float64
kd::Float64
kω::Float64
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of a Virtual Inertia with SRF using VSM for active power controller
# Arguments
- `Ta::Float64`: VSM inertia constant, validation range: `(0, nothing)`
- `kd::Float64`: VSM damping constant, validation range: `(0, nothing)`
- `kω::Float64`: frequency droop gain, validation range: `(0, nothing)`
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the VirtualInertia model are:
θ_oc: Phase angle displacement of the virtual synchronous generator model
ω_oc: Speed of the rotating reference frame of the virtual synchronous generator model
- `n_states::Int`: (**Do not modify.**) VirtualInertia has two states
"""
mutable struct VirtualInertia <: ActivePowerControl
"VSM inertia constant"
Ta::Float64
"VSM damping constant"
kd::Float64
"frequency droop gain"
kω::Float64
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the VirtualInertia model are:
θ_oc: Phase angle displacement of the virtual synchronous generator model
ω_oc: Speed of the rotating reference frame of the virtual synchronous generator model"
states::Vector{Symbol}
"(**Do not modify.**) VirtualInertia has two states"
n_states::Int
end
function VirtualInertia(Ta, kd, kω, P_ref=1.0, ext=Dict{String, Any}(), )
VirtualInertia(Ta, kd, kω, P_ref, ext, [:θ_oc, :ω_oc], 2, )
end
function VirtualInertia(; Ta, kd, kω, P_ref=1.0, ext=Dict{String, Any}(), states=[:θ_oc, :ω_oc], n_states=2, )
VirtualInertia(Ta, kd, kω, P_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function VirtualInertia(::Nothing)
VirtualInertia(;
Ta=0,
kd=0,
kω=0,
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`VirtualInertia`](@ref) `Ta`."""
get_Ta(value::VirtualInertia) = value.Ta
"""Get [`VirtualInertia`](@ref) `kd`."""
get_kd(value::VirtualInertia) = value.kd
"""Get [`VirtualInertia`](@ref) `kω`."""
get_kω(value::VirtualInertia) = value.kω
"""Get [`VirtualInertia`](@ref) `P_ref`."""
get_P_ref(value::VirtualInertia) = value.P_ref
"""Get [`VirtualInertia`](@ref) `ext`."""
get_ext(value::VirtualInertia) = value.ext
"""Get [`VirtualInertia`](@ref) `states`."""
get_states(value::VirtualInertia) = value.states
"""Get [`VirtualInertia`](@ref) `n_states`."""
get_n_states(value::VirtualInertia) = value.n_states
"""Set [`VirtualInertia`](@ref) `Ta`."""
set_Ta!(value::VirtualInertia, val) = value.Ta = val
"""Set [`VirtualInertia`](@ref) `kd`."""
set_kd!(value::VirtualInertia, val) = value.kd = val
"""Set [`VirtualInertia`](@ref) `kω`."""
set_kω!(value::VirtualInertia, val) = value.kω = val
"""Set [`VirtualInertia`](@ref) `P_ref`."""
set_P_ref!(value::VirtualInertia, val) = value.P_ref = val
"""Set [`VirtualInertia`](@ref) `ext`."""
set_ext!(value::VirtualInertia, val) = value.ext = val
================================================
FILE: src/models/generated/VoltageModeControl.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct VoltageModeControl <: InnerControl
kpv::Float64
kiv::Float64
kffv::Float64
rv::Float64
lv::Float64
kpc::Float64
kic::Float64
kffi::Float64
ωad::Float64
kad::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters of an inner loop current control PID using virtual impedance based on ["A Virtual Synchronous Machine implementation for distributed control of power converters in SmartGrids."](https://doi.org/10.1016/j.epsr.2015.01.001)
# Arguments
- `kpv::Float64`: voltage controller proportional gain, validation range: `(0, nothing)`
- `kiv::Float64`: voltage controller integral gain, validation range: `(0, nothing)`
- `kffv::Float64`: Binary variable to enable feed-forward gain of voltage, validation range: `(0, nothing)`
- `rv::Float64`: virtual resistance, validation range: `(0, nothing)`
- `lv::Float64`: virtual inductance, validation range: `(0, nothing)`
- `kpc::Float64`: current controller proportional gain, validation range: `(0, nothing)`
- `kic::Float64`: current controller integral gain, validation range: `(0, nothing)`
- `kffi::Float64`: Binary variable to enable feed-forward gain of current, validation range: `(0, nothing)`
- `ωad::Float64`: active damping filter cutoff frequency (rad/sec), validation range: `(0, nothing)`
- `kad::Float64`: active damping gain, validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the VoltageModeControl model are:
ξd_ic: d-axis integrator state of the PI voltage controller,
ξq_ic: q-axis integrator state of the PI voltage controller,
γd_ic: d-axis integrator state of the PI current controller,
γq_ic: q-axis integrator state of the PI current controller,
ϕd_ic: d-axis low-pass filter of active damping,
ϕq_ic: q-axis low-pass filter of active damping
- `n_states::Int`: (**Do not modify.**) VoltageModeControl has 6 states
"""
mutable struct VoltageModeControl <: InnerControl
"voltage controller proportional gain"
kpv::Float64
"voltage controller integral gain"
kiv::Float64
"Binary variable to enable feed-forward gain of voltage"
kffv::Float64
"virtual resistance"
rv::Float64
"virtual inductance"
lv::Float64
"current controller proportional gain"
kpc::Float64
"current controller integral gain"
kic::Float64
"Binary variable to enable feed-forward gain of current"
kffi::Float64
"active damping filter cutoff frequency (rad/sec)"
ωad::Float64
"active damping gain"
kad::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the VoltageModeControl model are:
ξd_ic: d-axis integrator state of the PI voltage controller,
ξq_ic: q-axis integrator state of the PI voltage controller,
γd_ic: d-axis integrator state of the PI current controller,
γq_ic: q-axis integrator state of the PI current controller,
ϕd_ic: d-axis low-pass filter of active damping,
ϕq_ic: q-axis low-pass filter of active damping"
states::Vector{Symbol}
"(**Do not modify.**) VoltageModeControl has 6 states"
n_states::Int
end
function VoltageModeControl(kpv, kiv, kffv, rv, lv, kpc, kic, kffi, ωad, kad, ext=Dict{String, Any}(), )
VoltageModeControl(kpv, kiv, kffv, rv, lv, kpc, kic, kffi, ωad, kad, ext, [:ξd_ic, :ξq_ic, :γd_ic, :γq_ic, :ϕd_ic, :ϕq_ic], 6, )
end
function VoltageModeControl(; kpv, kiv, kffv, rv, lv, kpc, kic, kffi, ωad, kad, ext=Dict{String, Any}(), states=[:ξd_ic, :ξq_ic, :γd_ic, :γq_ic, :ϕd_ic, :ϕq_ic], n_states=6, )
VoltageModeControl(kpv, kiv, kffv, rv, lv, kpc, kic, kffi, ωad, kad, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function VoltageModeControl(::Nothing)
VoltageModeControl(;
kpv=0,
kiv=0,
kffv=0,
rv=0,
lv=0,
kpc=0,
kic=0,
kffi=0,
ωad=0,
kad=0,
ext=Dict{String, Any}(),
)
end
"""Get [`VoltageModeControl`](@ref) `kpv`."""
get_kpv(value::VoltageModeControl) = value.kpv
"""Get [`VoltageModeControl`](@ref) `kiv`."""
get_kiv(value::VoltageModeControl) = value.kiv
"""Get [`VoltageModeControl`](@ref) `kffv`."""
get_kffv(value::VoltageModeControl) = value.kffv
"""Get [`VoltageModeControl`](@ref) `rv`."""
get_rv(value::VoltageModeControl) = value.rv
"""Get [`VoltageModeControl`](@ref) `lv`."""
get_lv(value::VoltageModeControl) = value.lv
"""Get [`VoltageModeControl`](@ref) `kpc`."""
get_kpc(value::VoltageModeControl) = value.kpc
"""Get [`VoltageModeControl`](@ref) `kic`."""
get_kic(value::VoltageModeControl) = value.kic
"""Get [`VoltageModeControl`](@ref) `kffi`."""
get_kffi(value::VoltageModeControl) = value.kffi
"""Get [`VoltageModeControl`](@ref) `ωad`."""
get_ωad(value::VoltageModeControl) = value.ωad
"""Get [`VoltageModeControl`](@ref) `kad`."""
get_kad(value::VoltageModeControl) = value.kad
"""Get [`VoltageModeControl`](@ref) `ext`."""
get_ext(value::VoltageModeControl) = value.ext
"""Get [`VoltageModeControl`](@ref) `states`."""
get_states(value::VoltageModeControl) = value.states
"""Get [`VoltageModeControl`](@ref) `n_states`."""
get_n_states(value::VoltageModeControl) = value.n_states
"""Set [`VoltageModeControl`](@ref) `kpv`."""
set_kpv!(value::VoltageModeControl, val) = value.kpv = val
"""Set [`VoltageModeControl`](@ref) `kiv`."""
set_kiv!(value::VoltageModeControl, val) = value.kiv = val
"""Set [`VoltageModeControl`](@ref) `kffv`."""
set_kffv!(value::VoltageModeControl, val) = value.kffv = val
"""Set [`VoltageModeControl`](@ref) `rv`."""
set_rv!(value::VoltageModeControl, val) = value.rv = val
"""Set [`VoltageModeControl`](@ref) `lv`."""
set_lv!(value::VoltageModeControl, val) = value.lv = val
"""Set [`VoltageModeControl`](@ref) `kpc`."""
set_kpc!(value::VoltageModeControl, val) = value.kpc = val
"""Set [`VoltageModeControl`](@ref) `kic`."""
set_kic!(value::VoltageModeControl, val) = value.kic = val
"""Set [`VoltageModeControl`](@ref) `kffi`."""
set_kffi!(value::VoltageModeControl, val) = value.kffi = val
"""Set [`VoltageModeControl`](@ref) `ωad`."""
set_ωad!(value::VoltageModeControl, val) = value.ωad = val
"""Set [`VoltageModeControl`](@ref) `kad`."""
set_kad!(value::VoltageModeControl, val) = value.kad = val
"""Set [`VoltageModeControl`](@ref) `ext`."""
set_ext!(value::VoltageModeControl, val) = value.ext = val
================================================
FILE: src/models/generated/WPIDHY.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct WPIDHY <: TurbineGov
T_reg::Float64
reg::Float64
Kp::Float64
Ki::Float64
Kd::Float64
Ta::Float64
Tb::Float64
V_lim::MinMax
G_lim::MinMax
Tw::Float64
P_lim::MinMax
D::Float64
gate_openings::Tuple{Float64, Float64, Float64}
power_gate_openings::Tuple{Float64, Float64, Float64}
P_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
states_types::Vector{StateTypes}
internal::InfrastructureSystemsInternal
end
Woodward PID Hydro Governor
# Arguments
- `T_reg::Float64`: Input time constant of the governor in s, validation range: `(0, nothing)`
- `reg::Float64`: Input governor gain, validation range: `(0, nothing)`
- `Kp::Float64`: Governor proportional gain, validation range: `(0, nothing)`
- `Ki::Float64`: Governor integral gain, validation range: `(0, nothing)`
- `Kd::Float64`: Governor derivative gain, validation range: `(0, nothing)`
- `Ta::Float64`: Governor derivative/high-frequency time constant, validation range: `(0, nothing)`
- `Tb::Float64`: Gate-servo time constant, validation range: `(0, nothing)`
- `V_lim::MinMax`: Gate opening velocity limits `(G_min, G_max)`.
- `G_lim::MinMax`: Minimum/Maximum Gate velocity `(G_min, G_max)`.
- `Tw::Float64`: Water inertia time constant, sec, validation range: `(eps(), nothing)`
- `P_lim::MinMax`: Minimum/Maximum Gate openings `(P_min, P_max)`.
- `D::Float64`: Turbine damping coefficient, validation range: `(0, nothing)`
- `gate_openings::Tuple{Float64, Float64, Float64}`: Gate-opening speed at different loads
- `power_gate_openings::Tuple{Float64, Float64, Float64}`: Power at gate_openings
- `P_ref::Float64`: (default: `1.0`) Reference Power Set-point (pu), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the PIDGOV model are:
x_g1: Filtered input measurement,
x_g2: PI block internal state,
x_g3: First regulator state,
x_g4: Derivative block internal state,
x_g5: Second regulator state,
x_g6: Gate position state,
x_g7: Water inertia state
- `n_states::Int`: (**Do not modify.**) PIDGOV has 7 states
- `states_types::Vector{StateTypes}`: (**Do not modify.**) PIDGOV has 7 [differential](@ref states_list) [states](@ref S)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference
"""
mutable struct WPIDHY <: TurbineGov
"Input time constant of the governor in s"
T_reg::Float64
"Input governor gain"
reg::Float64
"Governor proportional gain"
Kp::Float64
"Governor integral gain"
Ki::Float64
"Governor derivative gain"
Kd::Float64
"Governor derivative/high-frequency time constant"
Ta::Float64
"Gate-servo time constant"
Tb::Float64
"Gate opening velocity limits `(G_min, G_max)`."
V_lim::MinMax
"Minimum/Maximum Gate velocity `(G_min, G_max)`."
G_lim::MinMax
"Water inertia time constant, sec"
Tw::Float64
"Minimum/Maximum Gate openings `(P_min, P_max)`."
P_lim::MinMax
"Turbine damping coefficient"
D::Float64
"Gate-opening speed at different loads"
gate_openings::Tuple{Float64, Float64, Float64}
"Power at gate_openings"
power_gate_openings::Tuple{Float64, Float64, Float64}
"Reference Power Set-point (pu)"
P_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the PIDGOV model are:
x_g1: Filtered input measurement,
x_g2: PI block internal state,
x_g3: First regulator state,
x_g4: Derivative block internal state,
x_g5: Second regulator state,
x_g6: Gate position state,
x_g7: Water inertia state"
states::Vector{Symbol}
"(**Do not modify.**) PIDGOV has 7 states"
n_states::Int
"(**Do not modify.**) PIDGOV has 7 [differential](@ref states_list) [states](@ref S)"
states_types::Vector{StateTypes}
"(**Do not modify.**) PowerSystems.jl internal reference"
internal::InfrastructureSystemsInternal
end
function WPIDHY(T_reg, reg, Kp, Ki, Kd, Ta, Tb, V_lim, G_lim, Tw, P_lim, D, gate_openings, power_gate_openings, P_ref=1.0, ext=Dict{String, Any}(), )
WPIDHY(T_reg, reg, Kp, Ki, Kd, Ta, Tb, V_lim, G_lim, Tw, P_lim, D, gate_openings, power_gate_openings, P_ref, ext, [:x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6, :x_g7], 7, [StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], InfrastructureSystemsInternal(), )
end
function WPIDHY(; T_reg, reg, Kp, Ki, Kd, Ta, Tb, V_lim, G_lim, Tw, P_lim, D, gate_openings, power_gate_openings, P_ref=1.0, ext=Dict{String, Any}(), states=[:x_g1, :x_g2, :x_g3, :x_g4, :x_g5, :x_g6, :x_g7], n_states=7, states_types=[StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid, StateTypes.Hybrid], internal=InfrastructureSystemsInternal(), )
WPIDHY(T_reg, reg, Kp, Ki, Kd, Ta, Tb, V_lim, G_lim, Tw, P_lim, D, gate_openings, power_gate_openings, P_ref, ext, states, n_states, states_types, internal, )
end
# Constructor for demo purposes; non-functional.
function WPIDHY(::Nothing)
WPIDHY(;
T_reg=0,
reg=0,
Kp=0,
Ki=0,
Kd=0,
Ta=0,
Tb=0,
V_lim=(min=0.0, max=0.0),
G_lim=(min=0.0, max=0.0),
Tw=0,
P_lim=(min=0.0, max=0.0),
D=0,
gate_openings=(0.0, 0.0, 0.0),
power_gate_openings=(0.0, 0.0, 0.0),
P_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`WPIDHY`](@ref) `T_reg`."""
get_T_reg(value::WPIDHY) = value.T_reg
"""Get [`WPIDHY`](@ref) `reg`."""
get_reg(value::WPIDHY) = value.reg
"""Get [`WPIDHY`](@ref) `Kp`."""
get_Kp(value::WPIDHY) = value.Kp
"""Get [`WPIDHY`](@ref) `Ki`."""
get_Ki(value::WPIDHY) = value.Ki
"""Get [`WPIDHY`](@ref) `Kd`."""
get_Kd(value::WPIDHY) = value.Kd
"""Get [`WPIDHY`](@ref) `Ta`."""
get_Ta(value::WPIDHY) = value.Ta
"""Get [`WPIDHY`](@ref) `Tb`."""
get_Tb(value::WPIDHY) = value.Tb
"""Get [`WPIDHY`](@ref) `V_lim`."""
get_V_lim(value::WPIDHY) = value.V_lim
"""Get [`WPIDHY`](@ref) `G_lim`."""
get_G_lim(value::WPIDHY) = value.G_lim
"""Get [`WPIDHY`](@ref) `Tw`."""
get_Tw(value::WPIDHY) = value.Tw
"""Get [`WPIDHY`](@ref) `P_lim`."""
get_P_lim(value::WPIDHY) = value.P_lim
"""Get [`WPIDHY`](@ref) `D`."""
get_D(value::WPIDHY) = value.D
"""Get [`WPIDHY`](@ref) `gate_openings`."""
get_gate_openings(value::WPIDHY) = value.gate_openings
"""Get [`WPIDHY`](@ref) `power_gate_openings`."""
get_power_gate_openings(value::WPIDHY) = value.power_gate_openings
"""Get [`WPIDHY`](@ref) `P_ref`."""
get_P_ref(value::WPIDHY) = value.P_ref
"""Get [`WPIDHY`](@ref) `ext`."""
get_ext(value::WPIDHY) = value.ext
"""Get [`WPIDHY`](@ref) `states`."""
get_states(value::WPIDHY) = value.states
"""Get [`WPIDHY`](@ref) `n_states`."""
get_n_states(value::WPIDHY) = value.n_states
"""Get [`WPIDHY`](@ref) `states_types`."""
get_states_types(value::WPIDHY) = value.states_types
"""Get [`WPIDHY`](@ref) `internal`."""
get_internal(value::WPIDHY) = value.internal
"""Set [`WPIDHY`](@ref) `T_reg`."""
set_T_reg!(value::WPIDHY, val) = value.T_reg = val
"""Set [`WPIDHY`](@ref) `reg`."""
set_reg!(value::WPIDHY, val) = value.reg = val
"""Set [`WPIDHY`](@ref) `Kp`."""
set_Kp!(value::WPIDHY, val) = value.Kp = val
"""Set [`WPIDHY`](@ref) `Ki`."""
set_Ki!(value::WPIDHY, val) = value.Ki = val
"""Set [`WPIDHY`](@ref) `Kd`."""
set_Kd!(value::WPIDHY, val) = value.Kd = val
"""Set [`WPIDHY`](@ref) `Ta`."""
set_Ta!(value::WPIDHY, val) = value.Ta = val
"""Set [`WPIDHY`](@ref) `Tb`."""
set_Tb!(value::WPIDHY, val) = value.Tb = val
"""Set [`WPIDHY`](@ref) `V_lim`."""
set_V_lim!(value::WPIDHY, val) = value.V_lim = val
"""Set [`WPIDHY`](@ref) `G_lim`."""
set_G_lim!(value::WPIDHY, val) = value.G_lim = val
"""Set [`WPIDHY`](@ref) `Tw`."""
set_Tw!(value::WPIDHY, val) = value.Tw = val
"""Set [`WPIDHY`](@ref) `P_lim`."""
set_P_lim!(value::WPIDHY, val) = value.P_lim = val
"""Set [`WPIDHY`](@ref) `D`."""
set_D!(value::WPIDHY, val) = value.D = val
"""Set [`WPIDHY`](@ref) `gate_openings`."""
set_gate_openings!(value::WPIDHY, val) = value.gate_openings = val
"""Set [`WPIDHY`](@ref) `power_gate_openings`."""
set_power_gate_openings!(value::WPIDHY, val) = value.power_gate_openings = val
"""Set [`WPIDHY`](@ref) `P_ref`."""
set_P_ref!(value::WPIDHY, val) = value.P_ref = val
"""Set [`WPIDHY`](@ref) `ext`."""
set_ext!(value::WPIDHY, val) = value.ext = val
"""Set [`WPIDHY`](@ref) `states_types`."""
set_states_types!(value::WPIDHY, val) = value.states_types = val
================================================
FILE: src/models/generated/ZeroOrderBESS.jl
================================================
#=
This file is auto-generated. Do not edit.
=#
#! format: off
"""
mutable struct ZeroOrderBESS <: DCSource
rated_voltage::Float64
rated_current::Float64
battery_voltage::Float64
battery_resistance::Float64
dc_dc_inductor::Float64
dc_link_capacitance::Float64
fs::Float64
kpv::Float64
kiv::Float64
kpi::Float64
kii::Float64
Vdc_ref::Float64
ext::Dict{String, Any}
states::Vector{Symbol}
n_states::Int
end
Parameters for the DC-side with a Battery Energy Storage System from ["Grid-Coupled Dynamic Response of Battery-Driven Voltage Source Converters."](https://arxiv.org/abs/2007.11776)
# Arguments
- `rated_voltage::Float64`: Rated voltage (V), validation range: `(0, nothing)`
- `rated_current::Float64`: Rated current (A), validation range: `(0, nothing)`
- `battery_voltage::Float64`: battery voltage in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `battery_resistance::Float64`: Battery resistance in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `dc_dc_inductor::Float64`: DC/DC inductance in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `dc_link_capacitance::Float64`: DC-link capacitance in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `fs::Float64`: DC/DC converter switching frequency (kHz), validation range: `(0, nothing)`
- `kpv::Float64`: voltage controller proportional gain, validation range: `(0, nothing)`
- `kiv::Float64`: voltage controller integral gain, validation range: `(0, nothing)`
- `kpi::Float64`: current controller proportional gain, validation range: `(0, nothing)`
- `kii::Float64`: current controller integral gain, validation range: `(0, nothing)`
- `Vdc_ref::Float64`: (default: `1.1`) Reference DC-Voltage Set-point in pu ([`DEVICE_BASE`](@ref per_unit)), validation range: `(0, nothing)`
- `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation.
- `states::Vector{Symbol}`: (**Do not modify.**) The [states](@ref S) of the ZeroOrderBESS model are:
v_dc: DC-link voltage,
i_b: Battery current,
ν: integrator state of the voltage controller,
ζ: integrator state of the PI current controller
- `n_states::Int`: (**Do not modify.**) ZeroOrderBESS has 4 states
"""
mutable struct ZeroOrderBESS <: DCSource
"Rated voltage (V)"
rated_voltage::Float64
"Rated current (A)"
rated_current::Float64
"battery voltage in pu ([`DEVICE_BASE`](@ref per_unit))"
battery_voltage::Float64
"Battery resistance in pu ([`DEVICE_BASE`](@ref per_unit))"
battery_resistance::Float64
"DC/DC inductance in pu ([`DEVICE_BASE`](@ref per_unit))"
dc_dc_inductor::Float64
"DC-link capacitance in pu ([`DEVICE_BASE`](@ref per_unit))"
dc_link_capacitance::Float64
"DC/DC converter switching frequency (kHz)"
fs::Float64
"voltage controller proportional gain"
kpv::Float64
"voltage controller integral gain"
kiv::Float64
"current controller proportional gain"
kpi::Float64
"current controller integral gain"
kii::Float64
"Reference DC-Voltage Set-point in pu ([`DEVICE_BASE`](@ref per_unit))"
Vdc_ref::Float64
"An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation."
ext::Dict{String, Any}
"(**Do not modify.**) The [states](@ref S) of the ZeroOrderBESS model are:
v_dc: DC-link voltage,
i_b: Battery current,
ν: integrator state of the voltage controller,
ζ: integrator state of the PI current controller"
states::Vector{Symbol}
"(**Do not modify.**) ZeroOrderBESS has 4 states"
n_states::Int
end
function ZeroOrderBESS(rated_voltage, rated_current, battery_voltage, battery_resistance, dc_dc_inductor, dc_link_capacitance, fs, kpv, kiv, kpi, kii, Vdc_ref=1.1, ext=Dict{String, Any}(), )
ZeroOrderBESS(rated_voltage, rated_current, battery_voltage, battery_resistance, dc_dc_inductor, dc_link_capacitance, fs, kpv, kiv, kpi, kii, Vdc_ref, ext, [:v_dc, :i_b, :ν, :ζ], 4, )
end
function ZeroOrderBESS(; rated_voltage, rated_current, battery_voltage, battery_resistance, dc_dc_inductor, dc_link_capacitance, fs, kpv, kiv, kpi, kii, Vdc_ref=1.1, ext=Dict{String, Any}(), states=[:v_dc, :i_b, :ν, :ζ], n_states=4, )
ZeroOrderBESS(rated_voltage, rated_current, battery_voltage, battery_resistance, dc_dc_inductor, dc_link_capacitance, fs, kpv, kiv, kpi, kii, Vdc_ref, ext, states, n_states, )
end
# Constructor for demo purposes; non-functional.
function ZeroOrderBESS(::Nothing)
ZeroOrderBESS(;
rated_voltage=0,
rated_current=0,
battery_voltage=0,
battery_resistance=0,
dc_dc_inductor=0,
dc_link_capacitance=0,
fs=0,
kpv=0,
kiv=0,
kpi=0,
kii=0,
Vdc_ref=0,
ext=Dict{String, Any}(),
)
end
"""Get [`ZeroOrderBESS`](@ref) `rated_voltage`."""
get_rated_voltage(value::ZeroOrderBESS) = value.rated_voltage
"""Get [`ZeroOrderBESS`](@ref) `rated_current`."""
get_rated_current(value::ZeroOrderBESS) = value.rated_current
"""Get [`ZeroOrderBESS`](@ref) `battery_voltage`."""
get_battery_voltage(value::ZeroOrderBESS) = value.battery_voltage
"""Get [`ZeroOrderBESS`](@ref) `battery_resistance`."""
get_battery_resistance(value::ZeroOrderBESS) = value.battery_resistance
"""Get [`ZeroOrderBESS`](@ref) `dc_dc_inductor`."""
get_dc_dc_inductor(value::ZeroOrderBESS) = value.dc_dc_inductor
"""Get [`ZeroOrderBESS`](@ref) `dc_link_capacitance`."""
get_dc_link_capacitance(value::ZeroOrderBESS) = value.dc_link_capacitance
"""Get [`ZeroOrderBESS`](@ref) `fs`."""
get_fs(value::ZeroOrderBESS) = value.fs
"""Get [`ZeroOrderBESS`](@ref) `kpv`."""
get_kpv(value::ZeroOrderBESS) = value.kpv
"""Get [`ZeroOrderBESS`](@ref) `kiv`."""
get_kiv(value::ZeroOrderBESS) = value.kiv
"""Get [`ZeroOrderBESS`](@ref) `kpi`."""
get_kpi(value::ZeroOrderBESS) = value.kpi
"""Get [`ZeroOrderBESS`](@ref) `kii`."""
get_kii(value::ZeroOrderBESS) = value.kii
"""Get [`ZeroOrderBESS`](@ref) `Vdc_ref`."""
get_Vdc_ref(value::ZeroOrderBESS) = value.Vdc_ref
"""Get [`ZeroOrderBESS`](@ref) `ext`."""
get_ext(value::ZeroOrderBESS) = value.ext
"""Get [`ZeroOrderBESS`](@ref) `states`."""
get_states(value::ZeroOrderBESS) = value.states
"""Get [`ZeroOrderBESS`](@ref) `n_states`."""
get_n_states(value::ZeroOrderBESS) = value.n_states
"""Set [`ZeroOrderBESS`](@ref) `rated_voltage`."""
set_rated_voltage!(value::ZeroOrderBESS, val) = value.rated_voltage = val
"""Set [`ZeroOrderBESS`](@ref) `rated_current`."""
set_rated_current!(value::ZeroOrderBESS, val) = value.rated_current = val
"""Set [`ZeroOrderBESS`](@ref) `battery_voltage`."""
set_battery_voltage!(value::ZeroOrderBESS, val) = value.battery_voltage = val
"""Set [`ZeroOrderBESS`](@ref) `battery_resistance`."""
set_battery_resistance!(value::ZeroOrderBESS, val) = value.battery_resistance = val
"""Set [`ZeroOrderBESS`](@ref) `dc_dc_inductor`."""
set_dc_dc_inductor!(value::ZeroOrderBESS, val) = value.dc_dc_inductor = val
"""Set [`ZeroOrderBESS`](@ref) `dc_link_capacitance`."""
set_dc_link_capacitance!(value::ZeroOrderBESS, val) = value.dc_link_capacitance = val
"""Set [`ZeroOrderBESS`](@ref) `fs`."""
set_fs!(value::ZeroOrderBESS, val) = value.fs = val
"""Set [`ZeroOrderBESS`](@ref) `kpv`."""
set_kpv!(value::ZeroOrderBESS, val) = value.kpv = val
"""Set [`ZeroOrderBESS`](@ref) `kiv`."""
set_kiv!(value::ZeroOrderBESS, val) = value.kiv = val
"""Set [`ZeroOrderBESS`](@ref) `kpi`."""
set_kpi!(value::ZeroOrderBESS, val) = value.kpi = val
"""Set [`ZeroOrderBESS`](@ref) `kii`."""
set_kii!(value::ZeroOrderBESS, val) = value.kii = val
"""Set [`ZeroOrderBESS`](@ref) `Vdc_ref`."""
set_Vdc_ref!(value::ZeroOrderBESS, val) = value.Vdc_ref = val
"""Set [`ZeroOrderBESS`](@ref) `ext`."""
set_ext!(value::ZeroOrderBESS, val) = value.ext = val
================================================
FILE: src/models/generated/includes.jl
================================================
include("Area.jl")
include("AreaInterchange.jl")
include("LoadZone.jl")
include("TransmissionInterface.jl")
include("ACBus.jl")
include("DCBus.jl")
include("Arc.jl")
include("Line.jl")
include("GenericArcImpedance.jl")
include("DiscreteControlledACBranch.jl")
include("MonitoredLine.jl")
include("PhaseShiftingTransformer.jl")
include("TapTransformer.jl")
include("Transformer2W.jl")
include("Transformer3W.jl")
include("PhaseShiftingTransformer3W.jl")
include("TwoTerminalGenericHVDCLine.jl")
include("TwoTerminalVSCLine.jl")
include("TwoTerminalLCCLine.jl")
include("TModelHVDCLine.jl")
include("InterruptiblePowerLoad.jl")
include("InterruptibleStandardLoad.jl")
include("ShiftablePowerLoad.jl")
include("FACTSControlDevice.jl")
include("FixedAdmittance.jl")
include("SwitchedAdmittance.jl")
include("PowerLoad.jl")
include("MotorLoad.jl")
include("StandardLoad.jl")
include("ExponentialLoad.jl")
include("SingleCageInductionMachine.jl")
include("SimplifiedSingleCageInductionMachine.jl")
include("DynamicExponentialLoad.jl")
include("ActiveConstantPowerLoad.jl")
include("InterconnectingConverter.jl")
include("CSVGN1.jl")
include("HydroDispatch.jl")
include("HydroTurbine.jl")
include("HydroPumpTurbine.jl")
include("HydroReservoir.jl")
include("RenewableDispatch.jl")
include("RenewableNonDispatch.jl")
include("ThermalStandard.jl")
include("SynchronousCondenser.jl")
include("ThermalMultiStart.jl")
include("EnergyReservoirStorage.jl")
include("ConstantReserve.jl")
include("ConstantReserveNonSpinning.jl")
include("ConstantReserveGroup.jl")
include("ReserveDemandCurve.jl")
include("VariableReserve.jl")
include("VariableReserveNonSpinning.jl")
include("AGC.jl")
include("AVRFixed.jl")
include("AVRSimple.jl")
include("SEXS.jl")
include("ESDC1A.jl")
include("ESDC2A.jl")
include("IEEET1.jl")
include("AVRTypeI.jl")
include("AVRTypeII.jl")
include("SCRX.jl")
include("ESAC1A.jl")
include("EXAC1A.jl")
include("EXAC1.jl")
include("EXAC2.jl")
include("ESAC6A.jl")
include("ESAC8B.jl")
include("ESST1A.jl")
include("EXPIC1.jl")
include("ESST4B.jl")
include("ST6B.jl")
include("ST8C.jl")
include("EXST1.jl")
include("EX4VSA.jl")
include("BaseMachine.jl")
include("RoundRotorMachine.jl")
include("SalientPoleMachine.jl")
include("AndersonFouadMachine.jl")
include("FullMachine.jl")
include("SauerPaiMachine.jl")
include("MarconatoMachine.jl")
include("OneDOneQMachine.jl")
include("SimpleAFMachine.jl")
include("SimpleFullMachine.jl")
include("SimpleMarconatoMachine.jl")
include("PSSFixed.jl")
include("PSSSimple.jl")
include("IEEEST.jl")
include("STAB1.jl")
include("PSS2A.jl")
include("PSS2B.jl")
include("PSS2C.jl")
include("SingleMass.jl")
include("FiveMassShaft.jl")
include("TGFixed.jl")
include("GasTG.jl")
include("DEGOV.jl")
include("DEGOV1.jl")
include("GeneralGovModel.jl")
include("PIDGOV.jl")
include("WPIDHY.jl")
include("SteamTurbineGov1.jl")
include("HydroTurbineGov.jl")
include("IEEETurbineGov1.jl")
include("TGTypeI.jl")
include("TGTypeII.jl")
include("TGSimple.jl")
include("AverageConverter.jl")
include("RenewableEnergyConverterTypeA.jl")
include("RenewableEnergyVoltageConverterTypeA.jl")
include("FixedDCSource.jl")
include("ZeroOrderBESS.jl")
include("LCLFilter.jl")
include("LCFilter.jl")
include("RLFilter.jl")
include("KauraPLL.jl")
include("ReducedOrderPLL.jl")
include("FixedFrequency.jl")
include("VirtualInertia.jl")
include("ActivePowerDroop.jl")
include("ActivePowerPI.jl")
include("ActiveVirtualOscillator.jl")
include("ActiveRenewableControllerAB.jl")
include("ReactiveRenewableControllerAB.jl")
include("ReactivePowerDroop.jl")
include("ReactivePowerPI.jl")
include("ReactiveVirtualOscillator.jl")
include("VoltageModeControl.jl")
include("CurrentModeControl.jl")
include("RECurrentControlB.jl")
include("MagnitudeOutputCurrentLimiter.jl")
include("InstantaneousOutputCurrentLimiter.jl")
include("PriorityOutputCurrentLimiter.jl")
include("SaturationOutputCurrentLimiter.jl")
include("HybridOutputCurrentLimiter.jl")
include("AggregateDistributedGenerationA.jl")
include("Source.jl")
include("PeriodicVariableSource.jl")
include("GenericDER.jl")
export get_A
export get_A1
export get_A2
export get_A3
export get_A4
export get_A5
export get_A6
export get_AT
export get_A_set
export get_A_tw
export get_Accel
export get_Ae
export get_At
export get_B
export get_B_shunt
export get_Be
export get_Brkpt
export get_C
export get_CBase
export get_D
export get_DB_h
export get_DB_l
export get_D_12
export get_D_23
export get_D_34
export get_D_45
export get_D_T
export get_D_dn
export get_D_ex
export get_D_hp
export get_D_ip
export get_D_lp
export get_D_turb
export get_D_up
export get_Dm
export get_E_lim
export get_E_sat
export get_Efd_lim
export get_FES_lim
export get_FRT_pnts
export get_Freq_Flag
export get_Ftrip_Flag
export get_G
export get_G_lim
export get_Gen_Flag
export get_H
export get_H_ex
export get_H_hp
export get_H_ip
export get_H_lim
export get_H_lp
export get_I_lr
export get_I_max
export get_Id_max
export get_Ifd_ref
export get_Iflim
export get_Io_lim
export get_Iq_lim
export get_Iq_max
export get_Iqinj_lim
export get_Iqr_lim
export get_Iqr_lims
export get_K
export get_K0
export get_K1
export get_K2
export get_K3
export get_K4
export get_K5
export get_K6
export get_K7
export get_K8
export get_KT
export get_K_a
export get_K_c
export get_K_c1
export get_K_c2
export get_K_ci
export get_K_d
export get_K_da
export get_K_ex
export get_K_f
export get_K_ff
export get_K_hp
export get_K_hv
export get_K_i
export get_K_i1
export get_K_i2
export get_K_ia
export get_K_ig
export get_K_im
export get_K_ip
export get_K_ir
export get_K_lp
export get_K_lr
export get_K_m
export get_K_p
export get_K_pa
export get_K_pg
export get_K_pm
export get_K_pr
export get_K_qi
export get_K_qp
export get_K_qv
export get_K_turb
export get_K_vi
export get_K_vp
export get_K_ω
export get_Ka
export get_Kb
export get_Kc
export get_Kd
export get_Kd_gov
export get_Ke
export get_Kf
export get_Kg
export get_Kh
export get_Ki
export get_Ki_gov
export get_Ki_load
export get_Ki_mw
export get_Ki_p
export get_Ki_q
export get_Kig
export get_Kip
export get_Kiq
export get_Kl
export get_Kp
export get_Kp_gov
export get_Kp_load
export get_Kp_p
export get_Kp_q
export get_Kpg
export get_Kpp
export get_Kpq
export get_Ks
export get_Ks1
export get_Ks2
export get_Ks3
export get_Kt
export get_Kv
export get_L_1d
export get_L_1q
export get_L_ad
export get_L_aq
export get_L_d
export get_L_f1d
export get_L_ff
export get_L_q
export get_Ld_ref
export get_Ls_lim
export get_Lv_pnts
export get_Lvpl1
export get_Lvpl_sw
export get_M_rtf
export get_N_rtf
export get_OEL_Flag
export get_Oel_lim
export get_PF_Flag
export get_PQ_Flag
export get_PSS_Hysteresis_param
export get_PSS_flags
export get_P_lim
export get_P_lim_inner
export get_P_ref
export get_PerOp_Flag
export get_Pf_Flag
export get_Pfa_ref
export get_Q_Flag
export get_Q_lim
export get_Q_lim_inner
export get_Q_ref
export get_Qref_Flag
export get_R
export get_R_1d
export get_R_1q
export get_R_c
export get_R_close
export get_R_f
export get_R_lim
export get_R_open
export get_R_r
export get_R_s
export get_R_source
export get_R_th
export get_Recon_Flag
export get_Ref_Flag
export get_Rmin
export get_Rp
export get_Rperm
export get_Rrpwr
export get_Rselect
export get_SCL_Flag
export get_SOC_ini
export get_SOC_lim
export get_SW1_Flag
export get_Se
export get_Spar
export get_T
export get_T1
export get_T10
export get_T11
export get_T12
export get_T13
export get_T1T3
export get_T2
export get_T2T4
export get_T3
export get_T4
export get_T5
export get_T6
export get_T7
export get_T8
export get_T9
export get_TFRT_pnts
export get_TVRT_pnts
export get_T_AA
export get_T_a
export get_T_act
export get_T_da
export get_T_eng
export get_T_f
export get_T_fltr
export get_T_ft
export get_T_fv
export get_T_g
export get_T_iq
export get_T_lim
export get_T_p
export get_T_pord
export get_T_q
export get_T_rate
export get_T_reg
export get_T_rv
export get_Ta
export get_Ta_2
export get_Ta_3
export get_Ta_4
export get_Ta_Tb
export get_Tb
export get_Tb1
export get_Tc
export get_Tc1
export get_Tcomp
export get_Td
export get_Td0_p
export get_Td0_pp
export get_Td_gov
export get_Te
export get_Tf
export get_Tf_1
export get_Tf_2
export get_Tf_load
export get_Tg
export get_Th
export get_Tj
export get_Tk
export get_Tm
export get_Tp
export get_Tpelec
export get_Tpord
export get_Tq0_p
export get_Tq0_pp
export get_Tr
export get_Trf
export get_Trv
export get_Ts
export get_Tsa
export get_Tsb
export get_Tv
export get_Tw
export get_Tw1
export get_Tw2
export get_Tw3
export get_Tw4
export get_U0
export get_UEL_Flag
export get_UEL_flags
export get_U_c
export get_VB1_max
export get_VB2_max
export get_VB_max
export get_VC_Flag
export get_VELM
export get_VES_lim
export get_VFE_lim
export get_VH_max
export get_VRT_pnts
export get_VV_pnts
export get_V_Flag
export get_V_frz
export get_V_lim
export get_V_lr
export get_V_pss
export get_V_ref
export get_V_ref0
export get_Va_lim
export get_Vcl
export get_Vcu
export get_Vdc_ref
export get_Vdip_lim
export get_Vf
export get_Vi_lim
export get_Vm_lim
export get_Vmax
export get_Vmin
export get_Vo_lim
export get_Vpi_lim
export get_Vpr
export get_Vr_lim
export get_Vrfrac
export get_Vs1_lim
export get_Vs2_lim
export get_Vst_lim
export get_Vtrip_Flag
export get_Wf_nl
export get_X_ad
export get_X_aq
export get_X_c
export get_X_l
export get_X_lr
export get_X_ls
export get_X_m
export get_X_p
export get_X_rr
export get_X_source
export get_X_ss
export get_X_th
export get_Xcomp
export get_Xd
export get_Xd_p
export get_Xd_pp
export get_Xl
export get_Xq
export get_Xq_p
export get_Xq_pp
export get_Y
export get_Y_increase
export get_Zerox
export get_a
export get_ac_setpoint_from
export get_ac_setpoint_to
export get_ac_voltage_control_from
export get_ac_voltage_control_to
export get_active_power
export get_active_power_flow
export get_active_power_flow_limits
export get_active_power_flow_primary
export get_active_power_flow_secondary
export get_active_power_flow_tertiary
export get_active_power_limits
export get_active_power_limits_from
export get_active_power_limits_pump
export get_active_power_limits_to
export get_active_power_losses
export get_active_power_pump
export get_admittance_limits
export get_angle
export get_angle_limits
export get_arc
export get_area
export get_available
export get_available_primary
export get_available_secondary
export get_available_tertiary
export get_b
export get_base_power
export get_base_power_12
export get_base_power_13
export get_base_power_23
export get_base_voltage
export get_base_voltage_primary
export get_base_voltage_secondary
export get_base_voltage_tertiary
export get_battery_resistance
export get_battery_voltage
export get_bias
export get_branch_id_control
export get_branch_status
export get_bus
export get_bus_control
export get_bustype
export get_c
export get_c_dc
export get_cf
export get_compounding_resistance
export get_conformity
export get_constant_active_power
export get_constant_reactive_power
export get_contributing_services
export get_control_mode
export get_control_objective
export get_control_objective_primary
export get_control_objective_secondary
export get_control_objective_tertiary
export get_conversion_factor
export get_converter_loss_from
export get_converter_loss_to
export get_current_active_power
export get_current_reactive_power
export get_cycle_limits
export get_d
export get_dP_lim
export get_d_t
export get_db
export get_dbd_pnts
export get_dc_bus
export get_dc_current
export get_dc_dc_inductor
export get_dc_link_capacitance
export get_dc_setpoint_from
export get_dc_setpoint_to
export get_dc_voltage_control_from
export get_dc_voltage_control_to
export get_delta_t
export get_deployed_fraction
export get_direction_mapping
export get_discrete_branch_type
export get_downstream_turbines
export get_droop_flag
export get_dynamic_injector
export get_e_lim
export get_efficiency
export get_eq_p
export get_ext
export get_f
export get_fdbd_pnts
export get_fe_lim
export get_feedback_flag
export get_fh
export get_fl
export get_flow_limits
export get_frequency
export get_from
export get_from_area
export get_from_branch_control
export get_fs
export get_fuel
export get_fuel_flag
export get_g
export get_gate_openings
export get_gate_position_limits
export get_head_to_volume_factor
export get_hysteresis_binary_logic
export get_impedance_active_power
export get_impedance_reactive_power
export get_inflow
export get_initial_ace
export get_initial_level
export get_initial_status
export get_initial_storage_capacity_level
export get_input_active_power_limits
export get_input_code
export get_input_code_1
export get_input_code_2
export get_intake_elevation
export get_internal_angle
export get_internal_angle_bias
export get_internal_angle_coefficients
export get_internal_angle_frequencies
export get_internal_voltage
export get_internal_voltage_bias
export get_internal_voltage_coefficients
export get_internal_voltage_frequencies
export get_inv_d_fluxlink
export get_inv_q_fluxlink
export get_inverter_base_voltage
export get_inverter_bridges
export get_inverter_capacitor_reactance
export get_inverter_extinction_angle
export get_inverter_extinction_angle_limits
export get_inverter_rc
export get_inverter_tap_limits
export get_inverter_tap_setting
export get_inverter_tap_step
export get_inverter_transformer_ratio
export get_inverter_xc
export get_is_filter_differential
export get_k1
export get_k2
export get_kWh_Cap
export get_kad
export get_kd
export get_kffi
export get_kffv
export get_ki_pll
export get_kic
export get_kii
export get_kiv
export get_kp_pll
export get_kpc
export get_kpi
export get_kpv
export get_kq
export get_kw
export get_kω
export get_l
export get_level_data_type
export get_level_targets
export get_lf
export get_lg
export get_load_balance_time_horizon
export get_load_response
export get_load_zone
export get_loss
export get_loss_function
export get_lv
export get_magnitude
export get_max_active_power
export get_max_constant_active_power
export get_max_constant_reactive_power
export get_max_current_active_power
export get_max_current_reactive_power
export get_max_dc_current
export get_max_dc_current_from
export get_max_dc_current_to
export get_max_flow
export get_max_impedance_active_power
export get_max_impedance_reactive_power
export get_max_output_fraction
export get_max_participation_factor
export get_max_reactive_power
export get_max_shunt_current
export get_min_compounding_voltage
export get_minimum_time
export get_motor_technology
export get_must_run
export get_n_states
export get_name
export get_number
export get_number_of_steps
export get_operation_cost
export get_outflow
export get_outflow_limits
export get_output_active_power_limits
export get_peak_active_power
export get_peak_reactive_power
export get_phase_angle_limits
export get_power_factor
export get_power_factor_weighting_fraction_from
export get_power_factor_weighting_fraction_to
export get_power_gate_openings
export get_power_mode
export get_power_trajectory
export get_powerhouse_elevation
export get_primary_group_number
export get_primary_shunt
export get_primary_star_arc
export get_primary_turns_ratio
export get_prime_mover_type
export get_q_nl
export get_r
export get_r_12
export get_r_13
export get_r_23
export get_r_load
export get_r_primary
export get_r_secondary
export get_r_tertiary
export get_ramp_limits
export get_rated_current
export get_rated_voltage
export get_rating
export get_rating_b
export get_rating_c
export get_rating_from
export get_rating_primary
export get_rating_secondary
export get_rating_tertiary
export get_rating_to
export get_rc_rfd
export get_reactive_power
export get_reactive_power_flow
export get_reactive_power_flow_primary
export get_reactive_power_flow_secondary
export get_reactive_power_flow_tertiary
export get_reactive_power_from
export get_reactive_power_limits
export get_reactive_power_limits_from
export get_reactive_power_limits_to
export get_reactive_power_required
export get_reactive_power_to
export get_rectifier_base_voltage
export get_rectifier_bridges
export get_rectifier_capacitor_reactance
export get_rectifier_delay_angle
export get_rectifier_delay_angle_limits
export get_rectifier_rc
export get_rectifier_tap_limits
export get_rectifier_tap_setting
export get_rectifier_tap_step
export get_rectifier_transformer_ratio
export get_rectifier_xc
export get_reg
export get_remote_bus_control
export get_remote_bus_control_1
export get_remote_bus_control_2
export get_requirement
export get_reserves
export get_rf
export get_rg
export get_rrpwr
export get_rv
export get_saturation_coeffs
export get_scheduled_dc_voltage
export get_secondary_group_number
export get_secondary_star_arc
export get_secondary_turns_ratio
export get_services
export get_speed_error_signal
export get_spillage_limits
export get_star_bus
export get_start_time_limits
export get_start_types
export get_states
export get_states_types
export get_status
export get_storage_capacity
export get_storage_level_limits
export get_storage_target
export get_storage_technology_type
export get_sustained_time
export get_switch
export get_switch_mode_voltage
export get_tF_delay
export get_tV_delay
export get_tap
export get_tertiary_group_number
export get_tertiary_star_arc
export get_tertiary_turns_ratio
export get_tfh
export get_tfl
export get_time_at_status
export get_time_frame
export get_time_limits
export get_to
export get_to_area
export get_to_branch_control
export get_transfer_setpoint
export get_transition_time
export get_travel_time
export get_turbine_type
export get_upstream_reservoirs
export get_upstream_turbines
export get_valve_position_limits
export get_variable
export get_vh_pnts
export get_violation_penalty
export get_vl_pnts
export get_voltage
export get_voltage_limits
export get_voltage_limits_from
export get_voltage_limits_to
export get_voltage_setpoint
export get_winding_group_number
export get_x
export get_x_12
export get_x_13
export get_x_23
export get_x_primary
export get_x_secondary
export get_x_tertiary
export get_α
export get_α_primary
export get_α_secondary
export get_α_tertiary
export get_β
export get_γ_d1
export get_γ_d2
export get_γ_q1
export get_γ_q2
export get_γ_qd
export get_γd
export get_γq
export get_θ_p
export get_θp
export get_θp_rad
export get_τ_limits
export get_τ_ref
export get_ψ
export get_ω_lp
export get_ω_ref
export get_ωad
export get_ωf
export get_ωz
export get_ϕ_I
export set_A!
export set_A1!
export set_A2!
export set_A3!
export set_A4!
export set_A5!
export set_A6!
export set_AT!
export set_A_set!
export set_A_tw!
export set_Accel!
export set_Ae!
export set_At!
export set_B!
export set_B_shunt!
export set_Be!
export set_Brkpt!
export set_C!
export set_CBase!
export set_D!
export set_DB_h!
export set_DB_l!
export set_D_12!
export set_D_23!
export set_D_34!
export set_D_45!
export set_D_T!
export set_D_dn!
export set_D_ex!
export set_D_hp!
export set_D_ip!
export set_D_lp!
export set_D_turb!
export set_D_up!
export set_Dm!
export set_E_lim!
export set_E_sat!
export set_Efd_lim!
export set_FES_lim!
export set_FRT_pnts!
export set_Freq_Flag!
export set_Ftrip_Flag!
export set_G!
export set_G_lim!
export set_Gen_Flag!
export set_H!
export set_H_ex!
export set_H_hp!
export set_H_ip!
export set_H_lim!
export set_H_lp!
export set_I_lr!
export set_I_max!
export set_Id_max!
export set_Ifd_ref!
export set_Iflim!
export set_Io_lim!
export set_Iq_lim!
export set_Iq_max!
export set_Iqinj_lim!
export set_Iqr_lim!
export set_Iqr_lims!
export set_K!
export set_K0!
export set_K1!
export set_K2!
export set_K3!
export set_K4!
export set_K5!
export set_K6!
export set_K7!
export set_K8!
export set_KT!
export set_K_a!
export set_K_c!
export set_K_c1!
export set_K_c2!
export set_K_ci!
export set_K_d!
export set_K_da!
export set_K_ex!
export set_K_f!
export set_K_ff!
export set_K_hp!
export set_K_hv!
export set_K_i!
export set_K_i1!
export set_K_i2!
export set_K_ia!
export set_K_ig!
export set_K_im!
export set_K_ip!
export set_K_ir!
export set_K_lp!
export set_K_lr!
export set_K_m!
export set_K_p!
export set_K_pa!
export set_K_pg!
export set_K_pm!
export set_K_pr!
export set_K_qi!
export set_K_qp!
export set_K_qv!
export set_K_turb!
export set_K_vi!
export set_K_vp!
export set_K_ω!
export set_Ka!
export set_Kb!
export set_Kc!
export set_Kd!
export set_Kd_gov!
export set_Ke!
export set_Kf!
export set_Kg!
export set_Kh!
export set_Ki!
export set_Ki_gov!
export set_Ki_load!
export set_Ki_mw!
export set_Ki_p!
export set_Ki_q!
export set_Kig!
export set_Kip!
export set_Kiq!
export set_Kl!
export set_Kp!
export set_Kp_gov!
export set_Kp_load!
export set_Kp_p!
export set_Kp_q!
export set_Kpg!
export set_Kpp!
export set_Kpq!
export set_Ks!
export set_Ks1!
export set_Ks2!
export set_Ks3!
export set_Kt!
export set_Kv!
export set_L_1d!
export set_L_1q!
export set_L_ad!
export set_L_aq!
export set_L_d!
export set_L_f1d!
export set_L_ff!
export set_L_q!
export set_Ld_ref!
export set_Ls_lim!
export set_Lv_pnts!
export set_Lvpl1!
export set_Lvpl_sw!
export set_M_rtf!
export set_N_rtf!
export set_OEL_Flag!
export set_Oel_lim!
export set_PF_Flag!
export set_PQ_Flag!
export set_PSS_Hysteresis_param!
export set_PSS_flags!
export set_P_lim!
export set_P_lim_inner!
export set_P_ref!
export set_PerOp_Flag!
export set_Pf_Flag!
export set_Pfa_ref!
export set_Q_Flag!
export set_Q_lim!
export set_Q_lim_inner!
export set_Q_ref!
export set_Qref_Flag!
export set_R!
export set_R_1d!
export set_R_1q!
export set_R_c!
export set_R_close!
export set_R_f!
export set_R_lim!
export set_R_open!
export set_R_r!
export set_R_s!
export set_R_source!
export set_R_th!
export set_Recon_Flag!
export set_Ref_Flag!
export set_Rmin!
export set_Rp!
export set_Rperm!
export set_Rrpwr!
export set_Rselect!
export set_SCL_Flag!
export set_SOC_ini!
export set_SOC_lim!
export set_SW1_Flag!
export set_Se!
export set_Spar!
export set_T!
export set_T1!
export set_T10!
export set_T11!
export set_T12!
export set_T13!
export set_T1T3!
export set_T2!
export set_T2T4!
export set_T3!
export set_T4!
export set_T5!
export set_T6!
export set_T7!
export set_T8!
export set_T9!
export set_TFRT_pnts!
export set_TVRT_pnts!
export set_T_AA!
export set_T_a!
export set_T_act!
export set_T_da!
export set_T_eng!
export set_T_f!
export set_T_fltr!
export set_T_ft!
export set_T_fv!
export set_T_g!
export set_T_iq!
export set_T_lim!
export set_T_p!
export set_T_pord!
export set_T_q!
export set_T_rate!
export set_T_reg!
export set_T_rv!
export set_Ta!
export set_Ta_2!
export set_Ta_3!
export set_Ta_4!
export set_Ta_Tb!
export set_Tb!
export set_Tb1!
export set_Tc!
export set_Tc1!
export set_Tcomp!
export set_Td!
export set_Td0_p!
export set_Td0_pp!
export set_Td_gov!
export set_Te!
export set_Tf!
export set_Tf_1!
export set_Tf_2!
export set_Tf_load!
export set_Tg!
export set_Th!
export set_Tj!
export set_Tk!
export set_Tm!
export set_Tp!
export set_Tpelec!
export set_Tpord!
export set_Tq0_p!
export set_Tq0_pp!
export set_Tr!
export set_Trf!
export set_Trv!
export set_Ts!
export set_Tsa!
export set_Tsb!
export set_Tv!
export set_Tw!
export set_Tw1!
export set_Tw2!
export set_Tw3!
export set_Tw4!
export set_U0!
export set_UEL_Flag!
export set_UEL_flags!
export set_U_c!
export set_VB1_max!
export set_VB2_max!
export set_VB_max!
export set_VC_Flag!
export set_VELM!
export set_VES_lim!
export set_VFE_lim!
export set_VH_max!
export set_VRT_pnts!
export set_VV_pnts!
export set_V_Flag!
export set_V_frz!
export set_V_lim!
export set_V_lr!
export set_V_pss!
export set_V_ref!
export set_V_ref0!
export set_Va_lim!
export set_Vcl!
export set_Vcu!
export set_Vdc_ref!
export set_Vdip_lim!
export set_Vf!
export set_Vi_lim!
export set_Vm_lim!
export set_Vmax!
export set_Vmin!
export set_Vo_lim!
export set_Vpi_lim!
export set_Vpr!
export set_Vr_lim!
export set_Vrfrac!
export set_Vs1_lim!
export set_Vs2_lim!
export set_Vst_lim!
export set_Vtrip_Flag!
export set_Wf_nl!
export set_X_ad!
export set_X_aq!
export set_X_c!
export set_X_l!
export set_X_lr!
export set_X_ls!
export set_X_m!
export set_X_p!
export set_X_rr!
export set_X_source!
export set_X_ss!
export set_X_th!
export set_Xcomp!
export set_Xd!
export set_Xd_p!
export set_Xd_pp!
export set_Xl!
export set_Xq!
export set_Xq_p!
export set_Xq_pp!
export set_Y!
export set_Y_increase!
export set_Zerox!
export set_a!
export set_ac_setpoint_from!
export set_ac_setpoint_to!
export set_ac_voltage_control_from!
export set_ac_voltage_control_to!
export set_active_power!
export set_active_power_flow!
export set_active_power_flow_limits!
export set_active_power_flow_primary!
export set_active_power_flow_secondary!
export set_active_power_flow_tertiary!
export set_active_power_limits!
export set_active_power_limits_from!
export set_active_power_limits_pump!
export set_active_power_limits_to!
export set_active_power_losses!
export set_active_power_pump!
export set_admittance_limits!
export set_angle!
export set_angle_limits!
export set_arc!
export set_area!
export set_available!
export set_available_primary!
export set_available_secondary!
export set_available_tertiary!
export set_b!
export set_base_power!
export set_base_power_12!
export set_base_power_13!
export set_base_power_23!
export set_base_voltage!
export set_base_voltage_primary!
export set_base_voltage_secondary!
export set_base_voltage_tertiary!
export set_battery_resistance!
export set_battery_voltage!
export set_bias!
export set_branch_id_control!
export set_branch_status!
export set_bus!
export set_bus_control!
export set_bustype!
export set_c!
export set_c_dc!
export set_cf!
export set_compounding_resistance!
export set_conformity!
export set_constant_active_power!
export set_constant_reactive_power!
export set_contributing_services!
export set_control_mode!
export set_control_objective!
export set_control_objective_primary!
export set_control_objective_secondary!
export set_control_objective_tertiary!
export set_conversion_factor!
export set_converter_loss_from!
export set_converter_loss_to!
export set_current_active_power!
export set_current_reactive_power!
export set_cycle_limits!
export set_d!
export set_dP_lim!
export set_d_t!
export set_db!
export set_dbd_pnts!
export set_dc_bus!
export set_dc_current!
export set_dc_dc_inductor!
export set_dc_link_capacitance!
export set_dc_setpoint_from!
export set_dc_setpoint_to!
export set_dc_voltage_control_from!
export set_dc_voltage_control_to!
export set_delta_t!
export set_deployed_fraction!
export set_direction_mapping!
export set_discrete_branch_type!
export set_downstream_turbines!
export set_droop_flag!
export set_dynamic_injector!
export set_e_lim!
export set_efficiency!
export set_eq_p!
export set_ext!
export set_f!
export set_fdbd_pnts!
export set_fe_lim!
export set_feedback_flag!
export set_fh!
export set_fl!
export set_flow_limits!
export set_frequency!
export set_from!
export set_from_area!
export set_from_branch_control!
export set_fs!
export set_fuel!
export set_fuel_flag!
export set_g!
export set_gate_openings!
export set_gate_position_limits!
export set_head_to_volume_factor!
export set_hysteresis_binary_logic!
export set_impedance_active_power!
export set_impedance_reactive_power!
export set_inflow!
export set_initial_ace!
export set_initial_level!
export set_initial_status!
export set_initial_storage_capacity_level!
export set_input_active_power_limits!
export set_input_code!
export set_input_code_1!
export set_input_code_2!
export set_intake_elevation!
export set_internal_angle!
export set_internal_angle_bias!
export set_internal_angle_coefficients!
export set_internal_angle_frequencies!
export set_internal_voltage!
export set_internal_voltage_bias!
export set_internal_voltage_coefficients!
export set_internal_voltage_frequencies!
export set_inv_d_fluxlink!
export set_inv_q_fluxlink!
export set_inverter_base_voltage!
export set_inverter_bridges!
export set_inverter_capacitor_reactance!
export set_inverter_extinction_angle!
export set_inverter_extinction_angle_limits!
export set_inverter_rc!
export set_inverter_tap_limits!
export set_inverter_tap_setting!
export set_inverter_tap_step!
export set_inverter_transformer_ratio!
export set_inverter_xc!
export set_is_filter_differential!
export set_k1!
export set_k2!
export set_kWh_Cap!
export set_kad!
export set_kd!
export set_kffi!
export set_kffv!
export set_ki_pll!
export set_kic!
export set_kii!
export set_kiv!
export set_kp_pll!
export set_kpc!
export set_kpi!
export set_kpv!
export set_kq!
export set_kw!
export set_kω!
export set_l!
export set_level_data_type!
export set_level_targets!
export set_lf!
export set_lg!
export set_load_balance_time_horizon!
export set_load_response!
export set_load_zone!
export set_loss!
export set_loss_function!
export set_lv!
export set_magnitude!
export set_max_active_power!
export set_max_constant_active_power!
export set_max_constant_reactive_power!
export set_max_current_active_power!
export set_max_current_reactive_power!
export set_max_dc_current!
export set_max_dc_current_from!
export set_max_dc_current_to!
export set_max_flow!
export set_max_impedance_active_power!
export set_max_impedance_reactive_power!
export set_max_output_fraction!
export set_max_participation_factor!
export set_max_reactive_power!
export set_max_shunt_current!
export set_min_compounding_voltage!
export set_minimum_time!
export set_motor_technology!
export set_must_run!
export set_n_states!
export set_name!
export set_number!
export set_number_of_steps!
export set_operation_cost!
export set_outflow!
export set_outflow_limits!
export set_output_active_power_limits!
export set_peak_active_power!
export set_peak_reactive_power!
export set_phase_angle_limits!
export set_power_factor!
export set_power_factor_weighting_fraction_from!
export set_power_factor_weighting_fraction_to!
export set_power_gate_openings!
export set_power_mode!
export set_power_trajectory!
export set_powerhouse_elevation!
export set_primary_group_number!
export set_primary_shunt!
export set_primary_star_arc!
export set_primary_turns_ratio!
export set_prime_mover_type!
export set_q_nl!
export set_r!
export set_r_12!
export set_r_13!
export set_r_23!
export set_r_load!
export set_r_primary!
export set_r_secondary!
export set_r_tertiary!
export set_ramp_limits!
export set_rated_current!
export set_rated_voltage!
export set_rating!
export set_rating_b!
export set_rating_c!
export set_rating_from!
export set_rating_primary!
export set_rating_secondary!
export set_rating_tertiary!
export set_rating_to!
export set_rc_rfd!
export set_reactive_power!
export set_reactive_power_flow!
export set_reactive_power_flow_primary!
export set_reactive_power_flow_secondary!
export set_reactive_power_flow_tertiary!
export set_reactive_power_from!
export set_reactive_power_limits!
export set_reactive_power_limits_from!
export set_reactive_power_limits_to!
export set_reactive_power_required!
export set_reactive_power_to!
export set_rectifier_base_voltage!
export set_rectifier_bridges!
export set_rectifier_capacitor_reactance!
export set_rectifier_delay_angle!
export set_rectifier_delay_angle_limits!
export set_rectifier_rc!
export set_rectifier_tap_limits!
export set_rectifier_tap_setting!
export set_rectifier_tap_step!
export set_rectifier_transformer_ratio!
export set_rectifier_xc!
export set_reg!
export set_remote_bus_control!
export set_remote_bus_control_1!
export set_remote_bus_control_2!
export set_requirement!
export set_reserves!
export set_rf!
export set_rg!
export set_rrpwr!
export set_rv!
export set_saturation_coeffs!
export set_scheduled_dc_voltage!
export set_secondary_group_number!
export set_secondary_star_arc!
export set_secondary_turns_ratio!
export set_services!
export set_speed_error_signal!
export set_spillage_limits!
export set_star_bus!
export set_start_time_limits!
export set_start_types!
export set_states!
export set_states_types!
export set_status!
export set_storage_capacity!
export set_storage_level_limits!
export set_storage_target!
export set_storage_technology_type!
export set_sustained_time!
export set_switch!
export set_switch_mode_voltage!
export set_tF_delay!
export set_tV_delay!
export set_tap!
export set_tertiary_group_number!
export set_tertiary_star_arc!
export set_tertiary_turns_ratio!
export set_tfh!
export set_tfl!
export set_time_at_status!
export set_time_frame!
export set_time_limits!
export set_to!
export set_to_area!
export set_to_branch_control!
export set_transfer_setpoint!
export set_transition_time!
export set_travel_time!
export set_turbine_type!
export set_upstream_reservoirs!
export set_upstream_turbines!
export set_valve_position_limits!
export set_variable!
export set_vh_pnts!
export set_violation_penalty!
export set_vl_pnts!
export set_voltage!
export set_voltage_limits!
export set_voltage_limits_from!
export set_voltage_limits_to!
export set_voltage_setpoint!
export set_winding_group_number!
export set_x!
export set_x_12!
export set_x_13!
export set_x_23!
export set_x_primary!
export set_x_secondary!
export set_x_tertiary!
export set_α!
export set_α_primary!
export set_α_secondary!
export set_α_tertiary!
export set_β!
export set_γ_d1!
export set_γ_d2!
export set_γ_q1!
export set_γ_q2!
export set_γ_qd!
export set_γd!
export set_γq!
export set_θ_p!
export set_θp!
export set_θp_rad!
export set_τ_limits!
export set_τ_ref!
export set_ψ!
export set_ω_lp!
export set_ω_ref!
export set_ωad!
export set_ωf!
export set_ωz!
export set_ϕ_I!
================================================
FILE: src/models/generation.jl
================================================
""" Supertype for all generation technologies"""
abstract type Generator <: StaticInjection end
const Generators = Array{<:Generator, 1}
""" Supertype for all Hydropower generation technologies"""
abstract type HydroGen <: Generator end
""" Supertype for all Hydropower generation technologies that are represented as units (i.e. HydroTurbine and HydroPumpTurbine)"""
abstract type HydroUnit <: HydroGen end
"""
Supertype for all renewable generation technologies
Requires the implementation of `get_rating`and `get_power_factor` methods
"""
abstract type RenewableGen <: Generator end
""" Supertype for all Thermal generation technologies"""
abstract type ThermalGen <: Generator end
function IS.get_limits(
valid_range::Union{NamedTuple{(:min, :max)}, NamedTuple{(:max, :min)}},
unused::T,
) where {T <: Generator}
# Gets min and max value defined for a field,
# e.g. "valid_range": {"min":-1.571, "max":1.571}.
return (min = valid_range.min, max = valid_range.max, zero = 0.0)
end
"""
Return the max active power for the Renewable Generation calculated as the `rating` * `power_factor`
"""
function get_max_active_power(d::T) where {T <: RenewableGen}
return get_rating(d) * get_power_factor(d)
end
"""
Return the max reactive power for the Renewable Generation calculated as the `rating` * sin(acos(`power_factor`))
"""
function get_max_reactive_power(d::T) where {T <: RenewableGen}
return get_rating(d) * sin(acos(get_power_factor(d)))
end
================================================
FILE: src/models/injection.jl
================================================
"""
Any StaticInjection struct that wants to support dynamic injectors must implement this
method to set the value.
The method is only for internal uses.
"""
function set_dynamic_injector!(
static_injector::T,
dynamic_injector::U,
) where {T <: StaticInjection, U <: Union{Nothing, DynamicInjection}}
current_dynamic_injector = get_dynamic_injector(static_injector)
if !isnothing(current_dynamic_injector) && !isnothing(dynamic_injector)
throw(
ArgumentError(
"cannot assign a dynamic injector on a device that already has one",
),
)
end
# All of these types implement this field.
static_injector.dynamic_injector = dynamic_injector
return
end
================================================
FILE: src/models/loads.jl
================================================
""" Supertype for all electric loads"""
abstract type ElectricLoad <: StaticInjection end
""" Supertype for all [static](@ref S) electric loads"""
abstract type StaticLoad <: ElectricLoad end
""" Supertype for all controllable loads"""
abstract type ControllableLoad <: StaticLoad end
================================================
FILE: src/models/reserves.jl
================================================
"""
Used to specify if a [`Reserve`](@ref) is upwards, downwards, or symmetric
"""
abstract type ReserveDirection end
"""
An upwards reserve to increase generation or reduce load
Upwards reserves are used when total load exceeds its expected level,
typically due to forecast errors or contingencies.
A [`Reserve`](@ref) can be specified as a `ReserveUp` when it is defined.
"""
abstract type ReserveUp <: ReserveDirection end
"""
A downwards reserve to decrease generation or increase load
Downwards reserves are used when total load falls below its expected level,
typically due to forecast errors or contingencies. Not work
A [`Reserve`](@ref) can be specified as a `ReserveDown` when it is defined.
"""
abstract type ReserveDown <: ReserveDirection end
"""
A symmetric reserve, procuring the same quantity (MW) of both upwards and downwards
reserves
A symmetric reserve is a special case. [`ReserveUp`](@ref) and [`ReserveDown`](@ref)
can be used individually to specify different quantities of upwards and downwards
reserves, respectively.
A [`Reserve`](@ref) can be specified as a `ReserveSymmetric` when it is defined.
"""
abstract type ReserveSymmetric <: ReserveDirection end
"""
Supertype for all reserve products, both spinning and non-spinning.
Concrete subtypes include [`Reserve`](@ref) (parameterized by [`ReserveDirection`](@ref))
and [`ReserveNonSpinning`](@ref).
"""
abstract type AbstractReserve <: Service end
"""
A reserve product to be able to respond to unexpected disturbances,
such as the sudden loss of a transmission line or generator.
"""
abstract type Reserve{T <: ReserveDirection} <: AbstractReserve end
"""
Supertype for non-spinning (quick-start) reserve products.
Non-spinning reserves can be brought online within a short time but are not
currently synchronized to the grid. See also [`Reserve`](@ref) for spinning reserves.
Concrete subtypes include [`ConstantReserveNonSpinning`](@ref) and
[`VariableReserveNonSpinning`](@ref).
"""
abstract type ReserveNonSpinning <: AbstractReserve end
================================================
FILE: src/models/serialization.jl
================================================
const _ENCODE_AS_UUID_A = (
Union{Nothing, Arc},
Union{Nothing, Area},
Union{Nothing, Bus},
Union{Nothing, LoadZone},
Union{Nothing, DynamicInjection},
Union{Nothing, StaticInjection},
Union{Nothing, HydroReservoir},
Vector{Service},
Vector{Reserve},
Vector{HydroUnit},
Vector{Device},
)
const _ENCODE_AS_UUID_B =
(
Arc,
Area,
Bus,
LoadZone,
DynamicInjection,
StaticInjection,
HydroReservoir,
Vector{Service},
Vector{Reserve},
Vector{HydroUnit},
Vector{Device},
)
@assert length(_ENCODE_AS_UUID_A) == length(_ENCODE_AS_UUID_B)
should_encode_as_uuid(val) = any(x -> val isa x, _ENCODE_AS_UUID_B)
should_encode_as_uuid(::Type{T}) where {T} = any(x -> T <: x, _ENCODE_AS_UUID_A)
const _CONTAINS_SHOULD_ENCODE = Union{Component, MarketBidCost} # PSY types with fields that we should_encode_as_uuid
function IS.serialize(component::T) where {T <: _CONTAINS_SHOULD_ENCODE}
@debug "serialize" _group = IS.LOG_GROUP_SERIALIZATION component T
data = Dict{String, Any}()
for name in fieldnames(T)
val = serialize_uuid_handling(getfield(component, name))
if name == :ext
if !IS.is_ext_valid_for_serialization(val)
error(
"component type=$T name=$(get_name(component)) has a value in its " *
"ext field that cannot be serialized.",
)
end
end
data[string(name)] = val
end
IS.add_serialization_metadata!(data, T)
# This is a temporary workaround until these types are not parameterized.
if T <: Reserve || T <: ConstantReserveGroup
data[IS.METADATA_KEY][IS.CONSTRUCT_WITH_PARAMETERS_KEY] = true
end
return data
end
"""
Serialize the value, encoding as UUIDs where necessary.
"""
function serialize_uuid_handling(val)
if should_encode_as_uuid(val)
if val isa Array
value = IS.get_uuid.(val)
elseif val === nothing
value = nothing
else
value = IS.get_uuid(val)
end
else
value = val
end
return serialize(value)
end
function IS.deserialize(
::Type{T},
data::Dict,
component_cache::Dict,
) where {T <: _CONTAINS_SHOULD_ENCODE}
@debug "deserialize Component" _group = IS.LOG_GROUP_SERIALIZATION T data
vals = Dict{Symbol, Any}()
for (name, type) in zip(fieldnames(T), fieldtypes(T))
field_name = string(name)
if haskey(data, field_name)
val = data[field_name]
else
continue
end
if val isa Dict && haskey(val, IS.METADATA_KEY)
vals[name] = deserialize_uuid_handling(
IS.get_type_from_serialization_metadata(IS.get_serialization_metadata(val)),
val,
component_cache,
)
else
vals[name] = deserialize_uuid_handling(type, val, component_cache)
end
end
type = IS.get_type_from_serialization_metadata(data[IS.METADATA_KEY])
return type(; vals...)
end
function IS.deserialize(::Type{Device}, data::Dict)
error("This form of IS.deserialize is not supported for Devices")
return
end
function _check_uuid_in_component_cache(uuid::Base.UUID, component_cache)
if !haskey(component_cache, uuid)
error(
"UUID $uuid not found in component cache while deserializing system. \
This may indicate that a component was removed improperly leaving a UUID \
reference inside the top level component. This can happen when removing Arc, Area, ACBus or LoadZone \
components for example. \
Check the documentation for the `remove_component!` function and review your workflow. \
",
)
end
return
end
"""
Deserialize the value, converting UUIDs to components where necessary.
"""
function deserialize_uuid_handling(field_type, val, component_cache)
@debug "deserialize_uuid_handling" _group = IS.LOG_GROUP_SERIALIZATION field_type val
if val === nothing
value = val
elseif should_encode_as_uuid(field_type)
if field_type <: Vector
_vals = field_type()
for _val in val
uuid = deserialize(Base.UUID, _val)
_check_uuid_in_component_cache(uuid, component_cache)
component = component_cache[uuid]
push!(_vals, component)
end
value = _vals
else
uuid = deserialize(Base.UUID, val)
_check_uuid_in_component_cache(uuid, component_cache)
component = component_cache[uuid]
value = component
end
elseif field_type <: _CONTAINS_SHOULD_ENCODE
value = IS.deserialize(field_type, val, component_cache)
elseif field_type <: Union{Nothing, _CONTAINS_SHOULD_ENCODE}
value = IS.deserialize(field_type.b, val, component_cache)
elseif field_type <: InfrastructureSystemsType
value = deserialize(field_type, val)
elseif field_type isa Union && field_type.a <: Nothing && !(field_type.b <: Union)
# Nothing has already been handled. Apply the second type as long as there isn't a
# third. Julia appears to always put the Nothing in field a.
value = deserialize(field_type.b, val)
else
value = deserialize(field_type, val)
end
return value
end
================================================
FILE: src/models/services.jl
================================================
"""
Supertype for all system services
Services (or ancillary services) include additional requirements and support
to ensure reliable electricity service to customers. Common services are
reserve products to be able to respond quickly to unexpected disturbances,
such as the sudden loss of a transmission line or generator.
"""
abstract type Service <: Component end
"""
All PowerSystems [Service](@ref) types support time series. This can be overridden for custom
types that do not support time series.
"""
supports_time_series(::Service) = true
"""
All PowerSystems [Service](@ref) types support supplemental attributes. This can be overridden for
custom service types that do not support supplemental attributes.
"""
supports_supplemental_attributes(::Service) = true
================================================
FILE: src/models/static_injection_subsystem.jl
================================================
"""
Abstract type for a subsystem that contains multiple instances of StaticInjection
Subtypes must implement:
- get_subcomponents(subsystem::StaticInjectionSubsystem)
The subcomponents in subtypes must be attached to the System as masked components.
"""
abstract type StaticInjectionSubsystem <: StaticInjection end
"""
Efficiently add all time series data in the subcomponent to the subsystem by copying the
underlying references.
"""
function copy_subcomponent_time_series!(
subsystem::StaticInjectionSubsystem,
subcomponent::Component,
)
# the existing_ts can remove entries from the set if the Subsystem has two device of
# the same type with the same time series type and label. Currently in the HybridSystem
# use case there can only be one devoe of each type.
existing_ts = Set(
(typeof(ts), get_name(ts)) for
ts in IS.get_time_series_multiple(subsystem)
)
name_mapping = Dict{Tuple{String, String}, String}()
device_name = get_name(subcomponent)
for ts in get_time_series_multiple(subcomponent)
name = get_name(ts)
key = (typeof(ts), name)
if !(key in existing_ts)
new_name = make_subsystem_time_series_name(subcomponent, ts)
if name in keys(name_mapping)
IS.@assert_op new_name == name_mapping[(device_name, name)]
continue
end
name_mapping[(device_name, name)] = new_name
end
end
copy_time_series!(subsystem, subcomponent; name_mapping = name_mapping)
@info "Copied time series from $(summary(subcomponent)) to $(summary(subsystem))"
end
function make_subsystem_time_series_name(subcomponent::Component, ts::TimeSeriesData)
return make_subsystem_time_series_name(typeof(subcomponent), get_name(ts))
end
function make_subsystem_time_series_name(subcomponent::Component, label::String)
return make_subsystem_time_series_name(typeof(subcomponent), label)
end
function make_subsystem_time_series_name(subcomponent::Type{<:Component}, label::String)
return IS.strip_module_name(subcomponent) * "__" * label
end
================================================
FILE: src/models/static_models.jl
================================================
"""
Abstract type for devices that [inject](@ref I) power or current
A [static](@ref S) injection is a steady state injection, such as modeling
the output power of a generator held constant over a five-minute period.
Many `StaticInjection` models can accept a [`DynamicInjection`](@ref) model
as an optional add-on for conducting [dynamic](@ref D) simulations.
"""
abstract type StaticInjection <: Device end
function supports_services(::T) where {T <: Device}
return false
end
function supports_services(::T) where {T <: StaticInjection}
return true
end
function get_services(device::Device)
if !supports_services(device)
error(ArgumentError(
"Device $(get_name(device)) does not support services",
))
end
return Vector{Service}()
end
get_dynamic_injector(d::StaticInjection) = nothing
function get_frequency_droop(static_injector::StaticInjection)
dynamic_injector = get_dynamic_injector(static_injector)
if isnothing(dynamic_injector)
throw(
ArgumentError(
"cannot get frequency droop for $(summary(static_injector)) because it does not have dynamic data.",
),
)
end
return get_frequency_droop(dynamic_injector)
end
================================================
FILE: src/models/storage.jl
================================================
""" Supertype for energy storage technologies"""
abstract type Storage <: StaticInjection end
================================================
FILE: src/models/supplemental_accessors.jl
================================================
"""
Return the appropriate accessor function for the given aggregation topology type.
For [`Area`](@ref) types, returns [`get_area`](@ref); for [`LoadZone`](@ref) types, returns [`get_load_zone`](@ref).
"""
get_aggregation_topology_accessor(::Type{Area}) = get_area
"""
Return the appropriate accessor function for the given aggregation topology type.
For [`Area`](@ref) types, returns [`get_area`](@ref); for [`LoadZone`](@ref) types, returns [`get_load_zone`](@ref).
"""
get_aggregation_topology_accessor(::Type{LoadZone}) = get_load_zone
"""
Set the [`LoadZone`](@ref) for an [`ACBus`](@ref).
"""
set_load_zone!(bus::ACBus, load_zone::LoadZone) = bus.load_zone = load_zone
"""
Set the [`Area`](@ref) for an [`ACBus`](@ref).
"""
set_area!(bus::ACBus, area::Area) = bus.area = area
"""
Remove the aggregation topology in a [`ACBus`](@ref) by setting the corresponding field to `nothing`.
"""
_remove_aggregration_topology!(bus::ACBus, ::LoadZone) = bus.load_zone = nothing
_remove_aggregration_topology!(bus::ACBus, ::Area) = bus.area = nothing
"""
Generic method to calculate the susceptance of [`ACTransmission`](@ref) devices.
"""
get_series_susceptance(b::ACTransmission) = 1 / get_x(b)
"""
Returns the series susceptance of a controllable 2-winding transformer (e.g., [`TapTransformer`](@ref), [`PhaseShiftingTransformer`](@ref)) following the convention
in power systems to define susceptance as the inverse of the imaginary part of the impedance.
In the case of phase shifter transformers the angle is ignored.
See also: [`get_series_susceptances`](@ref) for 3-winding transformers
"""
function get_series_susceptance(b::Union{TapTransformer, PhaseShiftingTransformer})
y = 1 / get_x(b)
y_a = y / (get_tap(b))
return y_a
end
function get_series_susceptance(::Union{PhaseShiftingTransformer3W, Transformer3W})
throw(
ArgumentError(
"get_series_susceptance not implemented for multi-winding transformers, use get_series_susceptances instead",
),
)
end
"""
Returns the series susceptance of a [`PhaseShiftingTransformer3W`](@ref) as three values
(for each of the 3 branches) following the convention in power systems to define susceptance as the inverse of the imaginary part of the impedance.
The phase shift angles are ignored in the susceptance calculation.
See also: [`get_series_susceptance`](@ref) for 2-winding transformers and [`get_series_susceptances`](@ref get_series_susceptances(b::Transformer3W)) for [`Transformer3W`](@ref)
"""
function get_series_susceptances(b::PhaseShiftingTransformer3W)
y1 = 1 / get_x_primary(b)
y2 = 1 / get_x_secondary(b)
y3 = 1 / get_x_tertiary(b)
y1_a = y1 / get_primary_turns_ratio(b)
y2_a = y2 / get_secondary_turns_ratio(b)
y3_a = y3 / get_tertiary_turns_ratio(b)
return (y1_a, y2_a, y3_a)
end
"""
Returns the series susceptance of a [`Transformer3W`](@ref) as three values
(for each of the 3 branches) following the convention
in power systems to define susceptance as the inverse of the imaginary part of the impedance.
See also: [`get_series_susceptance`](@ref) for 2-winding transformers and [`get_series_susceptances`](@ref get_series_susceptances(b::PhaseShiftingTransformer3W)) for [`PhaseShiftingTransformer3W`](@ref)
"""
function get_series_susceptances(b::Transformer3W)
Z1s = get_r_primary(b) + get_x_primary(b) * 1im
Z2s = get_r_secondary(b) + get_x_secondary(b) * 1im
Z3s = get_r_tertiary(b) + get_x_tertiary(b) * 1im
b1s = imag(1 / Z1s)
b2s = imag(1 / Z2s)
b3s = imag(1 / Z3s)
return (b1s, b2s, b3s)
end
"""
get_base_voltage(line::Union{Line, MonitoredLine})
Return the base voltage (kV) of a [`Line`](@ref) or [`MonitoredLine`](@ref) by reading the
`base_voltage` from both endpoints of the line's [`Arc`](@ref).
If the two bus voltages are identical, that value is returned directly. If they differ but
are within `BRANCH_BUS_VOLTAGE_DIFFERENCE_TOL` (percent), the value with fewer significant
figures is returned (i.e., the rounder number). If the difference exceeds the tolerance, an
error is thrown.
"""
function get_base_voltage(line::Union{Line, MonitoredLine})
v_from = get_base_voltage(get_from_bus(line))
v_to = get_base_voltage(get_to_bus(line))
v_from == v_to && return v_from
percent_diff = abs(v_from - v_to) / ((v_from + v_to) / 2)
if percent_diff > BRANCH_BUS_VOLTAGE_DIFFERENCE_TOL
error(
"Bus voltage mismatch on $(get_name(line)): " *
"from=$(v_from) kV, to=$(v_to) kV exceeds " *
"$(BRANCH_BUS_VOLTAGE_DIFFERENCE_TOL * 100)% tolerance.",
)
end
return _select_fewer_significant_figures(v_from, v_to)
end
"""
Select the value with fewer significant figures (the "rounder" number).
Uses trailing zeros after stripping the decimal point as a proxy.
"""
function _select_fewer_significant_figures(a::Float64, b::Float64)
sa = rstrip(string(a), '0')
sb = rstrip(string(b), '0')
la = length(sa)
lb = length(sb)
la < lb && return a
lb < la && return b
return max(a, b)
end
"""
get_high_voltage(t::TwoWindingTransformer)
Return the high-side base voltage (kV) of a [`TwoWindingTransformer`](@ref) as the
maximum of `base_voltage_primary` and `base_voltage_secondary`.
"""
function get_high_voltage(t::TwoWindingTransformer)
v_primary = get_base_voltage_primary(t)
v_secondary = get_base_voltage_secondary(t)
return max(v_primary, v_secondary)
end
"""
get_low_voltage(t::TwoWindingTransformer)
Return the low-side base voltage (kV) of a [`TwoWindingTransformer`](@ref) as the
minimum of `base_voltage_primary` and `base_voltage_secondary`.
"""
function get_low_voltage(t::TwoWindingTransformer)
v_primary = get_base_voltage_primary(t)
v_secondary = get_base_voltage_secondary(t)
return min(v_primary, v_secondary)
end
"""
Calculate the series admittance of a [`ACTransmission`](@ref) as the inverse of the complex impedance.
Returns 1/(R + jX) where R is resistance and X is reactance.
"""
get_series_admittance(b::ACTransmission) = 1 / (get_r(b) + get_x(b) * 1im)
"""
Calculate the series admittance of a [`PhaseShiftingTransformer`](@ref) accounting for the tap ratio.
For a phase-shifting transformer, the series admittance is calculated as the inverse of the
complex impedance modified by the tap ratio, following the same pattern as the susceptance calculation:
Y = 1/(tap * (R + jX)).
The phase angle α affects the admittance matrix construction but not the series impedance magnitude directly.
See also: [`get_series_susceptance`](@ref)
"""
function get_series_admittance(b::PhaseShiftingTransformer)
tap = get_tap(b)
Z_series = get_r(b) + get_x(b) * 1im
return 1 / (tap * Z_series)
end
"""
Calculate the series admittance of a [`TapTransformer`](@ref) accounting for the tap ratio.
For a tap transformer, the series admittance is calculated as the inverse of the
complex impedance modified by the tap ratio, following the same pattern as the susceptance calculation:
Y = 1/(tap * (R + jX)).
See also: [`get_series_susceptance`](@ref)
"""
function get_series_admittance(b::TapTransformer)
tap = get_tap(b)
Z_series = get_r(b) + get_x(b) * 1im
return 1 / (tap * Z_series)
end
"""
Calculate the series admittances of a [`PhaseShiftingTransformer3W`](@ref) as three complex values
(for each of the 3 branches) accounting for turns ratios.
For each winding, the series admittance is calculated following the same pattern as the susceptance calculation:
Yi = 1/(turns_ratio_i * (Ri + jXi)).
The phase shift angles affect the admittance matrix construction but not the series impedance magnitudes directly.
See also: [`get_series_admittance`](@ref) for 2-winding transformers
"""
function get_series_admittances(b::PhaseShiftingTransformer3W)
# Get the turns ratios for each winding
tap_primary = get_primary_turns_ratio(b)
tap_secondary = get_secondary_turns_ratio(b)
tap_tertiary = get_tertiary_turns_ratio(b)
# Calculate series impedances
Z1 = get_r_primary(b) + get_x_primary(b) * 1im
Z2 = get_r_secondary(b) + get_x_secondary(b) * 1im
Z3 = get_r_tertiary(b) + get_x_tertiary(b) * 1im
# Calculate admittances accounting for turns ratios (consistent with susceptance pattern)
Y1 = 1 / (tap_primary * Z1)
Y2 = 1 / (tap_secondary * Z2)
Y3 = 1 / (tap_tertiary * Z3)
return (Y1, Y2, Y3)
end
function get_series_admittance(::Union{PhaseShiftingTransformer3W, Transformer3W})
throw(
ArgumentError(
"get_series_admittance not implemented for multi-winding transformers, use get_series_admittances instead.",
),
)
end
"""
Return the max active power for a device as the max field in the named tuple returned by [`get_active_power_limits`](@ref).
"""
function get_max_active_power(d::T) where {T <: StaticInjection}
return get_active_power_limits(d).max
end
"""
Return the max reactive power for a device as the max field in the named tuple returned by [`get_reactive_power_limits`](@ref).
"""
function get_max_reactive_power(d::T)::Float64 where {T <: StaticInjection}
if isnothing(get_reactive_power_limits(d))
return Inf
end
return get_reactive_power_limits(d).max
end
"""
Return the max reactive power for a [`RenewableDispatch`](@ref) generator calculated as the `rating` * `power_factor` if
the field `reactive_power_limits` is `nothing`
"""
function get_max_reactive_power(d::RenewableDispatch)
reactive_power_limits = get_reactive_power_limits(d)
if isnothing(reactive_power_limits)
return get_rating(d) * sin(acos(get_power_factor(d)))
end
return reactive_power_limits.max
end
"""
Generic fallback function for getting active power limits. Throws `ArgumentError` for devices
that don't implement this function.
"""
get_active_power_limits(::T) where {T <: Device} =
throw(ArgumentError("get_active_power_limits not implemented for $T"))
"""
Generic fallback function for getting reactive power limits. Throws `ArgumentError` for devices
that don't implement this function.
"""
get_reactive_power_limits(::T) where {T <: Device} =
throw(ArgumentError("get_reactive_power_limits not implemented for $T"))
"""
Generic fallback function for getting device rating. Throws `ArgumentError` for devices
that don't implement this function.
"""
get_rating(::T) where {T <: Device} =
throw(ArgumentError("get_rating not implemented for $T"))
"""
Generic fallback function for getting power factor. Throws `ArgumentError` for devices
that don't implement this function.
"""
get_power_factor(::T) where {T <: Device} =
throw(ArgumentError("get_power_factor not implemented for $T"))
"""
Calculate the maximum active power for a [`StandardLoad`](@ref) or [`InterruptibleStandardLoad`](@ref)
by summing the maximum constant, impedance, and current components assuming a 1.0 voltage magnitude at the bus.
"""
function get_max_active_power(d::Union{InterruptibleStandardLoad, StandardLoad})
total_load = get_max_constant_active_power(d)
total_load += get_max_impedance_active_power(d)
total_load += get_max_current_active_power(d)
return total_load
end
"""
Get the maximum storage capacity for HydroReservoir.
"""
function get_max_storage_level(reservoir::HydroReservoir)
return get_storage_level_limits(reservoir).max
end
"""
Get the flow limits from source [`Area`](@ref) to destination [`Area`](@ref) for an [`AreaInterchange`](@ref).
"""
function get_from_to_flow_limit(a::AreaInterchange)
return get_flow_limits(a).from_to
end
"""
Get the flow limits from destination [`Area`](@ref) to source [`Area`](@ref) for an [`AreaInterchange`](@ref).
"""
function get_to_from_flow_limit(a::AreaInterchange)
return get_flow_limits(a).to_from
end
"""
Get the minimum active power flow limit for a [`TransmissionInterface`](@ref).
"""
function get_min_active_power_flow_limit(tx::TransmissionInterface)
return get_active_power_flow_limits(tx).min
end
"""
Get the maximum active power flow limit for a [`TransmissionInterface`](@ref).
"""
function get_max_active_power_flow_limit(tx::TransmissionInterface)
return get_active_power_flow_limits(tx).max
end
"""
Calculate the phase shift angle α for a [`TapTransformer`](@ref) or [`Transformer2W`](@ref) based on its winding group number.
Returns the angle in radians, calculated as -(π/6) * `winding_group_number`.
If the `winding_group_number` is `WindingGroupNumber.UNDEFINED`, returns 0.0 and issues a warning.
"""
function get_α(t::Union{TapTransformer, Transformer2W})
if get_winding_group_number(t) == WindingGroupNumber.UNDEFINED
@debug "winding group number for $(summary(t)) is undefined, assuming zero phase shift"
return 0.0
else
return get_winding_group_number(t).value * -(π / 6)
end
end
"""
Calculate the phase shift angle α for the primary winding of a [`Transformer3W`](@ref)
based on its primary winding group number. Returns the angle in radians, calculated
as -(π/6) * `primary_group_number`. If `primary_group_number` is `WindingGroupNumber.UNDEFINED`, returns 0.0 and issues a warning.
"""
function get_α_primary(t::Transformer3W)
if get_primary_group_number(t) == WindingGroupNumber.UNDEFINED
@warn "primary winding group number for $(summary(t)) is undefined, assuming zero phase shift"
return 0.0
else
return get_primary_group_number(t).value * -(π / 6)
end
end
"""
Calculate the phase shift angle α for the secondary winding of a [`Transformer3W`](@ref)
based on its secondary winding group number. Returns the angle in radians, calculated
as -(π/6) * `secondary_group_number`. If `secondary_group_number` is `WindingGroupNumber.UNDEFINED`, returns 0.0 and issues a warning.
"""
function get_α_secondary(t::Transformer3W)
if get_secondary_group_number(t) == WindingGroupNumber.UNDEFINED
@warn "secondary winding group number for $(summary(t)) is undefined, assuming zero phase shift"
return 0.0
else
return get_secondary_group_number(t).value * -(π / 6)
end
end
"""
Calculate the phase shift angle α for the tertiary winding of a [`Transformer3W`](@ref)
based on its tertiary winding group number. Returns the angle in radians, calculated
as -(π/6) * `tertiary_group_number`. If `tertiary_group_number` is `WindingGroupNumber.UNDEFINED`, returns 0.0 and issues a warning.
"""
function get_α_tertiary(t::Transformer3W)
if get_tertiary_group_number(t) == WindingGroupNumber.UNDEFINED
@warn "tertiary winding group number for $(summary(t)) is undefined, assuming zero phase shift"
return 0.0
else
return get_tertiary_group_number(t).value * -(π / 6)
end
end
function supports_services(::AreaInterchange)
return true
end
================================================
FILE: src/models/supplemental_constructors.jl
================================================
"""Accepts angle_limits as a Float64."""
function Line(
name,
available::Bool,
active_power_flow::Float64,
reactive_power_flow::Float64,
arc::Arc,
r,
x,
b,
rating,
angle_limits::Float64,
)
return Line(
name,
available,
active_power_flow,
reactive_power_flow,
arc::Arc,
r,
x,
b,
rating,
(min = -angle_limits, max = angle_limits),
)
end
"""Allows construction with bus type specified as a string for legacy code."""
function ACBus(
number,
name,
available,
bustype::String,
angle,
voltage,
voltage_limits,
base_voltage,
area,
load_zone;
ext = Dict{String, Any}(),
)
return ACBus(
number,
name,
available,
get_enum_value(ACBusTypes, bustype),
angle,
voltage,
voltage_limits,
base_voltage,
area,
load_zone,
ext,
InfrastructureSystemsInternal(),
)
end
"""Allows construction with bus type specified as a string for legacy code."""
function DiscreteControlledACBranch(
name,
available,
arc,
active_power_flow,
reactive_power_flow,
r,
x,
rating,
discrete_branch_type::String,
branch_status::String,
ext = Dict{String, Any}(),
internal = InfrastructureSystemsInternal(),
)
return DiscreteControlledACBranch(
name,
available,
arc,
active_power_flow,
reactive_power_flow,
r,
x,
rating,
get_enum_value(DiscreteControlledBranchType, discrete_branch_type),
get_enum_value(DiscreteControlledBranchStatus, branch_status),
ext,
internal,
)
end
"""Allows construction of FACT Devices with control modes."""
function FACTSControlDevice(
name,
available,
bus,
control_mode::String,
voltage_setpoint,
max_shunt_current,
reactive_power_required,
services = Device[],
dynamic_injector = nothing,
ext = Dict{String, Any}(),
internal = InfrastructureSystemsInternal(),
)
return FACTSControlDevice(
name,
available,
bus,
get_enum_value(FACTSOperationModes, control_mode),
voltage_setpoint,
max_shunt_current,
reactive_power_required,
services,
dynamic_injector,
ext,
internal,
)
end
"""Allows construction of a reserve from an iterator."""
function ConstantReserve(
name,
contributingdevices::IS.FlattenIteratorWrapper,
timeframe,
requirement,
time_series,
internal,
)
return ConstantReserve(
name,
collect(contributingdevices),
timeframe,
requirement,
time_series,
internal,
)
end
"""Allows construction of a EnergyReservoirStorage without the specification of a cost."""
function EnergyReservoirStorage(
name::AbstractString,
available::Bool,
bus,
prime_mover_type,
storage_technology_type,
storage_capacity,
storage_level_limits,
initial_storage_capacity_level,
rating,
active_power,
input_active_power_limits,
output_active_power_limits,
efficiency,
reactive_power,
reactive_power_limits,
base_power,
::Nothing,
services = Device[],
dynamic_injector = nothing,
ext = Dict{String, Any}(),
internal = InfrastructureSystemsInternal(),
)
EnergyReservoirStorage(
name,
available,
bus,
prime_mover_type,
storage_technology_type,
storage_capacity,
storage_level_limits,
initial_storage_capacity_level,
rating,
active_power,
input_active_power_limits,
output_active_power_limits,
efficiency,
reactive_power,
reactive_power_limits,
base_power,
StorageCost();
services = services,
dynamic_injector = dynamic_injector,
ext = ext,
internal = internal,
)
end
================================================
FILE: src/models/supplemental_setters.jl
================================================
"""
Set a single upstream turbine for a [`HydroReservoir`](@ref).
"""
function set_upstream_turbine!(reservoir::HydroReservoir, turbine::HydroUnit)
set_upstream_turbines!(reservoir, [turbine])
return
end
"""
Set a single downstream turbine for a [`HydroReservoir`](@ref).
"""
function set_downstream_turbine!(reservoir::HydroReservoir, turbine::HydroUnit)
set_downstream_turbines!(reservoir, [turbine])
return
end
function set_head_to_volume_factor!(reservoir::HydroReservoir, val::Float64)
return set_head_to_volume_factor!(reservoir, LinearCurve(val))
end
================================================
FILE: src/models/topological_elements.jl
================================================
"""
Abstract type to represent the structure and interconnectedness of the system
"""
abstract type Topology <: Component end
"""
Represents a geographical region of system components.
All subtypes must implement the method `get_aggregation_topology_accessor`.
"""
abstract type AggregationTopology <: Topology end
"""
All PowerSystems [AggregationTopology](@ref) types support time series. This can be overridden for specific custom
aggregation topology types that do not support time series.
"""
supports_time_series(::AggregationTopology) = true
"""
Abstract type to represent any type of Bus, AC or DC.
"""
abstract type Bus <: Topology end
"""
Return the method to be called on a ACBus to get its AggregationTopology value for this type.
"""
function get_aggregation_topology_accessor(::Type{T}) where {T <: AggregationTopology}
error("get_aggregation_topology_accessor must be implemented for $T")
return
end
function check_bus_params(
number,
name,
available,
bustype,
angle,
voltage,
voltage_limits,
base_voltage,
area,
load_zone,
ext,
internal,
)
if !isnothing(bustype)
if bustype == ACBusTypes.SLACK
bustype = ACBusTypes.REF
@debug "Changed bus type from SLACK to" _group = IS.LOG_GROUP_SYSTEM bustype
#elseif bustype == BusTypes.ISOLATED
# throw(DataFormatError("isolated buses are not supported; name=$name"))
end
end
return number,
name,
available,
bustype,
angle,
voltage,
voltage_limits,
base_voltage,
area,
load_zone,
ext,
internal
end
================================================
FILE: src/outages.jl
================================================
"""
Supertype for outage contingencies representing planned or unplanned equipment outages.
Concrete subtypes include [`GeometricDistributionForcedOutage`](@ref),
[`PlannedOutage`](@ref), and [`FixedForcedOutage`](@ref).
"""
abstract type Outage <: Contingency end
abstract type UnplannedOutage <: Outage end
"""
All PowerSystems [Outage](@ref) types support time series. This can be overridden for custom
outage types that do not support time series.
"""
supports_time_series(::Outage) = true
"""Get `internal`."""
get_internal(x::Outage) = x.internal
"""
Attribute that contains information regarding forced outages where the transition probabilities
are modeled with geometric distributions. The outage probabilities and recovery probabilities can be modeled as time
series.
# Arguments
- `mean_time_to_recovery::Float64`: Time elapsed to recovery after a failure in Milliseconds.
- `outage_transition_probability::Float64`: Characterizes the probability of failure (1 - p) in the geometric distribution.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems internal reference
"""
struct GeometricDistributionForcedOutage <: UnplannedOutage
mean_time_to_recovery::Float64
outage_transition_probability::Float64
internal::InfrastructureSystemsInternal
end
"""
GeometricDistributionForcedOutage(; mean_time_to_recovery, outage_transition_probability, internal)
Construct a [`GeometricDistributionForcedOutage`](@ref).
# Arguments
- `mean_time_to_recovery::Float64`: (default: `0.0`) Time elapsed to recovery after a failure in Milliseconds.
- `outage_transition_probability::Float64`: (default: `0.0`) Characterizes the probability of failure (1 - p) in the geometric distribution.
- `internal::InfrastructureSystemsInternal`: (default: `InfrastructureSystemsInternal()`) (**Do not modify.**) PowerSystems internal reference
"""
function GeometricDistributionForcedOutage(;
mean_time_to_recovery = 0.0,
outage_transition_probability = 0.0,
internal = InfrastructureSystemsInternal(),
)
return GeometricDistributionForcedOutage(
mean_time_to_recovery,
outage_transition_probability,
internal,
)
end
"""Get [`GeometricDistributionForcedOutage`](@ref) `time_to_recovery`."""
get_mean_time_to_recovery(value::GeometricDistributionForcedOutage) =
value.mean_time_to_recovery
"""Get [`GeometricDistributionForcedOutage`](@ref) `outage_transition_probability`."""
get_outage_transition_probability(value::GeometricDistributionForcedOutage) =
value.outage_transition_probability
"""
Attribute that contains information regarding planned outages.
# Arguments
- `outage_schedule::String`: String name of the time series used for the scheduled outages
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems internal reference
"""
struct PlannedOutage <: Outage
outage_schedule::String
internal::InfrastructureSystemsInternal
end
"""
PlannedOutage(; outage_schedule, internal)
Construct a [`PlannedOutage`](@ref).
# Arguments
- `outage_schedule::String`: String name of the time series used for the scheduled outages
- `internal::InfrastructureSystemsInternal`: (default: `InfrastructureSystemsInternal()`) (**Do not modify.**) PowerSystems internal reference
"""
function PlannedOutage(;
outage_schedule,
internal = InfrastructureSystemsInternal(),
)
return PlannedOutage(
outage_schedule,
internal,
)
end
"""Get [`PlannedOutage`](@ref) `outage_schedule`."""
get_outage_schedule(value::PlannedOutage) = value.outage_schedule
"""
Attribute that contains the representation of the status of the component forced outage.
The time series data for fixed outages can be obtained from the simulation of a stochastic process or historical information.
# Arguments
- `outage_status::Float64`: The forced outage status in the model. 1 represents outaged and 0 represents available.
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems internal reference
"""
struct FixedForcedOutage <: UnplannedOutage
outage_status::Float64
internal::InfrastructureSystemsInternal
end
"""
FixedForcedOutage(; outage_status, internal)
Construct a [`FixedForcedOutage`](@ref).
# Arguments
- `outage_status::Float64`: The forced outage status in the model. 1 represents outaged and 0 represents available.
- `internal::InfrastructureSystemsInternal`: (default: `InfrastructureSystemsInternal()`) (**Do not modify.**) PowerSystems internal reference
"""
function FixedForcedOutage(;
outage_status,
internal = InfrastructureSystemsInternal(),
)
return FixedForcedOutage(outage_status, internal)
end
"""Get [`FixedForcedOutage`](@ref) `outage_status`."""
get_outage_status(value::FixedForcedOutage) = value.outage_status
================================================
FILE: src/parsers/common.jl
================================================
const GENERATOR_MAPPING_FILE_PM =
joinpath(dirname(pathof(PowerSystems)), "parsers", "generator_mapping_pm.yaml")
const GENERATOR_MAPPING_FILE_CDM =
joinpath(dirname(pathof(PowerSystems)), "parsers", "generator_mapping_cdm.yaml")
const PSSE_DYR_MAPPING_FILE =
joinpath(dirname(pathof(PowerSystems)), "parsers", "psse_dynamic_mapping.yaml")
const STRING2FUEL =
Dict((normalize(string(x); casefold = true) => x) for x in instances(ThermalFuels))
merge!(
STRING2FUEL,
Dict(
"ng" => ThermalFuels.NATURAL_GAS,
"nuc" => ThermalFuels.NUCLEAR,
"gas" => ThermalFuels.NATURAL_GAS,
"oil" => ThermalFuels.DISTILLATE_FUEL_OIL,
"dfo" => ThermalFuels.DISTILLATE_FUEL_OIL,
"sync_cond" => ThermalFuels.OTHER,
"geothermal" => ThermalFuels.GEOTHERMAL,
"ag_byproduct" => ThermalFuels.AG_BYPRODUCT,
),
)
const STRING2PRIMEMOVER =
Dict((normalize(string(x); casefold = true) => x) for x in instances(PrimeMovers))
merge!(
STRING2PRIMEMOVER,
Dict(
"w2" => PrimeMovers.WT,
"wind" => PrimeMovers.WT,
"pv" => PrimeMovers.PVe,
"solar" => PrimeMovers.PVe,
"rtpv" => PrimeMovers.PVe,
"nb" => PrimeMovers.ST,
"steam" => PrimeMovers.ST,
"hydro" => PrimeMovers.HY,
"ror" => PrimeMovers.HY,
"pump" => PrimeMovers.PS,
"pumped_hydro" => PrimeMovers.PS,
"nuclear" => PrimeMovers.ST,
"sync_cond" => PrimeMovers.OT,
"csp" => PrimeMovers.CP,
"un" => PrimeMovers.OT,
"storage" => PrimeMovers.BA,
"ice" => PrimeMovers.IC,
),
)
"""Return a dict where keys are a tuple of input parameters (fuel, unit_type) and values are
generator types."""
function get_generator_mapping(filename::String)
genmap = open(filename) do file
YAML.load(file)
end
mappings = Dict{NamedTuple, DataType}()
for (gen_type, vals) in genmap
if gen_type == "GenericBattery"
@warn "GenericBattery type is no longer supported. The new type is EnergyReservoirStorage"
gen = EnergyReservoirStorage
else
gen = getfield(PowerSystems, Symbol(gen_type))
end
for val in vals
key = (fuel = val["fuel"], unit_type = val["type"])
if haskey(mappings, key)
error("duplicate generator mappings: $gen $(key.fuel) $(key.unit_type)")
end
mappings[key] = gen
end
end
return mappings
end
"""Return the PowerSystems generator type for this fuel and unit_type."""
function get_generator_type(fuel, unit_type, mappings::Dict{NamedTuple, DataType})
fuel = isnothing(fuel) ? "" : uppercase(fuel)
unit_type = uppercase(unit_type)
generator = nothing
# Try to match the unit_type if it's defined. If it's nothing then just match on fuel.
for ut in (unit_type, nothing), fu in (fuel, nothing)
key = (fuel = fu, unit_type = ut)
if haskey(mappings, key)
generator = mappings[key]
break
end
end
if isnothing(generator)
@error "No mapping for generator fuel=$fuel unit_type=$unit_type"
end
return generator
end
function calculate_gen_rating(
active_power_limits::Union{MinMax, Nothing},
reactive_power_limits::Union{MinMax, Nothing},
base_conversion::Float64,
)
reactive_power_max = isnothing(reactive_power_limits) ? 0.0 : reactive_power_limits.max
return calculate_gen_rating(
active_power_limits.max,
reactive_power_max,
base_conversion,
)
end
function calculate_gen_rating(
active_power_max::Float64,
reactive_power_max::Float64,
base_conversion::Float64,
)
rating = sqrt(active_power_max^2 + reactive_power_max^2)
if rating == 0.0
@warn "Rating calculation returned 0.0. Changing to 1.0 in the p.u. of the device."
return 1.0
end
return rating * base_conversion
end
function calculate_ramp_limit(
d::Dict{String, Any},
gen_name::Union{SubString{String}, String},
)
if haskey(d, "ramp_agc")
return (up = d["ramp_agc"], down = d["ramp_agc"])
end
if haskey(d, "ramp_10")
return (up = d["ramp_10"], down = d["ramp_10"])
end
if haskey(d, "ramp_30")
return (up = d["ramp_30"], down = d["ramp_30"])
end
if abs(d["pmax"]) > 0.0
@debug "No ramp limits found for generator $(gen_name). Using pmax as ramp limit."
return (up = abs(d["pmax"]), down = abs(d["pmax"]))
end
@warn "Not enough information to determine ramp limit for generator $(gen_name). Returning nothing"
return nothing
end
function string_compare(str1, str2; casefold = true)
return normalize(str1; casefold = casefold) === normalize(str2; casefold = casefold)
end
function string_occursin(str1, str2; casefold = true)
return occursin(
normalize(str1; casefold = casefold),
normalize(srt2; casefold = casefold),
)
end
function convert_units!(
value::Float64,
unit_conversion::NamedTuple{(:From, :To), Tuple{String, String}},
)
if string_compare(unit_conversion.From, "degree") &&
string_compare(unit_conversion.To, "radian")
value = deg2rad(value)
elseif string_compare(unit_conversion.From, "radian") &&
string_compare(unit_conversion.To, "degree")
value = rad2deg(value)
elseif string_compare(unit_conversion.From, "TW") &&
string_compare(unit_conversion.To, "MW")
value *= 1e6
elseif string_compare(unit_conversion.From, "TWh") &&
string_compare(unit_conversion.To, "MWh")
value *= 1e6
elseif string_compare(unit_conversion.From, "GW") &&
string_compare(unit_conversion.To, "MW")
value *= 1000
elseif string_compare(unit_conversion.From, "GWh") &&
string_compare(unit_conversion.To, "MWh")
value *= 1000
elseif string_compare(unit_conversion.From, "kW") &&
string_compare(unit_conversion.To, "MW")
value /= 1000
elseif string_compare(unit_conversion.From, "kWh") &&
string_compare(unit_conversion.To, "MWh")
value /= 1000
elseif string_compare(unit_conversion.From, "hour") &&
string_compare(unit_conversion.To, "second")
value *= 3600
elseif string_compare(unit_conversion.From, "minute") &&
string_compare(unit_conversion.To, "second")
value *= 60
elseif string_compare(unit_conversion.From, "hour") &&
string_compare(unit_conversion.To, "minute")
value *= 60
elseif string_compare(unit_conversion.From, "minute") &&
string_compare(unit_conversion.To, "hour")
value /= 60
elseif string_compare(unit_conversion.From, "second") &&
string_compare(unit_conversion.To, "minute")
value /= 60
elseif string_compare(unit_conversion.From, "second") &&
string_compare(unit_conversion.To, "hour")
value /= 3600
else
throw(
DataFormatError(
"Unit conversion from $(unit_conversion.From) to $(unit_conversion.To) not supported",
),
)
end
return value
end
function convert_units!(
value::Int,
unit_conversion::NamedTuple{(:From, :To), Tuple{String, String}},
)
return convert_units!(convert(Float64, value), unit_conversion)
end
function parse_enum_mapping(::Type{ThermalFuels}, fuel::AbstractString)
return STRING2FUEL[normalize(fuel; casefold = true)]
end
function parse_enum_mapping(::Type{ThermalFuels}, fuel::Symbol)
return parse_enum_mapping(ThermalFuels, string(fuel))
end
function parse_enum_mapping(::Type{PrimeMovers}, prime_mover::AbstractString)
return STRING2PRIMEMOVER[normalize(prime_mover; casefold = true)]
end
function parse_enum_mapping(::Type{PrimeMovers}, prime_mover::Symbol)
return parse_enum_mapping(PrimeMovers, string(prime_mover))
end
================================================
FILE: src/parsers/enums.jl
================================================
IS.@scoped_enum(
InputCategory,
BRANCH = 1,
BUS = 2,
DC_BRANCH = 3,
GENERATOR = 4,
LOAD = 5,
RESERVE = 6,
SIMULATION_OBJECTS = 7,
STORAGE = 8,
FACTS = 9,
DCBRTYPE = 10,
DCBRSTATUS = 11,
TICT = 12,
)
const ENUMS = (
AngleUnits,
ACBusTypes,
FACTSOperationModes,
DiscreteControlledBranchType,
DiscreteControlledBranchStatus,
WindingCategory,
ImpedanceCorrectionTransformerControlMode,
GeneratorCostModels,
InputCategory,
PrimeMovers,
StateTypes,
ReservoirDataType,
ReservoirLocation,
ThermalFuels,
UnitSystem,
LoadConformity,
WindingGroupNumber,
HydroTurbineType,
TransformerControlObjective,
)
const ENUM_MAPPINGS = Dict()
for enum in ENUMS
ENUM_MAPPINGS[enum] = Dict()
for value in instances(enum)
ENUM_MAPPINGS[enum][normalize(string(value); casefold = true)] = value
end
end
"""Get the enum value for the string. Case insensitive."""
function get_enum_value(enum, value::AbstractString)
if !haskey(ENUM_MAPPINGS, enum)
throw(ArgumentError("enum=$enum is not valid"))
end
val = normalize(value; casefold = true)
if !haskey(ENUM_MAPPINGS[enum], val)
throw(ArgumentError("enum=$enum does not have value=$val"))
end
return ENUM_MAPPINGS[enum][val]
end
Base.convert(::Type{AngleUnits}, val::AbstractString) = get_enum_value(AngleUnits, val)
Base.convert(::Type{ACBusTypes}, val::AbstractString) = get_enum_value(ACBusTypes, val)
Base.convert(::Type{LoadConformity}, val::AbstractString) =
get_enum_value(LoadConformity, val)
Base.convert(::Type{FACTSOperationModes}, val::AbstractString) =
get_enum_value(FACTSOperationModes, val)
Base.convert(::Type{DiscreteControlledBranchType}, val::AbstractString) =
get_enum_value(DiscreteControlledBranchType, val)
Base.convert(::Type{DiscreteControlledBranchStatus}, val::AbstractString) =
get_enum_value(DiscreteControlledBranchStatus, val)
Base.convert(::Type{WindingCategory}, val::AbstractString) =
get_enum_value(WindingCategory, val)
Base.convert(::Type{WindingGroupNumber}, val::AbstractString) =
get_enum_value(WindingGroupNumber, val)
Base.convert(::Type{ImpedanceCorrectionTransformerControlMode}, val::AbstractString) =
get_enum_value(ImpedanceCorrectionTransformerControlMode, val)
Base.convert(::Type{GeneratorCostModels}, val::AbstractString) =
get_enum_value(GeneratorCostModels, val)
Base.convert(::Type{PrimeMovers}, val::AbstractString) = get_enum_value(PrimeMovers, val)
Base.convert(::Type{StateTypes}, val::AbstractString) = get_enum_value(StateTypes, val)
Base.convert(::Type{ThermalFuels}, val::AbstractString) = get_enum_value(ThermalFuels, val)
Base.convert(::Type{TransformerControlObjective}, val::AbstractString) =
get_enum_value(TransformerControlObjective, val)
Base.convert(::Type{ReservoirLocation}, val::AbstractString) =
get_enum_value(ReservoirLocation, val)
Base.convert(::Type{HydroTurbineType}, val::AbstractString) =
get_enum_value(ReservoirLocation, val)
================================================
FILE: src/parsers/generator_mapping_cdm.yaml
================================================
# Parsing code ignores type=null.
HydroTurbine:
- {fuel: HYDRO, type: null}
- {fuel: HYDRO, type: HYDRO}
HydroDispatch:
- {fuel: HYDRO, type: ROR}
RenewableDispatch:
- {fuel: SOLAR, type: PV}
- {fuel: SOLAR, type: UN}
- {fuel: WIND, type: WIND}
- {fuel: WIND, type: null}
- {fuel: SOLAR, type: CSP} # TODO: may need a new struct
RenewableNonDispatch:
- {fuel: SOLAR, type: RTPV}
ThermalStandard:
- {fuel: OIL, type: null}
- {fuel: COAL, type: null}
- {fuel: NG, type: null}
- {fuel: GAS, type: null}
- {fuel: NUCLEAR, type: null}
- {fuel: NUC, type: null}
- {fuel: OTHER, type: OT}
SynchronousCondenser:
- {fuel: SYNC_COND, type: SYNC_COND}
EnergyReservoirStorage:
- {fuel: STORAGE, type: null}
================================================
FILE: src/parsers/generator_mapping_pm.yaml
================================================
# Parsing code ignores type=null.
HydroTurbine:
- {fuel: HYDRO, type: null}
- {fuel: HYDRO, type: HYDRO}
HydroDispatch:
- {fuel: HYDRO, type: ROR}
RenewableDispatch:
- {fuel: SOLAR, type: PV}
- {fuel: SOLAR, type: UN}
- {fuel: WIND, type: WIND}
- {fuel: WIND, type: null}
- {fuel: SOLAR, type: CSP} # TODO: may need a new struct
RenewableNonDispatch:
- {fuel: SOLAR, type: RTPV}
ThermalStandard:
- {fuel: OIL, type: null}
- {fuel: COAL, type: null}
- {fuel: NG, type: null}
- {fuel: GAS, type: null}
- {fuel: NUCLEAR, type: null}
- {fuel: NUC, type: null}
- {fuel: OTHER, type: OT}
SynchronousCondenser:
- {fuel: SYNC_COND, type: SYNC_COND}
EnergyReservoirStorage:
- {fuel: STORAGE, type: null}
================================================
FILE: src/parsers/im_io/LICENSE.md
================================================
Copyright (c) 2016, Los Alamos National Security, LLC
All rights reserved.
Copyright 2016. Los Alamos National Security, LLC. This software was produced under U.S. Government contract DE-AC52-06NA25396 for Los Alamos National Laboratory (LANL), which is operated by Los Alamos National Security, LLC for the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, LLC MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce derivative works, such modified software should be clearly marked, so as not to confuse it with the version available from LANL.
Additionally, redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. 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.
3. Neither the name of Los Alamos National Security, LLC, Los Alamos National Laboratory, LANL, the U.S. Government, 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 LOS ALAMOS NATIONAL SECURITY, LLC 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 LOS ALAMOS NATIONAL SECURITY, LLC 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: src/parsers/im_io/common.jl
================================================
"turns top level arrays into dicts"
function arrays_to_dicts!(data::Dict{String, <:Any})
# update lookup structure
for (k, v) in data
if isa(v, Array) && length(v) > 0 && isa(v[1], Dict)
#println("updating $(k)")
dict = Dict{Int, Any}()
for (i, item) in enumerate(v)
if haskey(item, "index")
key = item["index"]
else
key = i
end
if !(haskey(dict, key))
dict[key] = item
else
@warn "skipping component $(item["index"]) from the $(k) table because a component with the same id already exists"
end
end
data[k] = dict
end
end
end
"takes a row from a matrix and assigns the values names and types"
function row_to_typed_dict(row_data, columns)
dict_data = Dict{String, Any}()
for (i, v) in enumerate(row_data)
if i <= length(columns)
name, typ = columns[i]
dict_data[name] = check_type(typ, v)
else
dict_data["col_$(i)"] = v
end
end
return dict_data
end
"takes a row from a matrix and assigns the values names"
function row_to_dict(row_data, columns)
dict_data = Dict{String, Any}()
for (i, v) in enumerate(row_data)
if i <= length(columns)
dict_data[columns[i]] = v
else
dict_data["col_$(i)"] = v
end
end
return dict_data
end
row_to_dict(row_data) = row_to_dict(row_data, [])
================================================
FILE: src/parsers/im_io/data.jl
================================================
"recursively applies new_data to data, overwriting information"
function update_data!(data::Dict{String, <:Any}, new_data::Dict{String, <:Any})
if haskey(data, "per_unit") && haskey(new_data, "per_unit")
if data["per_unit"] != new_data["per_unit"]
error(
"update_data requires datasets in the same units, try make_per_unit and make_mixed_units",
)
end
else
@warn "running update_data with data that does not include per_unit field, units may be incorrect"
end
_update_data!(data, new_data)
return
end
"recursive call of _update_data"
function _update_data!(data::Dict{String, <:Any}, new_data::Dict{String, <:Any})
for (key, new_v) in new_data
if haskey(data, key)
v = data[key]
if isa(v, Dict) && isa(new_v, Dict)
_update_data!(v, new_v)
else
data[key] = new_v
end
else
data[key] = new_v
end
end
return
end
"checks if a given network data is a multinetwork"
ismultinetwork(data::Dict{String, <:Any}) =
(haskey(data, "multinetwork") && data["multinetwork"] == true)
"Transforms a single network into a multinetwork with several deepcopies of the original network"
function im_replicate(sn_data::Dict{String, <:Any}, count::Int, global_keys::Set{String})
@assert count > 0
if ismultinetwork(sn_data)
error("replicate can only be used on single networks")
end
name = get(sn_data, "name", "anonymous")
mn_data = Dict{String, Any}("nw" => Dict{String, Any}())
mn_data["multinetwork"] = true
sn_data_tmp = deepcopy(sn_data)
for k in global_keys
if haskey(sn_data_tmp, k)
mn_data[k] = sn_data_tmp[k]
end
# note this is robust to cases where k is not present in sn_data_tmp
delete!(sn_data_tmp, k)
end
mn_data["name"] = "$(count) replicates of $(name)"
for n in 1:count
mn_data["nw"]["$n"] = deepcopy(sn_data_tmp)
end
return mn_data
end
#=
"Attempts to determine if the given data is a component dictionary"
function _iscomponentdict(data::Dict)
return all( typeof(comp) <: Dict for (i, comp) in data )
end
=#
"Makes a string bold in the terminal"
function _bold(s::String)
return "\033[1m$(s)\033[0m"
end
"""
Makes a string grey in the terminal, does not seem to work well on Windows terminals
more info can be found at https://en.wikipedia.org/wiki/ANSI_escape_code
"""
function _grey(s::String)
return "\033[38;5;239m$(s)\033[0m"
end
"converts any value to a string, summarizes arrays and dicts"
function _value2string(v, float_precision::Int)
if typeof(v) <: AbstractFloat
return _float2string(v, float_precision)
end
if typeof(v) <: Array
return "[($(length(v)))]"
end
if typeof(v) <: Dict
return "{($(length(v)))}"
end
return "$(v)"
end
"""
converts a float value into a string of fixed precision
sprintf would do the job but this work around is needed because
sprintf cannot take format strings during runtime
"""
function _float2string(v::AbstractFloat, float_precision::Int)
#str = "$(round(v; digits=float_precision))"
str = "$(round(v; digits=float_precision))"
lhs = length(split(str, '.')[1])
return rpad(str, lhs + 1 + float_precision, "0")
end
"tests if two dicts are equal, up to floating point precision"
function compare_dict(d1, d2)
for (k1, v1) in d1
if !haskey(d2, k1)
#println(k1)
return false
end
v2 = d2[k1]
if isa(v1, Number)
if !_compare_numbers(v1, v2)
return false
end
elseif isa(v1, Array)
if length(v1) != length(v2)
return false
end
for i in 1:length(v1)
if isa(v1[i], Number)
if !_compare_numbers(v1[i], v2[i])
return false
end
else
if v1 != v2
#println(v1, " ", v2)
return false
end
end
end
elseif isa(v1, Dict)
if !compare_dict(v1, v2)
#println(v1, " ", v2)
return false
end
else
#println("2")
if !isapprox(v1, v2)
#println(v1, " ", v2)
return false
end
end
end
return true
end
"tests if two numbers are equal, up to floating point precision"
function _compare_numbers(v1, v2)
if isnan(v1)
#println("1.1")
if !isnan(v2)
#println(v1, " ", v2)
return false
end
else
#println("1.2")
if !isapprox(v1, v2)
#println(v1, " ", v2)
return false
end
end
return true
end
================================================
FILE: src/parsers/im_io/matlab.jl
================================================
#########################################################################
# #
# This file provides functions for interfacing with Matlab .m files #
# #
#########################################################################
# this could benefit from a much more robust parser
export parse_matlab_file, parse_matlab_string
"""
Parse a MATLAB `.m` file into a `Dict`.
"""
function parse_matlab_file(file_string::String; kwargs...)
data_string = read(open(file_string), String)
return parse_matlab_string(data_string; kwargs...)
end
"""
Parse a MATLAB data string into a `Dict`, extracting function definitions and matrix
assignments.
"""
function parse_matlab_string(data_string::String; extended = false)
data_lines = split(data_string, '\n')
matlab_dict = Dict{String, Any}()
struct_name = nothing
function_name = nothing
column_names = Dict{String, Any}()
last_index = length(data_lines)
index = 1
while index <= last_index
line = strip(data_lines[index])
line = "$(line)"
if length(line) <= 0 || strip(line)[1] == '%'
index = index + 1
continue
end
if occursin("function", line)
func, value = _extract_matlab_assignment(line)
struct_name = strip(replace(func, "function" => ""))
function_name = value
elseif occursin("=", line)
if struct_name !== nothing && !occursin("$(struct_name).", line)
@warn "assignments are expected to be made to \"$(struct_name)\" but given: $(line)"
end
if occursin("[", line)
matrix_dict = _parse_matlab_matrix(data_lines, index)
matlab_dict[matrix_dict["name"]] = matrix_dict["data"]
if haskey(matrix_dict, "column_names")
column_names[matrix_dict["name"]] = matrix_dict["column_names"]
end
index = index + matrix_dict["line_count"] - 1
elseif occursin("{", line)
cell_dict = _parse_matlab_cells(data_lines, index)
matlab_dict[cell_dict["name"]] = cell_dict["data"]
if haskey(cell_dict, "column_names")
column_names[cell_dict["name"]] = cell_dict["column_names"]
end
index = index + cell_dict["line_count"] - 1
else
name, value = _extract_matlab_assignment(line)
value = _type_value(value)
matlab_dict[name] = value
end
else
@error "Matlab parser skipping line number $(index) consisting of:\n $(line)"
end
index += 1
end
if extended
return matlab_dict, function_name, column_names
else
return matlab_dict
end
end
"breaks up matlab strings of the form 'name = value;'"
function _extract_matlab_assignment(string::AbstractString)
statement = split(string, ';')[1]
statement_parts = split(statement, '=')
@assert(length(statement_parts) == 2)
name = strip(statement_parts[1])
value = strip(statement_parts[2])
return name, value
end
"Attempts to determine the type of a string extracted from a matlab file"
function _type_value(value_string::AbstractString)
value_string = strip(value_string)
if occursin("'", value_string) # value is a string
value = strip(value_string, '\'')
else
# if value is a float
if occursin(".", value_string) || occursin("e", value_string)
value = check_type(Float64, value_string)
else # otherwise assume it is an int
value = check_type(Int, value_string)
end
end
return value
end
"Attempts to determine the type of an array of strings extracted from a matlab file"
function _type_array(string_array::Vector{T}) where {T <: AbstractString}
value_string = [strip(value_string) for value_string in string_array]
return if any(occursin("'", value_string) for value_string in string_array)
[strip(value_string, '\'') for value_string in string_array]
elseif any(
occursin(".", value_string) ||
occursin("e", value_string) ||
occursin("Inf", value_string) ||
occursin("NaN", value_string) for value_string in string_array
)
[check_type(Float64, value_string) for value_string in string_array]
else # otherwise assume it is an int
[check_type(Int, value_string) for value_string in string_array]
end
end
""
_parse_matlab_cells(lines, index) = _parse_matlab_data(lines, index, '{', '}')
""
_parse_matlab_matrix(lines, index) = _parse_matlab_data(lines, index, '[', ']')
""
function _parse_matlab_data(lines, index, start_char, end_char)
last_index = length(lines)
line_count = 0
columns = -1
@assert(occursin("=", lines[index + line_count]))
matrix_assignment = split(lines[index + line_count], '%')[1]
matrix_assignment = strip(matrix_assignment)
@assert(occursin(".", matrix_assignment))
matrix_assignment_parts = split(matrix_assignment, '=')
matrix_name = strip(matrix_assignment_parts[1])
matrix_assignment_rhs = ""
if length(matrix_assignment_parts) > 1
matrix_assignment_rhs = strip(matrix_assignment_parts[2])
end
line_count = line_count + 1
matrix_body_lines = [matrix_assignment_rhs]
found_close_bracket = occursin(string(end_char), matrix_assignment_rhs)
while index + line_count < last_index && !found_close_bracket
line = strip(lines[index + line_count])
if length(line) == 0 || line[1] == '%'
line_count += 1
continue
end
line = strip(split(line, '%')[1])
if occursin(string(end_char), line)
found_close_bracket = true
end
push!(matrix_body_lines, line)
line_count = line_count + 1
end
#print(matrix_body_lines)
matrix_body_lines =
[_add_line_delimiter(line, start_char, end_char) for line in matrix_body_lines]
#print(matrix_body_lines)
matrix_body = join(matrix_body_lines, ' ')
matrix_body =
strip(replace(strip(strip(matrix_body), start_char), "$(end_char);" => ""))
matrix_body_rows = split(matrix_body, ';')
matrix_body_rows = matrix_body_rows[1:(length(matrix_body_rows) - 1)]
matrix = []
for row in matrix_body_rows
row_items = split_line(strip(row))
#println(row_items)
push!(matrix, row_items)
if columns < 0
columns = length(row_items)
elseif columns != length(row_items)
@error "matrix parsing error, inconsistent number of items in each row\n$(row)"
end
end
rows = length(matrix)
typed_columns = [_type_array([matrix[r][c] for r in 1:rows]) for c in 1:columns]
for r in 1:rows
matrix[r] = [typed_columns[c][r] for c in 1:columns]
end
matrix_dict = Dict("name" => matrix_name, "data" => matrix, "line_count" => line_count)
if index > 1 && occursin("%column_names%", lines[index - 1])
column_names_string = lines[index - 1]
column_names_string = replace(column_names_string, "%column_names%" => "")
column_names = split(column_names_string)
if length(matrix[1]) != length(column_names)
@error "column name parsing error, data rows $(length(matrix[1])), column names $(length(column_names)) \n$(column_names)"
end
for (c, column_name) in enumerate(column_names)
if column_name == "index"
@error "column name parsing error, \"index\" is a reserved column name \n$(column_names)"
if !(typeof(typed_columns[c][1]) <: Int)
@error "the type of a column named \"index\" must be Int, but given $(typeof(typed_columns[c][1]))"
end
end
end
matrix_dict["column_names"] = column_names
end
return matrix_dict
end
""
function split_line(mp_line::AbstractString)
tokens = []
curr_token = ""
is_curr_token_quote = false
isquote(c) = (c == '\'' || c == '"')
function _push_curr_token()
if curr_pos <= length(mp_line)
curr_token *= mp_line[curr_pos]
end
curr_token = strip(curr_token)
if length(curr_token) > 0
push!(tokens, curr_token)
end
curr_token = ""
curr_pos += 1
is_curr_token_quote = false
end
function _push_curr_char()
curr_token *= mp_line[curr_pos]
curr_pos += 1
end
curr_pos = 1
while curr_pos <= length(mp_line)
if is_curr_token_quote
if mp_line[curr_pos] == curr_token[1]
if mp_line[curr_pos - 1] == '\\'
# If we are inside a quote and we see slash-quote, we should
# treat the quote character as a regular character.
_push_curr_char()
elseif curr_pos < length(mp_line) && mp_line[curr_pos + 1] == curr_token[1]
# If we are inside a quote, and we see two quotes in a row,
# we should append one of the quotes to the current
# token, then skip the other one.
curr_token *= mp_line[curr_pos]
curr_pos += 2
else
# If we are inside a quote, and we see an unescaped quote char,
# then the quote is ending. We should push the current token.
_push_curr_token()
end
else
# If we are inside a quote and we see a non-quote character,
# we should append that character to the current token.
_push_curr_char()
end
else
if isspace(mp_line[curr_pos]) && !isspace(mp_line[curr_pos + 1])
# If we are not inside a quote and we see a transition from
# space to non-space character, then the current token is done.
_push_curr_token()
elseif isquote(mp_line[curr_pos])
# If we are not inside a quote and we see a quote character,
# then a new quote is starting. We should append the quote
# character to the current token and switch to quote mode.
curr_token = strip(curr_token * mp_line[curr_pos])
is_curr_token_quote = true
curr_pos += 1
else
# If we are not inside a quote and we see a regular character,
# we should append that character to the current token.
_push_curr_char()
end
end
end
_push_curr_token()
return tokens
end
""
function _add_line_delimiter(mp_line::AbstractString, start_char, end_char)
if strip(mp_line) == string(start_char)
return mp_line
end
if !occursin(";", mp_line) && !occursin(string(end_char), mp_line)
mp_line = "$(mp_line);"
end
if occursin(string(end_char), mp_line)
prefix = strip(split(mp_line, end_char)[1])
if length(prefix) > 0 && !occursin(";", prefix)
mp_line = replace(mp_line, end_char => ";$(end_char)")
end
end
return mp_line
end
"Checks if the given value is of a given type, if not tries to make it that type"
function check_type(typ, value)
if isa(value, typ)
return value
elseif isa(value, String) || isa(value, SubString)
try
value = parse(typ, value)
return value
catch e
@error "parsing error, the matlab string \"$(value)\" can not be parsed to $(typ) data"
rethrow(e)
end
else
try
value = typ(value)
return value
catch e
@error "parsing error, the matlab value $(value) of type $(typeof(value)) can not be parsed to $(typ) data"
rethrow(e)
end
end
end
================================================
FILE: src/parsers/im_io.jl
================================================
include("im_io/matlab.jl")
include("im_io/common.jl")
include("im_io/data.jl")
================================================
FILE: src/parsers/pm_io/LICENSE.md
================================================
Copyright (c) 2016, Los Alamos National Security, LLC
All rights reserved.
Copyright 2016. Los Alamos National Security, LLC. This software was produced under U.S. Government contract DE-AC52-06NA25396 for Los Alamos National Laboratory (LANL), which is operated by Los Alamos National Security, LLC for the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, LLC MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce derivative works, such modified software should be clearly marked, so as not to confuse it with the version available from LANL.
Additionally, redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. 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.
3. Neither the name of Los Alamos National Security, LLC, Los Alamos National Laboratory, LANL, the U.S. Government, 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 LOS ALAMOS NATIONAL SECURITY, LLC 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 LOS ALAMOS NATIONAL SECURITY, LLC 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: src/parsers/pm_io/common.jl
================================================
"""
parse_file(
file;
import_all = false,
validate = true,
correct_branch_rating = true,
)
Parses a Matpower .m `file` or PTI (PSS(R)E-v33) .raw `file` into a
PowerModels data structure. All fields from PTI files will be imported if
`import_all` is true (Default: false).
"""
function parse_file(
file::String;
import_all = false,
validate = true,
correct_branch_rating = true,
)
pm_data = open(file) do io
pm_data = parse_file(
io;
import_all = import_all,
validate = validate,
correct_branch_rating = correct_branch_rating,
filetype = split(lowercase(file), '.')[end],
)
end
return pm_data
end
"Parses the iostream from a file"
function parse_file(
io::IO;
import_all = false,
validate = true,
correct_branch_rating = true,
filetype = "json",
)
if filetype == "m"
pm_data = parse_matpower(io; validate = validate)
elseif filetype == "raw"
pm_data = parse_psse(
io;
import_all = import_all,
validate = validate,
correct_branch_rating = correct_branch_rating,
)
elseif filetype == "json"
pm_data = parse_json(io; validate = validate)
else
@info("Unrecognized filetype")
end
# TODO: not sure if this relevant for all three file types, or only .m, JJS 3/7/19
move_genfuel_and_gentype!(pm_data)
return pm_data
end
"""
Runs various data quality checks on a PowerModels data dictionary.
Applies modifications in some cases. Reports modified component ids.
"""
function correct_network_data!(data::Dict{String, <:Any}; correct_branch_rating = true)
mod_gen = Dict{Symbol, Set{Int}}()
mod_branch = Dict{Symbol, Set{Int}}()
mod_dcline = Dict{Symbol, Set{Int}}()
check_conductors(data)
check_connectivity(data)
check_status(data)
check_reference_bus(data)
make_per_unit!(data)
mod_branch[:xfer_fix] = correct_transformer_parameters!(data)
mod_branch[:vad_bounds] = correct_voltage_angle_differences!(data)
mod_branch[:mva_zero] = if (correct_branch_rating)
correct_thermal_limits!(data)
else
# Set rate_a as 0.0 for those branch dict entries witn no "rate_a" key
branches = [branch for branch in values(data["branch"])]
if haskey(data, "ne_branch")
append!(branches, values(data["ne_branch"]))
end
for branch in branches
if !haskey(branch, "rate_a")
if haskey(data, "conductors")
error("Multiconductor Not Supported in PowerSystems")
else
branch["rate_a"] = 0.0
end
end
end
Set{Int}()
end
#mod_branch[:ma_zero] = correct_current_limits!(data)
mod_branch[:orientation] = correct_branch_directions!(data)
check_branch_loops(data)
mod_dcline[:losses] = correct_dcline_limits!(data)
check_voltage_setpoints(data)
check_storage_parameters(data)
check_switch_parameters(data)
gen, dcline = correct_cost_functions!(data)
mod_gen[:cost_pwl] = gen
mod_dcline[:cost_pwl] = dcline
simplify_cost_terms!(data)
return Dict(
"gen" => mod_gen,
"branch" => mod_branch,
"dcline" => mod_dcline,
)
end
UNIT_SYSTEM_MAPPING = Dict(
"SYSTEM_BASE" => IS.UnitSystem.SYSTEM_BASE,
"DEVICE_BASE" => IS.UnitSystem.DEVICE_BASE,
"NATURAL_UNITS" => IS.UnitSystem.NATURAL_UNITS,
"NA" => nothing,
)
================================================
FILE: src/parsers/pm_io/data.jl
================================================
# tools for working with a PowerModels data dict structure
""
function calc_branch_t(branch::Dict{String, <:Any})
tap_ratio = branch["tap"]
angle_shift = branch["shift"]
tr = tap_ratio .* cos.(angle_shift)
ti = tap_ratio .* sin.(angle_shift)
return tr, ti
end
""
function calc_branch_y(branch::Dict{String, <:Any})
y = LinearAlgebra.pinv(branch["br_r"] + im * branch["br_x"])
g, b = real(y), imag(y)
return g, b
end
""
function calc_theta_delta_bounds(data::Dict{String, <:Any})
bus_count = length(data["bus"])
branches = [branch for branch in values(data["branch"])]
if haskey(data, "ne_branch")
append!(branches, values(data["ne_branch"]))
end
angle_min = Real[]
angle_max = Real[]
conductors = 1
if haskey(data, "conductors")
conductors = data["conductors"]
end
conductor_ids = 1:conductors
for c in conductor_ids
angle_mins = [branch["angmin"][c] for branch in branches]
angle_maxs = [branch["angmax"][c] for branch in branches]
sort!(angle_mins)
sort!(angle_maxs; rev = true)
if length(angle_mins) > 1
# note that, this can occur when dclines are present
angle_count = min(bus_count - 1, length(branches))
angle_min_val = sum(angle_mins[1:angle_count])
angle_max_val = sum(angle_maxs[1:angle_count])
else
angle_min_val = angle_mins[1]
angle_max_val = angle_maxs[1]
end
push!(angle_min, angle_min_val)
push!(angle_max, angle_max_val)
end
if haskey(data, "conductors")
error("Multiconductor Not Supported in PowerSystems")
#amin = MultiConductorVector(angle_min)
#amax = MultiConductorVector(angle_max)
#return amin, amax
else
return angle_min[1], angle_max[1]
end
end
""
function calc_max_cost_index(data::Dict{String, Any})
if ismultinetwork(data) # ismultinetwork is in im_io/data.jl
max_index = 0
for (i, nw_data) in data["nw"]
nw_max_index = _calc_max_cost_index(nw_data)
max_index = max(max_index, nw_max_index)
end
return max_index
else
return _calc_max_cost_index(data)
end
end
""
function _calc_max_cost_index(data::Dict{String, <:Any})
max_index = 0
for (i, gen) in data["gen"]
if haskey(gen, "model")
if gen["model"] == 2
if haskey(gen, "cost")
max_index = max(max_index, length(gen["cost"]))
end
else
@info(
"skipping cost generator $(i) cost model in calc_cost_order, only model 2 is supported."
)
end
end
end
for (i, dcline) in data["dcline"]
if haskey(dcline, "model")
if dcline["model"] == 2
if haskey(dcline, "cost")
max_index = max(max_index, length(dcline["cost"]))
end
else
@info(
"skipping cost dcline $(i) cost model in calc_cost_order, only model 2 is supported."
)
end
end
end
return max_index
end
"maps component types to status parameters"
const pm_component_status = Dict(
"bus" => "bus_type",
"load" => "status",
"shunt" => "status",
"gen" => "gen_status",
"storage" => "status",
"switch" => "status",
"branch" => "br_status",
"dcline" => "br_status",
)
"maps component types to inactive status values"
const pm_component_status_inactive = Dict(
"bus" => 4,
"load" => 0,
"shunt" => 0,
"gen" => 0,
"storage" => 0,
"switch" => 0,
"branch" => 0,
"dcline" => 0,
)
const _pm_component_types_order = Dict(
"bus" => 1.0,
"load" => 2.0,
"shunt" => 3.0,
"gen" => 4.0,
"storage" => 5.0,
"switch" => 6.0,
"branch" => 7.0,
"dcline" => 8.0,
)
const _pm_component_parameter_order = Dict(
"bus_i" => 1.0,
"load_bus" => 2.0,
"shunt_bus" => 3.0,
"gen_bus" => 4.0,
"storage_bus" => 5.0,
"f_bus" => 6.0,
"t_bus" => 7.0,
"bus_name" => 9.1,
"base_kv" => 9.2,
"bus_type" => 9.3,
"vm" => 10.0,
"va" => 11.0,
"pd" => 20.0,
"qd" => 21.0,
"gs" => 30.0,
"bs" => 31.0,
"ps" => 35.0,
"qs" => 36.0,
"psw" => 37.0,
"qsw" => 38.0,
"pg" => 40.0,
"qg" => 41.0,
"vg" => 42.0,
"mbase" => 43.0,
"energy" => 44.0,
"br_r" => 50.0,
"br_x" => 51.0,
"g_fr" => 52.0,
"b_fr" => 53.0,
"g_to" => 54.0,
"b_to" => 55.0,
"tap" => 56.0,
"shift" => 57.0,
"vf" => 58.1,
"pf" => 58.2,
"qf" => 58.3,
"vt" => 58.4,
"pt" => 58.5,
"qt" => 58.6,
"loss0" => 58.7,
"loss1" => 59.8,
"vmin" => 60.0,
"vmax" => 61.0,
"pmin" => 62.0,
"pmax" => 63.0,
"qmin" => 64.0,
"qmax" => 65.0,
"rate_a" => 66.0,
"rate_b" => 67.0,
"rate_c" => 68.0,
"pminf" => 69.0,
"pmaxf" => 70.0,
"qminf" => 71.0,
"qmaxf" => 72.0,
"pmint" => 73.0,
"pmaxt" => 74.0,
"qmint" => 75.0,
"qmaxt" => 76.0,
"energy_rating" => 77.01,
"charge_rating" => 77.02,
"discharge_rating" => 77.03,
"charge_efficiency" => 77.04,
"discharge_efficiency" => 77.05,
"thermal_rating" => 77.06,
"qmin" => 77.07,
"qmax" => 77.08,
"qmin" => 77.09,
"qmax" => 77.10,
"r" => 77.11,
"x" => 77.12,
"p_loss" => 77.13,
"q_loss" => 77.14,
"status" => 80.0,
"gen_status" => 81.0,
"br_status" => 82.0,
"model" => 90.0,
"ncost" => 91.0,
"cost" => 92.0,
"startup" => 93.0,
"shutdown" => 94.0,
)
const _pm_component_status_parameters = Set(["status", "gen_status", "br_status"])
#component_table(data::Dict{String,Any}, component::String, args...) = component_table(data, component, args...)
#=
"recursively applies new_data to data, overwriting information"
function update_data!(data::Dict{String,<:Any}, new_data::Dict{String,<:Any})
if haskey(data, "conductors") && haskey(new_data, "conductors")
if data["conductors"] != new_data["conductors"]
error("update_data requires datasets with the same number of conductors")
end
else
if (haskey(data, "conductors") && !haskey(new_data, "conductors")) || (!haskey(data, "conductors") && haskey(new_data, "conductors"))
@info("running update_data with missing onductors fields, conductors may be incorrect")
end
end
update_data!(data, new_data)
end
=#
"""
Turns in given single network data in multinetwork data with a `count`
replicate of the given network. Note that this function performs a deepcopy
of the network data. Significant multinetwork space savings can often be
achieved by building application specific methods of building multinetwork
with minimal data replication.
"""
function replicate(
sn_data::Dict{String, <:Any},
count::Int;
global_keys::Set{String} = Set{String}(),
)
pm_global_keys = Set(["baseMVA", "per_unit"])
return im_replicate(sn_data, count, union(global_keys, pm_global_keys))
end
""
function _apply_func!(data::Dict{String, <:Any}, key::String, func)
if haskey(data, key)
data[key] = func(data[key]) # multiconductor not supported in PowerSystems
end
end
"Transforms network data into per-unit"
function make_per_unit!(data::Dict{String, <:Any})
if !haskey(data, "per_unit") || data["per_unit"] == false
data["per_unit"] = true
mva_base = data["baseMVA"]
if ismultinetwork(data)
for (i, nw_data) in data["nw"]
_make_per_unit!(nw_data, mva_base)
end
else
_make_per_unit!(data, mva_base)
end
end
end
""
function _make_per_unit!(data::Dict{String, <:Any}, mva_base::Real)
# to be consistent with matpower's opf.flow_lim= 'I' with current magnitude
# limit defined in MVA at 1 p.u. voltage
ka_base = mva_base
rescale = x -> x / mva_base
rescale_dual = x -> x * mva_base
rescale_ampere = x -> x / ka_base
if haskey(data, "bus")
for (i, bus) in data["bus"]
_apply_func!(bus, "va", deg2rad)
_apply_func!(bus, "lam_kcl_r", rescale_dual)
_apply_func!(bus, "lam_kcl_i", rescale_dual)
end
end
if haskey(data, "load")
for (i, load) in data["load"]
_apply_func!(load, "pd", rescale)
_apply_func!(load, "qd", rescale)
_apply_func!(load, "pi", rescale)
_apply_func!(load, "qi", rescale)
_apply_func!(load, "py", rescale)
_apply_func!(load, "qy", rescale)
end
end
if haskey(data, "shunt")
for (i, shunt) in data["shunt"]
_apply_func!(shunt, "gs", rescale)
_apply_func!(shunt, "bs", rescale)
end
end
if haskey(data, "switched_shunt")
for (i, sw_shunt) in data["switched_shunt"]
_apply_func!(sw_shunt, "gs", rescale)
_apply_func!(sw_shunt, "bs", rescale)
_apply_func!(sw_shunt, "y_increment", rescale)
end
end
if haskey(data, "gen")
for (i, gen) in data["gen"]
_apply_func!(gen, "pg", rescale)
_apply_func!(gen, "qg", rescale)
_apply_func!(gen, "pmax", rescale)
_apply_func!(gen, "pmin", rescale)
_apply_func!(gen, "qmax", rescale)
_apply_func!(gen, "qmin", rescale)
_apply_func!(gen, "ramp_agc", rescale)
_apply_func!(gen, "ramp_10", rescale)
_apply_func!(gen, "ramp_30", rescale)
_apply_func!(gen, "ramp_q", rescale)
_rescale_cost_model!(gen, mva_base)
end
end
if haskey(data, "storage")
for (i, strg) in data["storage"]
_apply_func!(strg, "energy", rescale)
_apply_func!(strg, "energy_rating", rescale)
_apply_func!(strg, "charge_rating", rescale)
_apply_func!(strg, "discharge_rating", rescale)
_apply_func!(strg, "thermal_rating", rescale)
_apply_func!(strg, "current_rating", rescale)
_apply_func!(strg, "qmin", rescale)
_apply_func!(strg, "qmax", rescale)
_apply_func!(strg, "p_loss", rescale)
_apply_func!(strg, "q_loss", rescale)
end
end
if haskey(data, "switch")
for (i, switch) in data["switch"]
_apply_func!(switch, "psw", rescale)
_apply_func!(switch, "qsw", rescale)
_apply_func!(switch, "thermal_rating", rescale)
_apply_func!(switch, "current_rating", rescale)
end
end
branches = []
if haskey(data, "branch")
append!(branches, values(data["branch"]))
end
if haskey(data, "ne_branch")
append!(branches, values(data["ne_branch"]))
end
for branch in branches
_apply_func!(branch, "rate_a", rescale)
_apply_func!(branch, "rate_b", rescale)
_apply_func!(branch, "rate_c", rescale)
_apply_func!(branch, "c_rating_a", rescale_ampere)
_apply_func!(branch, "c_rating_b", rescale_ampere)
_apply_func!(branch, "c_rating_c", rescale_ampere)
_apply_func!(branch, "shift", deg2rad)
_apply_func!(branch, "angmax", deg2rad)
_apply_func!(branch, "angmin", deg2rad)
_apply_func!(branch, "pf", rescale)
_apply_func!(branch, "pt", rescale)
_apply_func!(branch, "qf", rescale)
_apply_func!(branch, "qt", rescale)
_apply_func!(branch, "mu_sm_fr", rescale_dual)
_apply_func!(branch, "mu_sm_to", rescale_dual)
_apply_func!(branch, "ta_max", deg2rad)
_apply_func!(branch, "ta_min", deg2rad)
end
if haskey(data, "dcline")
for (i, dcline) in data["dcline"]
_apply_func!(dcline, "loss0", rescale)
_apply_func!(dcline, "pf", rescale)
_apply_func!(dcline, "pt", rescale)
_apply_func!(dcline, "qf", rescale)
_apply_func!(dcline, "qt", rescale)
_apply_func!(dcline, "pmaxt", rescale)
_apply_func!(dcline, "pmint", rescale)
_apply_func!(dcline, "pmaxf", rescale)
_apply_func!(dcline, "pminf", rescale)
_apply_func!(dcline, "qmaxt", rescale)
_apply_func!(dcline, "qmint", rescale)
_apply_func!(dcline, "qmaxf", rescale)
_apply_func!(dcline, "qminf", rescale)
_rescale_cost_model!(dcline, mva_base)
end
end
end
"Transforms network data into mixed-units (inverse of per-unit)"
function make_mixed_units!(data::Dict{String, <:Any})
if haskey(data, "per_unit") && data["per_unit"] == true
data["per_unit"] = false
mva_base = data["baseMVA"]
if ismultinetwork(data)
for (i, nw_data) in data["nw"]
_make_mixed_units!(nw_data, mva_base)
end
else
_make_mixed_units!(data, mva_base)
end
end
end
""
function _make_mixed_units!(data::Dict{String, <:Any})
mva_base = data["baseMVA"]
# to be consistent with matpower's opf.flow_lim= 'I' with current magnitude
# limit defined in MVA at 1 p.u. voltage
ka_base = mva_base
rescale = x -> x * mva_base
rescale_dual = x -> x / mva_base
rescale_ampere = x -> x * ka_base
if haskey(data, "bus")
for (i, bus) in data["bus"]
_apply_func!(bus, "va", rad2deg)
_apply_func!(bus, "lam_kcl_r", rescale_dual)
_apply_func!(bus, "lam_kcl_i", rescale_dual)
end
end
if haskey(data, "load")
for (i, load) in data["load"]
_apply_func!(load, "pd", rescale)
_apply_func!(load, "qd", rescale)
end
end
if haskey(data, "shunt")
for (i, shunt) in data["shunt"]
_apply_func!(shunt, "gs", rescale)
_apply_func!(shunt, "bs", rescale)
end
end
if haskey(data, "gen")
for (i, gen) in data["gen"]
_apply_func!(gen, "pg", rescale)
_apply_func!(gen, "qg", rescale)
_apply_func!(gen, "pmax", rescale)
_apply_func!(gen, "pmin", rescale)
_apply_func!(gen, "qmax", rescale)
_apply_func!(gen, "qmin", rescale)
_apply_func!(gen, "ramp_agc", rescale)
_apply_func!(gen, "ramp_10", rescale)
_apply_func!(gen, "ramp_30", rescale)
_apply_func!(gen, "ramp_q", rescale)
_rescale_cost_model!(gen, 1.0 / mva_base)
end
end
if haskey(data, "storage")
for (i, strg) in data["storage"]
_apply_func!(strg, "energy", rescale)
_apply_func!(strg, "energy_rating", rescale)
_apply_func!(strg, "charge_rating", rescale)
_apply_func!(strg, "discharge_rating", rescale)
_apply_func!(strg, "thermal_rating", rescale)
_apply_func!(strg, "current_rating", rescale)
_apply_func!(strg, "qmin", rescale)
_apply_func!(strg, "qmax", rescale)
_apply_func!(strg, "p_loss", rescale)
_apply_func!(strg, "q_loss", rescale)
end
end
if haskey(data, "switch")
for (i, switch) in data["switch"]
_apply_func!(switch, "psw", rescale)
_apply_func!(switch, "qsw", rescale)
_apply_func!(switch, "thermal_rating", rescale)
_apply_func!(switch, "current_rating", rescale)
end
end
branches = []
if haskey(data, "branch")
append!(branches, values(data["branch"]))
end
if haskey(data, "ne_branch")
append!(branches, values(data["ne_branch"]))
end
for branch in branches
_apply_func!(branch, "rate_a", rescale)
_apply_func!(branch, "rate_b", rescale)
_apply_func!(branch, "rate_c", rescale)
_apply_func!(branch, "c_rating_a", rescale_ampere)
_apply_func!(branch, "c_rating_b", rescale_ampere)
_apply_func!(branch, "c_rating_c", rescale_ampere)
_apply_func!(branch, "shift", rad2deg)
_apply_func!(branch, "angmax", rad2deg)
_apply_func!(branch, "angmin", rad2deg)
_apply_func!(branch, "pf", rescale)
_apply_func!(branch, "pt", rescale)
_apply_func!(branch, "qf", rescale)
_apply_func!(branch, "qt", rescale)
_apply_func!(branch, "mu_sm_fr", rescale_dual)
_apply_func!(branch, "mu_sm_to", rescale_dual)
_apply_func!(branch, "ta", rad2deg)
end
if haskey(data, "dcline")
for (i, dcline) in data["dcline"]
_apply_func!(dcline, "loss0", rescale)
_apply_func!(dcline, "pf", rescale)
_apply_func!(dcline, "pt", rescale)
_apply_func!(dcline, "qf", rescale)
_apply_func!(dcline, "qt", rescale)
_apply_func!(dcline, "pmaxt", rescale)
_apply_func!(dcline, "pmint", rescale)
_apply_func!(dcline, "pmaxf", rescale)
_apply_func!(dcline, "pminf", rescale)
_apply_func!(dcline, "qmaxt", rescale)
_apply_func!(dcline, "qmint", rescale)
_apply_func!(dcline, "qmaxf", rescale)
_apply_func!(dcline, "qminf", rescale)
_rescale_cost_model!(dcline, 1.0 / mva_base)
end
end
end
""
function _rescale_cost_model!(comp::Dict{String, <:Any}, scale::Real)
if "model" in keys(comp) && "cost" in keys(comp)
if comp["model"] == 1
for i in 1:2:length(comp["cost"])
comp["cost"][i] = comp["cost"][i] / scale
end
elseif comp["model"] == 2
degree = length(comp["cost"])
for (i, item) in enumerate(comp["cost"])
comp["cost"][i] = item * (scale^(degree - i))
end
else
@info("Skipping cost model of type $(comp["model"]) in per unit transformation")
end
end
end
"computes the generator cost from given network data"
function calc_gen_cost(data::Dict{String, <:Any})
@assert("per_unit" in keys(data) && data["per_unit"])
@assert(!haskey(data, "conductors"))
if ismultinetwork(data)
nw_costs = Dict{String, Any}()
for (i, nw_data) in data["nw"]
nw_costs[i] = _calc_gen_cost(nw_data)
end
return sum(nw_cost for (i, nw_cost) in nw_costs)
else
return _calc_gen_cost(data)
end
end
function _calc_gen_cost(data::Dict{String, <:Any})
cost = 0.0
for (i, gen) in data["gen"]
if gen["gen_status"] == 1
if haskey(gen, "model")
if gen["model"] == 1
cost += _calc_cost_pwl(gen, "pg")
elseif gen["model"] == 2
cost += _calc_cost_polynomial(gen, "pg")
else
@info "generator $(i) has an unknown cost model $(gen["model"])" maxlog =
PS_MAX_LOG
end
else
@info "generator $(i) does not have a cost model" maxlog = PS_MAX_LOG
end
end
end
return cost
end
"computes the dcline cost from given network data"
function calc_dcline_cost(data::Dict{String, <:Any})
@assert("per_unit" in keys(data) && data["per_unit"])
@assert(!haskey(data, "conductors"))
if ismultinetwork(data)
nw_costs = Dict{String, Any}()
for (i, nw_data) in data["nw"]
nw_costs[i] = _calc_dcline_cost(nw_data)
end
return sum(nw_cost for (i, nw_cost) in nw_costs)
else
return _calc_dcline_cost(data)
end
end
function _calc_dcline_cost(data::Dict{String, <:Any})
cost = 0.0
for (i, dcline) in data["dcline"]
if dcline["br_status"] == 1
if haskey(dcline, "model")
if dcline["model"] == 1
cost += _calc_cost_pwl(dcline, "pf")
elseif dcline["model"] == 2
cost += _calc_cost_polynomial(dcline, "pf")
else
@info "dcline $(i) has an unknown cost model $(dcline["model"])" maxlog =
PS_MAX_LOG
end
else
@info "dcline $(i) does not have a cost model" maxlog = PS_MAX_LOG
end
end
end
return cost
end
"""
compute lines in m and b from from pwl cost models data is a list of components.
Can be run on data or ref data structures
"""
function calc_cost_pwl_lines(comp_dict::Dict)
lines = Dict()
for (i, comp) in comp_dict
lines[i] = _calc_comp_lines(comp)
end
return lines
end
"""
compute lines in m and b from from pwl cost models
"""
function _calc_comp_lines(component::Dict{String, <:Any})
@assert component["model"] == 1
points = component["cost"]
line_data = []
for i in 3:2:length(points)
x1 = points[i - 2]
y1 = points[i - 1]
x2 = points[i - 0]
y2 = points[i + 1]
m = (y2 - y1) / (x2 - x1)
b = y1 - m * x1
push!(line_data, (slope = m, intercept = b))
end
for i in 2:length(line_data)
if line_data[i - 1].slope > line_data[i].slope
@info "non-convex pwl function found in points $(component["cost"])\nlines: $(line_data)" maxlog =
PS_MAX_LOG
end
end
return line_data
end
function _calc_cost_pwl(component::Dict{String, <:Any}, setpoint_id)
comp_lines = _calc_comp_lines(component)
setpoint = component[setpoint_id]
cost = -Inf
for line in comp_lines
cost = max(cost, line.slope * setpoint + line.intercept)
end
return cost
end
function _calc_cost_polynomial(component::Dict{String, <:Any}, setpoint_id)
cost_terms_rev = reverse(component["cost"])
setpoint = component[setpoint_id]
if length(cost_terms_rev) == 0
cost = 0.0
elseif length(cost_terms_rev) == 1
cost = cost_terms_rev[1]
elseif length(cost_terms_rev) == 2
cost = cost_terms_rev[1] + cost_terms_rev[2] * setpoint
else
cost_terms_rev_high = cost_terms_rev[3:end]
cost =
cost_terms_rev[1] +
cost_terms_rev[2] * setpoint +
sum(v * setpoint^(d + 1) for (d, v) in enumerate(cost_terms_rev_high))
end
return cost
end
"assumes a vaild ac solution is included in the data and computes the branch flow values"
function calc_branch_flow_ac(data::Dict{String, <:Any})
@assert("per_unit" in keys(data) && data["per_unit"])
@assert(!haskey(data, "conductors"))
if ismultinetwork(data)
nws = Dict{String, Any}()
for (i, nw_data) in data["nw"]
nws[i] = _calc_branch_flow_ac(nw_data)
end
return Dict{String, Any}(
"nw" => nws,
"per_unit" => data["per_unit"],
"baseMVA" => data["baseMVA"],
)
else
flows = _calc_branch_flow_ac(data)
flows["per_unit"] = data["per_unit"]
flows["baseMVA"] = data["baseMVA"]
return flows
end
end
"helper function for calc_branch_flow_ac"
function _calc_branch_flow_ac(data::Dict{String, <:Any})
vm = Dict(bus["index"] => bus["vm"] for (i, bus) in data["bus"])
va = Dict(bus["index"] => bus["va"] for (i, bus) in data["bus"])
flows = Dict{String, Any}()
for (i, branch) in data["branch"]
if branch["br_status"] != 0
f_bus = branch["f_bus"]
t_bus = branch["t_bus"]
g, b = calc_branch_y(branch)
tr, ti = calc_branch_t(branch)
g_fr = branch["g_fr"]
b_fr = branch["b_fr"]
g_to = branch["g_to"]
b_to = branch["b_to"]
tm = branch["tap"]
vm_fr = vm[f_bus]
vm_to = vm[t_bus]
va_fr = va[f_bus]
va_to = va[t_bus]
p_fr =
(g + g_fr) / tm^2 * vm_fr^2 +
(-g * tr + b * ti) / tm^2 * (vm_fr * vm_to * cos(va_fr - va_to)) +
(-b * tr - g * ti) / tm^2 * (vm_fr * vm_to * sin(va_fr - va_to))
q_fr =
-(b + b_fr) / tm^2 * vm_fr^2 -
(-b * tr - g * ti) / tm^2 * (vm_fr * vm_to * cos(va_fr - va_to)) +
(-g * tr + b * ti) / tm^2 * (vm_fr * vm_to * sin(va_fr - va_to))
p_to =
(g + g_to) * vm_to^2 +
(-g * tr - b * ti) / tm^2 * (vm_to * vm_fr * cos(va_to - va_fr)) +
(-b * tr + g * ti) / tm^2 * (vm_to * vm_fr * sin(va_to - va_fr))
q_to =
-(b + b_to) * vm_to^2 -
(-b * tr + g * ti) / tm^2 * (vm_to * vm_fr * cos(va_to - va_fr)) +
(-g * tr - b * ti) / tm^2 * (vm_to * vm_fr * sin(va_to - va_fr))
else
p_fr = NaN
q_fr = NaN
p_to = NaN
q_to = NaN
end
flows[i] = Dict("pf" => p_fr, "qf" => q_fr, "pt" => p_to, "qt" => q_to)
end
return Dict{String, Any}("branch" => flows)
end
"assumes a vaild dc solution is included in the data and computes the branch flow values"
function calc_branch_flow_dc(data::Dict{String, <:Any})
@assert("per_unit" in keys(data) && data["per_unit"])
@assert(!haskey(data, "conductors"))
if ismultinetwork(data)
nws = Dict{String, Any}()
for (i, nw_data) in data["nw"]
nws[i] = _calc_branch_flow_dc(nw_data)
end
return Dict{String, Any}(
"nw" => nws,
"per_unit" => data["per_unit"],
"baseMVA" => data["baseMVA"],
)
else
flows = _calc_branch_flow_dc(data)
flows["per_unit"] = data["per_unit"]
flows["baseMVA"] = data["baseMVA"]
return flows
end
end
"helper function for calc_branch_flow_dc"
function _calc_branch_flow_dc(data::Dict{String, <:Any})
vm = Dict(bus["index"] => bus["vm"] for (i, bus) in data["bus"])
va = Dict(bus["index"] => bus["va"] for (i, bus) in data["bus"])
flows = Dict{String, Any}()
for (i, branch) in data["branch"]
if branch["br_status"] != 0
f_bus = branch["f_bus"]
t_bus = branch["t_bus"]
g, b = calc_branch_y(branch)
p_fr = -b * (va[f_bus] - va[t_bus])
else
p_fr = NaN
end
flows[i] = Dict("pf" => p_fr, "qf" => NaN, "pt" => -p_fr, "qt" => NaN)
end
return Dict{String, Any}("branch" => flows)
end
"assumes a vaild solution is included in the data and computes the power balance at each bus"
function calc_power_balance(data::Dict{String, <:Any})
@assert("per_unit" in keys(data) && data["per_unit"]) # may not be strictly required
@assert(!haskey(data, "conductors"))
if ismultinetwork(data)
nws = Dict{String, Any}()
for (i, nw_data) in data["nw"]
nws[i] = _calc_power_balance(nw_data)
end
return Dict{String, Any}(
"nw" => nws,
"per_unit" => data["per_unit"],
"baseMVA" => data["baseMVA"],
)
else
flows = _calc_power_balance(data)
flows["per_unit"] = data["per_unit"]
flows["baseMVA"] = data["baseMVA"]
return flows
end
end
"helper function for calc_power_balance"
function _calc_power_balance(data::Dict{String, <:Any})
bus_values = Dict(bus["index"] => Dict{String, Float64}() for (i, bus) in data["bus"])
for (i, bus) in data["bus"]
bvals = bus_values[bus["index"]]
bvals["vm"] = bus["vm"]
bvals["pd"] = 0.0
bvals["qd"] = 0.0
bvals["gs"] = 0.0
bvals["bs"] = 0.0
bvals["ps"] = 0.0
bvals["qs"] = 0.0
bvals["pg"] = 0.0
bvals["qg"] = 0.0
bvals["p"] = 0.0
bvals["q"] = 0.0
bvals["psw"] = 0.0
bvals["qsw"] = 0.0
bvals["p_dc"] = 0.0
bvals["q_dc"] = 0.0
end
for (i, load) in data["load"]
if load["status"] != 0
bvals = bus_values[load["load_bus"]]
bvals["pd"] += load["pd"]
bvals["qd"] += load["qd"]
end
end
for (i, shunt) in data["shunt"]
if shunt["status"] != 0
bvals = bus_values[shunt["shunt_bus"]]
bvals["gs"] += shunt["gs"]
bvals["bs"] += shunt["bs"]
end
end
for (i, storage) in data["storage"]
if storage["status"] != 0
bvals = bus_values[storage["storage_bus"]]
bvals["ps"] += storage["ps"]
bvals["qs"] += storage["qs"]
end
end
for (i, gen) in data["gen"]
if gen["gen_status"] != 0
bvals = bus_values[gen["gen_bus"]]
bvals["pg"] += gen["pg"]
bvals["qg"] += gen["qg"]
end
end
for (i, switch) in data["switch"]
if switch["status"] != 0
bus_fr = switch["f_bus"]
bvals_fr = bus_values[bus_fr]
bvals_fr["psw"] += switch["psw"]
bvals_fr["qsw"] += switch["qsw"]
bus_to = switch["t_bus"]
bvals_to = bus_values[bus_to]
bvals_to["psw"] -= switch["psw"]
bvals_to["qsw"] -= switch["qsw"]
end
end
for (i, branch) in data["branch"]
if branch["br_status"] != 0
bus_fr = branch["f_bus"]
bvals_fr = bus_values[bus_fr]
bvals_fr["p"] += branch["pf"]
bvals_fr["q"] += branch["qf"]
bus_to = branch["t_bus"]
bvals_to = bus_values[bus_to]
bvals_to["p"] += branch["pt"]
bvals_to["q"] += branch["qt"]
end
end
for (i, dcline) in data["dcline"]
if dcline["br_status"] != 0
bus_fr = dcline["f_bus"]
bvals_fr = bus_values[bus_fr]
bvals_fr["p_dc"] += dcline["pf"]
bvals_fr["q_dc"] += dcline["qf"]
bus_to = dcline["t_bus"]
bvals_to = bus_values[bus_to]
bvals_to["p_dc"] += dcline["pt"]
bvals_to["q_dc"] += dcline["qt"]
end
end
deltas = Dict{String, Any}()
for (i, bus) in data["bus"]
if bus["bus_type"] != 4
bvals = bus_values[bus["index"]]
p_delta =
bvals["p"] + bvals["p_dc"] + bvals["psw"] - bvals["pg"] +
bvals["ps"] +
bvals["pd"] +
bvals["gs"] * (bvals["vm"]^2)
q_delta =
bvals["q"] + bvals["q_dc"] + bvals["qsw"] - bvals["qg"] +
bvals["qs"] +
bvals["qd"] - bvals["bs"] * (bvals["vm"]^2)
else
p_delta = NaN
q_delta = NaN
end
deltas[i] = Dict("p_delta" => p_delta, "q_delta" => q_delta)
end
return Dict{String, Any}("bus" => deltas)
end
""
function check_conductors(data::Dict{String, <:Any})
if ismultinetwork(data)
for (i, nw_data) in data["nw"]
_check_conductors(nw_data)
end
else
_check_conductors(data)
end
end
""
function _check_conductors(data::Dict{String, <:Any})
if haskey(data, "conductors") && data["conductors"] < 1
error("conductor values must be positive integers, given $(data["conductors"])")
end
end
"checks that voltage angle differences are within 90 deg., if not tightens"
function correct_voltage_angle_differences!(data::Dict{String, <:Any}, default_pad = 1.0472)
if ismultinetwork(data)
error("check_voltage_angle_differences does not yet support multinetwork data")
end
@assert("per_unit" in keys(data) && data["per_unit"])
default_pad_deg = round(rad2deg(default_pad); digits = 2)
modified = Set{Int}()
for c in 1:get(data, "conductors", 1)
cnd_str = haskey(data, "conductors") ? ", conductor $(c)" : ""
for (i, branch) in data["branch"]
angmin = branch["angmin"][c]
angmax = branch["angmax"][c]
if angmin <= -pi / 2
@info "this code only supports angmin values in -90 deg. to 90 deg., tightening the value on branch $i$(cnd_str) from $(rad2deg(angmin)) to -$(default_pad_deg) deg." maxlog =
PS_MAX_LOG
if haskey(data, "conductors")
branch["angmin"][c] = -default_pad
else
branch["angmin"] = -default_pad
end
push!(modified, branch["index"])
end
if angmax >= pi / 2
@info "this code only supports angmax values in -90 deg. to 90 deg., tightening the value on branch $i$(cnd_str) from $(rad2deg(angmax)) to $(default_pad_deg) deg." maxlog =
PS_MAX_LOG
if haskey(data, "conductors")
branch["angmax"][c] = default_pad
else
branch["angmax"] = default_pad
end
push!(modified, branch["index"])
end
if angmin == 0.0 && angmax == 0.0
@info "angmin and angmax values are 0, widening these values on branch $i$(cnd_str) to +/- $(default_pad_deg) deg." maxlog =
PS_MAX_LOG
if haskey(data, "conductors")
branch["angmin"][c] = -default_pad
branch["angmax"][c] = default_pad
else
branch["angmin"] = -default_pad
branch["angmax"] = default_pad
end
push!(modified, branch["index"])
end
end
end
return modified
end
"checks that each branch has a reasonable thermal rating-a, if not computes one"
function correct_thermal_limits!(data::Dict{String, <:Any})
if ismultinetwork(data)
error("correct_thermal_limits! does not yet support multinetwork data")
end
@assert("per_unit" in keys(data) && data["per_unit"])
mva_base = data["baseMVA"]
modified = Set{Int}()
branches = [branch for branch in values(data["branch"])]
if haskey(data, "ne_branch")
append!(branches, values(data["ne_branch"]))
end
for branch in branches
if !haskey(branch, "rate_a")
if haskey(data, "conductors")
error("Multiconductor Not Supported in PowerSystems")
else
branch["rate_a"] = 0.0
end
end
for c in 1:get(data, "conductors", 1)
cnd_str = haskey(data, "conductors") ? ", conductor $(c)" : ""
if branch["rate_a"][c] <= 0.0
theta_max = max(abs(branch["angmin"][c]), abs(branch["angmax"][c]))
r = branch["br_r"]
x = branch["br_x"]
z = r + im * x
y = LinearAlgebra.pinv(z)
y_mag = abs.(y[c, c])
fr_vmax = data["bus"][branch["f_bus"]]["vmax"][c]
to_vmax = data["bus"][branch["t_bus"]]["vmax"][c]
m_vmax = max(fr_vmax, to_vmax)
c_max = sqrt(fr_vmax^2 + to_vmax^2 - 2 * fr_vmax * to_vmax * cos(theta_max))
new_rate = y_mag * m_vmax * c_max
if haskey(branch, "c_rating_a") && branch["c_rating_a"][c] > 0.0
new_rate = min(new_rate, branch["c_rating_a"][c] * m_vmax)
end
@info "this code only supports positive rate_a values, changing the value on branch $(branch["index"])$(cnd_str) to $(round(mva_base*new_rate, digits=4))" maxlog =
PS_MAX_LOG
if haskey(data, "conductors")
branch["rate_a"][c] = new_rate
else
branch["rate_a"] = new_rate
end
push!(modified, branch["index"])
end
end
end
return modified
end
"checks that each branch has a reasonable current rating-a, if not computes one"
function correct_current_limits!(data::Dict{String, <:Any})
if ismultinetwork(data)
error("correct_current_limits! does not yet support multinetwork data")
end
@assert("per_unit" in keys(data) && data["per_unit"])
mva_base = data["baseMVA"]
modified = Set{Int}()
branches = [branch for branch in values(data["branch"])]
if haskey(data, "ne_branch")
append!(branches, values(data["ne_branch"]))
end
for branch in branches
if !haskey(branch, "c_rating_a")
if haskey(data, "conductors")
error("Multiconductor Not Supported in PowerSystems")
else
branch["c_rating_a"] = 0.0
end
end
for c in 1:get(data, "conductors", 1)
cnd_str = haskey(data, "conductors") ? ", conductor $(c)" : ""
if branch["c_rating_a"][c] <= 0.0
theta_max = max(abs(branch["angmin"][c]), abs(branch["angmax"][c]))
r = branch["br_r"]
x = branch["br_x"]
z = r + im * x
y = LinearAlgebra.pinv(z)
y_mag = abs.(y[c, c])
fr_vmax = data["bus"][string(branch["f_bus"])]["vmax"][c]
to_vmax = data["bus"][string(branch["t_bus"])]["vmax"][c]
m_vmax = max(fr_vmax, to_vmax)
new_c_rating =
y_mag *
sqrt(fr_vmax^2 + to_vmax^2 - 2 * fr_vmax * to_vmax * cos(theta_max))
if haskey(branch, "rate_a") && branch["rate_a"][c] > 0.0
fr_vmin = data["bus"][string(branch["f_bus"])]["vmin"][c]
to_vmin = data["bus"][string(branch["t_bus"])]["vmin"][c]
vm_min = min(fr_vmin, to_vmin)
new_c_rating = min(new_c_rating, branch["rate_a"] / vm_min)
end
@info(
"this code only supports positive c_rating_a values, changing the value on branch $(branch["index"])$(cnd_str) to $(mva_base*new_c_rating)"
)
if haskey(data, "conductors")
branch["c_rating_a"][c] = new_c_rating
else
branch["c_rating_a"] = new_c_rating
end
push!(modified, branch["index"])
end
end
end
return modified
end
"checks that all parallel branches have the same orientation"
function correct_branch_directions!(data::Dict{String, <:Any})
if ismultinetwork(data)
error("correct_branch_directions! does not yet support multinetwork data")
end
modified = Set{Int}()
orientations = Set()
for (i, branch) in data["branch"]
orientation = (branch["f_bus"], branch["t_bus"])
orientation_rev = (branch["t_bus"], branch["f_bus"])
if in(orientation_rev, orientations)
@info(
"reversing the orientation of branch $(i) $(orientation) to be consistent with other parallel branches"
)
branch_orginal = copy(branch)
branch["f_bus"] = branch_orginal["t_bus"]
branch["t_bus"] = branch_orginal["f_bus"]
branch["g_to"] = branch_orginal["g_fr"] .* branch_orginal["tap"]' .^ 2
branch["b_to"] = branch_orginal["b_fr"] .* branch_orginal["tap"]' .^ 2
branch["g_fr"] = branch_orginal["g_to"] ./ branch_orginal["tap"]' .^ 2
branch["b_fr"] = branch_orginal["b_to"] ./ branch_orginal["tap"]' .^ 2
branch["tap"] = 1 ./ branch_orginal["tap"]
branch["br_r"] = branch_orginal["br_r"] .* branch_orginal["tap"]' .^ 2
branch["br_x"] = branch_orginal["br_x"] .* branch_orginal["tap"]' .^ 2
branch["shift"] = -branch_orginal["shift"]
branch["angmin"] = -branch_orginal["angmax"]
branch["angmax"] = -branch_orginal["angmin"]
push!(modified, branch["index"])
else
push!(orientations, orientation)
end
end
return modified
end
"checks that all branches connect two distinct buses"
function check_branch_loops(data::Dict{String, <:Any})
if ismultinetwork(data)
error("check_branch_loops does not yet support multinetwork data")
end
for (i, branch) in data["branch"]
if branch["f_bus"] == branch["t_bus"]
throw(
DataFormatError(
"both sides of branch $(i) connect to bus $(branch["f_bus"])",
),
)
end
end
end
"checks that all buses are unique and other components link to valid buses"
function check_connectivity(data::Dict{String, <:Any})
if ismultinetwork(data)
error("check_connectivity does not yet support multinetwork data")
end
bus_ids = Set(bus["index"] for (i, bus) in data["bus"])
@assert(length(bus_ids) == length(data["bus"])) # if this is not true something very bad is going on
for (i, load) in data["load"]
if !(load["load_bus"] in bus_ids)
throw(DataFormatError("bus $(load["load_bus"]) in load $(i) is not defined"))
end
end
for (i, shunt) in data["shunt"]
if !(shunt["shunt_bus"] in bus_ids)
throw(DataFormatError("bus $(shunt["shunt_bus"]) in shunt $(i) is not defined"))
end
end
for (i, gen) in data["gen"]
if !(gen["gen_bus"] in bus_ids)
throw(DataFormatError("bus $(gen["gen_bus"]) in generator $(i) is not defined"))
end
end
for (i, strg) in data["storage"]
if !(strg["storage_bus"] in bus_ids)
throw(
DataFormatError(
"bus $(strg["storage_bus"]) in storage unit $(i) is not defined",
),
)
end
end
if haskey(data, "switch")
for (i, switch) in data["switch"]
if !(switch["f_bus"] in bus_ids)
throw(
DataFormatError(
"from bus $(branch["f_bus"]) in switch $(i) is not defined",
),
)
end
if !(switch["t_bus"] in bus_ids)
throw(
DataFormatError(
"to bus $(branch["t_bus"]) in switch $(i) is not defined",
),
)
end
end
end
for (i, branch) in data["branch"]
if !(branch["f_bus"] in bus_ids)
throw(
DataFormatError(
"from bus $(branch["f_bus"]) in branch $(i) is not defined",
),
)
end
if !(branch["t_bus"] in bus_ids)
throw(
DataFormatError("to bus $(branch["t_bus"]) in branch $(i) is not defined"),
)
end
end
for (i, dcline) in data["dcline"]
if !(dcline["f_bus"] in bus_ids)
throw(
DataFormatError(
"from bus $(dcline["f_bus"]) in dcline $(i) is not defined",
),
)
end
if !(dcline["t_bus"] in bus_ids)
throw(
DataFormatError("to bus $(dcline["t_bus"]) in dcline $(i) is not defined"),
)
end
end
end
"checks that active components are not connected to inactive buses, otherwise prints warnings"
function check_status(data::Dict{String, <:Any})
if ismultinetwork(data)
error("check_status does not yet support multinetwork data")
end
active_bus_ids = Set(bus["index"] for (i, bus) in data["bus"] if bus["bus_type"] != 4)
for (i, load) in data["load"]
if load["status"] != 0 && !(load["load_bus"] in active_bus_ids)
@warn("active load $(i) is connected to inactive bus $(load["load_bus"])")
end
end
for (i, shunt) in data["shunt"]
if shunt["status"] != 0 && !(shunt["shunt_bus"] in active_bus_ids)
@warn("active shunt $(i) is connected to inactive bus $(shunt["shunt_bus"])")
end
end
for (i, gen) in data["gen"]
if gen["gen_status"] != 0 && !(gen["gen_bus"] in active_bus_ids)
@warn("active generator $(i) is connected to inactive bus $(gen["gen_bus"])")
end
end
for (i, strg) in data["storage"]
if strg["status"] != 0 && !(strg["storage_bus"] in active_bus_ids)
@warn(
"active storage unit $(i) is connected to inactive bus $(strg["storage_bus"])"
)
end
end
for (i, branch) in data["branch"]
if branch["br_status"] != 0 && !(branch["f_bus"] in active_bus_ids)
@warn("active branch $(i) is connected to inactive bus $(branch["f_bus"])")
end
if branch["br_status"] != 0 && !(branch["t_bus"] in active_bus_ids)
@warn("active branch $(i) is connected to inactive bus $(branch["t_bus"])")
end
end
for (i, dcline) in data["dcline"]
if dcline["br_status"] != 0 && !(dcline["f_bus"] in active_bus_ids)
@warn("active dcline $(i) is connected to inactive bus $(dcline["f_bus"])")
end
if dcline["br_status"] != 0 && !(dcline["t_bus"] in active_bus_ids)
@warn("active dcline $(i) is connected to inactive bus $(dcline["t_bus"])")
end
end
end
"checks that contains at least one refrence bus"
function check_reference_bus(data::Dict{String, <:Any})
if ismultinetwork(data)
error("check_reference_bus does not yet support multinetwork data")
end
ref_buses = Dict{Int, Any}()
for (k, v) in data["bus"]
if v["bus_type"] == 3
ref_buses[k] = v
end
end
if length(ref_buses) == 0
if length(data["gen"]) > 0
big_gen = _biggest_generator(data["gen"])
gen_bus = big_gen["gen_bus"]
ref_bus = data["bus"][gen_bus]
ref_bus["bus_type"] = 3
@warn(
"no reference bus found, setting bus $(gen_bus) as reference based on generator $(big_gen["index"])"
)
else
(bus_item, state) = Base.iterate(values(data["bus"]))
bus_item["bus_type"] = 3
@warn(
"no reference bus found, setting bus $(bus_item["index"]) as reference"
)
end
end
return
end
"find the largest active generator in the network"
function _biggest_generator(gens)
biggest_gen = nothing
biggest_value = -Inf
for (k, gen) in gens
pmax = maximum(gen["pmax"])
if pmax > biggest_value
biggest_gen = gen
biggest_value = pmax
end
end
@assert(biggest_gen !== nothing)
return biggest_gen
end
"""
checks that each branch has a reasonable transformer parameters
this is important because setting tap == 0.0 leads to NaN computations, which are hard to debug
"""
function correct_transformer_parameters!(data::Dict{String, <:Any})
if ismultinetwork(data)
error("check_transformer_parameters does not yet support multinetwork data")
end
@assert("per_unit" in keys(data) && data["per_unit"])
modified = Set{Int}()
for (i, branch) in data["branch"]
if !haskey(branch, "tap")
@info "branch found without tap value, setting a tap to 1.0" maxlog = PS_MAX_LOG
if haskey(data, "conductors")
error("Multiconductor Not Supported in PowerSystems")
else
branch["tap"] = 1.0
end
push!(modified, branch["index"])
else
for c in 1:get(data, "conductors", 1)
cnd_str = haskey(data, "conductors") ? " on conductor $(c)" : ""
if branch["tap"][c] <= 0.0
@info(
"branch found with non-positive tap value of $(branch["tap"][c]), setting a tap to 1.0$(cnd_str)"
)
if haskey(data, "conductors")
branch["tap"][c] = 1.0
else
branch["tap"] = 1.0
end
push!(modified, branch["index"])
end
end
end
if !haskey(branch, "shift")
@info("branch found without shift value, setting a shift to 0.0")
if haskey(data, "conductors")
error("Multiconductor Not Supported in PowerSystems")
else
branch["shift"] = 0.0
end
push!(modified, branch["index"])
end
end
return modified
end
"""
checks that each storage unit has a reasonable parameters
"""
function check_storage_parameters(data::Dict{String, Any})
if ismultinetwork(data)
error("check_storage_parameters does not yet support multinetwork data")
end
for (i, strg) in data["storage"]
if strg["energy"] < 0.0
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-positive energy level $(strg["energy"])",
),
)
end
if strg["energy_rating"] < 0.0
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-positive energy rating $(strg["energy_rating"])",
),
)
end
if strg["charge_rating"] < 0.0
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-positive charge rating $(strg["energy_rating"])",
),
)
end
if strg["discharge_rating"] < 0.0
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-positive discharge rating $(strg["energy_rating"])",
),
)
end
if strg["r"] < 0.0
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-positive resistance $(strg["r"])",
),
)
end
if strg["x"] < 0.0
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-positive reactance $(strg["x"])",
),
)
end
if haskey(strg, "thermal_rating") && strg["thermal_rating"] < 0.0
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-positive thermal rating $(strg["thermal_rating"])",
),
)
end
if haskey(strg, "current_rating") && strg["current_rating"] < 0.0
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-positive current rating $(strg["thermal_rating"])",
),
)
end
if !isapprox(strg["x"], 0.0; atol = 1e-6, rtol = 1e-6)
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-zero reactance $(strg["x"]), which is currently ignored",
),
)
end
if strg["charge_efficiency"] < 0.0
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-positive charge efficiency of $(strg["charge_efficiency"])",
),
)
end
if strg["charge_efficiency"] <= 0.0 || strg["charge_efficiency"] > 1.0
@info "storage unit $(strg["index"]) charge efficiency of $(strg["charge_efficiency"]) is out of the valid range (0.0. 1.0]" maxlog =
PS_MAX_LOG
end
if strg["discharge_efficiency"] < 0.0
throw(
DataFormatError(
"storage unit $(strg["index"]) has a non-positive discharge efficiency of $(strg["discharge_efficiency"])",
),
)
end
if strg["discharge_efficiency"] <= 0.0 || strg["discharge_efficiency"] > 1.0
@info "storage unit $(strg["index"]) discharge efficiency of $(strg["discharge_efficiency"]) is out of the valid range (0.0. 1.0]" maxlog =
PS_MAX_LOG
end
if strg["p_loss"] > 0.0 && strg["energy"] <= 0.0
@info "storage unit $(strg["index"]) has positive active power losses but zero initial energy. This can lead to model infeasiblity." maxlog =
PS_MAX_LOG
end
if strg["q_loss"] > 0.0 && strg["energy"] <= 0.0
@info "storage unit $(strg["index"]) has positive reactive power losses but zero initial energy. This can lead to model infeasiblity." maxlog =
PS_MAX_LOG
end
end
end
"""
checks that each switch has a reasonable parameters
"""
function check_switch_parameters(data::Dict{String, <:Any})
if ismultinetwork(data)
error("check_switch_parameters does not yet support multinetwork data")
end
for (i, switch) in data["switch"]
if switch["state"] <= 0.0 &&
(!isapprox(switch["psw"], 0.0) || !isapprox(switch["qsw"], 0.0))
@info "switch $(switch["index"]) is open with non-zero power values $(switch["psw"]), $(switch["qsw"])" maxlog =
PS_MAX_LOG
end
if haskey(switch, "thermal_rating") && switch["thermal_rating"] < 0.0
throw(
DataFormatError(
"switch $(switch["index"]) has a non-positive thermal_rating $(switch["thermal_rating"])",
),
)
end
if haskey(switch, "current_rating") && switch["current_rating"] < 0.0
throw(
DataFormatError(
"switch $(switch["index"]) has a non-positive current_rating $(switch["current_rating"])",
),
)
end
end
end
"checks that parameters for dc lines are reasonable"
function correct_dcline_limits!(data::Dict{String, Any})
if ismultinetwork(data)
error("check_dcline_limits does not yet support multinetwork data")
end
@assert("per_unit" in keys(data) && data["per_unit"])
mva_base = data["baseMVA"]
modified = Set{Int}()
for c in 1:get(data, "conductors", 1)
cnd_str = haskey(data, "conductors") ? ", conductor $(c)" : ""
for (i, dcline) in data["dcline"]
if dcline["loss0"][c] < 0.0
new_rate = 0.0
@info "this code only supports positive loss0 values, changing the value on dcline $(dcline["index"])$(cnd_str) from $(mva_base*dcline["loss0"][c]) to $(mva_base*new_rate)" maxlog =
PS_MAX_LOG
if haskey(data, "conductors")
dcline["loss0"][c] = new_rate
else
dcline["loss0"] = new_rate
end
push!(modified, dcline["index"])
end
if dcline["loss0"][c] >=
dcline["pmaxf"][c] * (1 - dcline["loss1"][c]) + dcline["pmaxt"][c]
new_rate = 0.0
@info "this code only supports loss0 values which are consistent with the line flow bounds, changing the value on dcline $(dcline["index"])$(cnd_str) from $(mva_base*dcline["loss0"][c]) to $(mva_base*new_rate)" maxlog =
PS_MAX_LOG
if haskey(data, "conductors")
dcline["loss0"][c] = new_rate
else
dcline["loss0"] = new_rate
end
push!(modified, dcline["index"])
end
if dcline["loss1"][c] < 0.0
new_rate = 0.0
@info "this code only supports positive loss1 values, changing the value on dcline $(dcline["index"])$(cnd_str) from $(dcline["loss1"][c]) to $(new_rate)" maxlog =
PS_MAX_LOG
if haskey(data, "conductors")
dcline["loss1"][c] = new_rate
else
dcline["loss1"] = new_rate
end
push!(modified, dcline["index"])
end
if dcline["loss1"][c] >= 1.0
new_rate = 0.0
@info "this code only supports loss1 values < 1, changing the value on dcline $(dcline["index"])$(cnd_str) from $(dcline["loss1"][c]) to $(new_rate)" maxlog =
PS_MAX_LOG
if haskey(data, "conductors")
dcline["loss1"][c] = new_rate
else
dcline["loss1"] = new_rate
end
push!(modified, dcline["index"])
end
if dcline["pmint"][c] < 0.0 && dcline["loss1"][c] > 0.0
#new_rate = 0.0
@info "the dc line model is not meant to be used bi-directionally when loss1 > 0, be careful interpreting the results as the dc line losses can now be negative. change loss1 to 0 to avoid this warning" maxlog =
PS_MAX_LOG
#dcline["loss0"] = new_rate
end
end
end
return modified
end
"throws warnings if generator and dc line voltage setpoints are not consistent with the bus voltage setpoint"
function check_voltage_setpoints(data::Dict{String, <:Any})
if ismultinetwork(data)
error("check_voltage_setpoints does not yet support multinetwork data")
end
for c in 1:get(data, "conductors", 1)
cnd_str = haskey(data, "conductors") ? "conductor $(c) " : ""
for (i, gen) in data["gen"]
bus_id = gen["gen_bus"]
bus = data["bus"][bus_id]
if gen["vg"][c] != bus["vm"][c]
@info "the $(cnd_str)voltage setpoint on generator $(i) does not match the value at bus $(bus_id)" maxlog =
PS_MAX_LOG
end
end
for (i, dcline) in data["dcline"]
bus_fr_id = dcline["f_bus"]
bus_to_id = dcline["t_bus"]
bus_fr = data["bus"][bus_fr_id]
bus_to = data["bus"][bus_to_id]
if dcline["vf"][c] != bus_fr["vm"][c]
@info(
"the $(cnd_str)from bus voltage setpoint on dc line $(i) does not match the value at bus $(bus_fr_id)"
)
end
if dcline["vt"][c] != bus_to["vm"][c]
@info(
"the $(cnd_str)to bus voltage setpoint on dc line $(i) does not match the value at bus $(bus_to_id)"
)
end
end
end
end
"throws warnings if cost functions are malformed"
function correct_cost_functions!(data::Dict{String, <:Any})
if ismultinetwork(data)
error("check_cost_functions does not yet support multinetwork data")
end
modified_gen = Set{Int}()
for (i, gen) in data["gen"]
if _correct_cost_function!(i, gen, "generator")
push!(modified_gen, gen["index"])
end
end
modified_dcline = Set{Int}()
for (i, dcline) in data["dcline"]
if _correct_cost_function!(i, dcline, "dcline")
push!(modified_dcline, dcline["index"])
end
end
return (modified_gen, modified_dcline)
end
""
function _correct_cost_function!(id, comp, type_name)
modified = false
if "model" in keys(comp) && "cost" in keys(comp)
if comp["model"] == 1
if length(comp["cost"]) != 2 * comp["ncost"]
error(
"ncost of $(comp["ncost"]) not consistent with $(length(comp["cost"])) cost values on $(type_name) $(id)",
)
end
if length(comp["cost"]) < 4
error(
"cost includes $(comp["ncost"]) points, but at least two points are required on $(type_name) $(id)",
)
end
modified = _remove_pwl_cost_duplicates!(id, comp, type_name)
for i in 3:2:length(comp["cost"])
if comp["cost"][i - 2] >= comp["cost"][i]
error("non-increasing x values in pwl cost model on $(type_name) $(id)")
end
end
if "pmin" in keys(comp) && "pmax" in keys(comp)
pmin = sum(comp["pmin"]) # sum supports multi-conductor case
pmax = sum(comp["pmax"])
for i in 3:2:length(comp["cost"])
if comp["cost"][i] < pmin || comp["cost"][i] > pmax
@info(
"pwl x value $(comp["cost"][i]) is outside the bounds $(pmin)-$(pmax) on $(type_name) $(id)"
)
end
end
end
modified |= _simplify_pwl_cost!(id, comp, type_name)
elseif comp["model"] == 2
if length(comp["cost"]) != comp["ncost"]
error(
"ncost of $(comp["ncost"]) not consistent with $(length(comp["cost"])) cost values on $(type_name) $(id)",
)
end
else
@info "Unknown cost model of type $(comp["model"]) on $(type_name) $(id)" maxlog =
PS_MAX_LOG
end
end
return modified
end
"checks that each point in the a pwl function is unique, simplifies the function if duplicates appear"
function _remove_pwl_cost_duplicates!(id, comp, type_name, tolerance = 1e-2)
@assert comp["model"] == 1
unique_costs = Float64[comp["cost"][1], comp["cost"][2]]
for i in 3:2:length(comp["cost"])
x1 = unique_costs[end - 1]
y1 = unique_costs[end]
x2 = comp["cost"][i + 0]
y2 = comp["cost"][i + 1]
if !(isapprox(x1, x2) && isapprox(y1, y2))
push!(unique_costs, x2)
push!(unique_costs, y2)
end
end
# in the event that all of the given points are the same
# this code ensures that at least two of the points remain
if length(unique_costs) <= 2
push!(unique_costs, comp["cost"][end - 1])
push!(unique_costs, comp["cost"][end])
end
if length(unique_costs) < length(comp["cost"])
@info "removing duplicate points from pwl cost on $(type_name) $(id), $(comp["cost"]) -> $(unique_costs)" maxlog =
PS_MAX_LOG
comp["cost"] = unique_costs
comp["ncost"] = length(unique_costs) / 2
return true
end
return false
end
"checks the slope of each segment in a pwl function, simplifies the function if the slope changes is below a tolerance"
function _simplify_pwl_cost!(id, comp, type_name, tolerance = 1e-2)
@assert comp["model"] == 1
slopes = Float64[]
smpl_cost = Float64[]
prev_slope = nothing
x2, y2 = 0.0, 0.0
for i in 3:2:length(comp["cost"])
x1 = comp["cost"][i - 2]
y1 = comp["cost"][i - 1]
x2 = comp["cost"][i - 0]
y2 = comp["cost"][i + 1]
m = (y2 - y1) / (x2 - x1)
if prev_slope === nothing || (abs(prev_slope - m) > tolerance)
push!(smpl_cost, x1)
push!(smpl_cost, y1)
prev_slope = m
end
push!(slopes, m)
end
push!(smpl_cost, x2)
push!(smpl_cost, y2)
if length(smpl_cost) < length(comp["cost"])
@info "simplifying pwl cost on $(type_name) $(id), $(comp["cost"]) -> $(smpl_cost)" maxlog =
PS_MAX_LOG
comp["cost"] = smpl_cost
comp["ncost"] = length(smpl_cost) / 2
return true
end
return false
end
"trims zeros from higher order cost terms"
function simplify_cost_terms!(data::Dict{String, <:Any})
if ismultinetwork(data)
networks = data["nw"]
else
networks = [("0", data)]
end
modified_gen = Set{Int}()
modified_dcline = Set{Int}()
for (i, network) in networks
if haskey(network, "gen")
for (i, gen) in network["gen"]
if haskey(gen, "model") && gen["model"] == 2
ncost = length(gen["cost"])
for j in 1:ncost
if gen["cost"][1] == 0.0
gen["cost"] = gen["cost"][2:end]
else
break
end
end
if length(gen["cost"]) != ncost
gen["ncost"] = length(gen["cost"])
@info "removing $(ncost - gen["ncost"]) cost terms from generator $(i): $(gen["cost"])" maxlog =
PS_MAX_LOG
push!(modified_gen, gen["index"])
end
end
end
end
if haskey(network, "dcline")
for (i, dcline) in network["dcline"]
if haskey(dcline, "model") && dcline["model"] == 2
ncost = length(dcline["cost"])
for j in 1:ncost
if dcline["cost"][1] == 0.0
dcline["cost"] = dcline["cost"][2:end]
else
break
end
end
if length(dcline["cost"]) != ncost
dcline["ncost"] = length(dcline["cost"])
@info "removing $(ncost - dcline["ncost"]) cost terms from dcline $(i): $(dcline["cost"])" maxlog =
PS_MAX_LOG
push!(modified_dcline, dcline["index"])
end
end
end
end
end
return (modified_gen, modified_dcline)
end
"ensures all polynomial costs functions have the same number of terms"
function standardize_cost_terms!(data::Dict{String, <:Any}; order = -1)
comp_max_order = 1
if ismultinetwork(data)
networks = data["nw"]
else
networks = [("0", data)]
end
for (i, network) in networks
if haskey(network, "gen")
for (i, gen) in network["gen"]
if haskey(gen, "model") && gen["model"] == 2
max_nonzero_index = 1
for i in 1:length(gen["cost"])
max_nonzero_index = i
if gen["cost"][i] != 0.0
break
end
end
max_oder = length(gen["cost"]) - max_nonzero_index + 1
comp_max_order = max(comp_max_order, max_oder)
end
end
end
if haskey(network, "dcline")
for (i, dcline) in network["dcline"]
if haskey(dcline, "model") && dcline["model"] == 2
max_nonzero_index = 1
for i in 1:length(dcline["cost"])
max_nonzero_index = i
if dcline["cost"][i] != 0.0
break
end
end
max_oder = length(dcline["cost"]) - max_nonzero_index + 1
comp_max_order = max(comp_max_order, max_oder)
end
end
end
end
if comp_max_order <= order + 1
comp_max_order = order + 1
else
if order != -1 # if not the default
@info(
"a standard cost order of $(order) was requested but the given data requires an order of at least $(comp_max_order-1)"
)
end
end
for (i, network) in networks
if haskey(network, "gen")
_standardize_cost_terms!(network["gen"], comp_max_order, "generator")
end
if haskey(network, "dcline")
_standardize_cost_terms!(network["dcline"], comp_max_order, "dcline")
end
end
end
"ensures all polynomial costs functions have at exactly comp_order terms"
function _standardize_cost_terms!(
components::Dict{String, <:Any},
comp_order::Int,
cost_comp_name::String,
)
modified = Set{Int}()
for (i, comp) in components
if haskey(comp, "model") && comp["model"] == 2 && length(comp["cost"]) != comp_order
std_cost = [0.0 for i in 1:comp_order]
current_cost = reverse(comp["cost"])
#println("gen cost: $(comp["cost"])")
for i in 1:min(comp_order, length(current_cost))
std_cost[i] = current_cost[i]
end
comp["cost"] = reverse(std_cost)
comp["ncost"] = comp_order
#println("std gen cost: $(comp["cost"])")
@info "Updated $(cost_comp_name) $(comp["index"]) cost function with order $(length(current_cost)) to a function of order $(comp_order): $(comp["cost"])" maxlog =
PS_MAX_LOG
push!(modified, comp["index"])
end
end
return modified
end
"""
finds active network buses and branches that are not necessary for the
computation and sets their status to off.
Works on a PowerModels data dict, so that a it can be used without a GenericPowerModel object
Warning: this implementation has quadratic complexity, in the worst case
"""
function propagate_topology_status!(data::Dict{String, <:Any})
if ismultinetwork(data)
for (i, nw_data) in data["nw"]
_propagate_topology_status!(nw_data)
end
else
_propagate_topology_status!(data)
end
end
""
function _propagate_topology_status!(data::Dict{String, <:Any})
buses = Dict(bus["bus_i"] => bus for (i, bus) in data["bus"])
for (i, load) in data["load"]
if load["status"] != 0 && all(load["pd"] .== 0.0) && all(load["qd"] .== 0.0)
@info("deactivating load $(load["index"]) due to zero pd and qd")
load["status"] = 0
end
end
for (i, shunt) in data["shunt"]
if shunt["status"] != 0 && all(shunt["gs"] .== 0.0) && all(shunt["bs"] .== 0.0)
@info("deactivating shunt $(shunt["index"]) due to zero gs and bs")
shunt["status"] = 0
end
end
# compute what active components are incident to each bus
incident_load = bus_load_lookup(data["load"], data["bus"])
incident_active_load = Dict()
for (i, load_list) in incident_load
incident_active_load[i] = [load for load in load_list if load["status"] != 0]
end
incident_shunt = bus_shunt_lookup(data["shunt"], data["bus"])
incident_active_shunt = Dict()
for (i, shunt_list) in incident_shunt
incident_active_shunt[i] = [shunt for shunt in shunt_list if shunt["status"] != 0]
end
incident_gen = bus_gen_lookup(data["gen"], data["bus"])
incident_active_gen = Dict()
for (i, gen_list) in incident_gen
incident_active_gen[i] = [gen for gen in gen_list if gen["gen_status"] != 0]
end
incident_strg = bus_storage_lookup(data["storage"], data["bus"])
incident_active_strg = Dict()
for (i, strg_list) in incident_strg
incident_active_strg[i] = [strg for strg in strg_list if strg["status"] != 0]
end
incident_branch = Dict(bus["bus_i"] => [] for (i, bus) in data["bus"])
for (i, branch) in data["branch"]
push!(incident_branch[branch["f_bus"]], branch)
push!(incident_branch[branch["t_bus"]], branch)
end
incident_dcline = Dict(bus["bus_i"] => [] for (i, bus) in data["bus"])
for (i, dcline) in data["dcline"]
push!(incident_dcline[dcline["f_bus"]], dcline)
push!(incident_dcline[dcline["t_bus"]], dcline)
end
incident_switch = Dict(bus["bus_i"] => [] for (i, bus) in data["bus"])
for (i, switch) in data["switch"]
push!(incident_switch[switch["f_bus"]], switch)
push!(incident_switch[switch["t_bus"]], switch)
end
revised = false
for (i, branch) in data["branch"]
if branch["br_status"] != 0
f_bus = buses[branch["f_bus"]]
t_bus = buses[branch["t_bus"]]
if f_bus["bus_type"] == 4 || t_bus["bus_type"] == 4
@info "deactivating branch $(i):($(branch["f_bus"]),$(branch["t_bus"])) due to connecting bus status" maxlog =
PS_MAX_LOG
branch["br_status"] = 0
revised = true
end
end
end
for (i, dcline) in data["dcline"]
if dcline["br_status"] != 0
f_bus = buses[dcline["f_bus"]]
t_bus = buses[dcline["t_bus"]]
if f_bus["bus_type"] == 4 || t_bus["bus_type"] == 4
@info "deactivating dcline $(i):($(dcline["f_bus"]),$(dcline["t_bus"])) due to connecting bus status" maxlog =
PS_MAX_LOG
dcline["br_status"] = 0
revised = true
end
end
end
for (i, switch) in data["switch"]
if switch["status"] != 0
f_bus = buses[switch["f_bus"]]
t_bus = buses[switch["t_bus"]]
if f_bus["bus_type"] == 4 || t_bus["bus_type"] == 4
@info "deactivating switch $(i):($(switch["f_bus"]),$(switch["t_bus"])) due to connecting bus status" maxlog =
PS_MAX_LOG
switch["status"] = 0
revised = true
end
end
end
for (i, bus) in buses
if bus["bus_type"] == 4
for load in incident_active_load[i]
if load["status"] != 0
@info "deactivating load $(load["index"]) due to inactive bus $(i)" maxlog =
PS_MAX_LOG
load["status"] = 0
revised = true
end
end
for shunt in incident_active_shunt[i]
if shunt["status"] != 0
@info "deactivating shunt $(shunt["index"]) due to inactive bus $(i)" maxlog =
PS_MAX_LOG
shunt["status"] = 0
revised = true
end
end
for gen in incident_active_gen[i]
if gen["gen_status"] != 0
@info "deactivating generator $(gen["index"]) due to inactive bus $(i)" maxlog =
PS_MAX_LOG
gen["gen_status"] = 0
revised = true
end
end
for strg in incident_active_strg[i]
if strg["status"] != 0
@info "deactivating storage $(strg["index"]) due to inactive bus $(i)" maxlog =
PS_MAX_LOG
strg["status"] = 0
revised = true
end
end
end
end
return revised
end
"""
removes buses with single branch connections and without any other attached
components. Also removes connected components without suffuceint generation
or loads.
also deactivates 0 valued loads and shunts.
"""
function deactivate_isolated_components!(data::Dict{String, <:Any})
revised = false
pm_data = get_pm_data(data)
if _IM.ismultinetwork(pm_data)
for (i, pm_nw_data) in pm_data["nw"]
revised |= _deactivate_isolated_components!(pm_nw_data)
end
else
revised = _deactivate_isolated_components!(pm_data)
end
return revised
end
""
function _deactivate_isolated_components!(data::Dict{String, <:Any})
buses = Dict(bus["bus_i"] => bus for (i, bus) in data["bus"])
revised = false
for (i, load) in data["load"]
if load["status"] != 0 && all(load["pd"] .== 0.0) && all(load["qd"] .== 0.0)
@info "deactivating load $(load["index"]) due to zero pd and qd" maxlog =
PS_MAX_LOG
load["status"] = 0
revised = true
end
end
for (i, shunt) in data["shunt"]
if shunt["status"] != 0 && all(shunt["gs"] .== 0.0) && all(shunt["bs"] .== 0.0)
@info "deactivating shunt $(shunt["index"]) due to zero gs and bs" maxlog =
PS_MAX_LOG
shunt["status"] = 0
revised = true
end
end
# compute what active components are incident to each bus
incident_load = bus_load_lookup(data["load"], data["bus"])
incident_active_load = Dict()
for (i, load_list) in incident_load
incident_active_load[i] = [load for load in load_list if load["status"] != 0]
end
incident_shunt = bus_shunt_lookup(data["shunt"], data["bus"])
incident_active_shunt = Dict()
for (i, shunt_list) in incident_shunt
incident_active_shunt[i] = [shunt for shunt in shunt_list if shunt["status"] != 0]
end
incident_gen = bus_gen_lookup(data["gen"], data["bus"])
incident_active_gen = Dict()
for (i, gen_list) in incident_gen
incident_active_gen[i] = [gen for gen in gen_list if gen["gen_status"] != 0]
end
incident_strg = bus_storage_lookup(data["storage"], data["bus"])
incident_active_strg = Dict()
for (i, strg_list) in incident_strg
incident_active_strg[i] = [strg for strg in strg_list if strg["status"] != 0]
end
incident_branch = Dict(bus["bus_i"] => [] for (i, bus) in data["bus"])
for (i, branch) in data["branch"]
push!(incident_branch[branch["f_bus"]], branch)
push!(incident_branch[branch["t_bus"]], branch)
end
incident_dcline = Dict(bus["bus_i"] => [] for (i, bus) in data["bus"])
for (i, dcline) in data["dcline"]
push!(incident_dcline[dcline["f_bus"]], dcline)
push!(incident_dcline[dcline["t_bus"]], dcline)
end
incident_switch = Dict(bus["bus_i"] => [] for (i, bus) in data["bus"])
for (i, switch) in data["switch"]
push!(incident_switch[switch["f_bus"]], switch)
push!(incident_switch[switch["t_bus"]], switch)
end
changed = true
while changed
changed = false
for (i, bus) in buses
if bus["bus_type"] != 4
incident_active_edge = 0
if length(incident_branch[i]) +
length(incident_dcline[i]) +
length(incident_switch[i]) > 0
incident_branch_count =
sum([0; [branch["br_status"] for branch in incident_branch[i]]])
incident_dcline_count =
sum([0; [dcline["br_status"] for dcline in incident_dcline[i]]])
incident_switch_count =
sum([0; [switch["status"] for switch in incident_switch[i]]])
incident_active_edge =
incident_branch_count +
incident_dcline_count +
incident_switch_count
end
if incident_active_edge == 1 &&
length(incident_active_gen[i]) == 0 &&
length(incident_active_load[i]) == 0 &&
length(incident_active_shunt[i]) == 0 &&
length(incident_active_strg[i]) == 0
@info "deactivating bus $(i) due to dangling bus without generation, load, or storage" maxlog =
PS_MAX_LOG
bus["bus_type"] = 4
revised = true
changed = true
end
end
end
if changed
for (i, branch) in data["branch"]
if branch["br_status"] != 0
f_bus = buses[branch["f_bus"]]
t_bus = buses[branch["t_bus"]]
if f_bus["bus_type"] == 4 || t_bus["bus_type"] == 4
@info "deactivating branch $(i):($(branch["f_bus"]),$(branch["t_bus"])) due to connecting bus status" maxlog =
PS_MAX_LOG
branch["br_status"] = 0
end
end
end
for (i, dcline) in data["dcline"]
if dcline["br_status"] != 0
f_bus = buses[dcline["f_bus"]]
t_bus = buses[dcline["t_bus"]]
if f_bus["bus_type"] == 4 || t_bus["bus_type"] == 4
@info "deactivating dcline $(i):($(dcline["f_bus"]),$(dcline["t_bus"])) due to connecting bus status" maxlog =
PS_MAX_LOG
dcline["br_status"] = 0
end
end
end
for (i, switch) in data["switch"]
if switch["status"] != 0
f_bus = buses[switch["f_bus"]]
t_bus = buses[switch["t_bus"]]
if f_bus["bus_type"] == 4 || t_bus["bus_type"] == 4
@info "deactivating switch $(i):($(switch["f_bus"]),$(switch["t_bus"])) due to connecting bus status" maxlog =
PS_MAX_LOG
switch["status"] = 0
end
end
end
end
end
ccs = calc_connected_components(data)
for cc in ccs
cc_active_loads = [0]
cc_active_shunts = [0]
cc_active_gens = [0]
cc_active_strg = [0]
for i in cc
cc_active_loads = push!(cc_active_loads, length(incident_active_load[i]))
cc_active_shunts = push!(cc_active_shunts, length(incident_active_shunt[i]))
cc_active_gens = push!(cc_active_gens, length(incident_active_gen[i]))
end
active_load_count = sum(cc_active_loads)
active_shunt_count = sum(cc_active_shunts)
active_gen_count = sum(cc_active_gens)
if (active_load_count == 0 && active_shunt_count == 0 && active_strg_count == 0) ||
active_gen_count == 0
@info "deactivating connected component $(cc) due to isolation without generation and load" maxlog =
PS_MAX_LOG
for i in cc
buses[i]["bus_type"] = 4
end
revised = true
end
end
return revised
end
"""
attempts to deactive components that are not needed in the network by repeated
calls to `propagate_topology_status!` and `deactivate_isolated_components!`
warning: this implementation has quadratic complexity, in the worst case
"""
function simplify_network!(data::Dict{String, <:Any})
revised = true
iteration = 0
while revised
iteration += 1
revised = false
revised |= propagate_topology_status!(data)
revised |= deactivate_isolated_components!(data)
end
@info "network simplification fixpoint reached in $(iteration) rounds" maxlog =
PS_MAX_LOG
return revised
end
"""
determines the largest connected component of the network and turns everything else off
"""
function select_largest_component(data::Dict{String, Any})
if ismultinetwork(data)
for (i, nw_data) in data["nw"]
_select_largest_component(nw_data)
end
else
_select_largest_component(data)
end
end
""
function _select_largest_component!(data::Dict{String, <:Any})
ccs = calc_connected_components(data)
@info "found $(length(ccs)) components" maxlog = PS_MAX_LOG
if length(ccs) > 1
ccs_order = sort(collect(ccs); by = length)
largest_cc = ccs_order[end]
@info "largest component has $(length(largest_cc)) buses" maxlog = PS_MAX_LOG
for (i, bus) in data["bus"]
if bus["bus_type"] != 4 && !(bus["index"] in largest_cc)
bus["bus_type"] = 4
@info "deactivating bus $(i) due to small connected component" maxlog =
PS_MAX_LOG
end
end
correct_reference_buses!(data)
end
end
"""
checks that each connected components has a reference bus, if not, adds one
"""
function check_reference_buses(data::Dict{String, Any})
if ismultinetwork(data)
for (i, nw_data) in data["nw"]
_correct_reference_buses!(nw_data)
end
else
_correct_reference_buses!(data)
end
end
""
function _correct_reference_buses!(data::Dict{String, <:Any})
bus_lookup = Dict(bus["bus_i"] => bus for (i, bus) in data["bus"])
bus_gen = bus_gen_lookup(data["gen"], data["bus"])
ccs = calc_connected_components(data)
ccs_order = sort(collect(ccs); by = length)
bus_to_cc = Dict()
for (i, cc) in enumerate(ccs_order)
for bus_i in cc
bus_to_cc[bus_i] = i
end
end
cc_gens = Dict(i => Dict() for (i, cc) in enumerate(ccs_order))
for (i, gen) in data["gen"]
bus_id = gen["gen_bus"]
if haskey(bus_to_cc, bus_id)
cc_id = bus_to_cc[bus_id]
cc_gens[cc_id][i] = gen
end
end
for (i, cc) in enumerate(ccs_order)
correct_component_refrence_bus!(cc, bus_lookup, cc_gens[i])
end
end
"""
checks that a connected component has a reference bus, if not, tries to add one
"""
function correct_component_refrence_bus!(component_bus_ids, bus_lookup, component_gens)
refrence_buses = Set()
for bus_id in component_bus_ids
bus = bus_lookup[bus_id]
if bus["bus_type"] == 3
push!(refrence_buses, bus_id)
end
end
if length(refrence_buses) == 0
@info("no reference bus found in connected component $(component_bus_ids)")
component_gens_active =
Dict(k => v for (k, v) in component_gens if v["gen_status"] != 0)
if length(component_gens_active) > 0
big_gen = _biggest_generator(component_gens_active)
gen_bus = bus_lookup[big_gen["gen_bus"]]
gen_bus["bus_type"] = 3
@info(
"setting bus $(gen_bus["index"]) as reference bus in connected component $(component_bus_ids), based on generator $(big_gen["index"])"
)
else
@info(
"no generators found in connected component $(component_bus_ids), try running propagate_topology_status"
)
end
end
end
"builds a lookup list of what generators are connected to a given bus"
function bus_gen_lookup(gen_data::Dict{String, <:Any}, bus_data::Dict{String, <:Any})
bus_gen = Dict(bus["bus_i"] => [] for (i, bus) in bus_data)
for (i, gen) in gen_data
push!(bus_gen[gen["gen_bus"]], gen)
end
return bus_gen
end
"builds a lookup list of what loads are connected to a given bus"
function bus_load_lookup(load_data::Dict{String, <:Any}, bus_data::Dict{String, <:Any})
bus_load = Dict(bus["bus_i"] => [] for (i, bus) in bus_data)
for (i, load) in load_data
push!(bus_load[load["load_bus"]], load)
end
return bus_load
end
"builds a lookup list of what shunts are connected to a given bus"
function bus_shunt_lookup(shunt_data::Dict{String, <:Any}, bus_data::Dict{String, <:Any})
bus_shunt = Dict(bus["bus_i"] => [] for (i, bus) in bus_data)
for (i, shunt) in shunt_data
push!(bus_shunt[shunt["shunt_bus"]], shunt)
end
return bus_shunt
end
"builds a lookup list of what storage is connected to a given bus"
function bus_storage_lookup(
storage_data::Dict{String, <:Any},
bus_data::Dict{String, <:Any},
)
bus_storage = Dict(bus["bus_i"] => [] for (i, bus) in bus_data)
for (i, storage) in storage_data
push!(bus_storage[storage["storage_bus"]], storage)
end
return bus_storage
end
"""
computes the connected components of the network graph
returns a set of sets of bus ids, each set is a connected component
"""
function calc_connected_components(
pm_data::Dict{String, <:Any};
edges = ["branch", "dcline", "switch"],
)
if ismultinetwork(pm_data)
error("connected_components does not yet support multinetwork data")
end
active_bus = Dict(x for x in pm_data["bus"] if x.second["bus_type"] != 4)
active_bus_ids = Set{Int64}([bus["bus_i"] for (i, bus) in active_bus])
neighbors = Dict(i => Int[] for i in active_bus_ids)
for comp_type in edges
status_key = get(pm_component_status, comp_type, "status")
status_inactive = get(pm_component_status_inactive, comp_type, 0)
for edge in values(get(pm_data, comp_type, Dict()))
if get(edge, status_key, 1) != status_inactive &&
edge["f_bus"] in active_bus_ids &&
edge["t_bus"] in active_bus_ids
push!(neighbors[edge["f_bus"]], edge["t_bus"])
push!(neighbors[edge["t_bus"]], edge["f_bus"])
end
end
end
component_lookup = Dict(i => Set{Int}([i]) for i in active_bus_ids)
touched = Set{Int64}()
for i in active_bus_ids
if !(i in touched)
_cc_dfs(i, neighbors, component_lookup, touched)
end
end
ccs = (Set(values(component_lookup)))
return ccs
end
"""
DFS on a graph
"""
function _cc_dfs(i, neighbors, component_lookup, touched)
push!(touched, i)
for j in neighbors[i]
if !(j in touched)
for k in component_lookup[j]
push!(component_lookup[i], k)
end
for k in component_lookup[j]
component_lookup[k] = component_lookup[i]
end
_cc_dfs(j, neighbors, component_lookup, touched)
end
end
end
"""
given a network data dict and a mapping of current-bus-ids to new-bus-ids
modifies the data dict to reflect the proposed new bus ids.
"""
function update_bus_ids!(
data::Dict{String, <:Any},
bus_id_map::Dict{Int, Int};
injective = true,
)
data_it = ismultiinfrastructure(data) ? data["it"][pm_it_name] : data
if _IM.ismultinetwork(data_it) && apply_to_subnetworks
for (nw, nw_data) in data_it["nw"]
_update_bus_ids!(nw_data, bus_id_map; injective = injective)
end
else
_update_bus_ids!(data_it, bus_id_map; injective = injective)
end
end
function _update_bus_ids!(
data::Dict{String, <:Any},
bus_id_map::Dict{Int, Int};
injective = true,
)
# verify bus id map is injective
if injective
new_bus_ids = Set{Int}()
for (i, bus) in data["bus"]
new_id = get(bus_id_map, bus["index"], bus["index"])
if !(new_id in new_bus_ids)
push!(new_bus_ids, new_id)
else
throw(
error(
"bus id mapping given to update_bus_ids has an id clash on new bus id $(new_id)",
),
)
end
end
end
# start renumbering process
renumbered_bus_dict = Dict{String, Any}()
for (i, bus) in data["bus"]
new_id = get(bus_id_map, bus["index"], bus["index"])
bus["index"] = new_id
bus["bus_i"] = new_id
renumbered_bus_dict["$new_id"] = bus
end
data["bus"] = renumbered_bus_dict
# update bus numbering in dependent components
for (i, load) in data["load"]
load["load_bus"] = get(bus_id_map, load["load_bus"], load["load_bus"])
end
for (i, shunt) in data["shunt"]
shunt["shunt_bus"] = get(bus_id_map, shunt["shunt_bus"], shunt["shunt_bus"])
end
for (i, gen) in data["gen"]
gen["gen_bus"] = get(bus_id_map, gen["gen_bus"], gen["gen_bus"])
end
for (i, strg) in data["storage"]
strg["storage_bus"] = get(bus_id_map, strg["storage_bus"], strg["storage_bus"])
end
for (i, switch) in data["switch"]
switch["f_bus"] = get(bus_id_map, switch["f_bus"], switch["f_bus"])
switch["t_bus"] = get(bus_id_map, switch["t_bus"], switch["t_bus"])
end
branches = []
if haskey(data, "branch")
append!(branches, values(data["branch"]))
end
if haskey(data, "ne_branch")
append!(branches, values(data["ne_branch"]))
end
for branch in branches
branch["f_bus"] = get(bus_id_map, branch["f_bus"], branch["f_bus"])
branch["t_bus"] = get(bus_id_map, branch["t_bus"], branch["t_bus"])
end
for (i, dcline) in data["dcline"]
dcline["f_bus"] = get(bus_id_map, dcline["f_bus"], dcline["f_bus"])
dcline["t_bus"] = get(bus_id_map, dcline["t_bus"], dcline["t_bus"])
end
end
"""
given a network data dict merges buses that are connected by closed switches
converting the dataset into a pure bus-branch model.
"""
function resolve_swithces!(data::Dict{String, <:Any})
if ismultinetwork(data)
for (i, nw_data) in data["nw"]
_resolve_swithces!(nw_data, mva_base)
end
else
_resolve_swithces!(data, mva_base)
end
end
""
function _resolve_swithces!(data::Dict{String, <:Any})
if length(data["switch"]) <= 0
return
end
bus_sets = Dict{Int, Set{Int}}()
switch_status_key = pm_component_status["switch"]
switch_status_value = pm_component_status_inactive["switch"]
for (i, switch) in data["switch"]
if switch[switch_status_key] != switch_status_value && switch["state"] == 1
if !haskey(bus_sets, switch["f_bus"])
bus_sets[switch["f_bus"]] = Set{Int}([switch["f_bus"]])
end
if !haskey(bus_sets, switch["t_bus"])
bus_sets[switch["t_bus"]] = Set{Int}([switch["t_bus"]])
end
merged_set =
Set{Int}([bus_sets[switch["f_bus"]]..., bus_sets[switch["t_bus"]]...])
bus_sets[switch["f_bus"]] = merged_set
bus_sets[switch["t_bus"]] = merged_set
end
end
bus_id_map = Dict{Int, Int}()
for bus_set in Set(values(bus_sets))
bus_min = minimum(bus_set)
@info "merged buses $(join(bus_set, ",")) in to bus $(bus_min) based on switch status" maxlog =
PS_MAX_LOG
for i in bus_set
if i != bus_min
bus_id_map[i] = bus_min
end
end
end
update_bus_ids!(data, bus_id_map; injective = false)
for (i, branch) in data["branch"]
if branch["f_bus"] == branch["t_bus"]
@warn "switch removal resulted in both sides of branch $(i) connect to bus $(branch["f_bus"]), deactivating branch"
branch[pm_component_status["branch"]] = pm_component_status_inactive["branch"]
end
end
for (i, dcline) in data["dcline"]
if dcline["f_bus"] == dcline["t_bus"]
@warn "switch removal resulted in both sides of dcline $(i) connect to bus $(branch["f_bus"]), deactivating dcline"
branch[pm_component_status["dcline"]] = pm_component_status_inactive["dcline"]
end
end
@info "removed $(length(data["switch"])) switch components"
data["switch"] = Dict{String, Any}()
return
end
"""
Move gentype and genfuel fields to be subfields of gen
"""
function move_genfuel_and_gentype!(data::Dict{String, Any}) # added by PSY
ngen = length(data["gen"])
toplevkeys = ("genfuel", "gentype")
sublevkeys = ("fuel", "type")
for i in range(1; stop = length(toplevkeys))
if haskey(data, toplevkeys[i])
# check that lengths of category and generators match
if length(data[toplevkeys[i]]) != ngen
str = toplevkeys[i]
throw(
DataFormatError(
"length of $str does not equal the number of generators",
),
)
end
for (key, val) in data[toplevkeys[i]]
data["gen"][key][sublevkeys[i]] = val["col_1"]
end
delete!(data, toplevkeys[i])
end
end
end
================================================
FILE: src/parsers/pm_io/matpower.jl
================================================
#########################################################################
# #
# This file provides functions for interfacing with Matpower data files #
# #
#########################################################################
const MP_FIX_VOLTAGE_BUSES = [2, 3]
"Parses the matpwer data from either a filename or an IO object"
function parse_matpower(io::IO; validate = true)::Dict
mp_data = _parse_matpower_string(read(io, String))
pm_data = _matpower_to_powermodels!(mp_data)
if validate
correct_network_data!(pm_data)
end
return pm_data
end
function parse_matpower(file::String; kwargs...)::Dict
mp_data = open(file) do io
parse_matpower(io; kwargs...)
end
return mp_data
end
### Data and functions specific to Matpower format ###
const _mp_data_names = [
"mpc.version",
"mpc.baseMVA",
"mpc.bus",
"mpc.gen",
"mpc.branch",
"mpc.dcline",
"mpc.gencost",
"mpc.dclinecost",
"mpc.bus_name",
"mpc.storage",
"mpc.switch",
]
const _mp_bus_columns = [
("bus_i", Int),
("bus_type", Int),
("pd", Float64),
("qd", Float64),
("gs", Float64),
("bs", Float64),
("area", Int),
("vm", Float64),
("va", Float64),
("base_kv", Float64),
("zone", Int),
("vmax", Float64),
("vmin", Float64),
("lam_p", Float64),
("lam_q", Float64),
("mu_vmax", Float64),
("mu_vmin", Float64),
]
const _mp_bus_name_columns = [("name", Union{String, SubString{String}})]
const _mp_gen_columns = [
("gen_bus", Int),
("pg", Float64),
("qg", Float64),
("qmax", Float64),
("qmin", Float64),
("vg", Float64),
("mbase", Float64),
("gen_status", Int),
("pmax", Float64),
("pmin", Float64),
("pc1", Float64),
("pc2", Float64),
("qc1min", Float64),
("qc1max", Float64),
("qc2min", Float64),
("qc2max", Float64),
("ramp_agc", Float64),
("ramp_10", Float64),
("ramp_30", Float64),
("ramp_q", Float64),
("apf", Float64),
("mu_pmax", Float64),
("mu_pmin", Float64),
("mu_qmax", Float64),
("mu_qmin", Float64),
]
const _mp_branch_columns = [
("f_bus", Int),
("t_bus", Int),
("br_r", Float64),
("br_x", Float64),
("br_b", Float64),
("rate_a", Float64),
("rate_b", Float64),
("rate_c", Float64),
("tap", Float64),
("shift", Float64),
("br_status", Int),
("angmin", Float64),
("angmax", Float64),
("pf", Float64),
("qf", Float64),
("pt", Float64),
("qt", Float64),
("mu_sf", Float64),
("mu_st", Float64),
("mu_angmin", Float64),
("mu_angmax", Float64),
]
const _mp_dcline_columns = [
("f_bus", Int),
("t_bus", Int),
("br_status", Int),
("pf", Float64),
("pt", Float64),
("qf", Float64),
("qt", Float64),
("vf", Float64),
("vt", Float64),
("pmin", Float64),
("pmax", Float64),
("qminf", Float64),
("qmaxf", Float64),
("qmint", Float64),
("qmaxt", Float64),
("loss0", Float64),
("loss1", Float64),
("mu_pmin", Float64),
("mu_pmax", Float64),
("mu_qminf", Float64),
("mu_qmaxf", Float64),
("mu_qmint", Float64),
("mu_qmaxt", Float64),
]
const _mp_storage_columns = [
("storage_bus", Int),
("ps", Float64),
("qs", Float64),
("energy", Float64),
("energy_rating", Float64),
("charge_rating", Float64),
("discharge_rating", Float64),
("charge_efficiency", Float64),
("discharge_efficiency", Float64),
("thermal_rating", Float64),
("qmin", Float64),
("qmax", Float64),
("r", Float64),
("x", Float64),
("p_loss", Float64),
("q_loss", Float64),
("status", Int),
]
const _mp_switch_columns = [
("f_bus", Int),
("t_bus", Int),
("psw", Float64),
("qsw", Float64),
("state", Int),
("thermal_rating", Float64),
("status", Int),
]
""
function _parse_matpower_string(data_string::String)
matlab_data, func_name, colnames = parse_matlab_string(data_string; extended = true)
case = Dict{String, Any}()
if func_name !== nothing
case["name"] = func_name
else
@info(
string(
"no case name found in matpower file. The file seems to be missing \"function mpc = ...\"",
)
)
case["name"] = "no_name_found"
end
case["source_type"] = "matpower"
if haskey(matlab_data, "mpc.version")
case["source_version"] = matlab_data["mpc.version"]
else
@info(
string(
"no case version found in matpower file. The file seems to be missing \"mpc.version = ...\"",
)
)
case["source_version"] = "0.0.0+"
end
if haskey(matlab_data, "mpc.baseMVA")
case["baseMVA"] = Float64(matlab_data["mpc.baseMVA"])
else
@info(
string(
"no baseMVA found in matpower file. The file seems to be missing \"mpc.baseMVA = ...\"",
)
)
case["baseMVA"] = 1.0
end
if haskey(matlab_data, "mpc.bus")
buses = []
pv_bus_lookup = Dict{Int, Any}()
for bus_row in matlab_data["mpc.bus"]
bus_data = row_to_typed_dict(bus_row, _mp_bus_columns)
bus_data["index"] = check_type(Int, bus_row[1])
bus_data["source_id"] = ["bus", bus_data["index"]]
push!(buses, bus_data)
if bus_data["bus_type"] ∈ MP_FIX_VOLTAGE_BUSES
pv_bus_lookup[bus_data["index"]] = bus_data
end
end
case["bus"] = buses
else
error(
string(
"no bus table found in matpower file. The file seems to be missing \"mpc.bus = [...];\"",
),
)
end
if haskey(matlab_data, "mpc.gen")
gens = []
corrected_pv_bus_vm = Dict{Int, Float64}()
for (i, gen_row) in enumerate(matlab_data["mpc.gen"])
gen_data = row_to_typed_dict(gen_row, _mp_gen_columns)
bus_data = get(pv_bus_lookup, gen_data["gen_bus"], nothing)
if bus_data !== nothing
if bus_data["bus_type"] ∈ MP_FIX_VOLTAGE_BUSES &&
bus_data["vm"] != gen_data["vg"]
@info "Correcting vm in bus $(gen_data["gen_bus"]) to $(gen_data["vg"]) to match generator set-point"
if gen_data["gen_bus"] ∈ keys(corrected_pv_bus_vm)
if corrected_pv_bus_vm[gen_data["gen_bus"]] != gen_data["vg"]
@error(
"Generator voltage set-points for bus $(gen_data["gen_bus"]) are inconsistent. This can lead to unexpected results"
)
end
else
bus_data["vm"] = gen_data["vg"]
corrected_pv_bus_vm[gen_data["gen_bus"]] = gen_data["vg"]
end
end
end
gen_data["index"] = i
gen_data["source_id"] = ["gen", i]
push!(gens, gen_data)
end
case["gen"] = gens
else
error(
string(
"no gen table found in matpower file. The file seems to be missing \"mpc.gen = [...];\"",
),
)
end
if haskey(matlab_data, "mpc.branch")
branches = []
for (i, branch_row) in enumerate(matlab_data["mpc.branch"])
branch_data = row_to_typed_dict(branch_row, _mp_branch_columns)
branch_data["index"] = i
branch_data["source_id"] = ["branch", i]
push!(branches, branch_data)
end
case["branch"] = branches
else
error(
string(
"no branch table found in matpower file. The file seems to be missing \"mpc.branch = [...];\"",
),
)
end
if haskey(matlab_data, "mpc.dcline")
dclines = []
for (i, dcline_row) in enumerate(matlab_data["mpc.dcline"])
dcline_data = row_to_typed_dict(dcline_row, _mp_dcline_columns)
dcline_data["index"] = i
dcline_data["source_id"] = ["dcline", i]
push!(dclines, dcline_data)
end
case["dcline"] = dclines
end
if haskey(matlab_data, "mpc.storage")
storage = []
for (i, storage_row) in enumerate(matlab_data["mpc.storage"])
storage_data = row_to_typed_dict(storage_row, _mp_storage_columns)
storage_data["index"] = i
storage_data["source_id"] = ["storage", i]
push!(storage, storage_data)
end
case["storage"] = storage
end
if haskey(matlab_data, "mpc.switch")
switch = []
for (i, switch_row) in enumerate(matlab_data["mpc.switch"])
switch_data = row_to_typed_dict(switch_row, _mp_switch_columns)
switch_data["index"] = i
switch_data["source_id"] = ["switch", i]
push!(switch, switch_data)
end
case["switch"] = switch
end
if haskey(matlab_data, "mpc.bus_name")
bus_names = []
for (i, bus_name_row) in enumerate(matlab_data["mpc.bus_name"])
bus_name_data = row_to_typed_dict(bus_name_row, _mp_bus_name_columns)
bus_name_data["index"] = i
bus_name_data["source_id"] = ["bus_name", i]
push!(bus_names, bus_name_data)
end
case["bus_name"] = bus_names
if length(case["bus_name"]) != length(case["bus"])
error(
"incorrect Matpower file, the number of bus names ($(length(case["bus_name"]))) is inconsistent with the number of buses ($(length(case["bus"]))).\n",
)
end
end
if haskey(matlab_data, "mpc.gencost")
gencost = []
for (i, gencost_row) in enumerate(matlab_data["mpc.gencost"])
gencost_data = _mp_cost_data(gencost_row)
gencost_data["index"] = i
gencost_data["source_id"] = ["gencost", i]
push!(gencost, gencost_data)
end
case["gencost"] = gencost
if length(case["gencost"]) != length(case["gen"]) &&
length(case["gencost"]) != 2 * length(case["gen"])
error(
"incorrect Matpower file, the number of generator cost functions ($(length(case["gencost"]))) is inconsistent with the number of generators ($(length(case["gen"]))).\n",
)
end
end
if haskey(matlab_data, "mpc.dclinecost")
dclinecosts = []
for (i, dclinecost_row) in enumerate(matlab_data["mpc.dclinecost"])
dclinecost_data = _mp_cost_data(dclinecost_row)
dclinecost_data["index"] = i
dclinecost_data["source_id"] = ["dclinecost", i]
push!(dclinecosts, dclinecost_data)
end
case["dclinecost"] = dclinecosts
if length(case["dclinecost"]) != length(case["dcline"])
error(
"incorrect Matpower file, the number of dcline cost functions ($(length(case["dclinecost"]))) is inconsistent with the number of dclines ($(length(case["dcline"]))).\n",
)
end
end
for k in keys(matlab_data)
if !in(k, _mp_data_names) && startswith(k, "mpc.")
case_name = k[5:length(k)]
value = matlab_data[k]
if isa(value, Array)
column_names = []
if haskey(colnames, k)
column_names = colnames[k]
end
tbl = []
for (i, row) in enumerate(matlab_data[k])
row_data = row_to_dict(row, column_names)
row_data["index"] = i
row_data["source_id"] = [case_name, i]
push!(tbl, row_data)
end
case[case_name] = tbl
@info(
"extending matpower format with data: $(case_name) $(length(tbl))x$(length(tbl[1])-1)"
)
else
case[case_name] = value
@info("extending matpower format with constant data: $(case_name)")
end
end
end
return case
end
""
function _mp_cost_data(cost_row)
ncost = check_type(Int, cost_row[4])
model = check_type(Int, cost_row[1])
if model == 1
nr_parameters = ncost * 2
elseif model == 2
nr_parameters = ncost
end
cost_data = Dict(
"model" => model,
"startup" => check_type(Float64, cost_row[2]),
"shutdown" => check_type(Float64, cost_row[3]),
"ncost" => ncost,
"cost" => [check_type(Float64, x) for x in cost_row[5:(5 + nr_parameters - 1)]],
)
#=
# skip this literal interpretation, as its hard to invert
cost_values = [check_type(Float64, x) for x in cost_row[5:length(cost_row)]]
if cost_data["model"] == 1:
if length(cost_values)%2 != 0
error("incorrect matpower file, odd number of pwl cost function values")
end
for i in 0:(length(cost_values)/2-1)
p_idx = 1+2*i
f_idx = 2+2*i
cost_data["p_$(i)"] = cost_values[p_idx]
cost_data["f_$(i)"] = cost_values[f_idx]
end
else:
for (i,v) in enumerate(cost_values)
cost_data["c_$(length(cost_values)+1-i)"] = v
end
=#
return cost_data
end
### Data and functions specific to PowerModels format ###
"""
Converts a Matpower dict into a PowerModels dict
"""
function _matpower_to_powermodels!(mp_data::Dict{String, <:Any})
pm_data = mp_data
# required default values
if !haskey(pm_data, "dcline")
pm_data["dcline"] = []
end
if !haskey(pm_data, "gencost")
pm_data["gencost"] = []
end
if !haskey(pm_data, "dclinecost")
pm_data["dclinecost"] = []
end
if !haskey(pm_data, "storage")
pm_data["storage"] = []
end
if !haskey(pm_data, "switch")
pm_data["switch"] = []
end
# Add conformity key to bus data if not present
missing_conformity_loads = [
bus for bus in pm_data["bus"]
if (bus["pd"] != 0.0 || bus["qd"] != 0.0) && !haskey(bus, "conformity")
]
for bus in missing_conformity_loads
bus["conformity"] = 1
end
missing_conformity_count = length(missing_conformity_loads)
if missing_conformity_count > 0
@info "No conformity field found for $missing_conformity_count load(s). Setting to default value of 1 (Conforming Load)."
end
# translate component models
_mp2pm_branch!(pm_data)
_mp2pm_dcline!(pm_data)
# translate cost models
_add_dcline_costs!(pm_data)
# merge data tables
_merge_bus_name_data!(pm_data)
_merge_cost_data!(pm_data)
_merge_generic_data!(pm_data)
# split loads and shunts from buses
_split_loads_shunts!(pm_data)
# use once available
arrays_to_dicts!(pm_data)
base_voltages = Dict{Int64, Float64}(
bus_ind => bus_data["base_kv"] for (bus_ind, bus_data) in pm_data["bus"]
)
for transf in values(pm_data["branch"])
if transf["transformer"] == true && !haskey(transf, "base_voltage_from")
transf["base_voltage_from"] = base_voltages[transf["f_bus"]]
transf["base_voltage_to"] = base_voltages[transf["t_bus"]]
end
end
for optional in ["dcline", "load", "shunt", "storage", "switch"]
if length(pm_data[optional]) == 0
pm_data[optional] = Dict{String, Any}()
end
end
return pm_data
end
"""
_split_loads_shunts!(data)
Seperates Loads and Shunts in `data` under separate "load" and "shunt" keys in the
PowerModels data format. Includes references to originating bus via "load_bus"
and "shunt_bus" keys, respectively.
"""
function _split_loads_shunts!(data::Dict{String, Any})
data["load"] = []
data["shunt"] = []
load_num = 1
shunt_num = 1
for (i, bus) in enumerate(data["bus"])
if bus["pd"] != 0.0 || bus["qd"] != 0.0
append!(
data["load"],
[
Dict{String, Any}(
"pd" => bus["pd"],
"qd" => bus["qd"],
"load_bus" => bus["bus_i"],
"status" => convert(Int8, bus["bus_type"] != 4),
"conformity" => get(bus, "conformity", 1),
"index" => load_num,
"source_id" => ["bus", bus["bus_i"]],
),
],
)
load_num += 1
end
if bus["gs"] != 0.0 || bus["bs"] != 0.0
append!(
data["shunt"],
[
Dict{String, Any}(
"gs" => bus["gs"],
"bs" => bus["bs"],
"shunt_bus" => bus["bus_i"],
"status" => convert(Int8, bus["bus_type"] != 4),
"index" => shunt_num,
"source_id" => ["bus", bus["bus_i"]],
),
],
)
shunt_num += 1
end
for key in ["pd", "qd", "gs", "bs"]
delete!(bus, key)
end
end
end
"sets all branch transformer taps to 1.0, to simplify branch models"
function _mp2pm_branch!(data::Dict{String, Any})
branches = [branch for branch in data["branch"]]
if haskey(data, "ne_branch")
append!(branches, data["ne_branch"])
end
for branch in branches
if branch["tap"] == 0.0
branch["transformer"] = false
branch["tap"] = 1.0
# Evenly split the susceptance between the `from` and `to` ends
branch["b_fr"] = branch["br_b"] / 2.0
branch["b_to"] = branch["br_b"] / 2.0
else
branch["transformer"] = true
if branch["br_b"] != 0.0
@warn "Reflecting transformer shunts to primary; the ybus matrix will differ from matpower" maxlog =
5
branch["b_fr"] = (branch["br_b"] / branch["tap"]^2)
else
branch["b_fr"] = 0.0
end
branch["b_to"] = 0.0
end
branch["g_fr"] = 0.0
branch["g_to"] = 0.0
branch["base_power"] = data["baseMVA"]
delete!(branch, "br_b")
if branch["rate_a"] == 0.0
delete!(branch, "rate_a")
end
if branch["rate_b"] == 0.0
delete!(branch, "rate_b")
end
if branch["rate_c"] == 0.0
delete!(branch, "rate_c")
end
end
end
"adds pmin and pmax values at to and from buses"
function _mp2pm_dcline!(data::Dict{String, Any})
for dcline in data["dcline"]
pmin = dcline["pmin"]
pmax = dcline["pmax"]
loss0 = dcline["loss0"]
loss1 = dcline["loss1"]
delete!(dcline, "pmin")
delete!(dcline, "pmax")
if pmin >= 0 && pmax >= 0
pminf = pmin
pmaxf = pmax
pmint = loss0 - pmaxf * (1 - loss1)
pmaxt = loss0 - pminf * (1 - loss1)
end
if pmin >= 0 && pmax < 0
pminf = pmin
pmint = pmax
pmaxf = (-pmint + loss0) / (1 - loss1)
pmaxt = loss0 - pminf * (1 - loss1)
end
if pmin < 0 && pmax >= 0
pmaxt = -pmin
pmaxf = pmax
pminf = (-pmaxt + loss0) / (1 - loss1)
pmint = loss0 - pmaxf * (1 - loss1)
end
if pmin < 0 && pmax < 0
pmaxt = -pmin
pmint = pmax
pmaxf = (-pmint + loss0) / (1 - loss1)
pminf = (-pmaxt + loss0) / (1 - loss1)
end
dcline["pmaxt"] = pmaxt
dcline["pmint"] = pmint
dcline["pmaxf"] = pmaxf
dcline["pminf"] = pminf
# preserve the old pmin and pmax values
dcline["mp_pmin"] = pmin
dcline["mp_pmax"] = pmax
dcline["pt"] = -dcline["pt"] # matpower has opposite convention
dcline["qf"] = -dcline["qf"] # matpower has opposite convention
dcline["qt"] = -dcline["qt"] # matpower has opposite convention
end
end
"adds dcline costs, if gen costs exist"
function _add_dcline_costs!(data::Dict{String, Any})
if length(data["gencost"]) > 0 &&
length(data["dclinecost"]) <= 0 &&
length(data["dcline"]) > 0
@info("added zero cost function data for dclines")
model = data["gencost"][1]["model"]
if model == 1
for (i, dcline) in enumerate(data["dcline"])
dclinecost = Dict(
"index" => i,
"model" => 1,
"startup" => 0.0,
"shutdown" => 0.0,
"ncost" => 2,
"cost" => [dcline["pminf"], 0.0, dcline["pmaxf"], 0.0],
)
push!(data["dclinecost"], dclinecost)
end
else
for (i, dcline) in enumerate(data["dcline"])
dclinecost = Dict(
"index" => i,
"model" => 2,
"startup" => 0.0,
"shutdown" => 0.0,
"ncost" => 3,
"cost" => [0.0, 0.0, 0.0],
)
push!(data["dclinecost"], dclinecost)
end
end
end
end
"merges generator cost functions into generator data, if costs exist"
function _merge_cost_data!(data::Dict{String, Any})
if haskey(data, "gencost")
gen = data["gen"]
gencost = data["gencost"]
if length(gen) != length(gencost)
if length(gencost) > length(gen)
@warn(
"The last $(length(gencost) - length(gen)) generator cost records will be ignored due to too few generator records.",
)
gencost = gencost[1:length(gen)]
else
@warn(
"The number of generators ($(length(gen))) does not match the number of generator cost records ($(length(gencost))).",
)
end
end
for (i, gc) in enumerate(gencost)
g = gen[i]
@assert(g["index"] == gc["index"])
delete!(gc, "index")
delete!(gc, "source_id")
_check_keys(g, keys(gc))
merge!(g, gc)
end
delete!(data, "gencost")
end
if haskey(data, "dclinecost")
dcline = data["dcline"]
dclinecost = data["dclinecost"]
if length(dcline) != length(dclinecost)
@warn(
"The number of dclines ($(length(dcline))) does not match the number of dcline cost records ($(length(dclinecost))).",
)
end
for (i, dclc) in enumerate(dclinecost)
dcl = dcline[i]
@assert(dcl["index"] == dclc["index"])
delete!(dclc, "index")
delete!(dclc, "source_id")
_check_keys(dcl, keys(dclc))
merge!(dcl, dclc)
end
delete!(data, "dclinecost")
end
end
"merges bus name data into buses, if names exist"
function _merge_bus_name_data!(data::Dict{String, Any})
if haskey(data, "bus_name")
# can assume same length is same as bus
# this is validated during matpower parsing
for (i, bus_name) in enumerate(data["bus_name"])
bus = data["bus"][i]
delete!(bus_name, "index")
delete!(bus_name, "source_id")
_check_keys(bus, keys(bus_name))
merge!(bus, bus_name)
end
delete!(data, "bus_name")
end
end
"merges Matpower tables based on the table extension syntax"
function _merge_generic_data!(data::Dict{String, Any})
mp_matrix_names = [name[5:length(name)] for name in _mp_data_names]
key_to_delete = []
for (k, v) in data
if isa(v, Array)
for mp_name in mp_matrix_names
if startswith(k, "$(mp_name)_")
mp_matrix = data[mp_name]
push!(key_to_delete, k)
if length(mp_matrix) != length(v)
error(
"failed to extend the matpower matrix \"$(mp_name)\" with the matrix \"$(k)\" because they do not have the same number of rows, $(length(mp_matrix)) and $(length(v)) respectively.",
)
end
@info(
"extending matpower format by appending matrix \"$(k)\" in to \"$(mp_name)\""
)
for (i, row) in enumerate(mp_matrix)
merge_row = v[i]
#@assert(row["index"] == merge_row["index"]) # note this does not hold for the bus table
delete!(merge_row, "index")
delete!(merge_row, "source_id")
for key in keys(merge_row)
if haskey(row, key)
error(
"failed to extend the matpower matrix \"$(mp_name)\" with the matrix \"$(k)\" because they both share \"$(key)\" as a column name.",
)
end
row[key] = merge_row[key]
end
end
break # out of mp_matrix_names loop
end
end
end
end
for key in key_to_delete
delete!(data, key)
end
end
""
function _check_keys(data, keys)
for key in keys
if haskey(data, key)
error("attempting to overwrite value of $(key) in PowerModels data,\n$(data)")
end
end
end
================================================
FILE: src/parsers/pm_io/psse.jl
================================================
# Parse PSS(R)E data from PTI file into PowerModels data format
"""
_init_bus!(bus, id)
Initializes a `bus` of id `id` with default values given in the PSS(R)E
specification.
"""
function _init_bus!(bus::Dict{String, Any}, id::Int)
bus["bus_i"] = id
bus["bus_type"] = 1
bus["area"] = 1
bus["vm"] = 1.0
bus["va"] = 0.0
bus["base_kv"] = 1.0
bus["zone"] = 1
bus["name"] = " "
bus["vmax"] = 1.1
bus["vmin"] = 0.9
bus["index"] = id
return
end
function _find_bus_value(bus_i::Int, field::String, pm_bus_data::Array)
for bus in pm_bus_data
if bus["index"] == bus_i
return bus[field]
end
end
@info("Could not find bus $bus_i, returning 0 for field $field")
return 0
end
function _find_bus_value(bus_i::Int, field::String, pm_bus_data::Dict)
if !haskey(pm_bus_data, bus_i)
@info("Could not find bus $bus_i, returning 0 for field $field")
return 0
else
return pm_bus_data[bus_i][field]
end
end
"""
_get_bus_value(bus_i, field, pm_data)
Returns the value of `field` of `bus_i` from the PowerModels data. Requires
"bus" Dict to already be populated.
"""
function _get_bus_value(bus_i::Int, field::String, pm_data::Dict{String, Any})
return _find_bus_value(bus_i, field, pm_data["bus"])
end
"""
_find_max_bus_id(pm_data)
Returns the maximum bus id in `pm_data`
"""
function _find_max_bus_id(pm_data::Dict)::Int
max_id = 0
for bus in values(pm_data["bus"])
if bus["index"] > max_id && !endswith(bus["name"], "starbus")
max_id = bus["index"]
end
end
return max_id
end
"""
create_starbus(pm_data, transformer)
Creates a starbus from a given three-winding `transformer`. "source_id" is given
by `["bus_i", "name", "I", "J", "K", "CKT"]` where "bus_i" and "name" are the
modified names for the starbus, and "I", "J", "K" and "CKT" come from the
originating transformer, in the PSS(R)E transformer specification.
"""
function _create_starbus_from_transformer(
pm_data::Dict,
transformer::Dict,
starbus_id::Int,
)::Dict
starbus = Dict{String, Any}()
_init_bus!(starbus, starbus_id)
starbus["name"] = "starbus_$(transformer["I"])_$(transformer["J"])_$(transformer["K"])_$(strip(transformer["CKT"]))"
bus_type = 1
starbus["vm"] = transformer["VMSTAR"]
starbus["va"] = transformer["ANSTAR"]
starbus["bus_type"] = bus_type
if transformer["STAT"] != 0
starbus["bus_status"] = true
else
starbus["bus_status"] = false
end
starbus["area"] = _get_bus_value(transformer["I"], "area", pm_data)
starbus["zone"] = _get_bus_value(transformer["I"], "zone", pm_data)
starbus["hidden"] = true
starbus["source_id"] = push!(
["transformer", starbus["bus_i"], starbus["name"]],
transformer["I"],
transformer["J"],
transformer["K"],
transformer["CKT"],
)
return starbus
end
"Imports remaining top level component lists from `data_in` into `data_out`, excluding keys in `exclude`"
function _import_remaining_comps!(data_out::Dict, data_in::Dict; exclude = [])
for (comp_class, v) in data_in
if !(comp_class in exclude)
comps_out = Dict{String, Any}()
if isa(v, Array)
for (n, item) in enumerate(v)
if isa(item, Dict)
comp_out = Dict{String, Any}()
_import_remaining_keys!(comp_out, item)
if !("index" in keys(item))
comp_out["index"] = n
end
comps_out["$(n)"] = comp_out
else
@error("psse data parsing error, please post an issue")
end
end
elseif isa(v, Dict)
comps_out = Dict{String, Any}()
_import_remaining_keys!(comps_out, v)
else
@error("psse data parsing error, please post an issue")
end
data_out[lowercase(comp_class)] = comps_out
end
end
end
"Imports remaining keys from a source component into detestation component, excluding keys in `exclude`"
function _import_remaining_keys!(comp_dest::Dict, comp_src::Dict; exclude = [])
for (k, v) in comp_src
if !(k in exclude)
key = lowercase(k)
if !haskey(comp_dest, key)
comp_dest[key] = v
else
if key != "index"
@warn("duplicate key $(key), please post an issue")
end
end
end
end
end
"""
_psse2pm_branch!(pm_data, pti_data)
Parses PSS(R)E-style Branch data into a PowerModels-style Dict. "source_id" is
given by `["I", "J", "CKT"]` in PSS(R)E Branch specification.
"""
function _psse2pm_branch!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E Branch data into a PowerModels Dict..."
pm_data["branch"] = []
if haskey(pti_data, "BRANCH")
for branch in pti_data["BRANCH"]
if !haskey(branch, "I") || !haskey(branch, "J")
@error "Bus Data Incomplete for $(branch). Skipping branch creation"
continue
end
if first(branch["CKT"]) != '@' && first(branch["CKT"]) != '*'
sub_data = Dict{String, Any}()
sub_data["f_bus"] = pop!(branch, "I")
sub_data["t_bus"] = pop!(branch, "J")
bus_from = pm_data["bus"][sub_data["f_bus"]]
sub_data["base_voltage_from"] = bus_from["base_kv"]
bus_to = pm_data["bus"][sub_data["t_bus"]]
sub_data["base_voltage_to"] = bus_to["base_kv"]
if pm_data["has_isolated_type_buses"]
if !(bus_from["bus_type"] == 4 || bus_to["bus_type"] == 4)
push!(pm_data["connected_buses"], sub_data["f_bus"])
push!(pm_data["connected_buses"], sub_data["t_bus"])
end
end
sub_data["br_r"] = pop!(branch, "R")
sub_data["br_x"] = pop!(branch, "X")
sub_data["g_fr"] = pop!(branch, "GI")
# Evenly split the susceptance between the `from` and `to` ends
sub_data["b_fr"] = (branch["B"] / 2) + pop!(branch, "BI")
sub_data["g_to"] = pop!(branch, "GJ")
sub_data["b_to"] = (branch["B"] / 2) + pop!(branch, "BJ")
sub_data["ext"] = Dict{String, Any}(
"LEN" => pop!(branch, "LEN"),
)
if pm_data["source_version"] ∈ ("32", "33")
sub_data["rate_a"] = pop!(branch, "RATEA")
sub_data["rate_b"] = pop!(branch, "RATEB")
sub_data["rate_c"] = pop!(branch, "RATEC")
elseif pm_data["source_version"] == "35"
sub_data["rate_a"] = pop!(branch, "RATE1")
sub_data["rate_b"] = pop!(branch, "RATE2")
sub_data["rate_c"] = pop!(branch, "RATE3")
for i in 4:12
rate_key = "RATE$i"
if haskey(branch, rate_key)
sub_data["ext"][rate_key] = pop!(branch, rate_key)
end
end
else
error(
"Unsupported PSS(R)E source version: $(pm_data["source_version"])",
)
end
sub_data["tap"] = 1.0
sub_data["shift"] = 0.0
sub_data["br_status"] = pop!(branch, "ST")
sub_data["angmin"] = 0.0
sub_data["angmax"] = 0.0
sub_data["transformer"] = false
sub_data["source_id"] =
["branch", sub_data["f_bus"], sub_data["t_bus"], pop!(branch, "CKT")]
sub_data["index"] = length(pm_data["branch"]) + 1
if import_all
_import_remaining_keys!(sub_data, branch; exclude = ["B", "BI", "BJ"])
end
if sub_data["rate_a"] == 0.0
delete!(sub_data, "rate_a")
end
if sub_data["rate_b"] == 0.0
delete!(sub_data, "rate_b")
end
if sub_data["rate_c"] == 0.0
delete!(sub_data, "rate_c")
end
branch_isolated_bus_modifications!(pm_data, sub_data)
push!(pm_data["branch"], sub_data)
else
from_bus = branch["I"]
to_bus = branch["J"]
ckt = branch["CKT"]
@info "Branch $from_bus -> $to_bus with CKT=$ckt will be parsed as DiscreteControlledACBranch"
end
end
end
return
end
function branch_isolated_bus_modifications!(pm_data::Dict, branch_data::Dict)
bus_data = pm_data["bus"]
from_bus_no = branch_data["f_bus"]
to_bus_no = branch_data["t_bus"]
from_bus = bus_data[from_bus_no]
to_bus = bus_data[to_bus_no]
status_field = haskey(branch_data, "br_status") ? "br_status" : "state"
if (from_bus["bus_type"] == 4 || to_bus["bus_type"] == 4) &&
branch_data[status_field] == 1
@warn "Branch connected between buses $(from_bus_no) -> $(to_bus_no) is connected to an isolated bus. Setting branch status to 0."
branch_data[status_field] = 0
end
if from_bus["bus_type"] == 4
push!(pm_data["candidate_isolated_to_pq_buses"], from_bus_no)
end
if to_bus["bus_type"] == 4
push!(pm_data["candidate_isolated_to_pq_buses"], to_bus_no)
end
return
end
function transformer3W_isolated_bus_modifications!(pm_data::Dict, branch_data::Dict)
bus_data = pm_data["bus"]
primary_bus_number = branch_data["bus_primary"]
secondary_bus_number = branch_data["bus_secondary"]
tertiary_bus_number = branch_data["bus_tertiary"]
primary_bus = bus_data[primary_bus_number]
secondary_bus = bus_data[secondary_bus_number]
tertiary_bus = bus_data[tertiary_bus_number]
if branch_data["available"] == 1
if primary_bus["bus_type"] == 4
branch_data["available_primary"] = 0
@warn "Three winding transformer primary bus $(primary_bus_number) is isolated. Setting primary winding status to 0."
end
if secondary_bus["bus_type"] == 4
branch_data["available_secondary"] = 0
@warn "Three winding transformer secondary bus $(secondary_bus_number) is isolated. Setting secondary winding status to 0."
end
if tertiary_bus["bus_type"] == 4
branch_data["available_tertiary"] = 0
@warn "Three winding transformer tertiary bus $(tertiary_bus_number) is isolated. Setting tertiary winding status to 0."
end
if (
branch_data["available_primary"] == 0 &&
branch_data["available_secondary"] == 0 &&
branch_data["available_tertiary"] == 0
)
branch_data["available"] = 0
@warn "All three windings are unavailable. Setting overall transformer availability to 0"
end
end
if primary_bus["bus_type"] == 4
push!(pm_data["candidate_isolated_to_pq_buses"], primary_bus_number)
end
if secondary_bus["bus_type"] == 4
push!(pm_data["candidate_isolated_to_pq_buses"], secondary_bus_number)
end
if tertiary_bus["bus_type"] == 4
push!(pm_data["candidate_isolated_to_pq_buses"], tertiary_bus_number)
end
return
end
"""
_is_synch_condenser(sub_data, pm_data)
Returns `true` if the generator described by `sub_data` and `pm_data` meets the criteria for a synchronous condenser.
"""
function _is_synch_condenser(sub_data::Dict{String, Any}, pm_data::Dict{String, Any})
is_zero_pg = sub_data["pg"] == 0.0
has_q_limits = (sub_data["qmax"] != 0.0 || sub_data["qmin"] != 0.0)
has_zero_p_limits = (sub_data["pmax"] == 0.0 && sub_data["pmin"] == 0.0)
zero_control_mode = sub_data["m_control_mode"] == 0
is_pv_bus = pm_data["bus"][sub_data["gen_bus"]]["bus_type"] == 2
if is_zero_pg && has_q_limits && has_zero_p_limits && zero_control_mode
if !is_pv_bus
@warn "Generator $(sub_data["gen_bus"]) is likely a synchronous condenser but not connected to a PV bus."
end
return true
end
return false
end
function _determine_injector_status(
sub_data::Dict{String, Any},
pm_data::Dict{String, Any},
gen_bus::Int,
status_key::String,
bus_conversion_list::String,
)
# Special case for FACTS: MODE = 0 -> Unavailable, MODE = 1 -> Normal mode, MODE = 2 -> Link bypassed
if status_key == "MODE"
device_status = pop!(sub_data, status_key) != 0 ? true : false
else
device_status = pop!(sub_data, status_key) == 1 ? true : false
end
# If device is off keep it off.
if !device_status
return false
end
# If device is on check the topology and status of the bus it is connected to.
if pm_data["bus"][gen_bus]["bus_type"] == 4
gen_bus_connected = gen_bus ∈ pm_data["connected_buses"]
if gen_bus_connected && device_status
@warn "Device connected to bus $(gen_bus) is marked as available, but the bus is set isolated and not topologically isolated. Setting device status to 1 and the bus added to candidate for conversion."
push!(pm_data[bus_conversion_list], gen_bus)
pm_data["bus"][gen_bus]["bus_status"] = true
return true
elseif !gen_bus_connected && device_status
@warn "Device connected to bus $(gen_bus) is marked as available, but the bus is set isolated. Setting device status to 0."
pm_data["bus"][gen_bus]["bus_status"] = false
return false
else
error("Unrecognized generator and bus status combination.")
end
else
sub_data["gen_status"] = true
return true
end
end
"""
_psse2pm_generator!(pm_data, pti_data)
Parses PSS(R)E-style Generator data in a PowerModels-style Dict. "source_id" is
given by `["I", "ID"]` in PSS(R)E Generator specification.
"""
function _psse2pm_generator!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E Generator data into a PowerModels Dict..."
if haskey(pti_data, "GENERATOR")
pm_data["gen"] = Vector{Dict{String, Any}}(undef, length(pti_data["GENERATOR"]))
for (ix, gen) in enumerate(pti_data["GENERATOR"])
sub_data = Dict{String, Any}()
sub_data["gen_bus"] = pop!(gen, "I")
sub_data["gen_status"] =
_determine_injector_status(
gen,
pm_data,
sub_data["gen_bus"],
"STAT",
"candidate_isolated_to_pv_buses",
)
sub_data["pg"] = pop!(gen, "PG")
sub_data["qg"] = pop!(gen, "QG")
sub_data["vg"] = pop!(gen, "VS")
sub_data["mbase"] = pop!(gen, "MBASE")
sub_data["pmin"] = pop!(gen, "PB")
sub_data["pmax"] = pop!(gen, "PT")
sub_data["qmin"] = pop!(gen, "QB")
sub_data["qmax"] = pop!(gen, "QT")
sub_data["rt_source"] = pop!(gen, "RT")
sub_data["xt_source"] = pop!(gen, "XT")
sub_data["r_source"] = pop!(gen, "ZR")
sub_data["x_source"] = pop!(gen, "ZX")
sub_data["m_control_mode"] = pop!(gen, "WMOD")
if _is_synch_condenser(sub_data, pm_data)
sub_data["fuel"] = "SYNC_COND"
sub_data["type"] = "SYNC_COND"
end
if pm_data["source_version"] == "35"
sub_data["ext"] = Dict{String, Any}(
"NREG" => pop!(gen, "NREG"),
"BASLOD" => pop!(gen, "BASLOD"),
)
elseif pm_data["source_version"] ∈ ("32", "33")
sub_data["ext"] = Dict{String, Any}(
"IREG" => pop!(gen, "IREG"),
"WPF" => pop!(gen, "WPF"),
"WMOD" => sub_data["m_control_mode"],
"GTAP" => pop!(gen, "GTAP"),
"RMPCT" => pop!(gen, "RMPCT"),
)
else
error("Unsupported PSS(R)E source version: $(pm_data["source_version"])")
end
# Default Cost functions
sub_data["model"] = 2
sub_data["startup"] = 0.0
sub_data["shutdown"] = 0.0
sub_data["ncost"] = 2
sub_data["cost"] = [1.0, 0.0]
sub_data["source_id"] =
["generator", string(sub_data["gen_bus"]), pop!(gen, "ID")]
sub_data["index"] = ix
if import_all
_import_remaining_keys!(sub_data, gen)
end
pm_data["gen"][ix] = sub_data
end
else
pm_data["gen"] = Vector{Dict{String, Any}}()
end
end
function _psse2pm_area_interchange!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E AreaInterchange data into a PowerModels Dict..."
pm_data["area_interchange"] = []
if haskey(pti_data, "AREA INTERCHANGE")
for area_int in pti_data["AREA INTERCHANGE"]
sub_data = Dict{String, Any}()
sub_data["area_name"] = pop!(area_int, "ARNAME")
sub_data["area_number"] = pop!(area_int, "I")
sub_data["bus_number"] = pop!(area_int, "ISW")
sub_data["net_interchange"] = pop!(area_int, "PDES")
sub_data["tol_interchange"] = pop!(area_int, "PTOL")
sub_data["index"] = length(pm_data["area_interchange"]) + 1
if import_all
_import_remaining_keys!(sub_data, area_int)
end
push!(pm_data["area_interchange"], sub_data)
end
end
end
function _psse2pm_interarea_transfer!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E InterAreaTransfer data into a PowerModels Dict..."
pm_data["interarea_transfer"] = []
if haskey(pti_data, "INTER-AREA TRANSFER")
for interarea in pti_data["INTER-AREA TRANSFER"]
sub_data = Dict{String, Any}()
sub_data["area_from"] = pop!(interarea, "ARFROM")
sub_data["area_to"] = pop!(interarea, "ARTO")
sub_data["transfer_id"] = pop!(interarea, "TRID")
sub_data["power_transfer"] = pop!(interarea, "PTRAN")
sub_data["index"] = length(pm_data["interarea_transfer"]) + 1
if import_all
_import_remaining_keys!(sub_data, interarea)
end
push!(pm_data["interarea_transfer"], sub_data)
end
end
end
function _psse2pm_zone!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E Zone data into a PowerModels Dict..."
pm_data["zone"] = []
if haskey(pti_data, "ZONE")
for zone in pti_data["ZONE"]
sub_data = Dict{String, Any}()
sub_data["zone_number"] = pop!(zone, "I")
sub_data["zone_name"] = pop!(zone, "ZONAME")
sub_data["index"] = length(pm_data["zone"]) + 1
if import_all
_import_remaining_keys!(sub_data, zone)
end
push!(pm_data["zone"], sub_data)
end
end
end
"""
_psse2pm_bus!(pm_data, pti_data)
Parses PSS(R)E-style Bus data into a PowerModels-style Dict. "source_id" is given
by ["I", "NAME"] in PSS(R)E Bus specification.
"""
function _psse2pm_bus!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E Bus data into a PowerModels Dict..."
pm_data["has_isolated_type_buses"] = false
pm_data["bus"] = Dict{Int, Any}()
if haskey(pti_data, "BUS")
for bus in pti_data["BUS"]
sub_data = Dict{String, Any}()
sub_data["bus_i"] = bus["I"]
sub_data["bus_type"] = pop!(bus, "IDE")
if sub_data["bus_type"] == 4
@warn "The PSS(R)E data contains buses designated as isolated. The parser will check if the buses are connected or topologically isolated."
pm_data["has_isolated_type_buses"] = true
sub_data["bus_status"] = false
pm_data["connected_buses"] = Set{Int}()
pm_data["candidate_isolated_to_pq_buses"] = Set{Int}()
pm_data["candidate_isolated_to_pv_buses"] = Set{Int}()
else
sub_data["bus_status"] = true
end
sub_data["area"] = pop!(bus, "AREA")
sub_data["vm"] = pop!(bus, "VM")
sub_data["va"] = pop!(bus, "VA")
sub_data["base_kv"] = pop!(bus, "BASKV")
sub_data["zone"] = pop!(bus, "ZONE")
sub_data["name"] = pop!(bus, "NAME")
sub_data["vmax"] = pop!(bus, "NVHI")
sub_data["vmin"] = pop!(bus, "NVLO")
sub_data["hidden"] = false
sub_data["source_id"] = ["bus", "$(bus["I"])"]
sub_data["index"] = pop!(bus, "I")
if import_all
_import_remaining_keys!(sub_data, bus)
end
if haskey(pm_data["bus"], sub_data["bus_i"])
error("Repeated $(sub_data["bus_i"])")
end
pm_data["bus"][sub_data["bus_i"]] = sub_data
end
end
return
end
"""
_psse2pm_load!(pm_data, pti_data)
Parses PSS(R)E-style Load data into a PowerModels-style Dict. "source_id" is given
by `["I", "ID"]` in the PSS(R)E Load specification.
"""
function _psse2pm_load!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E Load data into a PowerModels Dict..."
pm_data["load"] = []
if haskey(pti_data, "LOAD")
for load in pti_data["LOAD"]
sub_data = Dict{String, Any}()
sub_data["load_bus"] = pop!(load, "I")
sub_data["pd"] = pop!(load, "PL")
sub_data["qd"] = pop!(load, "QL")
sub_data["pi"] = pop!(load, "IP")
sub_data["qi"] = pop!(load, "IQ")
sub_data["py"] = pop!(load, "YP")
# Reactive power component of constant Y load.
# Positive for an inductive load (consumes Q)
# Negative for a capacitive load (injects Q)
sub_data["qy"] = -pop!(load, "YQ")
sub_data["conformity"] = pop!(load, "SCALE")
sub_data["source_id"] = ["load", sub_data["load_bus"], pop!(load, "ID")]
sub_data["interruptible"] = pop!(load, "INTRPT")
sub_data["ext"] = Dict{String, Any}()
if pm_data["source_version"] ∈ ("32", "33")
sub_data["ext"]["LOADTYPE"] = ""
elseif pm_data["source_version"] == "35"
sub_data["ext"]["LOADTYPE"] = pop!(load, "LOADTYPE", "")
else
error("Unsupported PSS(R)E source version: $(pm_data["source_version"])")
end
sub_data["status"] =
_determine_injector_status(
load,
pm_data,
sub_data["load_bus"],
"STATUS",
"candidate_isolated_to_pq_buses",
)
sub_data["index"] = length(pm_data["load"]) + 1
if import_all
_import_remaining_keys!(sub_data, load)
end
push!(pm_data["load"], sub_data)
end
end
end
"""
_psse2pm_shunt!(pm_data, pti_data)
Parses PSS(R)E-style Fixed and Switched Shunt data into a PowerModels-style
Dict. "source_id" is given by `["I", "ID"]` for Fixed Shunts, and `["I", "SWREM"]`
for Switched Shunts, as given by the PSS(R)E Fixed and Switched Shunts
specifications.
"""
function _psse2pm_shunt!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E Fixed & Switched Shunt data into a PowerModels Dict..."
pm_data["shunt"] = []
if haskey(pti_data, "FIXED SHUNT")
for shunt in pti_data["FIXED SHUNT"]
sub_data = Dict{String, Any}()
sub_data["shunt_bus"] = pop!(shunt, "I")
sub_data["gs"] = pop!(shunt, "GL")
sub_data["bs"] = pop!(shunt, "BL")
sub_data["status"] = _determine_injector_status(
shunt,
pm_data,
sub_data["shunt_bus"],
"STATUS",
"candidate_isolated_to_pq_buses",
)
sub_data["source_id"] =
["fixed shunt", sub_data["shunt_bus"], pop!(shunt, "ID")]
sub_data["index"] = length(pm_data["shunt"]) + 1
if import_all
_import_remaining_keys!(sub_data, shunt)
end
push!(pm_data["shunt"], sub_data)
end
end
pm_data["switched_shunt"] = []
if haskey(pti_data, "SWITCHED SHUNT")
for switched_shunt in pti_data["SWITCHED SHUNT"]
sub_data = Dict{String, Any}()
sub_data["shunt_bus"] = pop!(switched_shunt, "I")
sub_data["gs"] = 0.0
sub_data["bs"] = pop!(switched_shunt, "BINIT")
sub_data["status"] = _determine_injector_status(
switched_shunt,
pm_data,
sub_data["shunt_bus"],
"STAT",
"candidate_isolated_to_pq_buses",
)
sub_data["admittance_limits"] =
(pop!(switched_shunt, "VSWLO"), pop!(switched_shunt, "VSWHI"))
step_numbers = Dict(
k => v for
(k, v) in switched_shunt if startswith(k, "N") && isdigit(last(k))
)
step_numbers_sorted =
sort(collect(keys(step_numbers)); by = x -> parse(Int, x[2:end]))
sub_data["step_number"] = [step_numbers[k] for k in step_numbers_sorted]
sub_data["step_number"] = sub_data["step_number"][sub_data["step_number"] .!= 0]
sub_data["ext"] = Dict{String, Any}(
"MODSW" => switched_shunt["MODSW"],
"ADJM" => switched_shunt["ADJM"],
"RMPCT" => switched_shunt["RMPCT"],
"RMIDNT" => switched_shunt["RMIDNT"],
)
y_increment = Dict(
k => v for
(k, v) in switched_shunt if startswith(k, "B") && isdigit(last(k))
)
y_increment_sorted =
sort(collect(keys(y_increment)); by = x -> parse(Int, x[2:end]))
sub_data["y_increment"] = [y_increment[k] for k in y_increment_sorted]im
sub_data["y_increment"] = sub_data["y_increment"][sub_data["y_increment"] .!= 0]
if pm_data["source_version"] == "35"
sub_data["sw_id"] = pop!(switched_shunt, "ID")
initial_ss_status = Dict(
k => v for
(k, v) in switched_shunt if startswith(k, "S") && isdigit(last(k))
)
initial_ss_status_sorted =
sort(collect(keys(initial_ss_status)); by = x -> parse(Int, x[2:end]))
sub_data["initial_status"] =
[initial_ss_status[k] for k in initial_ss_status_sorted]
sub_data["initial_status"] =
sub_data["initial_status"][1:length(sub_data["step_number"])]
sub_data["ext"]["NREG"] = pop!(switched_shunt, "NREG")
elseif pm_data["source_version"] ∈ ("32", "33")
sub_data["ext"]["SWREM"] = switched_shunt["SWREM"]
sub_data["initial_status"] = ones(Int, length(sub_data["y_increment"]))
else
error("Unsupported PSS(R)E source version: $(pm_data["source_version"])")
end
sub_data["index"] = length(pm_data["switched_shunt"]) + 1
sub_data["source_id"] =
["switched shunt", sub_data["shunt_bus"], sub_data["index"]]
if import_all
_import_remaining_keys!(sub_data, switched_shunt)
end
push!(pm_data["switched_shunt"], sub_data)
end
end
end
function apply_tap_correction!(
windv_value::Float64,
transformer::Dict{String, Any},
cod_key::String,
rmi_key::String,
rma_key::String,
ntp_key::String,
cw_value::Int64,
winding_name::String,
)
if abs(transformer[cod_key]) ∈ [1, 2] && cw_value ∈ [1, 2, 3]
tap_positions = collect(
range(
transformer[rmi_key],
transformer[rma_key];
length = Int(transformer[ntp_key]),
),
)
closest_tap_ix = argmin(abs.(tap_positions .- windv_value))
if !isapprox(
windv_value,
tap_positions[closest_tap_ix];
atol = PARSER_TAP_RATIO_CORRECTION_TOL,
)
@warn "Transformer $winding_name winding tap setting is not on a step; $windv_value set to $(tap_positions[closest_tap_ix])"
return tap_positions[closest_tap_ix]
end
end
return windv_value
end
# Base Power has a different key in sub_data depending on the number of windings
function _transformer_mag_pu_conversion(
transformer::Dict,
sub_data::Dict,
base_power::Float64,
)
if isapprox(transformer["MAG1"], ZERO_IMPEDANCE_REACTANCE_THRESHOLD) &&
isapprox(transformer["MAG2"], ZERO_IMPEDANCE_REACTANCE_THRESHOLD)
@warn "Transformer $(sub_data["f_bus"]) -> $(sub_data["t_bus"]) has zero MAG1 and MAG2 values."
return 0.0, 0.0
else
G_pu = 1e-6 * transformer["MAG1"] / base_power
mag_diff = transformer["MAG2"]^2 - G_pu^2
@assert mag_diff >= -ZERO_IMPEDANCE_REACTANCE_THRESHOLD
B_pu = sqrt(max(0.0, mag_diff))
return G_pu, B_pu
end
end
"""
_psse2pm_transformer!(pm_data, pti_data)
Parses PSS(R)E-style Transformer data into a PowerModels-style Dict. "source_id"
is given by `["I", "J", "K", "CKT", "winding"]`, where "winding" is 0 if
transformer is two-winding, and 1, 2, or 3 for three-winding, and the remaining
keys are defined in the PSS(R)E Transformer specification.
"""
function _psse2pm_transformer!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E Transformer data into a PowerModels Dict..."
if !haskey(pm_data, "branch")
pm_data["branch"] = []
end
if haskey(pti_data, "TRANSFORMER")
starbus_id = 10^ceil(Int, log10(abs(_find_max_bus_id(pm_data)))) + 1
for transformer in pti_data["TRANSFORMER"]
if !(transformer["CZ"] in [1, 2, 3])
@warn(
"transformer CZ value outside of valid bounds assuming the default value of 1. Given $(transformer["CZ"]), should be 1, 2 or 3",
)
transformer["CZ"] = 1
end
if !(transformer["CW"] in [1, 2, 3])
@warn(
"transformer CW value outside of valid bounds assuming the default value of 1. Given $(transformer["CW"]), should be 1, 2 or 3",
)
transformer["CW"] = 1
end
if !(transformer["CM"] in [1, 2])
@warn(
"transformer CM value outside of valid bounds assuming the default value of 1. Given $(transformer["CM"]), should be 1 or 2",
)
transformer["CM"] = 1
end
if transformer["K"] == 0 # Two-winding Transformers
sub_data = Dict{String, Any}()
sub_data["f_bus"] = transformer["I"]
sub_data["t_bus"] = transformer["J"]
if pm_data["has_isolated_type_buses"]
bus_from = pm_data["bus"][sub_data["f_bus"]]
bus_to = pm_data["bus"][sub_data["t_bus"]]
if !(bus_from["bus_type"] == 4 || bus_to["bus_type"] == 4)
push!(pm_data["connected_buses"], sub_data["f_bus"])
push!(pm_data["connected_buses"], sub_data["t_bus"])
end
end
# Store base_power
if transformer["SBASE1-2"] < 0.0
throw(
IS.InvalidValue(
"Transformer $(sub_data["f_bus"]) -> $(sub_data["t_bus"]) has non-positive base power SBASE1-2: $(transformer["SBASE1-2"])",
),
)
end
if iszero(transformer["SBASE1-2"])
sub_data["base_power"] = pm_data["baseMVA"]
else
sub_data["base_power"] = transformer["SBASE1-2"]
end
if iszero(transformer["NOMV1"])
sub_data["base_voltage_from"] =
_get_bus_value(transformer["I"], "base_kv", pm_data)
else
sub_data["base_voltage_from"] = transformer["NOMV1"]
end
if iszero(transformer["NOMV2"])
sub_data["base_voltage_to"] =
_get_bus_value(transformer["J"], "base_kv", pm_data)
else
sub_data["base_voltage_to"] = transformer["NOMV2"]
end
# Unit Transformations
# Data must be stored in the DEVICE_BASE
# Z_base_device = (V_device)^2 / S_device, Z_base_sys = (V_device)^2 / S_sys
# Z_ohms = Z_pu_sys * Z_base_sys, Z_pu_device = Z_ohms / Z_device = Z_pu_sys * S_device / S_sys
mva_ratio = sub_data["base_power"] / pm_data["baseMVA"]
Z_base_device = sub_data["base_voltage_from"]^2 / sub_data["base_power"]
Z_base_sys = sub_data["base_voltage_from"]^2 / pm_data["baseMVA"]
#_get_bus_value(transformer["I"], "base_kv", pm_data)^2 /
#pm_data["baseMVA"]
if transformer["CZ"] == 2 # "for resistance and reactance in pu on system MVA base and winding voltage base"
# Compute br_r and br_x in pu of device base
br_r, br_x = transformer["R1-2"], transformer["X1-2"]
else # NOT "for resistance and reactance in pu on system MVA base and winding voltage base"
if transformer["CZ"] == 3 # "for transformer load loss in watts and impedance magnitude in pu on a specified MVA base and winding voltage base."
br_r = 1e-6 * transformer["R1-2"] / sub_data["base_power"] # device pu
br_x = sqrt(transformer["X1-2"]^2 - br_r^2) # device pu
else # "CZ" = 1 in system base pu
@assert transformer["CZ"] == 1
br_r, br_x = transformer["R1-2"], transformer["X1-2"] # sys pu
if iszero(Z_base_device) # NOMV1 = 0.0: use the power ratios
br_r = transformer["R1-2"] * mva_ratio
br_x = transformer["X1-2"] * mva_ratio
else # NOMV1 could potentially be different than the bus_voltage, use impedance ratios
br_r = (transformer["R1-2"] * Z_base_sys) / Z_base_device
br_x = (transformer["X1-2"] * Z_base_sys) / Z_base_device
end
end
end
# Zeq scaling for tap2 (see eq (4.21b) in PROGRAM APPLICATION GUIDE 1 in PSSE installation folder)
# Unit Transformations
if transformer["CW"] == 1 # "for off-nominal turns ratio in pu of winding bus base voltage"
br_r *= transformer["WINDV2"]^2
br_x *= transformer["WINDV2"]^2
# NOT "for off-nominal turns ratio in pu of winding bus base voltage"
elseif transformer["CW"] == 2 # "for winding voltage in kV"
br_r *=
(
transformer["WINDV2"] /
_get_bus_value(transformer["J"], "base_kv", pm_data)
)^2
br_x *=
(
transformer["WINDV2"] /
_get_bus_value(transformer["J"], "base_kv", pm_data)
)^2
elseif transformer["CW"] == 3 # "for off-nominal turns ratio in pu of nominal winding voltage, NOMV1, NOMV2 and NOMV3."
#The nominal (rated) Winding 2 voltage base in kV, or zero to indicate
# that nominal Winding 2 voltage is assumed to be identical to the base
# voltage of bus J. NOMV2 is used in converting tap ratio data between values
# in per unit of nominal Winding 2 voltage and values in per unit of Winding 2
#bus base voltage when CW is 3. NOMV2 = 0.0 by default.
if iszero(transformer["NOMV2"])
nominal_voltage_ratio = 1.0
else
nominal_voltage_ratio =
transformer["NOMV2"] /
_get_bus_value(transformer["J"], "base_kv", pm_data)
end
br_r *= (transformer["WINDV2"] * (nominal_voltage_ratio))^2
br_x *= (transformer["WINDV2"] * (nominal_voltage_ratio))^2
else
error("invalid transformer $(transformer["CW"])")
end
if transformer["X1-2"] < 0.0 && br_x < 0.0
@warn "Transformer $(sub_data["f_bus"]) -> $(sub_data["t_bus"]) has negative impedance values X1-2: $(transformer["X1-2"]), br_x: $(br_x)"
end
sub_data["br_r"] = br_r
sub_data["br_x"] = br_x
if transformer["CM"] == 1
# Transform admittance to device per unit
mva_ratio_12 = sub_data["base_power"] / pm_data["baseMVA"]
sub_data["g_fr"] = transformer["MAG1"] / mva_ratio_12
sub_data["b_fr"] = transformer["MAG2"] / mva_ratio_12
else # CM=2: MAG1 are no load loss in Watts and MAG2 is the exciting current in pu, in device base.
@assert transformer["CM"] == 2
G_pu, B_pu = _transformer_mag_pu_conversion(
transformer,
sub_data,
sub_data["base_power"],
)
sub_data["g_fr"] = G_pu
sub_data["b_fr"] = B_pu
end
sub_data["g_to"] = 0.0
sub_data["b_to"] = 0.0
sub_data["ext"] = Dict{String, Any}(
"psse_name" => transformer["NAME"],
"CW" => transformer["CW"],
"CZ" => transformer["CZ"],
"CM" => transformer["CM"],
"COD1" => transformer["COD1"],
"CONT1" => transformer["CONT1"],
"NOMV1" => transformer["NOMV1"],
"NOMV2" => transformer["NOMV2"],
"WINDV1" => transformer["WINDV1"],
"WINDV2" => transformer["WINDV2"],
"SBASE1-2" => transformer["SBASE1-2"],
"RMI1" => transformer["RMI1"],
"RMA1" => transformer["RMA1"],
"NTP1" => transformer["NTP1"],
"R1-2" => transformer["R1-2"],
"X1-2" => transformer["X1-2"],
"MAG1" => transformer["MAG1"],
"MAG2" => transformer["MAG2"],
)
if pm_data["source_version"] ∈ ("32", "33")
sub_data["rate_a"] = pop!(transformer, "RATA1")
sub_data["rate_b"] = pop!(transformer, "RATB1")
sub_data["rate_c"] = pop!(transformer, "RATC1")
elseif pm_data["source_version"] == "35"
sub_data["rate_a"] = pop!(transformer, "RATE11")
sub_data["rate_b"] = pop!(transformer, "RATE12")
sub_data["rate_c"] = pop!(transformer, "RATE13")
for i in 4:12
rate_key = "RATE1$i"
if haskey(transformer, rate_key)
sub_data["ext"][rate_key] = pop!(transformer, rate_key)
end
end
else
error(
"Unsupported PSS(R)E source version: $(pm_data["source_version"])",
)
end
if sub_data["rate_a"] == 0.0
delete!(sub_data, "rate_a")
end
if sub_data["rate_b"] == 0.0
delete!(sub_data, "rate_b")
end
if sub_data["rate_c"] == 0.0
delete!(sub_data, "rate_c")
end
if import_all
sub_data["windv1"] = transformer["WINDV1"]
sub_data["windv2"] = transformer["WINDV2"]
sub_data["nomv1"] = transformer["NOMV1"]
sub_data["nomv2"] = transformer["NOMV2"]
end
windv1 = pop!(transformer, "WINDV1")
windv1 = apply_tap_correction!(
windv1,
transformer,
"COD1",
"RMI1",
"RMA1",
"NTP1",
transformer["CW"],
"primary",
)
sub_data["tap"] = windv1 / pop!(transformer, "WINDV2")
sub_data["shift"] = pop!(transformer, "ANG1")
if transformer["CW"] != 1 # NOT "for off-nominal turns ratio in pu of winding bus base voltage"
sub_data["tap"] *=
_get_bus_value(transformer["J"], "base_kv", pm_data) /
_get_bus_value(transformer["I"], "base_kv", pm_data)
if transformer["CW"] == 3 # "for off-nominal turns ratio in pu of nominal winding voltage, NOMV1, NOMV2 and NOMV3."
if iszero(transformer["NOMV1"])
winding1_nominal_voltage =
_get_bus_value(transformer["I"], "base_kv", pm_data)
else
winding1_nominal_voltage = transformer["NOMV1"]
end
if iszero(transformer["NOMV2"])
winding2_nominal_voltage =
_get_bus_value(transformer["J"], "base_kv", pm_data)
else
winding2_nominal_voltage = transformer["NOMV2"]
end
sub_data["tap"] *=
winding1_nominal_voltage / winding2_nominal_voltage
end
end
if import_all
sub_data["cw"] = transformer["CW"]
end
if transformer["STAT"] == 0 || transformer["STAT"] == 2
sub_data["br_status"] = 0
else
sub_data["br_status"] = 1
end
sub_data["angmin"] = 0.0
sub_data["angmax"] = 0.0
sub_data["source_id"] = [
"transformer",
pop!(transformer, "I"),
pop!(transformer, "J"),
pop!(transformer, "K"),
pop!(transformer, "CKT"),
0,
]
sub_data["transformer"] = true
sub_data["correction_table"] = transformer["TAB1"]
sub_data["index"] = length(pm_data["branch"]) + 1
sub_data["COD1"] = transformer["COD1"]
if import_all
_import_remaining_keys!(
sub_data,
transformer;
exclude = [
"I",
"J",
"K",
"CZ",
"CW",
"R1-2",
"R2-3",
"R3-1",
"X1-2",
"X2-3",
"X3-1",
"SBASE1-2",
"SBASE2-3",
"SBASE3-1",
"MAG1",
"MAG2",
"STAT",
"NOMV1",
"NOMV2",
],
)
end
branch_isolated_bus_modifications!(pm_data, sub_data)
push!(pm_data["branch"], sub_data)
else # Three-winding Transformers
# Create 3w-transformer key
if !haskey(pm_data, "3w_transformer")
pm_data["3w_transformer"] = []
end
bus_id1, bus_id2, bus_id3 =
transformer["I"], transformer["J"], transformer["K"]
# Creates a starbus (or "dummy" bus) to which each winding of the transformer will connect
starbus = _create_starbus_from_transformer(pm_data, transformer, starbus_id)
pm_data["bus"][starbus_id] = starbus
if pm_data["has_isolated_type_buses"]
bus_primary = pm_data["bus"][bus_id1]
bus_secondary = pm_data["bus"][bus_id2]
bus_tertiary = pm_data["bus"][bus_id3]
push!(pm_data["connected_buses"], starbus_id) # Starbus should never be converted to isolated
# If one bus winding is isolated, the other two buses should still be considered connected:
!(bus_primary["bus_type"] == 4) &&
push!(pm_data["connected_buses"], bus_id1)
!(bus_secondary["bus_type"] == 4) &&
push!(pm_data["connected_buses"], bus_id2)
!(bus_tertiary["bus_type"] == 4) &&
push!(pm_data["connected_buses"], bus_id3)
end
# Add parameters to the 3w-transformer key
sub_data = Dict{String, Any}()
bases = [
transformer["SBASE1-2"],
transformer["SBASE2-3"],
transformer["SBASE3-1"],
]
base_names = [
"base_power_12",
"base_power_23",
"base_power_13",
]
for (ix, base) in enumerate(bases)
if base < 0.0
throw(
IS.InvalidValue(
"Transformer $(transformer[I]) -> $(transformer["J"]) -> $(transformer["K"]) has negative base power $base",
),
)
end
if iszero(base)
sub_data[base_names[ix]] = pm_data["baseMVA"]
else
sub_data[base_names[ix]] = base
end
end
if iszero(transformer["NOMV1"])
sub_data["base_voltage_primary"] =
_get_bus_value(transformer["I"], "base_kv", pm_data)
else
sub_data["base_voltage_primary"] = transformer["NOMV1"]
end
if iszero(transformer["NOMV2"])
sub_data["base_voltage_secondary"] =
_get_bus_value(transformer["J"], "base_kv", pm_data)
else
sub_data["base_voltage_secondary"] = transformer["NOMV2"]
end
if iszero(transformer["NOMV3"])
sub_data["base_voltage_tertiary"] =
_get_bus_value(transformer["K"], "base_kv", pm_data)
else
sub_data["base_voltage_tertiary"] = transformer["NOMV3"]
end
mva_ratio_12 = sub_data["base_power_12"] / pm_data["baseMVA"]
mva_ratio_23 = sub_data["base_power_23"] / pm_data["baseMVA"]
mva_ratio_31 = sub_data["base_power_13"] / pm_data["baseMVA"]
Z_base_device_1 = transformer["NOMV1"]^2 / sub_data["base_power_12"]
Z_base_device_2 = transformer["NOMV2"]^2 / sub_data["base_power_23"]
Z_base_device_3 = transformer["NOMV3"]^2 / sub_data["base_power_13"]
Z_base_sys_1 = (sub_data["base_voltage_primary"])^2 / pm_data["baseMVA"]
Z_base_sys_2 =
(sub_data["base_voltage_secondary"])^2 / pm_data["baseMVA"]
Z_base_sys_3 =
(sub_data["base_voltage_tertiary"])^2 / pm_data["baseMVA"]
# Create 3 branches from a three winding transformer (one for each winding, which will each connect to the starbus)
br_r12, br_r23, br_r31 =
transformer["R1-2"], transformer["R2-3"], transformer["R3-1"]
br_x12, br_x23, br_x31 =
transformer["X1-2"], transformer["X2-3"], transformer["X3-1"]
# Unit Transformations
if transformer["CZ"] == 3 # "for transformer load loss in watts and impedance magnitude in pu on a specified MVA base and winding voltage base."
# In device base
br_r12 *= 1e-6 / sub_data["base_power_12"]
br_r23 *= 1e-6 / sub_data["base_power_23"]
br_r31 *= 1e-6 / sub_data["base_power_13"]
br_x12 = sqrt(br_x12^2 - br_r12^2)
br_x23 = sqrt(br_x23^2 - br_r23^2)
br_x31 = sqrt(br_x31^2 - br_r31^2)
# Unit Transformations
elseif transformer["CZ"] == 1 # "for resistance and reactance in pu on system MVA base (transform to device base)"
if iszero(Z_base_device_1) # NOMV1 = 0.0: use the power ratios
br_r12 *= mva_ratio_12
br_x12 *= mva_ratio_12
else # NOMV1 could potentially be different than the bus_voltage, use impedance ratios
br_r12 *= Z_base_sys_1 / Z_base_device_1
br_x12 *= Z_base_sys_1 / Z_base_device_1
end
if iszero(Z_base_device_2) # NOMV2 = 0.0: use the power ratios
br_r23 *= mva_ratio_23
br_x23 *= mva_ratio_23
else # NOMV2 could potentially be different than the bus_voltage, use impedance ratios
br_r23 *= Z_base_sys_2 / Z_base_device_2
br_x23 *= Z_base_sys_2 / Z_base_device_2
end
if iszero(Z_base_device_3) # NOMV3 = 0.0: use the power ratios
br_r31 *= mva_ratio_31
br_x31 *= mva_ratio_31
else # NOMV3 could potentially be different than the bus_voltage, use impedance ratios
br_r31 *= Z_base_sys_3 / Z_base_device_3
br_x31 *= Z_base_sys_3 / Z_base_device_3
end
end
# Compute primary,secondary, tertiary impedances in system base, then convert to base power of appropriate winding
if iszero(Z_base_device_1)
br_r12_sysbase = br_r12 / mva_ratio_12
br_x12_sysbase = br_x12 / mva_ratio_12
else
br_r12_sysbase = br_r12 * (Z_base_device_1 / Z_base_sys_1)
br_x12_sysbase = br_x12 * (Z_base_device_1 / Z_base_sys_1)
end
if iszero(Z_base_device_2)
br_r23_sysbase = br_r23 / mva_ratio_23
br_x23_sysbase = br_x23 / mva_ratio_23
else
br_r23_sysbase = br_r23 * (Z_base_device_2 / Z_base_sys_2)
br_x23_sysbase = br_x23 * (Z_base_device_2 / Z_base_sys_2)
end
if iszero(Z_base_device_3)
br_r31_sysbase = br_r31 / mva_ratio_31
br_x31_sysbase = br_x31 / mva_ratio_31
else
br_r31_sysbase = br_r31 * (Z_base_device_3 / Z_base_sys_3)
br_x31_sysbase = br_x31 * (Z_base_device_3 / Z_base_sys_3)
end
# See "Power System Stability and Control", ISBN: 0-07-035958-X, Eq. 6.72
Zr_p = 1 / 2 * (br_r12_sysbase - br_r23_sysbase + br_r31_sysbase)
Zr_s = 1 / 2 * (br_r23_sysbase - br_r31_sysbase + br_r12_sysbase)
Zr_t = 1 / 2 * (br_r31_sysbase - br_r12_sysbase + br_r23_sysbase)
Zx_p = 1 / 2 * (br_x12_sysbase - br_x23_sysbase + br_x31_sysbase)
Zx_s = 1 / 2 * (br_x23_sysbase - br_x31_sysbase + br_x12_sysbase)
Zx_t = 1 / 2 * (br_x31_sysbase - br_x12_sysbase + br_x23_sysbase)
# See PSSE Manual (Section 1.15.1 "Three-Winding Transformer Notes" of Data Formats file)
zero_names = []
if isapprox(Zx_p, 0.0; atol = eps(Float32))
push!(zero_names, "primary")
Zx_p = ZERO_IMPEDANCE_REACTANCE_THRESHOLD
end
if isapprox(Zx_s, 0.0; atol = eps(Float32))
push!(zero_names, "secondary")
Zx_s = ZERO_IMPEDANCE_REACTANCE_THRESHOLD
end
if isapprox(Zx_t, 0.0; atol = eps(Float32))
push!(zero_names, "tertiary")
Zx_t = ZERO_IMPEDANCE_REACTANCE_THRESHOLD
end
if !isempty(zero_names)
@info "Zero impedance reactance detected in 3W Transformer $(transformer["NAME"]) for winding(s): $(join(zero_names, ", ")). Setting to threshold value $(ZERO_IMPEDANCE_REACTANCE_THRESHOLD)."
end
if iszero(Z_base_device_1)
Zr_p *= mva_ratio_12
Zx_p *= mva_ratio_12
else
Zr_p *= Z_base_sys_1 / Z_base_device_1
Zx_p *= Z_base_sys_1 / Z_base_device_1
end
if iszero(Z_base_device_2)
Zr_s *= mva_ratio_23
Zx_s *= mva_ratio_23
else
Zr_s *= Z_base_sys_2 / Z_base_device_2
Zx_s *= Z_base_sys_2 / Z_base_device_2
end
if iszero(Z_base_device_3)
Zr_t *= mva_ratio_31
Zx_t *= mva_ratio_31
else
Zr_t *= Z_base_sys_3 / Z_base_device_3
Zx_t *= Z_base_sys_3 / Z_base_device_3
end
sub_data["name"] = transformer["NAME"]
sub_data["bus_primary"] = bus_id1
sub_data["bus_secondary"] = bus_id2
sub_data["bus_tertiary"] = bus_id3
sub_data["available"] = false
if transformer["STAT"] != 0
sub_data["available"] = true
end
sub_data["available_primary"] = true
sub_data["available_secondary"] = true
sub_data["available_tertiary"] = true
if transformer["STAT"] == 2
sub_data["available_secondary"] = false
end
if transformer["STAT"] == 3
sub_data["available_tertiary"] = false
end
if transformer["STAT"] == 4
sub_data["available_primary"] = false
end
if transformer["STAT"] == 0
sub_data["available_primary"] = false
sub_data["available_secondary"] = false
sub_data["available_tertiary"] = false
end
sub_data["star_bus"] = starbus_id
sub_data["active_power_flow_primary"] = 0.0
sub_data["reactive_power_flow_primary"] = 0.0
sub_data["active_power_flow_secondary"] = 0.0
sub_data["reactive_power_flow_secondary"] = 0.0
sub_data["active_power_flow_tertiary"] = 0.0
sub_data["reactive_power_flow_tertiary"] = 0.0
sub_data["r_primary"] = Zr_p
sub_data["x_primary"] = Zx_p
sub_data["r_secondary"] = Zr_s
sub_data["x_secondary"] = Zx_s
sub_data["r_tertiary"] = Zr_t
sub_data["x_tertiary"] = Zx_t
if pm_data["source_version"] ∈ ("32", "33")
sub_data["rating_primary"] =
min(
transformer["RATA1"],
transformer["RATB1"],
transformer["RATC1"],
)
sub_data["rating_secondary"] =
min(
transformer["RATA2"],
transformer["RATB2"],
transformer["RATC2"],
)
sub_data["rating_tertiary"] =
min(
transformer["RATA3"],
transformer["RATB3"],
transformer["RATC3"],
)
sub_data["rating"] = min(
sub_data["rating_primary"],
sub_data["rating_secondary"],
sub_data["rating_tertiary"],
)
elseif pm_data["source_version"] == "35"
sub_data["rating_primary"] =
min(
transformer["RATE11"],
transformer["RATE12"],
transformer["RATE13"],
)
sub_data["rating_secondary"] =
min(
transformer["RATE21"],
transformer["RATE22"],
transformer["RATE23"],
)
sub_data["rating_tertiary"] =
min(
transformer["RATE31"],
transformer["RATE32"],
transformer["RATE33"],
)
sub_data["rating"] = min(
sub_data["rating_primary"],
sub_data["rating_secondary"],
sub_data["rating_tertiary"],
)
else
error(
"Unsupported PSS(R)E source version: $(pm_data["source_version"])",
)
end
sub_data["r_12"] = br_r12
sub_data["x_12"] = br_x12
sub_data["r_23"] = br_r23
sub_data["x_23"] = br_x23
sub_data["r_13"] = br_r31
sub_data["x_13"] = br_x31
if transformer["CM"] == 1
# Transform admittance to device per unit
mva_ratio_12 = sub_data["base_power_12"] / pm_data["baseMVA"]
sub_data["g"] = transformer["MAG1"] / mva_ratio_12
sub_data["b"] = transformer["MAG2"] / mva_ratio_12
else # CM=2: MAG1 are no load loss in Watts and MAG2 is the exciting current in pu, in device base.
@assert transformer["CM"] == 2
G_pu, B_pu = _transformer_mag_pu_conversion(
transformer,
sub_data,
sub_data["base_power_12"],
)
sub_data["g"] = G_pu
sub_data["b"] = B_pu
end
# If CM = 1 & MAG2 != 0 -> MAG2 < 0
# If CM = 2 & MAG2 != 0 -> MAG2 > 0
sub_data["primary_correction_table"] = transformer["TAB1"]
sub_data["secondary_correction_table"] = transformer["TAB2"]
sub_data["tertiary_correction_table"] = transformer["TAB3"]
sub_data["primary_phase_shift_angle"] = transformer["ANG1"] * pi / 180.0
sub_data["secondary_phase_shift_angle"] = transformer["ANG2"] * pi / 180.0
sub_data["tertiary_phase_shift_angle"] = transformer["ANG3"] * pi / 180.0
windv1 = transformer["WINDV1"]
windv2 = transformer["WINDV2"]
windv3 = transformer["WINDV3"]
windv1 = apply_tap_correction!(
windv1,
transformer,
"COD1",
"RMI1",
"RMA1",
"NTP1",
transformer["CW"],
"primary",
)
windv2 = apply_tap_correction!(
windv2,
transformer,
"COD2",
"RMI2",
"RMA2",
"NTP2",
transformer["CW"],
"secondary",
)
windv3 = apply_tap_correction!(
windv3,
transformer,
"COD3",
"RMI3",
"RMA3",
"NTP3",
transformer["CW"],
"tertiary",
)
if transformer["CW"] == 1
sub_data["primary_turns_ratio"] = windv1
sub_data["secondary_turns_ratio"] = windv2
sub_data["tertiary_turns_ratio"] = windv3
elseif transformer["CW"] == 2
sub_data["primary_turns_ratio"] =
windv1 / _get_bus_value(transformer["I"], "base_kv", pm_data)
sub_data["secondary_turns_ratio"] =
windv2 / _get_bus_value(transformer["J"], "base_kv", pm_data)
sub_data["tertiary_turns_ratio"] =
windv3 / _get_bus_value(transformer["K"], "base_kv", pm_data)
else
@assert transformer["CW"] == 3
sub_data["primary_turns_ratio"] =
windv1 * (
sub_data["base_voltage_primary"] /
_get_bus_value(transformer["I"], "base_kv", pm_data)
)
sub_data["secondary_turns_ratio"] =
windv2 * (
sub_data["base_voltage_secondary"] /
_get_bus_value(transformer["J"], "base_kv", pm_data)
)
sub_data["tertiary_turns_ratio"] =
windv3 * (
sub_data["base_voltage_tertiary"] /
_get_bus_value(transformer["K"], "base_kv", pm_data)
)
end
sub_data["circuit"] = strip(transformer["CKT"])
sub_data["COD1"] = transformer["COD1"]
sub_data["COD2"] = transformer["COD2"]
sub_data["COD3"] = transformer["COD3"]
sub_data["ext"] = Dict{String, Any}(
"psse_name" => transformer["NAME"],
"CW" => transformer["CW"],
"CZ" => transformer["CZ"],
"CM" => transformer["CM"],
"MAG1" => transformer["MAG1"],
"MAG2" => transformer["MAG2"],
"VMSTAR" => transformer["VMSTAR"],
"ANSTAR" => transformer["ANSTAR"],
)
for prefix in TRANSFORMER3W_PARAMETER_NAMES
for i in 1:length(WINDING_NAMES)
key = "$prefix$i"
if pm_data["source_version"] ∈ ("32", "33")
sub_data["ext"][key] = transformer[key]
else
continue
end
end
end
for suffix in ["1-2", "2-3", "3-1"]
sub_data["ext"]["R$suffix"] = transformer["R$suffix"]
sub_data["ext"]["X$suffix"] = transformer["X$suffix"]
end
sub_data["index"] = length(pm_data["3w_transformer"]) + 1
if import_all
_import_remaining_keys!(
sub_data,
transformer;
exclude = [
"NAME",
"STAT",
"MAG1",
"MAG2",
"WINDV1",
"WINDV2",
"WINDV3",
],
)
end
transformer3W_isolated_bus_modifications!(pm_data, sub_data)
push!(pm_data["3w_transformer"], sub_data)
starbus_id += 1 # after adding the 1st 3WT, increase the counter
end
end
end
return
end
"""
_psse2pm_dcline!(pm_data, pti_data)
Parses PSS(R)E-style Two-Terminal and VSC DC Lines data into a PowerModels
compatible Dict structure by first converting them to a simple DC Line Model.
For Two-Terminal DC lines, "source_id" is given by `["IPR", "IPI", "NAME"]` in the
PSS(R)E Two-Terminal DC specification. For Voltage Source Converters, "source_id"
is given by `["IBUS1", "IBUS2", "NAME"]`, where "IBUS1" is "IBUS" of the first
converter bus, and "IBUS2" is the "IBUS" of the second converter bus, in the
PSS(R)E Voltage Source Converter specification.
"""
function _psse2pm_dcline!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E Two-Terminal and VSC DC line data into a PowerModels Dict..."
pm_data["dcline"] = []
pm_data["vscline"] = []
baseMVA = pm_data["baseMVA"]
if haskey(pti_data, "TWO-TERMINAL DC")
for dcline in pti_data["TWO-TERMINAL DC"]
sub_data = Dict{String, Any}()
# Unit conversions?
power_demand =
if dcline["MDC"] == 1
abs(dcline["SETVL"])
elseif dcline["MDC"] == 2
abs(dcline["SETVL"] * dcline["VSCHD"] / 1000) # Amp * V
else
0
end
sub_data["transfer_setpoint"] = dcline["SETVL"]
sub_data["name"] = strip(dcline["NAME"], ['"', '\''])
sub_data["f_bus"] = dcline["IPR"]
sub_data["t_bus"] = dcline["IPI"]
if pm_data["has_isolated_type_buses"]
push!(pm_data["connected_buses"], sub_data["f_bus"])
push!(pm_data["connected_buses"], sub_data["t_bus"])
end
if dcline["MDC"] == 1
sub_data["power_mode"] = true
else
sub_data["power_mode"] = false
end
sub_data["available"] = dcline["MDC"] == 0 ? false : true
sub_data["br_status"] = sub_data["available"]
sub_data["scheduled_dc_voltage"] = dcline["VSCHD"]
rectifier_base_voltage = dcline["EBASR"]
if rectifier_base_voltage == 0
throw(
ArgumentError(
"DC line $(sub_data["name"]): Rectifier base voltage EBASER cannot be 0",
),
)
end
ZbaseR = rectifier_base_voltage^2 / baseMVA
sub_data["rectifier_bridges"] = dcline["NBR"]
sub_data["rectifier_rc"] = dcline["RCR"] / ZbaseR
sub_data["rectifier_xc"] = dcline["XCR"] / ZbaseR
sub_data["rectifier_base_voltage"] = rectifier_base_voltage
inverter_base_voltage = dcline["EBASI"]
if inverter_base_voltage == 0
throw(
ArgumentError(
"DC line $(sub_data["name"]): Inverter base voltage EBASI cannot be 0",
),
)
end
ZbaseI = inverter_base_voltage^2 / baseMVA
sub_data["inverter_bridges"] = dcline["NBI"]
sub_data["inverter_rc"] = dcline["RCI"] / ZbaseI
sub_data["inverter_xc"] = dcline["XCI"] / ZbaseI
sub_data["inverter_base_voltage"] = inverter_base_voltage
sub_data["switch_mode_voltage"] = dcline["VCMOD"]
sub_data["compounding_resistance"] = dcline["RCOMP"]
sub_data["min_compounding_voltage"] = dcline["DCVMIN"]
sub_data["rectifier_transformer_ratio"] = dcline["TRR"]
sub_data["rectifier_tap_setting"] = dcline["TAPR"]
sub_data["rectifier_tap_limits"] = (min = dcline["TMNR"], max = dcline["TMXR"])
sub_data["rectifier_tap_step"] = dcline["STPR"]
sub_data["inverter_transformer_ratio"] = dcline["TRI"]
sub_data["inverter_tap_setting"] = dcline["TAPI"]
sub_data["inverter_tap_limits"] = (min = dcline["TMNI"], max = dcline["TMXI"])
sub_data["inverter_tap_step"] = dcline["STPI"]
sub_data["loss0"] = 0.0
sub_data["loss1"] = 0.0
sub_data["pf"] = power_demand
sub_data["active_power_flow"] = sub_data["pf"]
sub_data["pt"] = power_demand
sub_data["qf"] = 0.0
sub_data["qt"] = 0.0
sub_data["vf"] = _get_bus_value(pop!(dcline, "IPR"), "vm", pm_data)
sub_data["vt"] = _get_bus_value(pop!(dcline, "IPI"), "vm", pm_data)
sub_data["pminf"] = 0.0
sub_data["pmaxf"] = dcline["SETVL"] > 0 ? power_demand : -power_demand
sub_data["pmint"] = pop!(dcline, "SETVL") > 0 ? -power_demand : power_demand
sub_data["pmaxt"] = 0.0
anmn = []
for key in ["ANMNR", "ANMNI"]
if abs(dcline[key]) <= 90.0
push!(anmn, dcline[key])
else
push!(anmn, 0)
@info("$key outside reasonable limits, setting to 0 degress")
end
end
sub_data["rectifier_delay_angle_limits"] =
(min = deg2rad(anmn[1]), max = deg2rad(dcline["ANMXR"]))
sub_data["inverter_extinction_angle_limits"] =
(min = deg2rad(anmn[2]), max = deg2rad(dcline["ANMXI"]))
sub_data["rectifier_delay_angle"] = deg2rad(anmn[1])
sub_data["inverter_extinction_angle"] = deg2rad(anmn[2])
sub_data["qmaxf"] = 0.0
sub_data["qmaxt"] = 0.0
sub_data["qminf"] =
-max(abs(sub_data["pminf"]), abs(sub_data["pmaxf"])) * cosd(anmn[1])
sub_data["qmint"] =
-max(abs(sub_data["pmint"]), abs(sub_data["pmaxt"])) * cosd(anmn[2])
sub_data["active_power_limits_from"] =
(min = sub_data["pminf"], max = sub_data["pmaxf"])
sub_data["active_power_limits_to"] =
(min = sub_data["pmint"], max = sub_data["pmaxt"])
sub_data["reactive_power_limits_from"] =
(min = sub_data["qminf"], max = sub_data["qmaxf"])
sub_data["reactive_power_limits_to"] =
(min = sub_data["qmint"], max = sub_data["qmaxt"])
sub_data["rectifier_capacitor_reactance"] = dcline["XCAPR"] / ZbaseR
sub_data["inverter_capacitor_reactance"] = dcline["XCAPI"] / ZbaseI
sub_data["r"] = dcline["RDC"] / ZbaseR
if pm_data["source_version"] ∈ ("32", "33")
sub_data["ext"] = Dict{String, Any}(
"psse_name" => dcline["NAME"],
)
elseif pm_data["source_version"] == "35"
sub_data["ext"] = Dict{String, Any}(
"NDR" => dcline["NDR"],
"NDI" => dcline["NDI"],
)
else
error("Unsupported PSS(R)E source version: $(pm_data["source_version"])")
end
sub_data["source_id"] = [
"two-terminal dc",
sub_data["f_bus"],
sub_data["t_bus"],
pop!(dcline, "NAME"),
]
sub_data["index"] = length(pm_data["dcline"]) + 1
if import_all
_import_remaining_keys!(sub_data, dcline)
end
branch_isolated_bus_modifications!(pm_data, sub_data)
push!(pm_data["dcline"], sub_data)
end
end
if haskey(pti_data, "VOLTAGE SOURCE CONVERTER")
for dcline in pti_data["VOLTAGE SOURCE CONVERTER"]
# Converter buses : is the distinction between ac and dc side meaningful?
from_bus, to_bus = dcline["CONVERTER BUSES"]
# PowerWorld conversion from PTI to matpower seems to create two
# artificial generators from a VSC, but it is not clear to me how
# the value of "pg" is determined and adds shunt to the DC-side bus.
sub_data = Dict{String, Any}()
sub_data["name"] = strip(dcline["NAME"], ['"', '\''])
# VSC intended to be one or bi-directional?
sub_data["f_bus"] = from_bus["IBUS"]
sub_data["t_bus"] = to_bus["IBUS"]
if pm_data["has_isolated_type_buses"]
push!(pm_data["connected_buses"], sub_data["f_bus"])
push!(pm_data["connected_buses"], sub_data["t_bus"])
end
sub_data["br_status"] =
if dcline["MDC"] == 0 ||
from_bus["TYPE"] == 0 ||
to_bus["TYPE"] == 0
0
else
1
end
sub_data["available"] = sub_data["br_status"] == 0 ? false : true
sub_data["dc_voltage_control_from"] = from_bus["TYPE"] == 1 ? true : false
sub_data["dc_voltage_control_to"] = to_bus["TYPE"] == 1 ? true : false
sub_data["ac_voltage_control_from"] = from_bus["MODE"] == 1 ? true : false
sub_data["ac_voltage_control_to"] = to_bus["MODE"] == 1 ? true : false
sub_data["dc_setpoint_from"] = from_bus["DCSET"]
sub_data["dc_setpoint_to"] = to_bus["DCSET"]
sub_data["ac_setpoint_from"] = from_bus["ACSET"]
sub_data["ac_setpoint_to"] = to_bus["ACSET"]
# ALOSS, MINLOSS in kW, and BLOSS in kW/A. Divide by a 1000 to transform into MW, and divide by baseMVA to normalize to per-unit.
sub_data["converter_loss_from"] = LinearCurve(
from_bus["BLOSS"] / (1000.0 * baseMVA),
(from_bus["ALOSS"] + from_bus["MINLOSS"]) / (1000.0 * baseMVA),
)
sub_data["converter_loss_to"] = LinearCurve(
to_bus["BLOSS"] / (1000.0 * baseMVA),
(to_bus["ALOSS"] + to_bus["MINLOSS"]) / (1000.0 * baseMVA),
)
sub_data["pf"] = 0.0
sub_data["pt"] = 0.0
sub_data["qf"] = 0.0
sub_data["qt"] = 0.0
sub_data["qminf"] = from_bus["MINQ"] / baseMVA
sub_data["qmaxf"] = from_bus["MAXQ"] / baseMVA
sub_data["qmint"] = to_bus["MINQ"] / baseMVA
sub_data["qmaxt"] = to_bus["MAXQ"] / baseMVA
PTI_INF = 9999.0
sub_data["rating_from"] =
from_bus["SMAX"] == 0.0 ? PTI_INF : from_bus["SMAX"] / baseMVA
sub_data["rating_to"] =
to_bus["SMAX"] == 0.0 ? PTI_INF : to_bus["SMAX"] / baseMVA
sub_data["rating"] = min(sub_data["rating_from"], sub_data["rating_to"])
sub_data["max_dc_current_from"] =
from_bus["IMAX"] == 0.0 ? PTI_INF : from_bus["IMAX"]
sub_data["max_dc_current_to"] = to_bus["IMAX"] == 0.0 ? PTI_INF : to_bus["IMAX"]
sub_data["power_factor_weighting_fraction_from"] = from_bus["PWF"]
sub_data["power_factor_weighting_fraction_to"] = to_bus["PWF"]
qmax_from = max(abs(sub_data["qminf"]), abs(sub_data["qmaxf"]))
qmax_to = max(abs(sub_data["qmint"]), abs(sub_data["qmaxt"]))
sub_data["pmaxf"] = sqrt(sub_data["rating_from"]^2 - qmax_from^2)
sub_data["pmaxt"] = sqrt(sub_data["rating_to"]^2 - qmax_to^2)
sub_data["pminf"] = -sub_data["pmaxf"]
sub_data["pmint"] = -sub_data["pmaxt"]
if sub_data["dc_voltage_control_from"] && !sub_data["dc_voltage_control_to"]
base_voltage = sub_data["dc_setpoint_from"]
flow_setpoint = sub_data["dc_setpoint_to"]
elseif !sub_data["dc_voltage_control_from"] && sub_data["dc_voltage_control_to"]
base_voltage = sub_data["dc_setpoint_to"]
flow_setpoint = -sub_data["dc_setpoint_from"]
else
error(
"At least one converter in converter $(sub_data["name"]) must set a voltage control.",
)
end
Zbase = base_voltage^2 / baseMVA
sub_data["r"] = dcline["RDC"] / Zbase
sub_data["pf"] = flow_setpoint / baseMVA
sub_data["if"] = 1000.0 * (flow_setpoint / base_voltage)
sub_data["ext"] = Dict{String, Any}(
"REMOT_FROM" => from_bus["REMOT"],
"REMOT_TO" => to_bus["REMOT"],
"RMPCT_FROM" => from_bus["RMPCT"],
"RMPCT_TO" => to_bus["RMPCT"],
"ALOSS_FROM" => from_bus["ALOSS"],
"ALOSS_TO" => to_bus["ALOSS"],
"MINLOSS_FROM" => from_bus["MINLOSS"],
"MINLOSS_TO" => to_bus["MINLOSS"],
"TYPE_FROM" => from_bus["TYPE"],
"TYPE_TO" => to_bus["TYPE"],
"MODE_FROM" => from_bus["MODE"],
"MODE_TO" => to_bus["MODE"],
"RDC" => dcline["RDC"],
)
sub_data["source_id"] =
["vsc dc", sub_data["f_bus"], sub_data["t_bus"], dcline["NAME"]]
sub_data["index"] = length(pm_data["vscline"]) + 1
if import_all
_import_remaining_keys!(sub_data, dcline)
for cb in sub_data["converter buses"]
for (k, v) in cb
cb[lowercase(k)] = v
delete!(cb, k)
end
end
end
branch_isolated_bus_modifications!(pm_data, sub_data)
push!(pm_data["vscline"], sub_data)
end
end
end
function _psse2pm_facts!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E FACTs devices data into a PowerModels Dict..."
pm_data["facts"] = []
if haskey(pti_data, "FACTS CONTROL DEVICE")
for facts in pti_data["FACTS CONTROL DEVICE"]
@info(
"""FACTs are supported via a simplification approach for terminal_bus = 0 (STATCOM operation)"""
)
sub_data = Dict{String, Any}()
sub_data["name"] = strip(facts["NAME"], ['"', '\''])
sub_data["control_mode"] = facts["MODE"]
sub_data["bus"] = facts["I"] # Sending end bus number
sub_data["tbus"] = facts["J"] # Terminal end bus number
sub_data["available"] = _determine_injector_status(
facts,
pm_data,
sub_data["bus"],
"MODE",
"candidate_isolated_to_pq_buses",
)
sub_data["voltage_setpoint"] = facts["VSET"]
sub_data["max_shunt_current"] = facts["SHMX"]
# % of MVAr required to hold voltage at sending bus
if facts["RMPCT"] < 0
@warn "% MVAr required must me positive."
end
sub_data["reactive_power_required"] = facts["RMPCT"]
sub_data["ext"] = Dict{String, Any}()
if pm_data["source_version"] == "35"
sub_data["ext"]["NREG"] = facts["NREG"]
sub_data["ext"]["MNAME"] = facts["MNAME"]
elseif pm_data["source_version"] ∈ ("32", "33")
sub_data["ext"] = Dict{String, Any}(
"J" => facts["J"],
)
else
error("Unsupported PSS(R)E source version: $(pm_data["source_version"])")
end
sub_data["source_id"] =
["facts", sub_data["bus"], sub_data["name"]]
sub_data["index"] = length(pm_data["facts"]) + 1
if import_all
_import_remaining_keys!(sub_data, facts)
end
push!(pm_data["facts"], sub_data)
end
end
return
end
function _build_switch_breaker_sub_data(
pm_data::Dict,
dict_object::Dict,
device_type::String,
discrete_device_type::Int,
index::Int,
)
sub_data = Dict{String, Any}()
sub_data["f_bus"] = pop!(dict_object, "I")
sub_data["t_bus"] = pop!(dict_object, "J")
if pm_data["has_isolated_type_buses"]
push!(pm_data["connected_buses"], sub_data["f_bus"])
push!(pm_data["connected_buses"], sub_data["t_bus"])
end
sub_data["x"] = pop!(dict_object, "X")
sub_data["active_power_flow"] = 0.0
sub_data["reactive_power_flow"] = 0.0
sub_data["psw"] = sub_data["active_power_flow"]
sub_data["qsw"] = sub_data["reactive_power_flow"]
sub_data["discrete_branch_type"] = discrete_device_type
sub_data["ext"] = Dict{String, Any}()
if haskey(dict_object, "STAT")
sub_data["state"] = pop!(dict_object, "STAT")
elseif haskey(dict_object, "ST")
sub_data["state"] = pop!(dict_object, "ST")
else
@warn "No STAT or ST field found in the data for switch/breaker. Assuming it is off."
sub_data["state"] = 0.0
end
if pm_data["source_version"] == ("35")
sub_data["r"] = 0.0
sub_data["rating"] = pop!(dict_object, "RATE1")
for i in 2:12
rate_key = "RATE$i"
if haskey(dict_object, rate_key)
sub_data["ext"][rate_key] = pop!(dict_object, rate_key)
end
end
else
sub_data["r"] = pop!(dict_object, "R")
sub_data["rating"] = pop!(dict_object, "RATEA")
end
sub_data["source_id"] =
[device_type, sub_data["f_bus"], sub_data["t_bus"], dict_object["CKT"]]
sub_data["index"] = index
return sub_data
end
function _psse2pm_switch_breaker!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E Switches & Breakers data into a PowerModels Dict..."
pm_data["breaker"] = []
pm_data["switch"] = []
mapping = Dict('@' => ("breaker", 1), '*' => ("switch", 0))
# PSS(R)E v35 STYPE values:
# 1 - Generic connector, 2 - Circuit breaker, 3 - Disconnect switch.
# Generic connectors are stored in the "switch" list and distinguished via
# discrete_branch_type = OTHER (2).
mapping_v35 = Dict(
1 => ("switch", 2),
2 => ("breaker", 1),
3 => ("switch", 0),
)
# Always check for legacy entries in PSSe 35 for switches and breakers set as @ or *
if haskey(pti_data, "SWITCHES_AS_BRANCHES")
for branch in pti_data["SWITCHES_AS_BRANCHES"]
branch_init = first(branch["CKT"])
# Check if character is in the mapping
if haskey(mapping, branch_init)
branch_type, discrete_branch_type = mapping[branch_init]
sub_data = _build_switch_breaker_sub_data(
pm_data,
branch,
branch_type,
discrete_branch_type,
length(pm_data[branch_type]) + 1,
)
if import_all
_import_remaining_keys!(sub_data, branch)
end
branch_isolated_bus_modifications!(pm_data, sub_data)
push!(pm_data[branch_type], sub_data)
end
end
end
if haskey(pti_data, "SWITCHING DEVICE")
if pm_data["source_version"] == "35"
for switching_device in pti_data["SWITCHING DEVICE"]
stype = get(switching_device, "STYPE", nothing)
type_mapping = get(mapping_v35, stype, nothing)
if isnothing(type_mapping)
@warn "Unsupported SWITCHING DEVICE STYPE=$(stype). Skipping entry."
continue
end
device_type, discrete_branch_type = type_mapping
sub_data = _build_switch_breaker_sub_data(
pm_data,
switching_device,
device_type,
discrete_branch_type,
length(pm_data[device_type]) + 1,
)
if import_all
_import_remaining_keys!(sub_data, switching_device)
end
branch_isolated_bus_modifications!(pm_data, sub_data)
push!(pm_data[device_type], sub_data)
end
else
error("Unsupported PSS(R)E source version: $(pm_data["source_version"])")
end
end
return
end
function _psse2pm_multisection_line!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Adding PSS(R)E Multi-section Lines data into the branches PowerModels Dict..."
branch_lookup = Dict{Tuple{Int, Int}, Int}()
if haskey(pm_data, "branch")
for branch in pm_data["branch"]
branch_lookup[(branch["f_bus"], branch["t_bus"])] = branch["index"]
end
end
if haskey(pti_data, "MULTI-SECTION LINE")
for multisec_line in pti_data["MULTI-SECTION LINE"]
filter!(x -> x.second != "", multisec_line)
f_bus = multisec_line["I"]
t_bus = multisec_line["J"]
id = filter(isdigit, multisec_line["ID"])
# Sort by dummy bus index
dummy_buses = sort([
(k, v) for (k, v) in multisec_line if startswith(k, "DUM") && v != ""
])
dummy_bus_numbers = [x[2] for x in dummy_buses]
all_buses = [f_bus; dummy_bus_numbers; t_bus]
for ix in 1:(length(all_buses) - 1)
branch_index = nothing
if haskey(branch_lookup, (all_buses[ix], all_buses[ix + 1]))
branch_index = branch_lookup[(all_buses[ix], all_buses[ix + 1])]
elseif haskey(branch_lookup, (all_buses[ix + 1], all_buses[ix]))
branch_index = branch_lookup[(all_buses[ix + 1], all_buses[ix])]
else
@warn "Branch between buses $(all_buses[ix]) and $(all_buses[ix + 1]) not found in branch data. Skipping segment."
continue
end
# Proceed if a valid branch is found
if branch_index !== nothing
ext = get(pm_data["branch"][branch_index], "ext", Dict{String, Any}())
ext["from_multisection"] = true
ext["multisection_psse_entry"] = multisec_line
pm_data["branch"][branch_index]["ext"] = ext
end
end
end
end
return
end
function sort_values_by_key_prefix(imp_correction::Dict{String, <:Any}, prefix::String)
sorted_values = [
last(pair) for pair in sort(
[
(parse(Int, k[2:end]), v) for
(k, v) in imp_correction if startswith(k, prefix)
];
by = first,
)
]
first_non_zero_index = findfirst(x -> x != 0.0, reverse(sorted_values))
sorted_values = sorted_values[1:(length(sorted_values) - first_non_zero_index + 1)]
return sorted_values
end
function sort_values_by_key_prefix_v35(imp_correction::Dict{String, <:Any}, prefix::String)
# For v35, we need to handle "Re(F1)", "Im(F1)" format
sorted_values = [
last(pair) for pair in sort(
[
(parse(Int, match(r"\d+", k).match), v) for
(k, v) in imp_correction if startswith(k, prefix) && contains(k, r"\d+")
];
by = first,
)
]
# Remove trailing zeros in IC data that indicate end of entry (0.00000,0.00000,0.00000)
# Acoording to PSSE DataFormat Section 1.18. TIC Tables
# Check if the last entry is all zeros across (T, Re(F), Im(F))
while !isempty(sorted_values)
last_index = length(sorted_values)
keys_to_check = ["T$last_index", "Re(F$last_index)", "Im(F$last_index)"]
if all(k -> haskey(imp_correction, k) && imp_correction[k] == 0.0, keys_to_check)
pop!(sorted_values)
else
break
end
end
return sorted_values
end
function _psse2pm_impedance_correction!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@info "Parsing PSS(R)E Transformer Impedance Correction Tables data into a PowerModels Dict..."
pm_data["impedance_correction"] = []
if haskey(pti_data, "IMPEDANCE CORRECTION")
for imp_correction in pti_data["IMPEDANCE CORRECTION"]
sub_data = Dict{String, Any}()
sub_data["table_number"] = imp_correction["I"]
is_v35 =
any(k -> contains(k, "Re(F") || contains(k, "Im(F"), keys(imp_correction))
if is_v35
sub_data["scaling_factor"] =
sort_values_by_key_prefix_v35(imp_correction, "Re(F")
sub_data["scaling_factor_imag"] =
sort_values_by_key_prefix_v35(imp_correction, "Im(F")
sub_data["tap_or_angle"] =
sort_values_by_key_prefix_v35(imp_correction, "T")
else
sub_data["scaling_factor"] = sort_values_by_key_prefix(imp_correction, "F")
sub_data["tap_or_angle"] = sort_values_by_key_prefix(imp_correction, "T")
end
sub_data["index"] = length(pm_data["impedance_correction"]) + 1
if import_all
_import_remaining_keys!(sub_data, imp_correction)
end
push!(pm_data["impedance_correction"], sub_data)
end
end
return
end
function _psse2pm_substation_data!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@warn "Parsing PSS(R)E Substation data into a PowerModels Dict..."
pm_data["substation_data"] = []
if haskey(pti_data, "SUBSTATION DATA")
for substation_data in pti_data["SUBSTATION DATA"]
sub_data = Dict{String, Any}()
sub_data["name"] = substation_data["NAME"]
sub_data["substation_is"] = substation_data["IS"]
sub_data["latitude"] = substation_data["LATITUDE"]
sub_data["longitude"] = substation_data["LONGITUDE"]
sub_data["nodes"] = substation_data["NODES"]
if import_all
_import_remaining_keys!(sub_data, substation_data)
end
sub_data["index"] = length(pm_data["substation_data"]) + 1
push!(pm_data["substation_data"], sub_data)
end
end
end
function _psse2pm_storage!(pm_data::Dict, pti_data::Dict, import_all::Bool)
@warn "This PSS(R)E parser currently doesn't support Storage data parsing..."
pm_data["storage"] = []
return
end
"""
_pti_to_powermodels!(pti_data)
Converts PSS(R)E-style data parsed from a PTI raw file, passed by `pti_data`
into a format suitable for use internally in PowerModels. Imports all remaining
data from the PTI file if `import_all` is true (Default: false).
"""
function _pti_to_powermodels!(
pti_data::Dict;
import_all = false,
validate = true,
correct_branch_rating = true,
)::Dict
pm_data = Dict{String, Any}()
rev = pop!(pti_data["CASE IDENTIFICATION"][1], "REV")
pm_data["per_unit"] = false
pm_data["source_type"] = "pti"
pm_data["source_version"] = "$rev"
pm_data["baseMVA"] = pop!(pti_data["CASE IDENTIFICATION"][1], "SBASE")
pm_data["name"] = pop!(pti_data["CASE IDENTIFICATION"][1], "NAME")
if import_all
_import_remaining_keys!(pm_data, pti_data["CASE IDENTIFICATION"][1])
end
_psse2pm_interarea_transfer!(pm_data, pti_data, import_all)
_psse2pm_area_interchange!(pm_data, pti_data, import_all)
_psse2pm_zone!(pm_data, pti_data, import_all)
# Order matters here. Buses need to parsed first
_psse2pm_bus!(pm_data, pti_data, import_all)
# Branches need to be parsed after buses to find topologically connected buses
_psse2pm_branch!(pm_data, pti_data, import_all)
_psse2pm_switch_breaker!(pm_data, pti_data, import_all)
_psse2pm_multisection_line!(pm_data, pti_data, import_all)
_psse2pm_transformer!(pm_data, pti_data, import_all)
# Injectors need to be parsed after branches and transformers to find topologically connected buses
_psse2pm_load!(pm_data, pti_data, import_all)
_psse2pm_shunt!(pm_data, pti_data, import_all)
_psse2pm_generator!(pm_data, pti_data, import_all)
_psse2pm_facts!(pm_data, pti_data, import_all)
_psse2pm_dcline!(pm_data, pti_data, import_all)
_psse2pm_impedance_correction!(pm_data, pti_data, import_all)
_psse2pm_substation_data!(pm_data, pti_data, import_all)
_psse2pm_storage!(pm_data, pti_data, import_all)
if pm_data["has_isolated_type_buses"]
bus_numbers = Set(v["bus_i"] for (_, v) in pm_data["bus"])
topologically_isolated_buses = setdiff(bus_numbers, pm_data["connected_buses"])
convert_to_pq =
setdiff(
pm_data["candidate_isolated_to_pq_buses"],
pm_data["candidate_isolated_to_pv_buses"],
)
convert_to_pv = pm_data["candidate_isolated_to_pv_buses"]
for b in setdiff!(convert_to_pq, topologically_isolated_buses)
pm_data["bus"][b]["bus_type"] = 1
end
for b in setdiff!(convert_to_pv, topologically_isolated_buses)
pm_data["bus"][b]["bus_type"] = 2
end
if !isempty(topologically_isolated_buses)
for b in topologically_isolated_buses
if pm_data["bus"][b]["bus_type"] == 4
continue
else
b_number = pm_data["bus"][b]["bus_i"]
b_type = pm_data["bus"][b]["bus_type"]
if b_type == 3
error(
"PSEE reference bus $(b_number) that is topologically isolated from the system. Indicates an error in the data.",
)
end
@error "PSEE data file contains a topologically isolated bus $(b_number) that is disconnected from the system and set to bus_type = $(b_type) instead of 4. Likely indicates an error in the data."
pm_data["bus"][b]["bus_type"] = 4
pm_data["bus"][b]["bus_status"] = false
end
end
end
end
if import_all
_import_remaining_comps!(
pm_data,
pti_data;
exclude = [
"CASE IDENTIFICATION",
"BUS",
"LOAD",
"FIXED SHUNT",
"SWITCHED SHUNT",
"GENERATOR",
"BRANCH",
"TRANSFORMER",
"TWO-TERMINAL DC",
"VOLTAGE SOURCE CONVERTER",
],
)
end
# update lookup structure
for (k, v) in pm_data
if isa(v, Array)
dict = Dict{String, Any}()
for item in v
@assert("index" in keys(item))
dict[string(item["index"])] = item
end
pm_data[k] = dict
end
end
if validate
correct_network_data!(pm_data; correct_branch_rating = correct_branch_rating)
end
return pm_data
end
"""
parse_psse(filename::String; kwargs...)::Dict
Parses directly from file
"""
function parse_psse(filename::String; kwargs...)::Dict
pm_data = open(filename) do f
parse_psse(f; kwargs...)
end
return pm_data
end
"""
function parse_psse(io::IO; kwargs...)::Dict
Parses directly from iostream
"""
function parse_psse(io::IO; kwargs...)::Dict
@info(
"The PSS(R)E parser currently supports buses, loads, shunts, generators, branches, switches, breakers, IC tables, transformers, facts, and dc lines",
)
pti_data = parse_pti(io)
pm = _pti_to_powermodels!(pti_data; kwargs...)
return pm
end
================================================
FILE: src/parsers/pm_io/pti.jl
================================================
#####################################################################
# #
# This file provides functions for interfacing with pti .raw files #
# #
#####################################################################
"""
A list of data file sections in the order that they appear in a PTI v33/v35 file
"""
const _pti_sections = [
"CASE IDENTIFICATION",
"BUS",
"LOAD",
"FIXED SHUNT",
"GENERATOR",
"BRANCH",
"TRANSFORMER",
"AREA INTERCHANGE",
"TWO-TERMINAL DC",
"VOLTAGE SOURCE CONVERTER",
"IMPEDANCE CORRECTION",
"MULTI-TERMINAL DC",
"MULTI-SECTION LINE",
"ZONE",
"INTER-AREA TRANSFER",
"OWNER",
"FACTS CONTROL DEVICE",
"SWITCHED SHUNT",
"GNE DEVICE",
"INDUCTION MACHINE",
]
const _pti_sections_v35 = vcat(
_pti_sections[1:6],
["SWITCHING DEVICE"],
_pti_sections[7:end],
"SUBSTATION DATA",
)
const _transaction_dtypes = [
("IC", Int64),
("SBASE", Float64),
("REV", Int64),
("XFRRAT", Float64),
("NXFRAT", Float64),
("BASFRQ", Float64),
]
const _transaction_dtypes_v35 = _transaction_dtypes
const _system_wide_dtypes_v35 = [
("THRSHZ", Float64),
("PQBRAK", Float64),
("BLOWUP", Float64),
("MAXISOLLVLS", Int64),
("CAMAXREPTSLN", Int64),
("CHKDUPCNTLBL", Int64),
("ITMX", Int64),
("ACCP", Float64),
("ACCQ", Float64),
("ACCM", Float64),
("TOL", Float64),
("ITMXN", Int64),
("ACCN", Float64),
("TOLN", Float64),
("VCTOLQ", Float64),
("VCTOLV", Float64),
("DVLIM", Float64),
("NDVFCT", Float64),
("ADJTHR", Float64),
("ACCTAP", Float64),
("TAPLIM", Float64),
("SWVBND", Float64),
("MXTPSS", Int64),
("MXSWIM", Int64),
("ITMXTY", Int64),
("ACCTY", Float64),
("TOLTY", Float64),
("METHOD", String),
("ACTAPS", Int64),
("AREAIN", Int64),
("PHSHFT", Int64),
("DCTAPS", Int64),
("SWSHNT", Int64),
("FLATST", Int64),
("VARLIM", Int64),
("NONDIV", Int64),
("IRATE", Int64),
("NAME", String),
("DESC", String),
]
const _system_wide_data_sections_v35 = Dict{String, Vector{String}}(
"GENERAL" =>
["THRSHZ", "PQBRAK", "BLOWUP", "MAXISOLLVLS", "CAMAXREPTSLN", "CHKDUPCNTLBL"],
"GAUSS" => ["ITMX", "ACCP", "ACCQ", "ACCM", "TOL"],
"NEWTON" => ["ITMXN", "ACCN", "TOLN", "VCTOLQ", "VCTOLV", "DVLIM", "NDVFCT"],
"ADJUST" => ["ADJTHR", "ACCTAP", "TAPLIM", "SWVBND", "MXTPSS", "MXSWIM"],
"TYSL" => ["ITMXTY", "ACCTY", "TOLTY"],
"SOLVER" => [
"METHOD",
"ACTAPS",
"AREAIN",
"PHSHFT",
"DCTAPS",
"SWSHNT",
"FLATST",
"VARLIM",
"NONDIV",
],
"RATING" => ["IRATE", "NAME", "DESC"],
)
const _bus_dtypes = [
("I", Int64),
("NAME", String),
("BASKV", Float64),
("IDE", Int64),
("AREA", Int64),
("ZONE", Int64),
("OWNER", Int64),
("VM", Float64),
("VA", Float64),
("NVHI", Float64),
("NVLO", Float64),
("EVHI", Float64),
("EVLO", Float64),
]
const _bus_dtypes_v35 = _bus_dtypes
const _load_dtypes = [
("I", Int64),
("ID", String),
("STATUS", Int64),
("AREA", Int64),
("ZONE", Int64),
("PL", Float64),
("QL", Float64),
("IP", Float64),
("IQ", Float64),
("YP", Float64),
("YQ", Float64),
("OWNER", Int64),
("SCALE", Int64),
("INTRPT", Int64),
]
const _load_dtypes_v35 = vcat(
_load_dtypes[1:14],
[
("DGENP", Float64),
("DGENQ", Float64),
("DGENM", Float64),
("LOADTYPE", String),
],
)
const _fixed_shunt_dtypes = [
("I", Int64),
("ID", String),
("STATUS", Int64),
("GL", Float64),
("BL", Float64),
]
const _fixed_shunt_dtypes_v35 = _fixed_shunt_dtypes
const _generator_dtypes = [
("I", Int64),
("ID", String),
("PG", Float64),
("QG", Float64),
("QT", Float64),
("QB", Float64),
("VS", Float64),
("IREG", Int64),
("MBASE", Float64),
("ZR", Float64),
("ZX", Float64),
("RT", Float64),
("XT", Float64),
("GTAP", Float64),
("STAT", Int64),
("RMPCT", Float64),
("PT", Float64),
("PB", Float64),
("O1", Int64),
("F1", Float64),
("O2", Int64),
("F2", Float64),
("O3", Int64),
("F3", Float64),
("O4", Int64),
("F4", Float64),
("WMOD", Int64),
("WPF", Float64),
]
const _generator_dtypes_v35 = vcat(
_generator_dtypes[1:8],
[("NREG", Int64)],
_generator_dtypes[9:18],
[("BASLOD", Int64)],
_generator_dtypes[19:end],
)
const _branch_dtypes = [
("I", Int64),
("J", Int64),
("CKT", String),
("R", Float64),
("X", Float64),
("B", Float64),
("RATEA", Float64),
("RATEB", Float64),
("RATEC", Float64),
("GI", Float64),
("BI", Float64),
("GJ", Float64),
("BJ", Float64),
("ST", Int64),
("MET", Int64),
("LEN", Float64),
("O1", Int64),
("F1", Float64),
("O2", Int64),
("F2", Float64),
("O3", Int64),
("F3", Float64),
("O4", Int64),
("F4", Float64),
]
const _branch_dtypes_v35 = vcat(
_branch_dtypes[1:6],
[
("NAME", String),
("RATE1", Float64),
("RATE2", Float64),
("RATE3", Float64),
("RATE4", Float64),
("RATE5", Float64),
("RATE6", Float64),
("RATE7", Float64),
("RATE8", Float64),
("RATE9", Float64),
("RATE10", Float64),
("RATE11", Float64),
("RATE12", Float64),
],
_branch_dtypes[10:end],
)
const _switching_dtypes_v35 = [
("I", Int64),
("J", Int64),
("CKT", String),
("X", Float64),
("RATE1", Float64),
("RATE2", Float64),
("RATE3", Float64),
("RATE4", Float64),
("RATE5", Float64),
("RATE6", Float64),
("RATE7", Float64),
("RATE8", Float64),
("RATE9", Float64),
("RATE10", Float64),
("RATE11", Float64),
("RATE12", Float64),
("STAT", Int64),
("NSTAT", Int64),
("MET", Int64),
("STYPE", Int64),
("NAME", String),
]
const _transformer_dtypes = [
("I", Int64),
("J", Int64),
("K", Int64),
("CKT", String),
("CW", Int64),
("CZ", Int64),
("CM", Int64),
("MAG1", Float64),
("MAG2", Float64),
("NMETR", Int64),
("NAME", String),
("STAT", Int64),
("O1", Int64),
("F1", Float64),
("O2", Int64),
("F2", Float64),
("O3", Int64),
("F3", Float64),
("O4", Int64),
("F4", Float64),
("VECGRP", String),
]
const _transformer_dtypes_v35 = _transformer_dtypes
const _transformer_3_1_dtypes = [
("R1-2", Float64),
("X1-2", Float64),
("SBASE1-2", Float64),
("R2-3", Float64),
("X2-3", Float64),
("SBASE2-3", Float64),
("R3-1", Float64),
("X3-1", Float64),
("SBASE3-1", Float64),
("VMSTAR", Float64),
("ANSTAR", Float64),
]
const _transformer_3_1_dtypes_v35 = _transformer_3_1_dtypes
const _transformer_3_2_dtypes = [
("WINDV1", Float64),
("NOMV1", Float64),
("ANG1", Float64),
("RATA1", Float64),
("RATB1", Float64),
("RATC1", Float64),
("COD1", Int64),
("CONT1", Int64),
("RMA1", Float64),
("RMI1", Float64),
("VMA1", Float64),
("VMI1", Float64),
("NTP1", Float64),
("TAB1", Int64),
("CR1", Float64),
("CX1", Float64),
("CNXA1", Float64),
]
const _transformer_3_2_dtypes_v35 = vcat(
_transformer_3_2_dtypes[1:3],
[
("RATE11", Float64),
("RATE12", Float64),
("RATE13", Float64),
("RATE14", Float64),
("RATE15", Float64),
("RATE16", Float64),
("RATE17", Float64),
("RATE18", Float64),
("RATE19", Float64),
("RATE110", Float64),
("RATE111", Float64),
("RATE112", Float64),
],
_transformer_3_2_dtypes[7:8],
[("NOD1", Int64)],
_transformer_3_2_dtypes[9:end],
)
const _transformer_3_3_dtypes = [
("WINDV2", Float64),
("NOMV2", Float64),
("ANG2", Float64),
("RATA2", Float64),
("RATB2", Float64),
("RATC2", Float64),
("COD2", Int64),
("CONT2", Int64),
("RMA2", Float64),
("RMI2", Float64),
("VMA2", Float64),
("VMI2", Float64),
("NTP2", Float64),
("TAB2", Int64),
("CR2", Float64),
("CX2", Float64),
("CNXA2", Float64),
]
const _transformer_3_3_dtypes_v35 = vcat(
_transformer_3_3_dtypes[1:3],
[
("RATE21", Float64),
("RATE22", Float64),
("RATE23", Float64),
("RATE24", Float64),
("RATE25", Float64),
("RATE26", Float64),
("RATE27", Float64),
("RATE28", Float64),
("RATE29", Float64),
("RATE210", Float64),
("RATE211", Float64),
("RATE212", Float64),
],
_transformer_3_3_dtypes[7:8],
[("NOD2", Int64)],
_transformer_3_3_dtypes[9:end],
)
const _transformer_3_4_dtypes = [
("WINDV3", Float64),
("NOMV3", Float64),
("ANG3", Float64),
("RATA3", Float64),
("RATB3", Float64),
("RATC3", Float64),
("COD3", Int64),
("CONT3", Int64),
("RMA3", Float64),
("RMI3", Float64),
("VMA3", Float64),
("VMI3", Float64),
("NTP3", Float64),
("TAB3", Int64),
("CR3", Float64),
("CX3", Float64),
("CNXA3", Float64),
]
const _transformer_3_4_dtypes_v35 = vcat(
_transformer_3_4_dtypes[1:3],
[
("RATE31", Float64),
("RATE32", Float64),
("RATE33", Float64),
("RATE34", Float64),
("RATE35", Float64),
("RATE36", Float64),
("RATE37", Float64),
("RATE38", Float64),
("RATE39", Float64),
("RATE310", Float64),
("RATE311", Float64),
("RATE312", Float64),
],
_transformer_3_4_dtypes[7:8],
[("NOD3", Int64)],
_transformer_3_4_dtypes[9:end],
)
const _transformer_2_1_dtypes =
[("R1-2", Float64), ("X1-2", Float64), ("SBASE1-2", Float64)]
const _transformer_2_1_dtypes_v35 = _transformer_2_1_dtypes
const _transformer_2_2_dtypes = [
("WINDV1", Float64),
("NOMV1", Float64),
("ANG1", Float64),
("RATA1", Float64),
("RATB1", Float64),
("RATC1", Float64),
("COD1", Int64),
("CONT1", Int64),
("RMA1", Float64),
("RMI1", Float64),
("VMA1", Float64),
("VMI1", Float64),
("NTP1", Float64),
("TAB1", Int64),
("CR1", Float64),
("CX1", Float64),
("CNXA1", Float64),
]
const _transformer_2_2_dtypes_v35 = vcat(
_transformer_2_2_dtypes[1:3],
[
("RATE11", Float64),
("RATE12", Float64),
("RATE13", Float64),
("RATE14", Float64),
("RATE15", Float64),
("RATE16", Float64),
("RATE17", Float64),
("RATE18", Float64),
("RATE19", Float64),
("RATE110", Float64),
("RATE111", Float64),
("RATE112", Float64),
],
_transformer_2_2_dtypes[7:8],
[("NOD1", Int64)],
_transformer_2_2_dtypes[9:end],
)
const _transformer_2_3_dtypes = [("WINDV2", Float64), ("NOMV2", Float64)]
const _transformer_2_3_dtypes_v35 = _transformer_2_3_dtypes
const _area_interchange_dtypes =
[("I", Int64), ("ISW", Int64), ("PDES", Float64), ("PTOL", Float64), ("ARNAME", String)]
const _area_interchange_dtypes_v35 = _area_interchange_dtypes
const _two_terminal_line_dtypes = [
("NAME", String),
("MDC", Int64),
("RDC", Float64),
("SETVL", Float64),
("VSCHD", Float64),
("VCMOD", Float64),
("RCOMP", Float64),
("DELTI", Float64),
("METER", String),
("DCVMIN", Float64),
("CCCITMX", Int64),
("CCCACC", Float64),
("IPR", Int64),
("NBR", Int64),
("ANMXR", Float64),
("ANMNR", Float64),
("RCR", Float64),
("XCR", Float64),
("EBASR", Float64),
("TRR", Float64),
("TAPR", Float64),
("TMXR", Float64),
("TMNR", Float64),
("STPR", Float64),
("ICR", Int64),
("IFR", Int64),
("ITR", Int64),
("IDR", String),
("XCAPR", Float64),
("IPI", Int64),
("NBI", Int64),
("ANMXI", Float64),
("ANMNI", Float64),
("RCI", Float64),
("XCI", Float64),
("EBASI", Float64),
("TRI", Float64),
("TAPI", Float64),
("TMXI", Float64),
("TMNI", Float64),
("STPI", Float64),
("ICI", Int64),
("IFI", Int64),
("ITI", Int64),
("IDI", String),
("XCAPI", Float64),
]
const _two_terminal_line_dtypes_v35 = vcat(
_two_terminal_line_dtypes[1:25],
[("NDR", Int64)],
_two_terminal_line_dtypes[26:42],
[("NDI", Int64)],
_two_terminal_line_dtypes[43:end],
)
const _vsc_line_dtypes = [
("NAME", String),
("MDC", Int64),
("RDC", Float64),
("O1", Int64),
("F1", Float64),
("O2", Int64),
("F2", Float64),
("O3", Int64),
("F3", Float64),
("O4", Int64),
("F4", Float64),
]
const _vsc_line_dtypes_35 = _vsc_line_dtypes
const _vsc_subline_dtypes = [
("IBUS", Int64),
("TYPE", Int64),
("MODE", Int64),
("DCSET", Float64),
("ACSET", Float64),
("ALOSS", Float64),
("BLOSS", Float64),
("MINLOSS", Float64),
("SMAX", Float64),
("IMAX", Float64),
("PWF", Float64),
("MAXQ", Float64),
("MINQ", Float64),
("REMOT", Int64),
("RMPCT", Float64),
]
const _vsc_subline_dtypes_v35 = _vsc_subline_dtypes
const _impedance_correction_dtypes = [
("I", Int64),
("T1", Float64),
("F1", Float64),
("T2", Float64),
("F2", Float64),
("T3", Float64),
("F3", Float64),
("T4", Float64),
("F4", Float64),
("T5", Float64),
("F5", Float64),
("T6", Float64),
("F6", Float64),
("T7", Float64),
("F7", Float64),
("T8", Float64),
("F8", Float64),
("T9", Float64),
("F9", Float64),
("T10", Float64),
("F10", Float64),
("T11", Float64),
("F11", Float64),
]
const _impedance_correction_dtypes_v35 = [
("I", Int64),
("T1", Float64), ("Re(F1)", Float64), ("Im(F1)", Float64),
("T2", Float64), ("Re(F2)", Float64), ("Im(F2)", Float64),
("T3", Float64), ("Re(F3)", Float64), ("Im(F3)", Float64),
("T4", Float64), ("Re(F4)", Float64), ("Im(F4)", Float64),
("T5", Float64), ("Re(F5)", Float64), ("Im(F5)", Float64),
("T6", Float64), ("Re(F6)", Float64), ("Im(F6)", Float64),
("T7", Float64), ("Re(F7)", Float64), ("Im(F7)", Float64),
("T8", Float64), ("Re(F8)", Float64), ("Im(F8)", Float64),
("T9", Float64), ("Re(F9)", Float64), ("Im(F9)", Float64),
("T10", Float64), ("Re(F10)", Float64), ("Im(F10)", Float64),
("T11", Float64), ("Re(F11)", Float64), ("Im(F11)", Float64),
("T12", Float64), ("Re(F12)", Float64), ("Im(F12)", Float64),
]
const _multi_term_main_dtypes = [
("NAME", String),
("NCONV", Int64),
("NDCBS", Int64),
("NDCLN", Int64),
("MDC", Int64),
("VCONV", Int64),
("VCMOD", Float64),
("VCONVN", Float64),
]
const _multi_term_main_dtypes_v35 = _multi_term_main_dtypes
const _multi_term_nconv_dtypes = [
("IB", Int64),
("N", Int64),
("ANGMX", Float64),
("ANGMN", Float64),
("RC", Float64),
("XC", Float64),
("EBAS", Float64),
("TR", Float64),
("TAP", Float64),
("TPMX", Float64),
("TPMN", Float64),
("TSTP", Float64),
("SETVL", Float64),
("DCPF", Float64),
("MARG", Float64),
("CNVCOD", Int64),
]
const _multi_term_nconv_dtypes_v35 = _multi_term_nconv_dtypes
const _multi_term_ndcbs_dtypes = [
("IDC", Int64),
("IB", Int64),
("AREA", Int64),
("ZONE", Int64),
("DCNAME", String),
("IDC2", Int64),
("RGRND", Float64),
("OWNER", Int64),
]
const _multi_term_ndcbs_dtypes_v35 = _multi_term_ndcbs_dtypes
const _multi_term_ndcln_dtypes = [
("IDC", Int64),
("JDC", Int64),
("DCCKT", String),
("MET", Int64),
("RDC", Float64),
("LDC", Float64),
]
const _multi_term_ndcln_dtypes_v35 = _multi_term_ndcln_dtypes
const _multi_section_dtypes = [
("I", Int64),
("J", Int64),
("ID", String),
("MET", Int64),
("DUM1", Int64),
("DUM2", Int64),
("DUM3", Int64),
("DUM4", Int64),
("DUM5", Int64),
("DUM6", Int64),
("DUM7", Int64),
("DUM8", Int64),
("DUM9", Int64),
]
const _multi_section_dtypes_v35 = _multi_section_dtypes
const _zone_dtypes = [("I", Int64), ("ZONAME", String)]
const _zone_dtypes_v35 = _zone_dtypes
const _interarea_dtypes =
[("ARFROM", Int64), ("ARTO", Int64), ("TRID", String), ("PTRAN", Float64)]
const _interarea_dtypes_v35 = _interarea_dtypes
const _owner_dtypes = [("I", Int64), ("OWNAME", String)]
const _owner_dtypes_v35 = _owner_dtypes
const _FACTS_dtypes = [
("NAME", String),
("I", Int64),
("J", Int64),
("MODE", Int64),
("PDES", Float64),
("QDES", Float64),
("VSET", Float64),
("SHMX", Float64),
("TRMX", Float64),
("VTMN", Float64),
("VTMX", Float64),
("VSMX", Float64),
("IMX", Float64),
("LINX", Float64),
("RMPCT", Float64),
("OWNER", Int64),
("SET1", Float64),
("SET2", Float64),
("VSREF", Int64),
("REMOT", Int64),
("MNAME", String),
]
const _FACTS_dtypes_v35 = vcat(
_FACTS_dtypes[1:19],
[
("FCREG", Int64),
("NREG", Int64),
("MNAME", String),
],
)
const _switched_shunt_dtypes = [
("I", Int64),
("MODSW", Int64),
("ADJM", Int64),
("STAT", Int64),
("VSWHI", Float64),
("VSWLO", Float64),
("SWREM", Int64),
("RMPCT", Float64),
("RMIDNT", String),
("BINIT", Float64),
("N1", Int64),
("B1", Float64),
("N2", Int64),
("B2", Float64),
("N3", Int64),
("B3", Float64),
("N4", Int64),
("B4", Float64),
("N5", Int64),
("B5", Float64),
("N6", Int64),
("B6", Float64),
("N7", Int64),
("B7", Float64),
("N8", Int64),
("B8", Float64),
]
const _switched_shunt_dtypes_v35 = vcat(
_switched_shunt_dtypes[1],
[("ID", String)],
_switched_shunt_dtypes[2:7],
[
("NREG", Int64),
("RMPCT", Float64),
("RMIDNT", String),
("BINIT", Float64),
("S1", Int64), ("N1", Int64), ("B1", Float64),
("S2", Int64), ("N2", Int64), ("B2", Float64),
("S3", Int64), ("N3", Int64), ("B3", Float64),
("S4", Int64), ("N4", Int64), ("B4", Float64),
("S5", Int64), ("N5", Int64), ("B5", Float64),
("S6", Int64), ("N6", Int64), ("B6", Float64),
("S7", Int64), ("N7", Int64), ("B7", Float64),
("S8", Int64), ("N8", Int64), ("B8", Float64),
],
)
# TODO: Account for multiple lines in GNE Device entries
const _gne_device_dtypes = [
("NAME", String),
("MODEL", String),
("NTERM", Int64),
("BUSi", Int64),
("NREAL", Int64),
("NINTG", Int64),
("NCHAR", Int64),
("STATUS", Int64),
("OWNER", Int64),
("NMETR", Int64),
("REALi", Float64),
("INTGi", Int64),
("CHARi", String),
]
const _gne_device_dtypes_v35 = _gne_device_dtypes
const _induction_machine_dtypes = [
("I", Int64),
("ID", String),
("STAT", Int64),
("SCODE", Int64),
("DCODE", Int64),
("AREA", Int64),
("ZONE", Int64),
("OWNER", Int64),
("TCODE", Int64),
("BCODE", Int64),
("MBASE", Float64),
("RATEKV", Float64),
("PCODE", Int64),
("PSET", Float64),
("H", Float64),
("A", Float64),
("B", Float64),
("D", Float64),
("E", Float64),
("RA", Float64),
("XA", Float64),
("XM", Float64),
("R1", Float64),
("X1", Float64),
("R2", Float64),
("X2", Float64),
("X3", Float64),
("E1", Float64),
("SE1", Float64),
("E2", Float64),
("SE2", Float64),
("IA1", Float64),
("IA2", Float64),
("XAMULT", Float64),
]
const _induction_machine_dtypes_v35 = _induction_machine_dtypes
const _substation_dtypes_v35 = [
("IS", Int64),
("NAME", String),
("LATITUDE", Float64),
("LONGITUDE", Float64),
("SGR", Float64),
]
"""
lookup array of data types for PTI file sections given by
`field_name`, as enumerated by PSS/E Program Operation Manual.
"""
const _pti_dtypes = Dict{String, Array}(
"BUS" => _bus_dtypes,
"LOAD" => _load_dtypes,
"FIXED SHUNT" => _fixed_shunt_dtypes,
"GENERATOR" => _generator_dtypes,
"BRANCH" => _branch_dtypes,
"TRANSFORMER" => _transformer_dtypes,
"TRANSFORMER TWO-WINDING LINE 1" => _transformer_2_1_dtypes,
"TRANSFORMER TWO-WINDING LINE 2" => _transformer_2_2_dtypes,
"TRANSFORMER TWO-WINDING LINE 3" => _transformer_2_3_dtypes,
"TRANSFORMER THREE-WINDING LINE 1" => _transformer_3_1_dtypes,
"TRANSFORMER THREE-WINDING LINE 2" => _transformer_3_2_dtypes,
"TRANSFORMER THREE-WINDING LINE 3" => _transformer_3_3_dtypes,
"TRANSFORMER THREE-WINDING LINE 4" => _transformer_3_4_dtypes,
"AREA INTERCHANGE" => _area_interchange_dtypes,
"TWO-TERMINAL DC" => _two_terminal_line_dtypes,
"VOLTAGE SOURCE CONVERTER" => _vsc_line_dtypes,
"VOLTAGE SOURCE CONVERTER SUBLINES" => _vsc_subline_dtypes,
"IMPEDANCE CORRECTION" => _impedance_correction_dtypes,
"MULTI-TERMINAL DC" => _multi_term_main_dtypes,
"MULTI-TERMINAL DC NCONV" => _multi_term_nconv_dtypes,
"MULTI-TERMINAL DC NDCBS" => _multi_term_ndcbs_dtypes,
"MULTI-TERMINAL DC NDCLN" => _multi_term_ndcln_dtypes,
"MULTI-SECTION LINE" => _multi_section_dtypes,
"ZONE" => _zone_dtypes,
"INTER-AREA TRANSFER" => _interarea_dtypes,
"OWNER" => _owner_dtypes,
"FACTS CONTROL DEVICE" => _FACTS_dtypes,
"SWITCHED SHUNT" => _switched_shunt_dtypes,
"CASE IDENTIFICATION" => _transaction_dtypes,
"GNE DEVICE" => _gne_device_dtypes,
"INDUCTION MACHINE" => _induction_machine_dtypes,
)
const _pti_dtypes_v35 = Dict{String, Array}(
"BUS" => _bus_dtypes_v35,
"LOAD" => _load_dtypes_v35,
"FIXED SHUNT" => _fixed_shunt_dtypes_v35,
"GENERATOR" => _generator_dtypes_v35,
"BRANCH" => _branch_dtypes_v35,
"SWITCHING DEVICE" => _switching_dtypes_v35,
"TRANSFORMER" => _transformer_dtypes_v35,
"TRANSFORMER TWO-WINDING LINE 1" => _transformer_2_1_dtypes_v35,
"TRANSFORMER TWO-WINDING LINE 2" => _transformer_2_2_dtypes_v35,
"TRANSFORMER TWO-WINDING LINE 3" => _transformer_2_3_dtypes_v35,
"TRANSFORMER THREE-WINDING LINE 1" => _transformer_3_1_dtypes_v35,
"TRANSFORMER THREE-WINDING LINE 2" => _transformer_3_2_dtypes_v35,
"TRANSFORMER THREE-WINDING LINE 3" => _transformer_3_3_dtypes_v35,
"TRANSFORMER THREE-WINDING LINE 4" => _transformer_3_4_dtypes_v35,
"AREA INTERCHANGE" => _area_interchange_dtypes_v35,
"TWO-TERMINAL DC" => _two_terminal_line_dtypes_v35,
"VOLTAGE SOURCE CONVERTER" => _vsc_line_dtypes_35,
"VOLTAGE SOURCE CONVERTER SUBLINES" => _vsc_subline_dtypes_v35,
"IMPEDANCE CORRECTION" => _impedance_correction_dtypes_v35,
"MULTI-TERMINAL DC" => _multi_term_main_dtypes_v35,
"MULTI-TERMINAL DC NCONV" => _multi_term_nconv_dtypes_v35,
"MULTI-TERMINAL DC NDCBS" => _multi_term_ndcbs_dtypes_v35,
"MULTI-TERMINAL DC NDCLN" => _multi_term_ndcln_dtypes_v35,
"MULTI-SECTION LINE" => _multi_section_dtypes_v35,
"ZONE" => _zone_dtypes_v35,
"INTER-AREA TRANSFER" => _interarea_dtypes_v35,
"OWNER" => _owner_dtypes_v35,
"FACTS CONTROL DEVICE" => _FACTS_dtypes_v35,
"SWITCHED SHUNT" => _switched_shunt_dtypes_v35,
"CASE IDENTIFICATION" => _transaction_dtypes_v35,
"GNE DEVICE" => _gne_device_dtypes_v35,
"INDUCTION MACHINE" => _induction_machine_dtypes_v35,
"SUBSTATION DATA" => _substation_dtypes_v35,
)
const _default_case_identification = Dict(
"IC" => 0,
"SBASE" => 100.0,
"REV" => 33,
"XFRRAT" => 0,
"NXFRAT" => 0,
"BASFRQ" => 60,
)
const _default_case_identification_v35 = Dict(
"IC" => 0,
"SBASE" => 100.0,
"REV" => 35,
"XFRRAT" => 0,
"NXFRAT" => 0,
"BASFRQ" => 60,
)
const _default_bus = Dict(
"BASKV" => 0.0,
"IDE" => 1,
"AREA" => 1,
"ZONE" => 1,
"OWNER" => 1,
"VM" => 1.0,
"VA" => 0.0,
"NVHI" => 1.1,
"NVLO" => 0.9,
"EVHI" => 1.1,
"EVLO" => 0.9,
"NAME" => " ",
)
const _default_bus_v35 = _default_bus
const _default_load = Dict(
"ID" => "1",
"STATUS" => 1,
"PL" => 0.0,
"QL" => 0.0,
"IP" => 0.0,
"IQ" => 0.0,
"YP" => 0.0,
"YQ" => 0.0,
"SCALE" => 1,
"INTRPT" => 0,
"AREA" => nothing,
"ZONE" => nothing,
"OWNER" => nothing,
)
const _default_load_v35 = merge(
_default_load,
Dict(
"DGENP" => 0.0,
"DGENQ" => 0.0,
"DGENM" => 0.0,
"LOADTYPE" => nothing,
),
)
const _default_fixed_shunt = Dict("ID" => "1", "STATUS" => 1, "GL" => 0.0, "BL" => 0.0)
const _default_fixed_shunt_v35 = _default_fixed_shunt
const _default_generator = Dict(
"ID" => "1",
"PG" => 0.0,
"QG" => 0.0,
"QT" => 9999.0,
"QB" => -9999.0,
"VS" => 1.0,
"IREG" => 0,
"MBASE" => nothing,
"ZR" => 0.0,
"ZX" => 1.0,
"RT" => 0.0,
"XT" => 0.0,
"GTAP" => 1.0,
"STAT" => 1,
"RMPCT" => 100.0,
"PT" => 9999.0,
"PB" => -9999.0,
"O1" => nothing,
"O2" => 0,
"O3" => 0,
"O4" => 0,
"F1" => 1.0,
"F2" => 1.0,
"F3" => 1.0,
"F4" => 1.0,
"WMOD" => 0,
"WPF" => 1.0,
)
const _default_generator_v35 = merge(_default_generator, Dict(
"NREG" => 0,
"BASLOD" => 0,
))
const _default_branch = Dict(
"CKT" => "1",
"B" => 0.0,
"RATEA" => 0.0,
"RATEB" => 0.0,
"RATEC" => 0.0,
"GI" => 0.0,
"BI" => 0.0,
"GJ" => 0.0,
"BJ" => 0.0,
"ST" => 1,
"MET" => 1,
"LEN" => 0.0,
"O1" => nothing,
"O2" => 0,
"O3" => 0,
"O4" => 0,
"F1" => 1.0,
"F2" => 1.0,
"F3" => 1.0,
"F4" => 1.0,
)
const _default_branch_v35 = merge(
_default_branch,
Dict(
"RATE1" => 0.0,
"RATE2" => 0.0,
"RATE3" => 0.0,
"RATE4" => 0.0,
"RATE5" => 0.0,
"RATE6" => 0.0,
"RATE7" => 0.0,
"RATE8" => 0.0,
"RATE9" => 0.0,
"RATE10" => 0.0,
"RATE11" => 0.0,
"RATE12" => 0.0,
),
)
const _default_switching_device_v35 = Dict(
"CKT" => "1",
"RATE1" => 0.0,
"RATE2" => 0.0,
"RATE3" => 0.0,
"RATE4" => 0.0,
"RATE5" => 0.0,
"RATE6" => 0.0,
"RATE7" => 0.0,
"RATE8" => 0.0,
"RATE9" => 0.0,
"RATE10" => 0.0,
"RATE11" => 0.0,
"RATE12" => 0.0,
"STAT" => 1,
"NSTAT" => 1,
"MET" => 0.0,
"STYPE" => 0.0,
"NAME" => "",
)
const _default_transformer = Dict(
"K" => 0,
"CKT" => "1",
"CW" => 1,
"CZ" => 1,
"CM" => 1,
"MAG1" => 0.0,
"MAG2" => 0.0,
"NMETR" => 2,
"NAME" => " ",
"STAT" => 1,
"O1" => nothing,
"O2" => 0,
"O3" => 0,
"O4" => 0,
"F1" => 1.0,
"F2" => 1.0,
"F3" => 1.0,
"F4" => 1.0,
"VECGRP" => " ",
"R1-2" => 0.0,
"SBASE1-2" => nothing,
"R2-3" => 0.0,
"SBASE2-3" => nothing,
"R3-1" => 0.0,
"SBASE3-1" => nothing,
"VMSTAR" => 1.0,
"ANSTAR" => 0.0,
"WINDV1" => nothing,
"NOMV1" => 0.0,
"ANG1" => 0.0,
"RATA1" => 0.0,
"RATB1" => 0.0,
"RATC1" => 0.0,
"COD1" => 0,
"CONT1" => 0,
"RMA1" => 1.1,
"RMI1" => 0.9,
"VMA1" => 1.1,
"VMI1" => 0.9,
"NTP1" => 33,
"TAB1" => 0,
"CR1" => 0.0,
"CX1" => 0.0,
"CNXA1" => 0.0,
"WINDV2" => nothing,
"NOMV2" => 0.0,
"ANG2" => 0.0,
"RATA2" => 0.0,
"RATB2" => 0.0,
"RATC2" => 0.0,
"COD2" => 0,
"CONT2" => 0,
"RMA2" => 1.1,
"RMI2" => 0.9,
"VMA2" => 1.1,
"VMI2" => 0.9,
"NTP2" => 33,
"TAB2" => 0,
"CR2" => 0.0,
"CX2" => 0.0,
"CNXA2" => 0.0,
"WINDV3" => nothing,
"NOMV3" => 0.0,
"ANG3" => 0.0,
"RATA3" => 0.0,
"RATB3" => 0.0,
"RATC3" => 0.0,
"COD3" => 0,
"CONT3" => 0,
"RMA3" => 1.1,
"RMI3" => 0.9,
"VMA3" => 1.1,
"VMI3" => 0.9,
"NTP3" => 33,
"TAB3" => 0,
"CR3" => 0.0,
"CX3" => 0.0,
"CNXA3" => 0.0,
)
const _default_transformer_v35 = merge(
_default_transformer,
Dict(
"NOD1" => 0,
"NOD2" => 0,
"NOD3" => 0,
),
)
const _default_area_interchange =
Dict("ISW" => 0, "PDES" => 0.0, "PTOL" => 10.0, "ARNAME" => " ")
const _default_area_interchange_v35 = _default_area_interchange
const _default_two_terminal_dc = Dict(
"MDC" => 0,
"VCMOD" => 0.0,
"RCOMP" => 0.0,
"DELTI" => 0.0,
"METER" => "I",
"DCVMIN" => 0.0,
"CCCITMX" => 20,
"CCCACC" => 1.0,
"TRR" => 1.0,
"TAPR" => 1.0,
"TMXR" => 1.5,
"TMNR" => 0.51,
"STPR" => 0.00625,
"ICR" => 0,
"IFR" => 0,
"ITR" => 0,
"IDR" => "1",
"XCAPR" => 0.0,
"TRI" => 1.0,
"TAPI" => 1.0,
"TMXI" => 1.5,
"TMNI" => 0.51,
"STPI" => 0.00625,
"ICI" => 0,
"IFI" => 0,
"ITI" => 0,
"IDI" => "1",
"XCAPI" => 0.0,
)
const _default_two_terminal_dc_v35 = merge(_default_two_terminal_dc, Dict(
"NDR" => 0,
"NDI" => 0,
))
const _default_vsc_dc = Dict(
"MDC" => 1,
"O1" => nothing,
"O2" => 0,
"O3" => 0,
"O4" => 0,
"F1" => 1.0,
"F2" => 1.0,
"F3" => 1.0,
"F4" => 1.0,
"CONVERTER BUSES" => Dict(
"MODE" => 1,
"ACSET" => 1.0,
"ALOSS" => 1.0,
"BLOSS" => 0.0,
"MINLOSS" => 0.0,
"SMAX" => 0.0,
"IMAX" => 0.0,
"PWF" => 1.0,
"MAXQ" => 9999.0,
"MINQ" => -9999.0,
"REMOT" => 0,
"RMPCT" => 100.0,
),
)
const _default_vsc_dc_v35 = _default_vsc_dc
const _default_impedance_correction = Dict(
"T1" => 0.0,
"T2" => 0.0,
"T3" => 0.0,
"T4" => 0.0,
"T5" => 0.0,
"T6" => 0.0,
"T7" => 0.0,
"T8" => 0.0,
"T9" => 0.0,
"T10" => 0.0,
"T11" => 0.0,
"F1" => 0.0,
"F2" => 0.0,
"F3" => 0.0,
"F4" => 0.0,
"F5" => 0.0,
"F6" => 0.0,
"F7" => 0.0,
"F8" => 0.0,
"F9" => 0.0,
"F10" => 0.0,
"F11" => 0.0,
)
const _default_impedance_correction_v35 = Dict(
"T1" => 0.0, "Re(F1)" => 0.0, "Im(F1)" => 0.0,
"T2" => 0.0, "Re(F2)" => 0.0, "Im(F2)" => 0.0,
"T3" => 0.0, "Re(F3)" => 0.0, "Im(F3)" => 0.0,
"T4" => 0.0, "Re(F4)" => 0.0, "Im(F4)" => 0.0,
"T5" => 0.0, "Re(F5)" => 0.0, "Im(F5)" => 0.0,
"T6" => 0.0, "Re(F6)" => 0.0, "Im(F6)" => 0.0,
"T7" => 0.0, "Re(F7)" => 0.0, "Im(F7)" => 0.0,
"T8" => 0.0, "Re(F8)" => 0.0, "Im(F8)" => 0.0,
"T9" => 0.0, "Re(F9)" => 0.0, "Im(F9)" => 0.0,
"T10" => 0.0, "Re(F10)" => 0.0, "Im(F10)" => 0.0,
"T11" => 0.0, "Re(F11)" => 0.0, "Im(F11)" => 0.0,
"T12" => 0.0, "Re(F12)" => 0.0, "Im(F12)" => 0.0,
)
const _default_multi_term_dc = Dict(
"MDC" => 0,
"VCMOD" => 0.0,
"VCONVN" => 0,
"CONV" => Dict(
"TR" => 1.0,
"TAP" => 1.0,
"TPMX" => 1.5,
"TPMN" => 0.51,
"TSTP" => 0.00625,
"DCPF" => 1,
"MARG" => 0.0,
"CNVCOD" => 1,
),
"DCBS" => Dict(
"IB" => 0.0,
"AREA" => 1,
"ZONE" => 1,
"DCNAME" => " ",
"IDC2" => 0,
"RGRND" => 0.0,
"OWNER" => 1,
),
"DCLN" => Dict("DCCKT" => 1, "MET" => 1, "LDC" => 0.0),
)
const _default_multi_term_dc_v35 = _default_multi_term_dc
const _default_multi_section = Dict("ID" => "&1", "MET" => 1)
const _default_multi_section_v35 = _default_multi_section
const _default_zone = Dict("ZONAME" => " ")
const _default_zone_v35 = _default_zone
const _default_interarea = Dict("TRID" => 1, "PTRAN" => 0.0)
const _default_interarea_v35 = _default_interarea
const _default_owner = Dict("OWNAME" => " ")
const _default_owner_v35 = _default_owner
const _default_facts = Dict(
"J" => 0,
"MODE" => 1,
"PDES" => 0.0,
"QDES" => 0.0,
"VSET" => 1.0,
"SHMX" => 9999.0,
"TRMX" => 9999.0,
"VTMN" => 0.9,
"VTMX" => 1.1,
"VSMX" => 1.0,
"IMX" => 0.0,
"LINX" => 0.05,
"RMPCT" => 100.0,
"OWNER" => 1,
"SET1" => 0.0,
"SET2" => 0.0,
"VSREF" => 0,
"REMOT" => 0,
"MNAME" => "",
)
const _default_facts_v35 = merge(
Dict(k => v for (k, v) in pairs(_default_facts) if k != "REMOT"),
Dict(
"FCREG" => 0, # Replaces REMOT in v35
"NREG" => 0,
),
)
const _default_switched_shunt = Dict(
"MODSW" => 1,
"ADJM" => 0,
"STAT" => 1,
"VSWHI" => 1.0,
"VSWLO" => 1.0,
"SWREM" => 0,
"RMPCT" => 100.0,
"RMIDNT" => "",
"BINIT" => 0.0,
"S1" => 1, "N1" => 0, "B1" => 0.0,
"S2" => 1, "N2" => 0, "B2" => 0.0,
"S3" => 1, "N3" => 0, "B3" => 0.0,
"S4" => 1, "N4" => 0, "B4" => 0.0,
"S5" => 1, "N5" => 0, "B5" => 0.0,
"S6" => 1, "N6" => 0, "B6" => 0.0,
"S7" => 1, "N7" => 0, "B7" => 0.0,
"S8" => 1, "N8" => 0, "B8" => 0.0,
)
const _default_switched_shunt_v35 = merge(
Dict(k => v for (k, v) in pairs(_default_switched_shunt) if k != "SWREM"),
Dict(
"SWREG" => 0,
"ID" => "1",
"NAME" => "",
),
)
const _default_gne_device = Dict(
"NTERM" => 1,
"NREAL" => 0,
"NINTG" => 0,
"NCHAR" => 0,
"STATUS" => 1,
"OWNER" => nothing,
"NMETR" => nothing,
"REAL" => 0,
"INTG" => nothing,
"CHAR" => "1",
)
const _default_gne_device_v35 = _default_gne_device
const _default_induction_machine = Dict(
"ID" => 1,
"STAT" => 1,
"SCODE" => 1,
"DCODE" => 2,
"AREA" => nothing,
"ZONE" => nothing,
"OWNER" => nothing,
"TCODE" => 1,
"BCODE" => 1,
"MBASE" => nothing,
"RATEKV" => 0.0,
"PCODE" => 1,
"H" => 1.0,
"A" => 1.0,
"B" => 1.0,
"D" => 1.0,
"E" => 1.0,
"RA" => 0.0,
"XA" => 0.0,
"XM" => 2.5,
"R1" => 999.0,
"X1" => 999.0,
"R2" => 999.0,
"X2" => 999.0,
"X3" => 0.0,
"E1" => 1.0,
"SE1" => 0.0,
"E2" => 1.2,
"SE2" => 0.0,
"IA1" => 0.0,
"IA2" => 0.0,
"XAMULT" => 1,
)
const _default_induction_machine_v35 = _default_induction_machine
const _default_substation_data_v35 = Dict(
"NAME" => "",
"LATI" => 0.0,
"LONG" => 0.0,
"SGR" => 0.1,
)
const _pti_defaults = Dict(
"BUS" => _default_bus,
"LOAD" => _default_load,
"FIXED SHUNT" => _default_fixed_shunt,
"GENERATOR" => _default_generator,
"BRANCH" => _default_branch,
"TRANSFORMER" => _default_transformer,
"AREA INTERCHANGE" => _default_area_interchange,
"TWO-TERMINAL DC" => _default_two_terminal_dc,
"VOLTAGE SOURCE CONVERTER" => _default_vsc_dc,
"IMPEDANCE CORRECTION" => _default_impedance_correction,
"MULTI-TERMINAL DC" => _default_multi_term_dc,
"MULTI-SECTION LINE" => _default_multi_section,
"ZONE" => _default_zone,
"INTER-AREA TRANSFER" => _default_interarea,
"OWNER" => _default_owner,
"FACTS CONTROL DEVICE" => _default_facts,
"SWITCHED SHUNT" => _default_switched_shunt,
"CASE IDENTIFICATION" => _default_case_identification,
"GNE DEVICE" => _default_gne_device,
"INDUCTION MACHINE" => _default_induction_machine,
)
const _pti_defaults_v35 = Dict(
"BUS" => _default_bus,
"LOAD" => _default_load,
"FIXED SHUNT" => _default_fixed_shunt,
"GENERATOR" => _default_generator,
"BRANCH" => _default_branch,
"SWITCHING DEVICE" => _default_switching_device_v35,
"TRANSFORMER" => _default_transformer,
"AREA INTERCHANGE" => _default_area_interchange,
"TWO-TERMINAL DC" => _default_two_terminal_dc,
"VOLTAGE SOURCE CONVERTER" => _default_vsc_dc,
"IMPEDANCE CORRECTION" => _default_impedance_correction,
"MULTI-TERMINAL DC" => _default_multi_term_dc,
"MULTI-SECTION LINE" => _default_multi_section,
"ZONE" => _default_zone,
"INTER-AREA TRANSFER" => _default_interarea,
"OWNER" => _default_owner,
"FACTS CONTROL DEVICE" => _default_facts,
"SWITCHED SHUNT" => _default_switched_shunt,
"CASE IDENTIFICATION" => _default_case_identification,
"GNE DEVICE" => _default_gne_device,
"INDUCTION MACHINE" => _default_induction_machine,
"SUBSTATION DATA" => _default_substation_data_v35,
)
function _correct_nothing_values!(data::Dict)
if !haskey(data, "BUS")
return
end
sbase = data["CASE IDENTIFICATION"][1]["SBASE"]
bus_lookup = Dict(bus["I"] => bus for bus in data["BUS"])
if haskey(data, "LOAD")
for load in data["LOAD"]
load_bus = bus_lookup[load["I"]]
if load["AREA"] === nothing
load["AREA"] = load_bus["AREA"]
end
if load["ZONE"] === nothing
load["ZONE"] = load_bus["ZONE"]
end
if load["OWNER"] === nothing
load["OWNER"] = load_bus["OWNER"]
end
end
end
if haskey(data, "GENERATOR")
for gen in data["GENERATOR"]
gen_bus = bus_lookup[gen["I"]]
if haskey(gen, "OWNER") && gen["OWNER"] === nothing
gen["OWNER"] = gen_bus["OWNER"]
end
if gen["MBASE"] === nothing
gen["MBASE"] = sbase
end
end
end
if haskey(data, "BRANCH")
for branch in data["BRANCH"]
branch_bus = bus_lookup[branch["I"]]
if haskey(branch, "OWNER") && branch["OWNER"] === nothing
branch["OWNER"] = branch_bus["OWNER"]
end
end
end
if haskey(data, "TRANSFORMER")
for transformer in data["TRANSFORMER"]
transformer_bus = bus_lookup[transformer["I"]]
for base_id in ["SBASE1-2", "SBASE2-3", "SBASE3-1"]
if haskey(transformer, base_id) && transformer[base_id] === nothing
transformer[base_id] = sbase
end
end
for winding_id in ["WINDV1", "WINDV2", "WINDV3"]
if haskey(transformer, winding_id) && transformer[winding_id] === nothing
if transformer["CW"] == 2
transformer[winding_id] = transformer_bus["BASKV"]
else
transformer[winding_id] = 1.0
end
end
end
end
end
#=
# TODO update this default value
if haskey(data, "VOLTAGE SOURCE CONVERTER")
for mdc in data["VOLTAGE SOURCE CONVERTER"]
mdc["O1"] = Expr(:call, :_get_component_property, data["BUS"], "OWNER", "I", get(get(component, "CONVERTER BUSES", [Dict()])[1], "IBUS", 0))
end
end
=#
if haskey(data, "GNE DEVICE")
for gne in data["GNE DEVICE"]
gne_bus = bus_lookup[gne["I"]]
if haskey(gne, "OWNER") && gne["OWNER"] === nothing
gne["OWNER"] = gne_bus["OWNER"]
end
if haskey(gne, "NMETR") && gne["NMETR"] === nothing
gne["NMETR"] = gne_bus["NTERM"]
end
end
end
if haskey(data, "INDUCTION MACHINE")
for indm in data["INDUCTION MACHINE"]
indm_bus = bus_lookup[indm["I"]]
if indm["AREA"] === nothing
indm["AREA"] = indm_bus["AREA"]
end
if indm["ZONE"] === nothing
indm["ZONE"] = indm_bus["ZONE"]
end
if indm["OWNER"] === nothing
indm["OWNER"] = indm_bus["OWNER"]
end
if indm["MBASE"] === nothing
indm["MBASE"] = sbase
end
end
end
end
"""
This is an experimental method for parsing elements and setting defaults at the same time.
It is not currently working but would reduce memory allocations if implemented correctly.
"""
function _parse_elements(
elements::Array,
dtypes::Array,
defaults::Dict,
section::AbstractString,
)
data = Dict{String, Any}()
if length(elements) > length(dtypes)
@warn(
"ignoring $(length(elements) - length(dtypes)) extra values in section $section, only $(length(dtypes)) items are defined"
)
elements = elements[1:length(dtypes)]
end
for (i, element) in enumerate(elements)
field, dtype = dtypes[i]
element = strip(element)
if dtype == String
if startswith(element, "'") && endswith(element, "'")
data[field] = element[2:(end - 1)]
else
data[field] = element
end
else
if length(element) <= 0
# this will be set to a default in the cleanup phase
data[field] = nothing
else
try
data[field] = parse(dtype, element)
catch message
if isa(message, Meta.ParseError)
data[field] = element
else
@error(
"value '$element' for $field in section $section is not of type $dtype."
)
end
end
end
end
end
if length(elements) < length(dtypes)
for (field, dtype) in dtypes[length(elements):end]
data[field] = defaults[field]
#=
if length(missing_fields) > 0
for field in missing_fields
data[field] = ""
end
missing_str = join(missing_fields, ", ")
if !(section == "SWITCHED SHUNT" && startswith(missing_str, "N")) &&
!(section == "MULTI-SECTION LINE" && startswith(missing_str, "DUM")) &&
!(section == "IMPEDANCE CORRECTION" && startswith(missing_str, "T"))
@warn("The following fields in $section are missing: $missing_str")
end
end
=#
end
end
return data
end
"""
_parse_line_element!(data, elements, section)
Internal function. Parses a single "line" of data elements from a PTI file, as
given by `elements` which is an array of the line, typically split at `,`.
Elements are parsed into data types given by `section` and saved into `data::Dict`.
"""
function _parse_line_element!(
data::Dict,
elements::Array,
section::AbstractString,
dtypes::Dict{String, Array},
)
missing_fields = []
for (i, (field, dtype)) in enumerate(dtypes[section])
if i > length(elements)
@debug "Have run out of elements in $section at $field" _group =
IS.LOG_GROUP_PARSING
push!(missing_fields, field)
continue
else
element = strip(elements[i])
end
try
if dtype != String && element != ""
data[field] = parse(dtype, element)
else
if dtype == String && startswith(element, "'") && endswith(element, "'")
data[field] = chop(element[nextind(element, 1):end])
else
data[field] = element
end
end
catch message
if isa(message, Meta.ParseError)
data[field] = element
else
error(
"value '$element' for $field in section $section is not of type $dtype.",
)
end
end
end
if length(missing_fields) > 0
for field in missing_fields
data[field] = ""
end
missing_str = join(missing_fields, ", ")
if !(section == "SWITCHED SHUNT" && startswith(missing_str, "N")) &&
!(section == "MULTI-SECTION LINE" && startswith(missing_str, "DUM")) &&
!(section == "IMPEDANCE CORRECTION" && startswith(missing_str, "T"))
@debug "The following fields in $section are missing: $missing_str"
end
end
end
const _comment_split = r"(?!\B[\'][^\']*)[\/](?![^\']*[\']\B)"
const _split_string = r",(?=(?:[^']*'[^']*')*[^']*$)"
"""
_get_line_elements(line)
Internal function. Uses regular expressions to extract all separate data
elements from a line of a PTI file and populate them into an `Array{String}`.
Comments, typically indicated at the end of a line with a `'/'` character,
are also extracted separately, and `Array{Array{String}, String}` is returned.
"""
function _get_line_elements(line::AbstractString)
if count(i -> (i == "'"), line) % 2 == 1
throw(
DataFormatError(
"There are an uneven number of single-quotes in \"{line}\", the line cannot be parsed.",
),
)
end
line_comment = split(line, _comment_split; limit = 2)
line = strip(line_comment[1])
comment = length(line_comment) > 1 ? strip(line_comment[2]) : ""
elements = split(line, _split_string)
return (elements, comment)
end
"""
Process substation data with elements and parse associated nodes
"""
function parse_substation_nodes!(
section_data::Dict{String, Any},
data_lines::Vector{String},
start_line_index::Int,
)::Int
"""Parse nodes for a substation and return the updated line index"""
section_data["NODES"] = []
temp_line_index = start_line_index + 1
# Look for "BEGIN SUBSTATION NODE DATA" comment
while temp_line_index <= length(data_lines)
temp_line = data_lines[temp_line_index]
if contains(temp_line, "BEGIN SUBSTATION NODE DATA")
temp_line_index += 1
break
end
temp_line_index += 1
end
# Parse node data until we hit the end marker
while temp_line_index <= length(data_lines)
temp_line = data_lines[temp_line_index]
if startswith(temp_line, "0 /") && (
contains(temp_line, "END OF SUBSTATION NODE DATA") ||
contains(temp_line, "SUBSTATION TERMINAL DATA")
)
return temp_line_index
end
if contains(temp_line, "BEGIN SUBSTATION DATA BLOCK")
return temp_line_index - 1
end
if !startswith(temp_line, "@!") && !isempty(strip(temp_line))
(check_elements, check_comment) = _get_line_elements(temp_line)
if length(check_elements) == 5 &&
tryparse(Int, strip(check_elements[1])) !== nothing &&
occursin('\'', check_elements[2]) &&
tryparse(Float64, strip(check_elements[3])) !== nothing &&
tryparse(Float64, strip(check_elements[4])) !== nothing &&
tryparse(Float64, strip(check_elements[5])) !== nothing
return temp_line_index - 1
end
end
if startswith(temp_line, "@!")
temp_line_index += 1
continue
end
if !isempty(strip(temp_line))
(node_elements, node_comment) = _get_line_elements(temp_line)
if length(node_elements) >= 4
if length(node_elements) >= 3 &&
length(strip(node_elements[3])) == 3 &&
startswith(strip(node_elements[3]), "'") &&
endswith(strip(node_elements[3]), "'")
return temp_line_index - 1
end
end
if length(node_elements) >= 4 && length(node_elements) <= 6
node_data = Dict{String, Any}()
node_data["NI"] = parse(Int, strip(node_elements[1]))
name_string = strip(node_elements[2])
if startswith(name_string, "'") && endswith(name_string, "'")
name_string = name_string[2:(end - 1)] # Remove quotes
end
node_data["NAME"] = strip(name_string)
i_value = strip(node_elements[3])
if startswith(i_value, "'") && endswith(i_value, "'")
i_value = i_value[2:(end - 1)] # Remove quotes
end
node_data["I"] = parse(Int, strip(i_value))
node_data["STATUS"] = parse(Int, strip(node_elements[4]))
if length(node_elements) >= 5 && !isempty(strip(node_elements[5]))
node_data["VM"] = parse(Float64, strip(node_elements[5]))
end
if length(node_elements) >= 6 && !isempty(strip(node_elements[6]))
node_data["VA"] = parse(Float64, strip(node_elements[6]))
end
push!(section_data["NODES"], node_data)
elseif length(node_elements) > 6
return temp_line_index - 1
end
end
temp_line_index += 1
end
return temp_line_index
end
"""
Process substation data with elements and parse associated nodes
"""
function process_substation_data!(
section_data,
elements,
section,
current_dtypes,
data_lines,
line_index,
pti_data,
)
try
_parse_line_element!(section_data, elements, section, current_dtypes)
if haskey(section_data, "NAME")
section_data["NAME"] = strip(section_data["NAME"])
end
# Parse nodes for this substation
updated_line_index = parse_substation_nodes!(section_data, data_lines, line_index)
if haskey(pti_data, section)
push!(pti_data[section], section_data)
else
pti_data[section] = [section_data]
end
return updated_line_index
catch message
error("Parsing failed at line $line_index: $(sprint(showerror, message))")
end
end
"""
_parse_pti_data(data_string, sections)
Internal function. Parse a PTI raw file into a `Dict`, given the
`data_string` of the file and a list of the `sections` in the PTI
file (typically given by default by `get_pti_sections()`.
"""
function _parse_pti_data(data_io::IO)
sections = deepcopy(_pti_sections)
sections_v35 = deepcopy(_pti_sections_v35)
data_lines = readlines(data_io)
skip_lines = 0
skip_sublines = 0
subsection = ""
is_v35 = false
pti_data = Dict{String, Array{Dict}}()
section = popfirst!(sections)
section_v35 = popfirst!(sections_v35)
section_data = Dict{String, Any}()
if any(startswith.(data_lines, "@!"))
is_v35 = true
end
header_line_start = is_v35 ? 2 : 1 # Start in second line due to @!
# Dynamically handle the start of BUS DATA section
# In v35 files, BUS DATA starts in different lines due to the fields GENERAL,GAUSS,NEWTON,ADJUST,TYSL,SOLVER,RATING
# This fields are optional in the file and when not found, the start of the reading vary a lot
bus_data_start = if is_v35
found_start = 25 # Default of most files
for i in 3:min(35, length(data_lines))
line = strip(data_lines[i])
# Skip comments and system-wide data
if startswith(
line,
r"@!|GENERAL,|GAUSS,|NEWTON,|ADJUST,|TYSL,|SOLVER,|RATING,",
) || isempty(line)
continue
end
# Look for section marker of BUS DATA
if contains(line, "END OF SYSTEM-WIDE DATA") ||
(
tryparse(Int, split(line, ',')[1] |> strip) !== nothing &&
contains(line, "'")
)
found_start = if contains(line, "END OF SYSTEM-WIDE DATA")
(i + (startswith(strip(data_lines[i + 1]), "@!") ? 2 : 1))
else
i
end
break
end
end
# New updated start section
found_start
else
4 # Start for all v33 files
end
current_dtypes = is_v35 ? _pti_dtypes_v35 : _pti_dtypes
line_index = 1
while line_index <= length(data_lines)
line = data_lines[line_index]
if startswith(line, "@!")
line_index += 1
continue
end
(elements, comment) = _get_line_elements(line)
first_element = strip(elements[1])
if is_v35 && (line_index == 3 || line_index == 4) &&
section_v35 == "CASE IDENTIFICATION"
comment_line = strip(line)
comment_key = line_index == 3 ? "Comment_Line_1" : "Comment_Line_2"
if haskey(pti_data, "CASE IDENTIFICATION") &&
!isempty(pti_data["CASE IDENTIFICATION"])
pti_data["CASE IDENTIFICATION"][1][comment_key] = comment_line
@debug "Added $comment_key: $comment_line" _group = IS.LOG_GROUP_PARSING
end
line_index += 1
continue
end
if is_v35 && line_index >= 3 && line_index < bus_data_start
line_index += 1
continue
end
if line_index > (is_v35 ? bus_data_start - 1 : 3) && length(elements) != 0 &&
first_element == "Q"
break
elseif line_index > (is_v35 ? bus_data_start - 1 : 3) && length(elements) != 0 &&
first_element == "0"
if line_index == bus_data_start
section = is_v35 ? popfirst!(sections_v35) : popfirst!(sections)
end
if length(elements) > 1
@info(
"At line $line_index, new section started with '0', but additional non-comment data is present. Pattern '^\\s*0\\s*[/]*.*' is reserved for section start/end.",
)
elseif length(comment) > 0
@debug "At line $line_index, switched to $section" _group =
IS.LOG_GROUP_PARSING
end
current_sections = is_v35 ? sections_v35 : sections
if !isempty(current_sections)
section = popfirst!(current_sections)
end
line_index += 1
continue
else
if line_index == bus_data_start
section = is_v35 ? popfirst!(sections_v35) : popfirst!(sections)
section_data = Dict{String, Any}()
end
if skip_lines > 0
skip_lines -= 1
line_index += 1
continue
end
if section == "IMPEDANCE CORRECTION" && is_v35
temporal_ic_elements = Vector{Vector{String}}()
while line_index <= length(data_lines)
line = data_lines[line_index]
if startswith(line, "0 /") || startswith(line, "Q")
if !isempty(temporal_ic_elements)
last_entry_elements = temporal_ic_elements[end]
section_data_final = Dict{String, Any}()
section_data_final["I"] =
parse(Int64, strip(last_entry_elements[1]))
processing_elements = last_entry_elements[2:end]
point_index = 1
element_index = 1
while element_index <= length(processing_elements) &&
element_index + 2 <= length(processing_elements)
t_str = strip(processing_elements[element_index])
re_str = strip(processing_elements[element_index + 1])
im_str = strip(processing_elements[element_index + 2])
if !isempty(t_str) && !isempty(re_str) && !isempty(im_str)
section_data_final["T$point_index"] =
parse(Float64, t_str)
section_data_final["Re(F$point_index)"] =
parse(Float64, re_str)
section_data_final["Im(F$point_index)"] =
parse(Float64, im_str)
point_index += 1
end
element_index += 3
end
if haskey(pti_data, section)
push!(pti_data[section], section_data_final)
else
pti_data[section] = [section_data_final]
end
end
break
end
if startswith(line, "@!")
line_index += 1
continue
end
if isempty(strip(line))
line_index += 1
continue
end
(elements, comment) = _get_line_elements(line)
first_element = strip(elements[1])
if tryparse(Int64, first_element) === nothing
line_index += 1
if !isempty(temporal_ic_elements)
append!(temporal_ic_elements[end], elements)
end
continue
end
if !isempty(temporal_ic_elements)
last_entry_elements = temporal_ic_elements[end]
section_data_prev = Dict{String, Any}()
section_data_prev["I"] = parse(Int64, strip(last_entry_elements[1]))
processing_elements = last_entry_elements[2:end]
point_index = 1
element_index = 1
while element_index <= length(processing_elements) &&
element_index + 2 <= length(processing_elements)
t_str = strip(processing_elements[element_index])
re_str = strip(processing_elements[element_index + 1])
im_str = strip(processing_elements[element_index + 2])
if !isempty(t_str) && !isempty(re_str) && !isempty(im_str)
section_data_prev["T$point_index"] = parse(Float64, t_str)
section_data_prev["Re(F$point_index)"] =
parse(Float64, re_str)
section_data_prev["Im(F$point_index)"] =
parse(Float64, im_str)
point_index += 1
end
element_index += 3
end
if haskey(pti_data, section)
push!(pti_data[section], section_data_prev)
else
pti_data[section] = [section_data_prev]
end
end
push!(temporal_ic_elements, elements)
line_index += 1
end
elseif !(
section in [
"CASE IDENTIFICATION",
"SWITCHING DEVICE DATA",
"TRANSFORMER",
"VOLTAGE SOURCE CONVERTER",
"IMPEDANCE CORRECTION",
"MULTI-TERMINAL DC",
"TWO-TERMINAL DC",
"GNE DEVICE",
"SUBSTATION DATA",
]
)
section_data = Dict{String, Any}()
try
_parse_line_element!(section_data, elements, section, current_dtypes)
catch message
throw(
@error(
"Parsing failed at line $line_index: $(sprint(showerror, message))"
)
)
end
line_index += 1
elseif section == "CASE IDENTIFICATION"
if line_index == header_line_start
try
_parse_line_element!(
section_data,
elements,
section,
current_dtypes,
)
catch message
throw(
@error(
"Parsing failed at line $line_index: $(sprint(showerror, message))",
),
)
end
if section_data["REV"] != "" && section_data["REV"] < 33
@info(
"Version $(section_data["REV"]) of PTI format is unsupported, parser may not function correctly.",
)
end
if is_v35
if haskey(pti_data, section)
push!(pti_data[section], section_data)
else
pti_data[section] = [section_data]
end
end
else
if is_v35
if line_index == 3
comment_line = strip(line)
if haskey(pti_data, section) && !isempty(pti_data[section])
pti_data[section][1]["Comment_Line_1"] = comment_line
end
elseif line_index == 4
comment_line = strip(line)
if haskey(pti_data, section) && !isempty(pti_data[section])
pti_data[section][1]["Comment_Line_2"] = comment_line
end
end
elseif !is_v35 && line_index > header_line_start
section_data["Comment_Line_$(line_index - 1)"] = strip(line)
end
end
if line_index < (bus_data_start - 1)
line_index += 1
continue
end
line_index += 1
elseif section == "SWITCHING DEVICE"
if is_v35
section_data = Dict{String, Any}()
try
_parse_line_element!(
section_data,
elements,
section,
current_dtypes,
)
catch message
throw(
@error(
"Parsing failed at line $line_index: $(sprint(showerror, message))",
),
)
end
else
@info("SWITCHING DEVICE DATA section found in non-v35 file, skipping.")
end
line_index += 1
elseif section == "TRANSFORMER"
section_data = Dict{String, Any}()
if parse(Int64, _get_line_elements(line)[1][3]) == 0 # two winding transformer
winding = "TWO-WINDING"
skip_lines = 3
elseif parse(Int64, _get_line_elements(line)[1][3]) != 0 # three winding transformer
winding = "THREE-WINDING"
skip_lines = 4
else
@error("Cannot detect type of Transformer")
end
try
for transformer_line in 0:4
if transformer_line == 0
temp_section = section
else
temp_section =
join([section, winding, "LINE", transformer_line], " ")
end
if winding == "TWO-WINDING" && transformer_line == 4
break
else
elements = _get_line_elements(
data_lines[line_index + transformer_line],
)[1]
_parse_line_element!(
section_data,
elements,
temp_section,
current_dtypes,
)
end
end
catch message
throw(
@error(
"Parsing failed at line $line_index: $(sprint(showerror, message))",
),
)
end
line_index += 1
elseif section == "VOLTAGE SOURCE CONVERTER"
vsc_line_length = length(_get_line_elements(line)[1])
# VSC DC LINE DATA can have 5 or 11 elements in all cases possible
# "CSC-VSC ",1, 1.5800, 28,1.0000
# "CSC-VSC ",1, 1.5800, 28,1.0000,,,,,,
# "CSC-VSC ",1, 1.5800, 28,1.0000,1.0,0.0,1.0,0.0,1.0,0.0
# This is how originally the parser was written
if vsc_line_length == 5 || vsc_line_length == 11
section_data = Dict{String, Any}()
try
_parse_line_element!(
section_data,
elements,
section,
current_dtypes,
)
catch message
throw(
@error(
"Parsing failed at line $line_index: $(sprint(showerror, message))",
),
)
end
skip_sublines = 2
line_index += 1
continue
elseif skip_sublines > 0
skip_sublines -= 1
subsection_data = Dict{String, Any}()
for (field, dtype) in _pti_dtypes["$section SUBLINES"]
element = popfirst!(elements)
if element != ""
subsection_data[field] = parse(dtype, element)
else
line_index += 1
subsection_data[field] = ""
end
end
if haskey(section_data, "CONVERTER BUSES")
push!(section_data["CONVERTER BUSES"], subsection_data)
else
section_data["CONVERTER BUSES"] = [subsection_data]
line_index += 1
continue
end
end
line_index += 1
elseif section == "TWO-TERMINAL DC"
section_data = Dict{String, Any}()
if length(_get_line_elements(line)[1]) == 12
(elements, comment) = _get_line_elements(
join(data_lines[line_index:(line_index + 2)], ','),
)
skip_lines = 2
end
try
_parse_line_element!(section_data, elements, section, current_dtypes)
catch message
throw(
@error(
"Parsing failed at line $line_index: $(sprint(showerror, message))",
),
)
end
line_index += 1
elseif section == "IMPEDANCE CORRECTION" && !is_v35
section_data = Dict{String, Any}()
try
_parse_line_element!(section_data, elements, section, current_dtypes)
catch message
throw(
@error(
"Parsing failed at line $line_index: $(sprint(showerror, message))",
),
)
end
line_index += 1
elseif section == "MULTI-TERMINAL DC"
if skip_sublines == 0
section_data = Dict{String, Any}()
try
_parse_line_element!(
section_data,
elements,
section,
current_dtypes,
)
catch message
throw(
@error(
"Parsing failed at line $line_index: $(sprint(showerror, message))",
),
)
end
if section_data["NCONV"] > 0
skip_sublines = section_data["NCONV"]
subsection = "NCONV"
line_index += 1
continue
elseif section_data["NDCBS"] > 0
skip_sublines = section_data["NDCBS"]
subsection = "NDCBS"
line_index += 1
continue
elseif section_data["NDCLN"] > 0
skip_sublines = section_data["NDCLN"]
subsection = "NDCLN"
line_index += 1
continue
end
end
if skip_sublines > 0
skip_sublines -= 1
subsection_data = Dict{String, Any}()
try
_parse_line_element!(
subsection_data,
elements,
"$section $subsection",
current_dtypes,
)
catch message
throw(
error(
"Parsing failed at line $line_index: $(sprint(showerror, message))",
),
)
end
if haskey(section_data, "$(subsection[2:end])")
section_data["$(subsection[2:end])"] =
push!(section_data["$(subsection[2:end])"], subsection_data)
if skip_sublines > 0 && subsection != "NDCLN"
line_index += 1
continue
end
else
section_data["$(subsection[2:end])"] = [subsection_data]
if skip_sublines > 0 && subsection != "NDCLN"
line_index += 1
continue
end
end
if skip_sublines == 0 && subsection != "NDCLN"
if subsection == "NDCBS"
skip_sublines = section_data["NDCLN"]
subsection = "NDCLN"
line_index += 1
continue
elseif subsection == "NCONV"
skip_sublines = section_data["NDCBS"]
subsection = "NDCBS"
line_index += 1
continue
end
elseif skip_sublines == 0 && subsection == "NDCLN"
subsection = ""
else
line_index += 1
continue
end
end
line_index += 1
elseif section == "SUBSTATION DATA" && is_v35
if startswith(line, "@!")
line_index += 1
continue
else
if length(elements) == 4 && occursin('\'', elements[1])
first_part = elements[1]
if occursin(",'", first_part)
comma_quote_pos = findfirst(",'", first_part)
if comma_quote_pos !== nothing
is_part = first_part[1:(comma_quote_pos[1] - 1)]
name_part = first_part[(comma_quote_pos[1] + 1):end]
corrected_elements = [
is_part,
name_part,
elements[2],
elements[3],
elements[4],
]
if length(corrected_elements) == 5 &&
occursin('\'', corrected_elements[2]) &&
tryparse(Float64, strip(corrected_elements[3])) !==
nothing &&
tryparse(Float64, strip(corrected_elements[4])) !==
nothing &&
tryparse(Float64, strip(corrected_elements[5])) !==
nothing
@debug "Parsing substation data line: $line" _group =
IS.LOG_GROUP_PARSING
section_data = Dict{String, Any}()
line_index = process_substation_data!(
section_data,
corrected_elements,
section,
current_dtypes,
data_lines,
line_index,
pti_data,
)
end
end
end
elseif length(elements) == 5 &&
occursin('\'', elements[2]) &&
tryparse(Float64, strip(elements[3])) !== nothing &&
tryparse(Float64, strip(elements[4])) !== nothing &&
tryparse(Float64, strip(elements[5])) !== nothing
section_data = Dict{String, Any}()
line_index = process_substation_data!(
section_data,
elements,
section,
current_dtypes,
data_lines,
line_index,
pti_data,
)
end
line_index += 1
continue
end
line_index += 1
elseif section == "GNE DEVICE"
# TODO: handle multiple lines of GNE Device
@info("GNE DEVICE parsing is not supported.")
line_index += 1
else
line_index += 1
end
end
if subsection != ""
@debug "appending data" _group = IS.LOG_GROUP_PARSING
end
if haskey(pti_data, section)
if section == "IMPEDANCE CORRECTION" &&
pti_data["CASE IDENTIFICATION"][1]["REV"] == 35
continue
else
push!(pti_data[section], section_data)
end
else
pti_data[section] = [section_data]
end
end
_split_breakers_and_branches!(pti_data)
_populate_defaults!(pti_data)
_correct_nothing_values!(pti_data)
return pti_data
end
"""
parse_pti(filename::String)
Open PTI raw file given by `filename`, returning a `Dict` of the data parsed
into the proper types.
"""
function parse_pti(filename::String)::Dict
pti_data = open(filename) do f
parse_pti(f)
end
return pti_data
end
"""
parse_pti(io::IO)
Reads PTI data in `io::IO`, returning a `Dict` of the data parsed into the
proper types.
"""
function parse_pti(io::IO)::Dict
pti_data = _parse_pti_data(io)
try
pti_data["CASE IDENTIFICATION"][1]["NAME"] = match(
r"^\$",
lowercase(io.name),
).captures[1]
catch
throw(error("This file is unrecognized and cannot be parsed"))
end
return pti_data
end
function _split_breakers_and_branches!(data::Dict)
if !haskey(data, "BRANCH")
@info "No BRANCH section found in the system."
return data
end
breakers = sizehint!(eltype(data["BRANCH"])[], length(data["BRANCH"]))
delete_ixs = Int[]
for (ix, item) in enumerate(data["BRANCH"])
if first(item["CKT"]) == '@' || first(item["CKT"]) == '*'
push!(breakers, item)
push!(delete_ixs, ix)
end
end
if isempty(delete_ixs)
@info "No breakers modeled as branches using @ or * found in the system."
return data
else
@info "Found $(length(breakers)) breakers in the system modeled as branches."
end
deleteat!(data["BRANCH"], delete_ixs)
data["SWITCHES_AS_BRANCHES"] = breakers
return data
end
"""
_populate_defaults!(pti_data)
Internal function. Populates empty fields with PSS(R)E PTI v33 default values
"""
function _populate_defaults!(data::Dict)
for section in _pti_sections
if haskey(data, section)
component_defaults = _pti_defaults[section]
for component in data[section]
for (field, field_value) in component
if isa(field_value, Array)
sub_component_defaults = component_defaults[field]
for sub_component in field_value
for (sub_field, sub_field_value) in sub_component
if sub_field_value == ""
try
sub_component[sub_field] =
sub_component_defaults[sub_field]
catch msg
if isa(msg, KeyError)
@warn(
"'$sub_field' in '$field' in '$section' has no default value",
)
else
rethrow(msg)
end
end
end
end
end
elseif field_value == "" &&
!(field in ["Comment_Line_1", "Comment_Line_2"]) &&
!startswith(field, "DUM")
try
component[field] = component_defaults[field]
catch msg
if isa(msg, KeyError)
@warn("'$field' in '$section' has no default value",)
else
rethrow(msg)
end
end
end
end
end
end
end
end
================================================
FILE: src/parsers/pm_io.jl
================================================
include("pm_io/matpower.jl")
include("pm_io/common.jl")
include("pm_io/pti.jl")
include("pm_io/psse.jl")
include("pm_io/data.jl")
================================================
FILE: src/parsers/power_models_data.jl
================================================
"""Container for data parsed by PowerModels"""
struct PowerModelsData
data::Dict{String, Any}
end
"""
Constructs PowerModelsData from a raw file.
Currently Supports MATPOWER and PSSE data files parsed by PowerModels.
"""
function PowerModelsData(file::Union{String, IO}; kwargs...)
validate = get(kwargs, :pm_data_corrections, true)
import_all = get(kwargs, :import_all, false)
correct_branch_rating = get(kwargs, :correct_branch_rating, true)
pm_dict = parse_file(
file;
import_all = import_all,
validate = validate,
correct_branch_rating = correct_branch_rating,
)
pm_data = PowerModelsData(pm_dict)
correct_pm_transformer_status!(pm_data)
return pm_data
end
"""
Constructs a System from PowerModelsData.
# Arguments
- `pm_data::Union{PowerModelsData, Union{String, IO}}`: PowerModels data object or supported
load flow case (*.m, *.raw)
# Keyword arguments
- `ext::Dict`: Contains user-defined parameters. Should only contain standard types.
- `runchecks::Bool`: Run available checks on input fields and when add_component! is called.
Throws InvalidValue if an error is found.
- `time_series_in_memory::Bool=false`: Store time series data in memory instead of HDF5.
- `config_path::String`: specify path to validation config file
- `pm_data_corrections::Bool=true` : Run the PowerModels data corrections (aka :validate in PowerModels)
- `import_all:Bool=false` : Import all fields from PTI files
# Examples
```julia
sys = System(
pm_data, config_path = "ACTIVSg25k_validation.json",
bus_name_formatter = x->string(x["name"]*"-"*string(x["index"])),
load_name_formatter = x->strip(join(x["source_id"], "_"))
)
```
"""
function System(pm_data::PowerModelsData; kwargs...)
runchecks = get(kwargs, :runchecks, true)
data = pm_data.data
if length(data["bus"]) < 1
throw(DataFormatError("There are no buses in this file."))
end
@info "Constructing System from Power Models" data["name"] data["source_type"]
sys = System(data["baseMVA"]; kwargs...)
source_type = data["source_type"]
bus_number_to_bus = read_bus!(sys, data; kwargs...)
read_loads!(sys, data, bus_number_to_bus; kwargs...)
read_loadzones!(sys, data, bus_number_to_bus; kwargs...)
read_gen!(sys, data, bus_number_to_bus; kwargs...)
for component_type in ["switch", "breaker"]
read_switch_breaker!(sys, data, bus_number_to_bus, component_type; kwargs...)
end
read_branch!(sys, data, bus_number_to_bus; kwargs...)
read_switched_shunt!(sys, data, bus_number_to_bus; kwargs...)
read_shunt!(sys, data, bus_number_to_bus; kwargs...)
read_dcline!(sys, data, bus_number_to_bus, source_type; kwargs...)
read_vscline!(sys, data, bus_number_to_bus; kwargs...)
read_facts!(sys, data, bus_number_to_bus; kwargs...)
read_storage!(sys, data, bus_number_to_bus; kwargs...)
read_3w_transformer!(sys, data, bus_number_to_bus; kwargs...)
if runchecks
check(sys)
end
substation_data = get(data, "substation_data", [])
add_geographic_info_to_buses!(sys, substation_data)
return sys
end
function correct_pm_transformer_status!(pm_data::PowerModelsData)
for (k, branch) in pm_data.data["branch"]
f_bus_bvolt = pm_data.data["bus"][branch["f_bus"]]["base_kv"]
t_bus_bvolt = pm_data.data["bus"][branch["t_bus"]]["base_kv"]
percent_difference =
abs(f_bus_bvolt - t_bus_bvolt) / ((f_bus_bvolt + t_bus_bvolt) / 2)
if !branch["transformer"] &&
percent_difference > BRANCH_BUS_VOLTAGE_DIFFERENCE_TOL
branch["transformer"] = true
branch["base_power"] = pm_data.data["baseMVA"]
branch["ext"] = Dict{String, Any}()
@warn "Branch $(branch["f_bus"]) - $(branch["t_bus"]) has different voltage levels endpoints (from: $(f_bus_bvolt)kV, to: $(t_bus_bvolt)kV) which exceed the $(BRANCH_BUS_VOLTAGE_DIFFERENCE_TOL*100)% threshold; converting to transformer."
if !haskey(branch, "base_voltage_from")
branch["base_voltage_from"] = f_bus_bvolt
branch["base_voltage_to"] = t_bus_bvolt
end
end
end
end
"""
Internal component name retrieval from pm2ps_dict
"""
function _get_pm_dict_name(device_dict::Dict)::String
if haskey(device_dict, "shunt_bus")
# With shunts, we have FixedAdmittance and SwitchedAdmittance types.
# To avoid potential name collision, we add the connected bus number to the name.
name = join(strip.(string.((device_dict["shunt_bus"], device_dict["name"]))), "-")
elseif haskey(device_dict, "name")
name = string(device_dict["name"])
elseif haskey(device_dict, "source_id")
name = strip(join(string.(device_dict["source_id"]), "-"))
else
name = string(device_dict["index"])
end
return name
end
function _get_pm_bus_name(device_dict::Dict, unique_names::Bool)
if haskey(device_dict, "name")
if unique_names
name = strip(device_dict["name"])
else
name = strip(device_dict["name"]) * "_" * string(device_dict["bus_i"])
end
else
name = strip(join(string.(device_dict["source_id"]), "-"))
end
return name
end
"""
Internal branch name retrieval from pm2ps_dict
"""
function _get_pm_branch_name(device_dict, bus_f::ACBus, bus_t::ACBus)
# Additional if-else are used to catch line id in PSSe parsing cases
if haskey(device_dict, "name")
index = device_dict["name"]
elseif device_dict["source_id"][1] == "branch" && length(device_dict["source_id"]) > 2
index = strip(device_dict["source_id"][4])
elseif (
device_dict["source_id"][1] == "switch" || device_dict["source_id"][1] == "breaker"
) && length(device_dict["source_id"]) > 2
index = string(device_dict["source_id"][4][2])
elseif device_dict["source_id"][1] == "transformer" &&
length(device_dict["source_id"]) > 3
index = strip(device_dict["source_id"][5])
else
index = device_dict["index"]
end
return "$(get_name(bus_f))-$(get_name(bus_t))-i_$index"
end
function _is_psse_branch_source_id(device_dict::Dict)
if !haskey(device_dict, "source_id") || isempty(device_dict["source_id"])
return false
end
source_type = device_dict["source_id"][1]
return source_type in ("branch", "switch", "breaker", "transformer")
end
function _get_pm_branch_name_with_counter!(
device_dict::Dict,
bus_f::ACBus,
bus_t::ACBus,
branch_pair_counts::Dict{Tuple{String, String}, Int},
)
if _is_psse_branch_source_id(device_dict)
pair_key = (get_name(bus_f), get_name(bus_t))
branch_pair_counts[pair_key] = get(branch_pair_counts, pair_key, 0) + 1
index = branch_pair_counts[pair_key]
return "$(pair_key[1])-$(pair_key[2])-i_$(index)"
end
return _get_pm_branch_name(device_dict, bus_f, bus_t)
end
"""
Internal 3WT name retrieval from pm2ps_dict
"""
function _get_pm_3w_name(
device_dict,
bus_primary::ACBus,
bus_secondary::ACBus,
bus_tertiary::ACBus,
)
ckt = device_dict["circuit"]
return "$(get_name(bus_primary))-$(get_name(bus_secondary))-$(get_name(bus_tertiary))-i_$ckt"
end
"""Add geographic coordinates to all buses using pre-built lookup"""
function add_geographic_info_to_buses!(sys, substation_data)
if isempty(substation_data)
@warn "No substation data found"
return
end
bus_coords_lookup = Dict{Int, GeographicInfo}()
for (_, substation) in substation_data
if haskey(substation, "nodes") && haskey(substation, "latitude") &&
haskey(substation, "longitude")
lat, lon = substation["latitude"], substation["longitude"]
geo_info = GeographicInfo(;
geo_json = Dict(
"type" => "Point",
"coordinates" => [lon, lat],
),
)
for node in substation["nodes"]
if haskey(node, "I")
bus_coords_lookup[node["I"]] = geo_info
end
end
end
end
begin_supplemental_attributes_update(sys) do
buses_with_coords = 0
buses_without_coords = 0
for bus in get_components(ACBus, sys)
bus_number = get_number(bus)
if haskey(bus_coords_lookup, bus_number)
geo_info = bus_coords_lookup[bus_number]
add_supplemental_attribute!(sys, bus, geo_info)
buses_with_coords += 1
else
buses_without_coords += 1
end
end
@info "Added coordinates to $(buses_with_coords) buses, $(buses_without_coords) buses without coordinates"
end
end
"""
Parses ITC data from a dictionary and constructs a lookup table
of piecewise linear scaling functions.
"""
function _impedance_correction_table_lookup(data::Dict)
ict_instances = Dict{Tuple{Int64, WindingCategory}, ImpedanceCorrectionData}()
@info "Reading Impedance Correction Table data"
if !haskey(data, "impedance_correction")
@info "There is no Impedance Correction Table data in this file"
return ict_instances
end
for (_, table_data) in data["impedance_correction"]
table_number = table_data["table_number"]
x = table_data["tap_or_angle"]
y = table_data["scaling_factor"]
if length(x) == length(y)
if length(x) < 2
@warn "Skipping impedance correction entry due to insufficient data points ($(length(x)) < 2): $(x)"
continue
end
pwl_data = PiecewiseLinearData([(x[i], y[i]) for i in eachindex(x)])
table_type =
if (
x[1] >= PSSE_PARSER_TAP_RATIO_LBOUND &&
x[1] <= PSSE_PARSER_TAP_RATIO_UBOUND
)
ImpedanceCorrectionTransformerControlMode.TAP_RATIO
else
ImpedanceCorrectionTransformerControlMode.PHASE_SHIFT_ANGLE
end
for winding_index in instances(WindingCategory)
ict_instances[(table_number, winding_index)] = ImpedanceCorrectionData(;
table_number = table_number,
impedance_correction_curve = pwl_data,
transformer_winding = winding_index,
transformer_control_mode = table_type,
)
end
else
throw(
DataFormatError(
"Impedance correction mismatch at table $table_number: tap/angle and scaling count differs.",
),
)
end
end
return ict_instances
end
"""
Function to attach ICTs to a single Transformer component.
"""
function _attach_single_ict!(
sys::System,
transformer::Union{TwoWindingTransformer, ThreeWindingTransformer},
name::String,
d::Dict,
table_key::String,
winding_idx::WindingCategory,
ict_instances::Dict{Tuple{Int64, WindingCategory}, ImpedanceCorrectionData},
)
if isempty(ict_instances)
return
end
if haskey(d, table_key)
table_number = d[table_key]
cache_key = (table_number, winding_idx)
if haskey(ict_instances, cache_key)
ict = ict_instances[cache_key]
add_supplemental_attribute!(sys, transformer, ict)
else
@debug "No correction table associated with transformer $name for winding $winding_idx."
end
end
return
end
"""
Attaches the corresponding ICT data to a Transformer2W component.
"""
function _attach_impedance_correction_tables!(
sys::System,
transformer::TwoWindingTransformer,
name::String,
d::Dict,
ict_instances::Dict{Tuple{Int64, WindingCategory}, ImpedanceCorrectionData},
)
_attach_single_ict!(
sys,
transformer,
name,
d,
"correction_table",
WindingCategory.TR2W_WINDING,
ict_instances,
)
return
end
"""
Attaches the corresponding ICT data to a Transformer3W component.
"""
function _attach_impedance_correction_tables!(
sys::System,
transformer::ThreeWindingTransformer,
name::String,
d::Dict,
ict_instances::Dict{Tuple{Int64, WindingCategory}, ImpedanceCorrectionData},
)
if isempty(ict_instances)
return
end
for winding_category in instances(WindingCategory)
winding_category == WindingCategory.TR2W_WINDING && continue
key = "$(WINDING_NAMES[winding_category])_correction_table"
_attach_single_ict!(sys, transformer, name, d, key, winding_category, ict_instances)
end
return
end
"""
Creates a PowerSystems.ACBus from a PowerSystems bus dictionary
"""
function make_bus(bus_dict::Dict{String, Any})
bus = ACBus(
bus_dict["number"],
bus_dict["name"],
bus_dict["available"],
bus_dict["bustype"],
bus_dict["angle"],
bus_dict["voltage"],
bus_dict["voltage_limits"],
bus_dict["base_voltage"],
bus_dict["area"],
bus_dict["zone"],
)
return bus
end
function make_bus(
bus_name::Union{String, SubString{String}},
bus_number::Int,
d,
bus_types,
area::Area,
)
bus = make_bus(
Dict{String, Any}(
"name" => bus_name,
"number" => bus_number,
"available" => d["bus_status"],
"bustype" => bus_types[d["bus_type"]],
"angle" => d["va"],
"voltage" => d["vm"],
"voltage_limits" => (min = d["vmin"], max = d["vmax"]),
"base_voltage" => d["base_kv"],
"area" => area,
"zone" => nothing,
),
)
return bus
end
# Disabling this because not all matpower files define areas even when bus definitions
# contain area references.
#function read_area!(sys::System, data::Dict; kwargs...)
# if !haskey(data, "areas")
# @info "There are no Areas in this file"
# return
# end
#
# for (key, val) in data["areas"]
# area = Area(string(val["col_1"]))
# add_component!(sys, area; skip_validation = SKIP_PM_VALIDATION)
# end
#end
function read_bus!(sys::System, data::Dict; kwargs...)
@info "Reading bus data"
bus_number_to_bus = Dict{Int, ACBus}()
bus_types = instances(ACBusTypes)
unique_bus_names = true
bus_data = SortedDict{Int, Any}()
# Bus name uniqueness is not enforced by PSSE. This loop avoids forcing the users to have to
# pass the bus formatter always for larger datasets.
bus_names = Set{String}()
for (k, b) in data["bus"]
# If buses aren't unique stop searching and growing the set
if unique_bus_names && haskey(b, "name")
if b["name"] ∈ bus_names
unique_bus_names = false
end
push!(bus_names, b["name"])
end
bus_data[k] = b
end
if isempty(bus_data)
@error "No bus data found" # TODO : need for a model without a bus
end
default_bus_naming = x -> _get_pm_bus_name(x, unique_bus_names)
_get_name = get(kwargs, :bus_name_formatter, default_bus_naming)
default_area_naming = string
# The formatter for area_name should be a function that transform the Area Int to a String
_get_name_area = get(kwargs, :area_name_formatter, default_area_naming)
for (i, (d_key, d)) in enumerate(bus_data)
# d id the data dict for each bus
# d_key is bus key
bus_name = strip(_get_name(d))
bus_number = Int(d["bus_i"])
area_name = _get_name_area(d["area"])
area = get_component(Area, sys, area_name)
if isnothing(area)
area = Area(area_name)
add_component!(sys, area; skip_validation = SKIP_PM_VALIDATION)
end
# Store area data into ext dictionary
ext = Dict{String, Any}(
"ARNAME" => "",
"I" => "",
"ISW" => "",
"PDES" => "",
"PTOL" => "",
)
if data["source_type"] == "pti" && haskey(data, "area_interchange")
for (_, area_data) in data["area_interchange"]
if haskey(area_data, "area_number") &&
string(area_data["area_number"]) == area_name
ext["ARNAME"] = strip(get(area_data, "area_name", ""))
ext["I"] = string(get(area_data, "area_number", ""))
ext["ISW"] = string(get(area_data, "bus_number", ""))
ext["PDES"] = get(area_data, "net_interchange", "")
ext["PTOL"] = get(area_data, "tol_interchange", "")
break # Only one match is allowed
end
end
end
set_ext!(area, ext)
if !haskey(d, "bus_status")
d["bus_status"] = true
end
bus = make_bus(bus_name, bus_number, d, bus_types, area)
has_component(ACBus, sys, bus_name) && throw(
DataFormatError(
"Found duplicate bus names for $(get_name(bus)), consider reviewing your `bus_name_formatter` function",
),
)
bus_number_to_bus[bus.number] = bus
add_component!(sys, bus; skip_validation = SKIP_PM_VALIDATION)
end
if data["source_type"] == "pti" && haskey(data, "interarea_transfer")
# get Inter-area Transfers as AreaInterchange
for (k, d) in data["interarea_transfer"]
area_from_name = _get_name_area(d["area_from"])
area_to_name = _get_name_area(d["area_to"])
transfer_id = get(d, "transfer_id", "1") # 1 by default
from_area = get_component(Area, sys, area_from_name)
to_area = get_component(Area, sys, area_to_name)
name = "$(area_from_name)_$(area_to_name)_$(transfer_id)"
available = true
active_power_flow = d["power_transfer"]
flow_limits = (from_to = -INFINITE_BOUND, to_from = INFINITE_BOUND)
ext = Dict{String, Any}(
"index" => d["index"],
"source_id" => ["interarea_transfer", k],
)
interarea_inter = AreaInterchange(;
name = name,
available = available,
active_power_flow = active_power_flow,
from_area = from_area,
to_area = to_area,
flow_limits = flow_limits,
ext = ext,
)
add_component!(sys, interarea_inter; skip_validation = SKIP_PM_VALIDATION)
end
end
return bus_number_to_bus
end
function make_interruptible_powerload(d::Dict, bus::ACBus, sys_mbase::Float64; kwargs...)
operation_cost = LoadCost(;
variable = zero(CostCurve),
fixed = 0.0,
)
_get_name = get(kwargs, :load_name_formatter, x -> strip(join(x["source_id"])))
return InterruptiblePowerLoad(;
name = _get_name(d),
available = d["status"],
bus = bus,
active_power = d["pd"],
reactive_power = d["qd"],
max_active_power = d["pd"],
max_reactive_power = d["qd"],
base_power = sys_mbase,
operation_cost = operation_cost,
ext = get(d, "ext", Dict{String, Any}()),
)
end
function make_interruptible_standardload(d::Dict, bus::ACBus, sys_mbase::Float64; kwargs...)
operation_cost = LoadCost(;
variable = zero(CostCurve),
fixed = 0.0,
)
_get_name = get(kwargs, :load_name_formatter, x -> strip(join(x["source_id"])))
return InterruptibleStandardLoad(;
name = _get_name(d),
available = d["status"],
bus = bus,
base_power = sys_mbase,
conformity = d["conformity"],
operation_cost = operation_cost,
constant_active_power = d["pd"],
constant_reactive_power = d["qd"],
current_active_power = d["pi"],
current_reactive_power = d["qi"],
impedance_active_power = d["py"],
impedance_reactive_power = d["qy"],
max_constant_active_power = d["pd"],
max_constant_reactive_power = d["qd"],
max_current_active_power = d["pi"],
max_current_reactive_power = d["qi"],
max_impedance_active_power = d["py"],
max_impedance_reactive_power = d["qy"],
ext = get(d, "ext", Dict{String, Any}()),
)
end
function make_power_load(d::Dict, bus::ACBus, sys_mbase::Float64; kwargs...)
_get_name = get(kwargs, :load_name_formatter, x -> strip(join(x["source_id"])))
return PowerLoad(;
name = _get_name(d),
available = d["status"],
bus = bus,
active_power = d["pd"],
reactive_power = d["qd"],
max_active_power = d["pd"],
max_reactive_power = d["qd"],
base_power = sys_mbase,
conformity = d["conformity"],
ext = get(d, "ext", Dict{String, Any}()),
)
end
function make_standard_load(d::Dict, bus::ACBus, sys_mbase::Float64; kwargs...)
_get_name = get(kwargs, :load_name_formatter, x -> strip(join(x["source_id"])))
return StandardLoad(;
name = _get_name(d),
available = d["status"],
bus = bus,
constant_active_power = d["pd"],
constant_reactive_power = d["qd"],
current_active_power = d["pi"],
current_reactive_power = d["qi"],
impedance_active_power = d["py"],
impedance_reactive_power = d["qy"],
max_constant_active_power = d["pd"],
max_constant_reactive_power = d["qd"],
max_current_active_power = d["pi"],
max_current_reactive_power = d["qi"],
max_impedance_active_power = d["py"],
max_impedance_reactive_power = d["qy"],
base_power = sys_mbase,
conformity = d["conformity"],
ext = get(d, "ext", Dict{String, Any}()),
)
end
function read_loads!(sys::System, data, bus_number_to_bus::Dict{Int, ACBus}; kwargs...)
@info "Reading Load data in PowerModels dict to populate System ..."
if !haskey(data, "load")
@error "There are no loads in this file"
return
end
sys_mbase = data["baseMVA"]
for d_key in keys(data["load"])
d = data["load"][d_key]
bus = bus_number_to_bus[d["load_bus"]]
is_interruptible = haskey(d, "interruptible")
if data["source_type"] == "pti" && is_interruptible && d["interruptible"] != 1
load = make_standard_load(d, bus, sys_mbase; kwargs...)
has_component(StandardLoad, sys, get_name(load)) && throw(
DataFormatError(
"Found duplicate load names of $(summary(load)), consider formatting names with `load_name_formatter` kwarg",
),
)
elseif data["source_type"] == "pti" && is_interruptible && d["interruptible"] == 1
load = make_interruptible_standardload(d, bus, sys_mbase; kwargs...)
has_component(InterruptibleStandardLoad, sys, get_name(load)) && throw(
DataFormatError(
"Found duplicate interruptible load names of $(summary(load)), consider formatting names with `load_name_formatter` kwarg",
),
)
else
load = make_power_load(d, bus, sys_mbase; kwargs...)
has_component(PowerLoad, sys, get_name(load)) && throw(
DataFormatError(
"Found duplicate load names of $(summary(load)), consider formatting names with `load_name_formatter` kwarg",
),
)
end
add_component!(sys, load; skip_validation = SKIP_PM_VALIDATION)
end
end
function make_loadzone(
name::String,
active_power::Float64,
reactive_power::Float64;
kwargs...,
)
return LoadZone(;
name = name,
peak_active_power = active_power,
peak_reactive_power = reactive_power,
)
end
function read_loadzones!(
sys::System,
data::Dict{String, Any},
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading LoadZones data in PowerModels dict to populate System ..."
zones = Set{Int}()
zone_bus_map = Dict{Int, Vector}()
for (_, bus) in data["bus"]
push!(zones, bus["zone"])
push!(get!(zone_bus_map, bus["zone"], Vector()), bus)
end
load_zone_map =
Dict{Int, Dict{String, Float64}}(i => Dict("pd" => 0.0, "qd" => 0.0) for i in zones)
for (key, load) in data["load"]
zone = data["bus"][load["load_bus"]]["zone"]
load_zone_map[zone]["pd"] += load["pd"]
load_zone_map[zone]["qd"] += load["qd"]
# Use get with defaults because matpower data doesn't have other load representations
load_zone_map[zone]["pd"] += get(load, "pi", 0.0)
load_zone_map[zone]["qd"] += get(load, "qi", 0.0)
load_zone_map[zone]["pd"] += get(load, "py", 0.0)
load_zone_map[zone]["qd"] += get(load, "qy", 0.0)
end
default_loadzone_naming = string
# The formatter for loadzone_name should be a function that transform the LoadZone Int to a String
_get_name = get(kwargs, :loadzone_name_formatter, default_loadzone_naming)
@info "Reading Zone data"
if !haskey(data, "zone")
@info "There is no Zone data in this file"
else
for (_, v) in data["zone"]
zone_number = v["zone_number"]
if !(zone_number in zones)
@warn "Skipping empty LoadZone $(zone_number)-$(v["zone_name"])"
end
end
end
for zone in zones
name = _get_name(zone)
load_zone = make_loadzone(
name,
load_zone_map[zone]["pd"],
load_zone_map[zone]["qd"];
kwargs...,
)
add_component!(sys, load_zone; skip_validation = SKIP_PM_VALIDATION)
for bus in zone_bus_map[zone]
set_load_zone!(bus_number_to_bus[bus["bus_i"]], load_zone)
end
end
end
function make_hydro_dispatch(
gen_name::Union{SubString{String}, String},
d::Dict,
bus::ACBus,
sys_mbase::Float64,
)
curtailcost = HydroGenerationCost(zero(CostCurve), 0.0)
if d["mbase"] != 0.0
mbase = d["mbase"]
else
@warn "Generator $gen_name has base power equal to zero: $(d["mbase"]). Changing it to system base: $sys_mbase" _group =
IS.LOG_GROUP_PARSING
mbase = sys_mbase
end
base_conversion = sys_mbase / mbase
return HydroDispatch(; # No way to define storage parameters for gens in PM so can only make HydroDispatch
name = gen_name,
available = Bool(d["gen_status"]),
bus = bus,
active_power = d["pg"] * base_conversion,
reactive_power = d["qg"] * base_conversion,
rating = calculate_gen_rating(d["pmax"], d["qmax"], base_conversion),
prime_mover_type = parse_enum_mapping(PrimeMovers, d["type"]),
active_power_limits = (
min = d["pmin"] * base_conversion,
max = d["pmax"] * base_conversion,
),
reactive_power_limits = (
min = d["qmin"] * base_conversion,
max = d["qmax"] * base_conversion,
),
ramp_limits = calculate_ramp_limit(d, gen_name),
time_limits = nothing,
operation_cost = curtailcost,
base_power = mbase,
)
end
function make_hydro_reservoir(
gen_name::Union{SubString{String}, String},
d::Dict,
bus::ACBus,
sys_mbase::Float64,
)
curtailcost = HydroGenerationCost(zero(CostCurve), 0.0)
if d["mbase"] != 0.0
mbase = d["mbase"]
else
@warn "Generator $gen_name has base power equal to zero: $(d["mbase"]). Changing it to system base: $sys_mbase" _group =
IS.LOG_GROUP_PARSING
mbase = sys_mbase
end
base_conversion = sys_mbase / mbase
return HydroDispatch(; # No way to define storage parameters for gens in PM so can only make HydroDispatch
name = gen_name,
available = Bool(d["gen_status"]),
bus = bus,
active_power = d["pg"] * base_conversion,
reactive_power = d["qg"] * base_conversion,
rating = calculate_gen_rating(d["pmax"], d["qmax"], base_conversion),
prime_mover_type = parse_enum_mapping(PrimeMovers, d["type"]),
active_power_limits = (
min = d["pmin"] * base_conversion,
max = d["pmax"] * base_conversion,
),
reactive_power_limits = (
min = d["qmin"] * base_conversion,
max = d["qmax"] * base_conversion,
),
ramp_limits = calculate_ramp_limit(d, gen_name),
time_limits = nothing,
operation_cost = curtailcost,
base_power = mbase,
)
end
function make_renewable_dispatch(
gen_name::Union{SubString{String}, String},
d::Dict,
bus::ACBus,
sys_mbase::Float64,
)
cost = RenewableGenerationCost(zero(CostCurve))
if d["mbase"] != 0.0
mbase = d["mbase"]
else
@warn "Generator $gen_name has base power equal to zero: $(d["mbase"]). Changing it to system base: $sys_mbase" _group =
IS.LOG_GROUP_PARSING
mbase = sys_mbase
end
base_conversion = sys_mbase / mbase
rating = calculate_gen_rating(d["pmax"], d["qmax"], base_conversion)
if rating > mbase
@warn "rating is larger than base power for $gen_name, setting to $mbase" _group =
IS.LOG_GROUP_PARSING
rating = mbase
end
generator = RenewableDispatch(;
name = gen_name,
available = Bool(d["gen_status"]),
bus = bus,
active_power = d["pg"] * base_conversion,
reactive_power = d["qg"] * base_conversion,
rating = rating * base_conversion,
prime_mover_type = parse_enum_mapping(PrimeMovers, d["type"]),
reactive_power_limits = (
min = d["qmin"] * base_conversion,
max = d["qmax"] * base_conversion,
),
power_factor = 1.0,
operation_cost = cost,
base_power = mbase,
)
return generator
end
function make_renewable_fix(
gen_name::Union{SubString{String}, String},
d::Dict,
bus::ACBus,
sys_mbase::Float64,
)
if d["mbase"] != 0.0
mbase = d["mbase"]
else
@warn "Generator $gen_name has base power equal to zero: $(d["mbase"]). Changing it to system base: $sys_mbase" _group =
IS.LOG_GROUP_PARSING
mbase = sys_mbase
end
base_conversion = sys_mbase / mbase
generator = RenewableNonDispatch(;
name = gen_name,
available = Bool(d["gen_status"]),
bus = bus,
active_power = d["pg"] * base_conversion,
reactive_power = d["qg"] * base_conversion,
rating = float(d["pmax"]) * base_conversion,
prime_mover_type = parse_enum_mapping(PrimeMovers, d["type"]),
power_factor = 1.0,
base_power = mbase,
)
return generator
end
function make_generic_battery(
storage_name::Union{SubString{String}, String},
d::Dict,
bus::ACBus,
)
energy_rating = iszero(d["energy_rating"]) ? d["energy"] : d["energy_rating"]
storage = EnergyReservoirStorage(;
name = storage_name,
available = Bool(d["status"]),
bus = bus,
prime_mover_type = PrimeMovers.BA,
storage_technology_type = StorageTech.OTHER_CHEM,
storage_capacity = energy_rating,
storage_level_limits = (min = 0.0, max = energy_rating),
initial_storage_capacity_level = d["energy"] / energy_rating,
rating = d["thermal_rating"],
active_power = d["ps"],
input_active_power_limits = (min = 0.0, max = d["charge_rating"]),
output_active_power_limits = (min = 0.0, max = d["discharge_rating"]),
efficiency = (in = d["charge_efficiency"], out = d["discharge_efficiency"]),
reactive_power = d["qs"],
reactive_power_limits = (min = d["qmin"], max = d["qmax"]),
base_power = d["thermal_rating"],
)
return storage
end
function _is_likely_motor_load(d::Dict, gen_name::Union{SubString{String}, String})
# A motor load is likely if it has a negative active power and a non-zero reactive power.
# This is a heuristic and may not be accurate for all cases.
# likely_motor_load
if d["pmin"] < 0 && d["pmax"] < 0 && d["pg"] < 0
@warn "Generator $gen_name is likely a motor load with negative active power: $(d["pg"]) and negative power limits: (min = $(d["pmin"]), max = $(d["pmax"])) \
this component will be parsed as a thermal generator with negative active power limits. You can convert the device to a MotorLoad for more accurate modeling."
end
if d["pmin"] == 0 && d["pmax"] == 0 && d["pg"] < 0
@warn "Generator $gen_name is likely a motor load with negative active power: $(d["pg"]) and undefined active power limits \
this component will be parsed as a thermal generator with negative active power injection. You can convert the device to a MotorLoad for more accurate modeling."
end
if d["pmin"] < 0 && d["pmax"] == 0
@warn "Generator $gen_name is likely something that is not a ThermalGenerators with negative power limits: (min = $(d["pmin"]), max = $(d["pmax"])) \
this component will be parsed as a thermal generator with negative active power limits. Check this entry for more accurate modeling."
end
return
end
# TODO test this more directly?
"""
The polynomial term follows the convention that for an n-degree polynomial, at least n + 1 components are needed.
c(p) = c_n*p^n+...+c_1p+c_0
c_o is stored in the field in of the Econ Struct
"""
function make_thermal_gen(
gen_name::Union{SubString{String}, String},
d::Dict,
bus::ACBus,
sys_mbase::Float64,
)
if haskey(d, "model")
model = GeneratorCostModels(d["model"])
# Input data layout: table B-4 of https://matpower.org/docs/MATPOWER-manual.pdf
if model == GeneratorCostModels.PIECEWISE_LINEAR
# For now, we make the fixed cost the y-intercept of the first segment of the
# piecewise curve and the variable cost a PiecewiseLinearData representing
# the data minus this fixed cost; in a future update, there will be no
# separation between the PiecewiseLinearData and the fixed cost.
cost_component = d["cost"]
power_p = [i for (ix, i) in enumerate(cost_component) if isodd(ix)]
cost_p = [i for (ix, i) in enumerate(cost_component) if iseven(ix)]
points = collect(zip(power_p, cost_p))
(first_x, first_y) = first(points)
fixed = max(0.0,
first_y - first(get_slopes(PiecewiseLinearData(points))) * first_x,
)
cost = PiecewiseLinearData([(x, y - fixed) for (x, y) in points])
elseif model == GeneratorCostModels.POLYNOMIAL
# For now, we make the variable cost a QuadraticFunctionData with all but the
# constant term and make the fixed cost the constant term; in a future update,
# there will be no separation between the QuadraticFunctionData and the fixed
# cost.
# This transforms [3.0, 1.0, 4.0, 2.0] into [(1, 4.0), (2, 1.0), (3, 3.0)]
coeffs = enumerate(reverse(d["cost"][1:(end - 1)]))
coeffs = Dict((i, c / sys_mbase^i) for (i, c) in coeffs)
quadratic_degrees = [2, 1, 0]
(keys(coeffs) <= Set(quadratic_degrees)) || throw(
ArgumentError(
"Can only handle polynomials up to degree two; given coefficients $coeffs",
),
)
cost = QuadraticFunctionData(get.(Ref(coeffs), quadratic_degrees, 0)...)
fixed = (d["ncost"] >= 1) ? last(d["cost"]) : 0.0
end
cost = CostCurve(InputOutputCurve((cost)), UnitSystem.DEVICE_BASE)
startup = d["startup"]
shutdn = d["shutdown"]
else
@warn "Generator cost data not included for Generator: $gen_name"
tmpcost = ThermalGenerationCost(nothing)
cost = tmpcost.variable
fixed = tmpcost.fixed
startup = tmpcost.start_up
shutdn = tmpcost.shut_down
end
operation_cost = ThermalGenerationCost(;
variable = cost,
fixed = fixed,
start_up = startup,
shut_down = shutdn,
)
if !haskey(d, "ext")
d["ext"] = Dict{String, Float64}()
end
if haskey(d, "r_source") && haskey(d, "x_source")
d["ext"]["r"] = d["r_source"]
d["ext"]["x"] = d["x_source"]
end
if haskey(d, "rt_source") && haskey(d, "xt_source")
d["ext"]["rt"] = d["rt_source"]
d["ext"]["xt"] = d["xt_source"]
end
if d["mbase"] != 0.0
mbase = d["mbase"]
else
@warn "Generator $gen_name has base power equal to zero: $(d["mbase"]). Changing it to system base: $sys_mbase" _group =
IS.LOG_GROUP_PARSING
mbase = sys_mbase
end
base_conversion = sys_mbase / mbase
_is_likely_motor_load(d, gen_name)
thermal_gen = ThermalStandard(;
name = gen_name,
status = Bool(d["gen_status"]),
available = Bool(d["gen_status"]),
bus = bus,
active_power = d["pg"] * base_conversion,
reactive_power = d["qg"] * base_conversion,
rating = calculate_gen_rating(d["pmax"], d["qmax"], base_conversion),
prime_mover_type = parse_enum_mapping(PrimeMovers, d["type"]),
fuel = parse_enum_mapping(ThermalFuels, d["fuel"]),
active_power_limits = (
min = d["pmin"] * base_conversion,
max = d["pmax"] * base_conversion,
),
reactive_power_limits = (
min = d["qmin"] * base_conversion,
max = d["qmax"] * base_conversion,
),
ramp_limits = calculate_ramp_limit(d, gen_name),
time_limits = nothing,
operation_cost = operation_cost,
base_power = mbase,
ext = get(d, "ext", Dict{String, Any}()),
)
return thermal_gen
end
function make_synchronous_condenser(
gen_name::Union{SubString{String}, String},
d::Dict,
bus::ACBus,
sys_mbase::Float64,
)
ext = get(d, "ext", Dict{String, Any}())
if haskey(d, "r_source") && haskey(d, "x_source")
ext["r"] = d["r_source"]
ext["x"] = d["x_source"]
end
if haskey(d, "rt_source") && haskey(d, "xt_source")
ext["rt"] = d["rt_source"]
ext["xt"] = d["xt_source"]
end
if d["mbase"] != 0.0
mbase = d["mbase"]
else
@warn "Generator $gen_name has base power equal to zero: $(d["mbase"]). Changing it to system base: $sys_mbase" _group =
IS.LOG_GROUP_PARSING
mbase = sys_mbase
end
# NOTE: qmax and qmin can be both negatives, so this approach is taken for the rating.
base_conversion = sys_mbase / mbase
synchronous_condenser = SynchronousCondenser(;
name = gen_name,
available = Bool(d["gen_status"]),
bus = bus,
reactive_power = d["qg"] * base_conversion,
rating = max(abs(d["qmax"]), abs(d["qmin"])) * base_conversion,
reactive_power_limits = (
min = d["qmin"] * base_conversion,
max = d["qmax"] * base_conversion,
),
base_power = mbase,
ext = ext,
)
return synchronous_condenser
end
"""
Transfer generators to ps_dict according to their classification
"""
function read_gen!(sys::System, data::Dict, bus_number_to_bus::Dict{Int, ACBus}; kwargs...)
@info "Reading generator data"
if !haskey(data, "gen")
@error "There are no Generators in this file"
return nothing
end
generator_mapping = get(kwargs, :generator_mapping, GENERATOR_MAPPING_FILE_PM)
try
generator_mapping = get_generator_mapping(generator_mapping)
catch e
@error "Error loading generator mapping $(generator_mapping)"
rethrow(e)
end
sys_mbase = data["baseMVA"]
_get_name = get(kwargs, :gen_name_formatter, _get_pm_dict_name)
for (name, pm_gen) in data["gen"]
gen_name = _get_name(pm_gen)
bus = bus_number_to_bus[pm_gen["gen_bus"]]
pm_gen["fuel"] = get(pm_gen, "fuel", "OTHER")
pm_gen["type"] = get(pm_gen, "type", "OT")
@debug "Found generator" _group = IS.LOG_GROUP_PARSING gen_name bus pm_gen["fuel"] pm_gen["type"]
gen_type = get_generator_type(pm_gen["fuel"], pm_gen["type"], generator_mapping)
if gen_type == ThermalStandard
generator = make_thermal_gen(gen_name, pm_gen, bus, sys_mbase)
elseif gen_type == HydroDispatch
generator = make_hydro_dispatch(gen_name, pm_gen, bus, sys_mbase)
elseif gen_type == HydroTurbine
# This method adds a
generator = make_hydro_reservoir(gen_name, pm_gen, bus, sys_mbase)
elseif gen_type == RenewableDispatch
generator = make_renewable_dispatch(gen_name, pm_gen, bus, sys_mbase)
elseif gen_type == RenewableNonDispatch
generator = make_renewable_fix(gen_name, pm_gen, bus, sys_mbase)
elseif gen_type == SynchronousCondenser
generator = make_synchronous_condenser(gen_name, pm_gen, bus, sys_mbase)
elseif gen_type == EnergyReservoirStorage
@warn "EnergyReservoirStorage should be defined as a PowerModels storage... Skipping"
continue
else
@error "Skipping unsupported generator" gen_type
continue
end
has_component(typeof(generator), sys, get_name(generator)) && throw(
DataFormatError(
"Found duplicate $(typeof(generator)) names of $(get_name(generator)), consider formatting names with `gen_name_formatter` kwarg",
),
)
add_component!(sys, generator; skip_validation = SKIP_PM_VALIDATION)
end
end
const _SHIFT_TO_GROUP_MAP = Dict{Float64, WindingGroupNumber}(
0.0 => WindingGroupNumber.GROUP_0,
-30.0 => WindingGroupNumber.GROUP_1,
-150.0 => WindingGroupNumber.GROUP_5,
180.0 => WindingGroupNumber.GROUP_6,
150.0 => WindingGroupNumber.GROUP_7,
30.0 => WindingGroupNumber.GROUP_11,
)
function _add_vector_control_group(d::Dict, angle_key::String, group_key::String)
angle = d[angle_key]
for (angle_key_deg, group) in _SHIFT_TO_GROUP_MAP
if isapprox(rad2deg(angle), angle_key_deg)
d[group_key] = group
return
end
end
d[group_key] = WindingGroupNumber.UNDEFINED
return
end
function get_branch_type_matpower(
d::Dict,
)
tap = d["tap"]
shift = d["shift"]
is_transformer = d["transformer"]
if !is_transformer
is_transformer = (tap != 0.0) && (tap != 1.0) || (shift != 0.0)
end
is_transformer || return Line
_add_vector_control_group(d, "shift", "group_number")
if d["group_number"] == WindingGroupNumber.UNDEFINED
return PhaseShiftingTransformer
elseif tap != 1.0
return TapTransformer
else
return Transformer2W
end
end
function get_branch_type_psse(
d::Dict,
)
if d["br_r"] == 0.0 && d["br_x"] == 0.0
return DiscreteControlledACBranch
end
is_transformer = d["transformer"]
tap = d["tap"]
if !is_transformer
if (tap != 0.0) && (tap != 1.0)
@warn "Transformer $d has tap ratio $tap, which is not 0.0 or 1.0; this is not a valid value for a Line. Parsing entry as a Transformer"
is_transformer = true
_add_vector_control_group(d, "shift", "group_number")
else
return Line
end
end
_add_vector_control_group(d, "shift", "group_number")
is_tap_controllable, is_alpha_controllable = _determine_control_modes(d, "COD1", "tap")
if d["group_number"] == WindingGroupNumber.UNDEFINED || is_alpha_controllable
return PhaseShiftingTransformer
elseif (is_tap_controllable || (tap != 1.0)) &&
d["group_number"] != WindingGroupNumber.UNDEFINED
return TapTransformer
elseif !is_tap_controllable && d["group_number"] != WindingGroupNumber.UNDEFINED
return Transformer2W
else
error("Couldn't infer the branch type for branch $d")
end
end
function make_branch(
name::String,
d::Dict,
bus_f::ACBus,
bus_t::ACBus,
source_type::String;
kwargs...,
)
if source_type == "matpower"
branch_type = get_branch_type_matpower(d)
elseif source_type == "pti"
branch_type = get_branch_type_psse(d)
else
error("Source Type $source_type not supported")
end
if d["transformer"] && branch_type == Line
throw(
DataFormatError(
"Branch data mismatched, cannot build the branch correctly for $d",
),
)
elseif branch_type == DiscreteControlledACBranch
value = _make_switch_from_zero_impedance_line(name, d, bus_f, bus_t)
elseif branch_type == Transformer2W
value = make_transformer_2w(name, d, bus_f, bus_t; kwargs...)
elseif branch_type == TapTransformer
value = make_tap_transformer(name, d, bus_f, bus_t; kwargs...)
elseif branch_type == PhaseShiftingTransformer
value = make_phase_shifting_transformer(name, d, bus_f, bus_t; kwargs...)
elseif branch_type == Line
value = make_line(name, d, bus_f, bus_t)
else
error("Unsupported branch type $branch_type")
end
return value
end
function _make_switch_from_zero_impedance_line(
name::String,
d::Dict,
bus_f::ACBus,
bus_t::ACBus,
)
pf = get(d, "pf", 0.0)
qf = get(d, "qf", 0.0)
available_value = d["br_status"] == 1
if get_bustype(bus_f) == ACBusTypes.ISOLATED ||
get_bustype(bus_t) == ACBusTypes.ISOLATED
available_value = false
end
if available_value == true
status_value = DiscreteControlledBranchStatus.CLOSED
else
status_value = DiscreteControlledBranchStatus.OPEN
end
@warn "Branch $name has zero impedance and available = $available_value; converting to a DiscreteControlledACBranch of type SWITCH with available = $available_value and branch_status = $status_value"
return DiscreteControlledACBranch(;
name = name,
available = Bool(available_value),
active_power_flow = pf,
reactive_power_flow = qf,
arc = Arc(bus_f, bus_t),
r = d["br_r"],
x = d["br_x"],
rating = _get_rating("Line", name, d, "rate_a"),
discrete_branch_type = DiscreteControlledBranchType.SWITCH,
branch_status = status_value,
)
end
function _get_rating(
branch_type::String,
name::AbstractString,
line_data::Dict,
key::String,
)
haskey(line_data, key) || return key == "rate_a" ? INFINITE_BOUND : nothing
if isapprox(line_data[key], 0.0)
@info(
"$branch_type $name rating value: $(line_data[key]). Unbounded value implied as per PSSe Manual"
)
return INFINITE_BOUND
else
return line_data[key]
end
end
function make_line(name::String, d::Dict, bus_f::ACBus, bus_t::ACBus)
pf = get(d, "pf", 0.0)
qf = get(d, "qf", 0.0)
available_value = d["br_status"] == 1
if get_bustype(bus_f) == ACBusTypes.ISOLATED ||
get_bustype(bus_t) == ACBusTypes.ISOLATED
available_value = false
end
ext = haskey(d, "ext") ? d["ext"] : Dict{String, Any}()
return Line(;
name = name,
available = available_value,
active_power_flow = pf,
reactive_power_flow = qf,
arc = Arc(bus_f, bus_t),
r = d["br_r"],
x = d["br_x"],
b = (from = d["b_fr"], to = d["b_to"]),
rating = _get_rating("Line", name, d, "rate_a"),
angle_limits = (min = d["angmin"], max = d["angmax"]),
rating_b = _get_rating("Line", name, d, "rate_b"),
rating_c = _get_rating("Line", name, d, "rate_c"),
ext = ext,
)
end
function make_switch_breaker(name::String, d::Dict, bus_f::ACBus, bus_t::ACBus)
return DiscreteControlledACBranch(;
name = name,
available = Bool(d["state"]),
active_power_flow = d["active_power_flow"],
reactive_power_flow = d["reactive_power_flow"],
arc = Arc(bus_f, bus_t),
r = d["r"],
x = d["x"],
rating = d["rating"],
discrete_branch_type = d["discrete_branch_type"],
branch_status = d["state"],
ext = get(d, "ext", Dict{String, Any}()),
)
end
function read_switch_breaker!(
sys::System,
data::Dict,
bus_number_to_bus::Dict{Int, ACBus},
device_type::String;
kwargs...,
)
@info "Reading $device_type data"
if !haskey(data, device_type)
@info "There is no $device_type data in this file"
return
end
_get_name = get(kwargs, :branch_name_formatter, _get_pm_branch_name)
for (_, d) in data[device_type]
bus_f = bus_number_to_bus[d["f_bus"]]
bus_t = bus_number_to_bus[d["t_bus"]]
name = _get_name(d, bus_f, bus_t)
value = make_switch_breaker(name, d, bus_f, bus_t)
add_component!(sys, value; skip_validation = SKIP_PM_VALIDATION)
end
end
function make_transformer_2w(
name::String,
d::Dict,
bus_f::ACBus,
bus_t::ACBus;
kwargs...,
)
pf = get(d, "pf", 0.0)
qf = get(d, "qf", 0.0)
available_value = d["br_status"] == 1
if get_bustype(bus_f) == ACBusTypes.ISOLATED ||
get_bustype(bus_t) == ACBusTypes.ISOLATED
available_value = false
end
return Transformer2W(;
name = name,
available = available_value,
active_power_flow = pf,
reactive_power_flow = qf,
arc = Arc(bus_f, bus_t),
r = d["br_r"],
x = d["br_x"],
primary_shunt = d["g_fr"] + im * d["b_fr"],
winding_group_number = d["group_number"],
rating = _get_rating("Transformer2W", name, d, "rate_a"),
rating_b = _get_rating("Transformer2W", name, d, "rate_b"),
rating_c = _get_rating("Transformer2W", name, d, "rate_c"),
base_power = d["base_power"],
# for psse inputs, these numbers may be different than the buses' base voltages
base_voltage_primary = d["base_voltage_from"],
base_voltage_secondary = d["base_voltage_to"],
ext = get(d, "ext", Dict{String, Any}()),
)
end
function make_3w_transformer(
name::String,
d::Dict,
bus_primary::ACBus,
bus_secondary::ACBus,
bus_tertiary::ACBus,
star_bus::ACBus,
)
pf = get(d, "pf", 0.0)
qf = get(d, "qf", 0.0)
return Transformer3W(;
name = name,
available = d["available"],
primary_star_arc = Arc(bus_primary, star_bus),
secondary_star_arc = Arc(bus_secondary, star_bus),
tertiary_star_arc = Arc(bus_tertiary, star_bus),
star_bus = star_bus,
active_power_flow_primary = pf,
reactive_power_flow_primary = qf,
active_power_flow_secondary = pf,
reactive_power_flow_secondary = qf,
active_power_flow_tertiary = pf,
reactive_power_flow_tertiary = qf,
r_primary = d["r_primary"],
x_primary = d["x_primary"],
r_secondary = d["r_secondary"],
x_secondary = d["x_secondary"],
r_tertiary = d["r_tertiary"],
x_tertiary = d["x_tertiary"],
rating = d["rating"],
r_12 = d["r_12"],
x_12 = d["x_12"],
r_23 = d["r_23"],
x_23 = d["x_23"],
r_13 = d["r_13"],
x_13 = d["x_13"],
base_power_12 = d["base_power_12"],
base_power_23 = d["base_power_23"],
base_power_13 = d["base_power_13"],
base_voltage_primary = d["base_voltage_primary"],
base_voltage_secondary = d["base_voltage_secondary"],
base_voltage_tertiary = d["base_voltage_tertiary"],
g = d["g"],
b = d["b"],
primary_turns_ratio = d["primary_turns_ratio"],
secondary_turns_ratio = d["secondary_turns_ratio"],
tertiary_turns_ratio = d["tertiary_turns_ratio"],
available_primary = d["available_primary"],
available_secondary = d["available_secondary"],
available_tertiary = d["available_tertiary"],
rating_primary = _get_rating("Transformer3W", name, d, "rating_primary"),
rating_secondary = _get_rating("Transformer3W", name, d, "rating_secondary"),
rating_tertiary = _get_rating("Transformer3W", name, d, "rating_tertiary"),
primary_group_number = d["primary_group_number"],
secondary_group_number = d["secondary_group_number"],
tertiary_group_number = d["tertiary_group_number"],
control_objective_primary = get(d, "COD1", -99),
control_objective_secondary = get(d, "COD2", -99),
control_objective_tertiary = get(d, "COD3", -99),
ext = get(d, "ext", Dict{String, Any}()),
)
end
function make_3w_phase_shifting_transformer(
name::String,
d::Dict,
bus_primary::ACBus,
bus_secondary::ACBus,
bus_tertiary::ACBus,
star_bus::ACBus,
)
pf = get(d, "pf", 0.0)
qf = get(d, "qf", 0.0)
return PhaseShiftingTransformer3W(;
name = name,
available = d["available"],
primary_star_arc = Arc(bus_primary, star_bus),
secondary_star_arc = Arc(bus_secondary, star_bus),
tertiary_star_arc = Arc(bus_tertiary, star_bus),
star_bus = star_bus,
active_power_flow_primary = pf,
reactive_power_flow_primary = qf,
active_power_flow_secondary = pf,
reactive_power_flow_secondary = qf,
active_power_flow_tertiary = pf,
reactive_power_flow_tertiary = qf,
r_primary = d["r_primary"],
x_primary = d["x_primary"],
r_secondary = d["r_secondary"],
x_secondary = d["x_secondary"],
r_tertiary = d["r_tertiary"],
x_tertiary = d["x_tertiary"],
rating = d["rating"],
r_12 = d["r_12"],
x_12 = d["x_12"],
r_23 = d["r_23"],
x_23 = d["x_23"],
r_13 = d["r_13"],
x_13 = d["x_13"],
α_primary = d["primary_phase_shift_angle"],
α_secondary = d["secondary_phase_shift_angle"],
α_tertiary = d["tertiary_phase_shift_angle"],
base_power_12 = d["base_power_12"],
base_power_23 = d["base_power_23"],
base_power_13 = d["base_power_13"],
base_voltage_primary = d["base_voltage_primary"],
base_voltage_secondary = d["base_voltage_secondary"],
base_voltage_tertiary = d["base_voltage_tertiary"],
g = d["g"],
b = d["b"],
primary_turns_ratio = d["primary_turns_ratio"],
secondary_turns_ratio = d["secondary_turns_ratio"],
tertiary_turns_ratio = d["tertiary_turns_ratio"],
available_primary = d["available_primary"],
available_secondary = d["available_secondary"],
available_tertiary = d["available_tertiary"],
rating_primary = _get_rating(
"PhaseShiftingTransformer3W",
name,
d,
"rating_primary",
),
rating_secondary = _get_rating(
"PhaseShiftingTransformer3W",
name,
d,
"rating_secondary",
),
rating_tertiary = _get_rating(
"PhaseShiftingTransformer3W",
name,
d,
"rating_tertiary",
),
control_objective_primary = get(d, "COD1", -99),
control_objective_secondary = get(d, "COD2", -99),
control_objective_tertiary = get(d, "COD3", -99),
ext = d["ext"],
)
end
function make_tap_transformer(
name::String,
d::Dict,
bus_f::ACBus,
bus_t::ACBus;
kwargs...,
)
pf = get(d, "pf", 0.0)
qf = get(d, "qf", 0.0)
available_value = d["br_status"] == 1
if get_bustype(bus_f) == ACBusTypes.ISOLATED ||
get_bustype(bus_t) == ACBusTypes.ISOLATED
available_value = false
end
ext = haskey(d, "ext") ? d["ext"] : Dict{String, Any}()
control_objective_formatter =
get(kwargs, :transformer_control_objective_formatter, nothing)
control_objective = if control_objective_formatter !== nothing
result = control_objective_formatter(name)
result !== nothing ? result : get(d, "COD1", -99)
else
get(d, "COD1", -99)
end
return TapTransformer(;
name = name,
available = available_value,
active_power_flow = pf,
reactive_power_flow = qf,
arc = Arc(bus_f, bus_t),
r = d["br_r"],
x = d["br_x"],
tap = d["tap"],
primary_shunt = d["g_fr"] + im * d["b_fr"],
winding_group_number = d["group_number"],
base_power = d["base_power"],
rating = _get_rating("TapTransformer", name, d, "rate_a"),
rating_b = _get_rating("TapTransformer", name, d, "rate_b"),
rating_c = _get_rating("TapTransformer", name, d, "rate_c"),
# for psse inputs, these numbers may be different than the buses' base voltages
base_voltage_primary = d["base_voltage_from"],
base_voltage_secondary = d["base_voltage_to"],
control_objective = control_objective,
ext = ext,
)
end
function make_phase_shifting_transformer(
name::String,
d::Dict,
bus_f::ACBus,
bus_t::ACBus;
kwargs...,
)
pf = get(d, "pf", 0.0)
qf = get(d, "qf", 0.0)
available_value = d["br_status"] == 1
if get_bustype(bus_f) == ACBusTypes.ISOLATED ||
get_bustype(bus_t) == ACBusTypes.ISOLATED
available_value = false
end
ext = haskey(d, "ext") ? d["ext"] : Dict{String, Any}()
control_objective_formatter =
get(kwargs, :transformer_control_objective_formatter, nothing)
control_objective = if control_objective_formatter !== nothing
result = control_objective_formatter(name)
result !== nothing ? result : get(d, "COD1", -99)
else
get(d, "COD1", -99)
end
return PhaseShiftingTransformer(;
name = name,
available = available_value,
active_power_flow = pf,
reactive_power_flow = qf,
arc = Arc(bus_f, bus_t),
r = d["br_r"],
x = d["br_x"],
tap = d["tap"],
primary_shunt = d["g_fr"] + im * d["b_fr"],
α = d["shift"],
base_power = d["base_power"],
rating = _get_rating("PhaseShiftingTransformer", name, d, "rate_a"),
rating_b = _get_rating("PhaseShiftingTransformer", name, d, "rate_b"),
rating_c = _get_rating("PhaseShiftingTransformer", name, d, "rate_c"),
# for psse inputs, these numbers may be different than the buses' base voltages
base_voltage_primary = d["base_voltage_from"],
base_voltage_secondary = d["base_voltage_to"],
control_objective = control_objective,
ext = ext,
)
end
function read_branch!(
sys::System,
data::Dict,
bus_number_to_bus::Dict{Int, ACBus}; kwargs...,
)
@info "Reading branch data"
if !haskey(data, "branch")
@info "There is no Branch data in this file"
return
end
_get_name = get(kwargs, :branch_name_formatter, nothing)
ict_instances = _impedance_correction_table_lookup(data)
branch_pair_counts = Dict{Tuple{String, String}, Int}()
source_type = data["source_type"]
for d in values(data["branch"])
bus_f = bus_number_to_bus[d["f_bus"]]
bus_t = bus_number_to_bus[d["t_bus"]]
name = if isnothing(_get_name)
if source_type == "pti"
_get_pm_branch_name_with_counter!(d, bus_f, bus_t, branch_pair_counts)
else
_get_pm_branch_name(d, bus_f, bus_t)
end
else
_get_name(d, bus_f, bus_t)
end
value = make_branch(name, d, bus_f, bus_t, source_type; kwargs...)
if !isnothing(value)
add_component!(sys, value; skip_validation = SKIP_PM_VALIDATION)
else
continue
end
if isa(value, TwoWindingTransformer)
_attach_impedance_correction_tables!(
sys,
value,
name,
d,
ict_instances,
)
end
end
return
end
function read_3w_transformer!(
sys::System,
data::Dict,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading 3W transformer data"
if !haskey(data, "3w_transformer")
@info "There is no 3W transformer data in this file"
return
end
_get_name = get(kwargs, :xfrm_3w_name_formatter, _get_pm_3w_name)
ict_instances = _impedance_correction_table_lookup(data)
for (_, d) in data["3w_transformer"]
bus_primary = bus_number_to_bus[d["bus_primary"]]
bus_secondary = bus_number_to_bus[d["bus_secondary"]]
bus_tertiary = bus_number_to_bus[d["bus_tertiary"]]
star_bus = bus_number_to_bus[d["star_bus"]]
name = _get_name(d, bus_primary, bus_secondary, bus_tertiary)
three_winding_transformer_type = get_three_winding_transformer_type(d)
if three_winding_transformer_type == PhaseShiftingTransformer3W
value = make_3w_phase_shifting_transformer(
name,
d,
bus_primary,
bus_secondary,
bus_tertiary,
star_bus,
)
elseif three_winding_transformer_type == Transformer3W
value = make_3w_transformer(
name,
d,
bus_primary,
bus_secondary,
bus_tertiary,
star_bus,
)
else
error(
"Unsupported three winding transformer type $three_winding_transformer_type",
)
end
add_component!(sys, value; skip_validation = SKIP_PM_VALIDATION)
_attach_impedance_correction_tables!(sys, value, name, d, ict_instances)
end
end
function _determine_control_modes(d::Dict, control_flag::String, tap_key::String)
control_code = get(d, control_flag, -99)
tap = d[tap_key]
is_tap_controllable = false
is_alpha_controllable = false
# There is no control
if control_code == 0
is_tap_controllable = false
is_alpha_controllable = false
# Reactive Power Control
elseif control_code ∈ [1, -1]
is_tap_controllable = true
is_alpha_controllable = false
# Voltage Control
elseif control_code ∈ [2, -2]
is_tap_controllable = true
is_alpha_controllable = false
# Active Power Control
elseif control_code ∈ [3, -3]
is_tap_controllable = true
is_alpha_controllable = true
# DC Line Control
elseif control_code ∈ [4, -4]
is_tap_controllable = true
is_alpha_controllable = true
# Asymmetric Active Power Control
elseif control_code ∈ [5, -5]
is_tap_controllable = true
is_alpha_controllable = true
elseif control_code == -99
@warn "Can't determine control objective for the transformer from the $(control_flag) field for $d"
if d["shift"] != 0.0
is_alpha_controllable = true
elseif (tap != 0.0) || (tap != 1.0)
is_tap_controllable = true
else
@warn "Can't determine control objective for the other fields. Will return a Transformer2W"
end
else
error(d)
end
return is_tap_controllable, is_alpha_controllable
end
function get_three_winding_transformer_type(d::Dict)
_add_vector_control_group(d, "primary_phase_shift_angle", "primary_group_number")
_add_vector_control_group(d, "secondary_phase_shift_angle", "secondary_group_number")
_add_vector_control_group(d, "tertiary_phase_shift_angle", "tertiary_group_number")
# NOTE: with current three winding transformer type hierarchy, tap controllable and not controllable three winding transformers are Transformer3W
_, primary_is_alpha_controllable =
_determine_control_modes(d, "COD1", "primary_turns_ratio")
_, secondary_is_alpha_controllable =
_determine_control_modes(d, "COD2", "secondary_turns_ratio")
_, tertiary_is_alpha_controllable =
_determine_control_modes(d, "COD3", "tertiary_turns_ratio")
if d["primary_group_number"] == WindingGroupNumber.UNDEFINED ||
d["secondary_group_number"] == WindingGroupNumber.UNDEFINED ||
d["tertiary_group_number"] == WindingGroupNumber.UNDEFINED ||
primary_is_alpha_controllable || secondary_is_alpha_controllable ||
tertiary_is_alpha_controllable
return PhaseShiftingTransformer3W
else
return Transformer3W
end
end
function make_dcline(name::String, d::Dict, bus_f::ACBus, bus_t::ACBus, source_type::String)
if source_type == "pti"
return TwoTerminalLCCLine(;
name = name,
available = d["available"],
arc = Arc(bus_f, bus_t),
active_power_flow = get(d, "pf", 0.0),
r = d["r"],
transfer_setpoint = d["transfer_setpoint"],
scheduled_dc_voltage = d["scheduled_dc_voltage"],
rectifier_bridges = d["rectifier_bridges"],
rectifier_delay_angle_limits = d["rectifier_delay_angle_limits"],
rectifier_rc = d["rectifier_rc"],
rectifier_xc = d["rectifier_xc"],
rectifier_base_voltage = d["rectifier_base_voltage"],
inverter_bridges = d["inverter_bridges"],
inverter_extinction_angle_limits = d["inverter_extinction_angle_limits"],
inverter_rc = d["inverter_rc"],
inverter_xc = d["inverter_xc"],
inverter_base_voltage = d["inverter_base_voltage"],
power_mode = d["power_mode"],
switch_mode_voltage = d["switch_mode_voltage"],
compounding_resistance = d["compounding_resistance"],
min_compounding_voltage = d["min_compounding_voltage"],
rectifier_transformer_ratio = d["rectifier_transformer_ratio"],
rectifier_tap_setting = d["rectifier_tap_setting"],
rectifier_tap_limits = d["rectifier_tap_limits"],
rectifier_tap_step = d["rectifier_tap_step"],
rectifier_delay_angle = d["rectifier_delay_angle"],
rectifier_capacitor_reactance = d["rectifier_capacitor_reactance"],
inverter_transformer_ratio = d["inverter_transformer_ratio"],
inverter_tap_setting = d["inverter_tap_setting"],
inverter_tap_limits = d["inverter_tap_limits"],
inverter_tap_step = d["inverter_tap_step"],
inverter_extinction_angle = d["inverter_extinction_angle"],
inverter_capacitor_reactance = d["inverter_capacitor_reactance"],
active_power_limits_from = d["active_power_limits_from"],
active_power_limits_to = d["active_power_limits_to"],
reactive_power_limits_from = d["reactive_power_limits_from"],
reactive_power_limits_to = d["reactive_power_limits_to"],
loss = LinearCurve(d["loss1"], d["loss0"]),
ext = get(d, "ext", Dict{String, Any}()),
)
elseif source_type == "matpower"
return TwoTerminalGenericHVDCLine(;
name = name,
available = d["br_status"] == 1,
active_power_flow = get(d, "pf", 0.0),
arc = Arc(bus_f, bus_t),
active_power_limits_from = (min = d["pminf"], max = d["pmaxf"]),
active_power_limits_to = (min = d["pmint"], max = d["pmaxt"]),
reactive_power_limits_from = (min = d["qminf"], max = d["qmaxf"]),
reactive_power_limits_to = (min = d["qmint"], max = d["qmaxt"]),
loss = LinearCurve(d["loss1"], d["loss0"]),
)
else
error("Not supported source type for DC lines: $source_type")
end
end
function read_dcline!(
sys::System,
data::Dict,
bus_number_to_bus::Dict{Int, ACBus},
source_type::String;
kwargs...,
)
@info "Reading DC Line data"
if !haskey(data, "dcline")
@info "There is no DClines data in this file"
return
end
_get_name = get(kwargs, :dcline_name_formatter, _get_pm_branch_name)
for (d_key, d) in data["dcline"]
d["name"] = get(d, "name", d_key)
bus_f = bus_number_to_bus[d["f_bus"]]
bus_t = bus_number_to_bus[d["t_bus"]]
name = _get_name(d, bus_f, bus_t)
dcline = make_dcline(name, d, bus_f, bus_t, source_type)
add_component!(sys, dcline; skip_validation = SKIP_PM_VALIDATION)
end
end
function make_vscline(name::String, d::Dict, bus_f::ACBus, bus_t::ACBus)
return TwoTerminalVSCLine(;
name = name,
available = d["available"],
arc = Arc(bus_f, bus_t),
active_power_flow = get(d, "pf", 0.0),
rating = d["rating"],
active_power_limits_from = (min = d["pminf"], max = d["pmaxf"]),
active_power_limits_to = (min = d["pmint"], max = d["pmaxt"]),
g = d["r"] == 0.0 ? 0.0 : 1.0 / d["r"],
dc_current = get(d, "if", 0.0),
reactive_power_from = get(d, "qf", 0.0),
dc_voltage_control_from = d["dc_voltage_control_from"],
ac_voltage_control_from = d["ac_voltage_control_from"],
dc_setpoint_from = d["dc_setpoint_from"],
ac_setpoint_from = d["ac_setpoint_from"],
converter_loss_from = d["converter_loss_from"],
max_dc_current_from = d["max_dc_current_from"],
rating_from = d["rating_from"],
reactive_power_limits_from = (min = d["qminf"], max = d["qmaxf"]),
power_factor_weighting_fraction_from = d["power_factor_weighting_fraction_from"],
reactive_power_to = get(d, "qt", 0.0),
dc_voltage_control_to = d["dc_voltage_control_to"],
ac_voltage_control_to = d["ac_voltage_control_to"],
dc_setpoint_to = d["dc_setpoint_to"],
ac_setpoint_to = d["ac_setpoint_to"],
converter_loss_to = d["converter_loss_to"],
max_dc_current_to = d["max_dc_current_to"],
rating_to = d["rating_to"],
reactive_power_limits_to = (min = d["qmint"], max = d["qmaxt"]),
power_factor_weighting_fraction_to = d["power_factor_weighting_fraction_to"],
ext = get(d, "ext", Dict{String, Any}()),
)
end
function read_vscline!(
sys::System,
data::Dict,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading VSC Line data"
if !haskey(data, "vscline")
@info "There is no VSC lines data in this file"
return
end
_get_name = get(kwargs, :vsc_line_name_formatter, _get_pm_branch_name)
for (d_key, d) in data["vscline"]
d["name"] = get(d, "name", d_key)
bus_f = bus_number_to_bus[d["f_bus"]]
bus_t = bus_number_to_bus[d["t_bus"]]
name = _get_name(d, bus_f, bus_t)
vscline = make_vscline(name, d, bus_f, bus_t)
add_component!(sys, vscline; skip_validation = SKIP_PM_VALIDATION)
end
end
function make_switched_shunt(name::String, d::Dict, bus::ACBus)
params = Dict(
:name => name,
:available => Bool(d["status"]),
:bus => bus,
:Y => (d["gs"] + d["bs"]im),
:number_of_steps => d["step_number"],
:Y_increase => d["y_increment"],
:admittance_limits => d["admittance_limits"],
:ext => d["ext"],
)
if haskey(d, "initial_status")
params[:initial_status] = d["initial_status"]
end
return SwitchedAdmittance(; params...)
end
function read_switched_shunt!(
sys::System,
data::Dict,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading switched shunt data"
if !haskey(data, "switched_shunt")
@info "There is no switched shunt data in this file"
return
end
_get_name = get(kwargs, :switched_shunt_name_formatter, _get_pm_dict_name)
for (d_key, d) in data["switched_shunt"]
d["name"] = get(d, "name", d_key)
name = _get_name(d)
bus = bus_number_to_bus[d["shunt_bus"]]
shunt = make_switched_shunt(name, d, bus)
add_component!(sys, shunt; skip_validation = SKIP_PM_VALIDATION)
end
end
function make_shunt(name::String, d::Dict, bus::ACBus)
return FixedAdmittance(;
name = name,
available = Bool(d["status"]),
bus = bus,
Y = (d["gs"] + d["bs"]im),
)
end
function make_facts(name::String, d::Dict, bus::ACBus)
if d["tbus"] != 0
@warn "Series FACTs not supported."
end
if d["control_mode"] > 3
throw(DataFormatError("Operation mode not supported."))
end
if d["reactive_power_required"] < 0
throw(DataFormatError("% MVAr required must me positive."))
end
return FACTSControlDevice(;
name = name,
available = Bool(d["available"]),
bus = bus,
control_mode = d["control_mode"],
voltage_setpoint = d["voltage_setpoint"],
max_shunt_current = d["max_shunt_current"],
reactive_power_required = d["reactive_power_required"],
ext = get(d, "ext", Dict{String, Any}()),
)
end
function read_facts!(
sys::System,
data::Dict,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading FACTS data"
if !haskey(data, "facts")
@info "There is no facts data in this file"
return
end
_get_name = get(kwargs, :bus_name_formatter, _get_pm_dict_name)
for (d_key, d) in data["facts"]
d["name"] = get(d, "name", d_key)
name = _get_name(d)
bus = bus_number_to_bus[d["bus"]]
full_name = "$(d["bus"])_$(name)"
facts = make_facts(full_name, d, bus)
add_component!(sys, facts; skip_validation = SKIP_PM_VALIDATION)
end
end
function read_shunt!(
sys::System,
data::Dict,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading shunt data"
if !haskey(data, "shunt")
@info "There is no shunt data in this file"
return
end
_get_name = get(kwargs, :shunt_name_formatter, _get_pm_dict_name)
for (d_key, d) in data["shunt"]
d["name"] = get(d, "name", d_key)
name = _get_name(d)
bus = bus_number_to_bus[d["shunt_bus"]]
shunt = make_shunt(name, d, bus)
add_component!(sys, shunt; skip_validation = SKIP_PM_VALIDATION)
end
end
function read_storage!(
sys::System,
data::Dict,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading storage data"
if !haskey(data, "storage")
@info "There is no storage data in this file"
return
end
_get_name = get(kwargs, :gen_name_formatter, _get_pm_dict_name)
for (d_key, d) in data["storage"]
d["name"] = get(d, "name", d_key)
name = _get_name(d)
bus = bus_number_to_bus[d["storage_bus"]]
storage = make_generic_battery(name, d, bus)
add_component!(sys, storage; skip_validation = SKIP_PM_VALIDATION)
end
end
================================================
FILE: src/parsers/power_system_table_data.jl
================================================
const POWER_SYSTEM_DESCRIPTOR_FILE =
joinpath(dirname(pathof(PowerSystems)), "descriptors", "power_system_inputs.json")
const INPUT_CATEGORY_NAMES = [
("branch", InputCategory.BRANCH),
("bus", InputCategory.BUS),
("dc_branch", InputCategory.DC_BRANCH),
("gen", InputCategory.GENERATOR),
("load", InputCategory.LOAD),
("reserves", InputCategory.RESERVE),
("storage", InputCategory.STORAGE),
]
struct PowerSystemTableData
base_power::Float64
category_to_df::Dict{InputCategory, DataFrames.DataFrame}
timeseries_metadata_file::Union{String, Nothing}
directory::String
user_descriptors::Dict
descriptors::Dict
generator_mapping::Dict{NamedTuple, DataType}
end
function PowerSystemTableData(
data::Dict{String, Any},
directory::String,
user_descriptors::Union{String, Dict},
descriptors::Union{String, Dict},
generator_mapping::Dict;
timeseries_metadata_file = joinpath(directory, "timeseries_pointers"),
)
category_to_df = Dict{InputCategory, DataFrames.DataFrame}()
if !haskey(data, "bus")
throw(DataFormatError("key 'bus' not found in input data"))
end
if !haskey(data, "base_power")
@warn "key 'base_power' not found in input data; using default=$(DEFAULT_BASE_MVA)"
end
base_power = get(data, "base_power", DEFAULT_BASE_MVA)
for (name, category) in INPUT_CATEGORY_NAMES
val = get(data, name, nothing)
if isnothing(val)
@debug "key '$name' not found in input data, set to nothing" _group =
IS.LOG_GROUP_PARSING
else
category_to_df[category] = val
end
end
if !isfile(timeseries_metadata_file)
if isfile(string(timeseries_metadata_file, ".json"))
timeseries_metadata_file = string(timeseries_metadata_file, ".json")
elseif isfile(string(timeseries_metadata_file, ".csv"))
timeseries_metadata_file = string(timeseries_metadata_file, ".csv")
else
timeseries_metadata_file = nothing
end
end
if user_descriptors isa AbstractString
user_descriptors = _read_config_file(user_descriptors)
end
if descriptors isa AbstractString
descriptors = _read_config_file(descriptors)
end
return PowerSystemTableData(
base_power,
category_to_df,
timeseries_metadata_file,
directory,
user_descriptors,
descriptors,
generator_mapping,
)
end
"""
Reads in all the data stored in csv files in a `directory`
!!! warning
This parser is planned for deprecation. `PowerSystems.jl` will be
moving to a database solution for handling data. There are plans to eventually include
utility functions to translate from .csv files to the database, but there will probably
be a gap in support. **Users are recommended to write their own custom Julia code to
import data from their unique data formats, rather than relying on this parsing
code.** See [How-to Build a `System` from CSV Files](@ref system_from_csv) for an example.
# Arguments
- `directory::AbstractString`: directory containing CSV files
- `base_power::Float64`: base power for [`System`](@ref)
- `user_descriptor_file::AbstractString`: customized input descriptor file. [Example](https://github.com/Sienna-Platform/PowerSystemsTestData/blob/master/RTS_GMLC/user_descriptors.yaml)
- `descriptor_file=POWER_SYSTEM_DESCRIPTOR_FILE`: `PowerSystems.jl` descriptor file. [Default](https://github.com/Sienna-Platform/PowerSystems.jl/blob/main/src/descriptors/power_system_inputs.json)
- `generator_mapping_file=GENERATOR_MAPPING_FILE_CDM`: generator mapping configuration file. [Default](https://github.com/Sienna-Platform/PowerSystems.jl/blob/main/src/parsers/generator_mapping_cdm.yaml)
- `timeseries_metadata_file = joinpath(directory, "timeseries_pointers")`: Time series pointers .json file. [Example](https://github.com/Sienna-Platform/PowerSystemsTestData/blob/master/RTS_GMLC/timeseries_pointers.json)
The general format for data in the `directory` is:
- bus.csv (required)
+ columns specifying `area` and `zone` will create a corresponding set of `Area` and `LoadZone` objects.
+ columns specifying `max_active_power` or `max_reactive_power` will create `PowerLoad` objects when nonzero values are encountered and will contribute to the `peak_active_power` and `peak_reactive_power` values for the
corresponding `LoadZone` object.
- branch.csv
- dc_branch.csv
- gen.csv
- load.csv
- reserves.csv
- storage.csv
# Custom construction of generators
Each generator will be defined as a concrete subtype of [`Generator`](@ref),
based on the `fuel` and `type` columns in `gen.csv` and the `generator_mapping_file`.
The default mapping file
is [`src/parsers/generator_mapping.yaml`](https://github.com/Sienna-Platform/PowerSystems.jl/blob/main/src/parsers/generator_mapping.yaml). You can override this behavior by specifying your own file.
# Custom Column names
`PowerSystems` provides am input mapping capability that allows you to keep your own
column names. For example, when parsing raw data for a generator the code expects a column
called `name`. If the raw data instead defines that column as `GEN UID` then
you can change the `custom_name` field under the `generator` category to
`GEN UID` in your YAML file.
To enable the parsing of a custom set of csv files, you can generate a configuration
file (such as `user_descriptors.yaml`) from the defaults, which are stored
in [`src/descriptors/power_system_inputs.json`](https://github.com/Sienna-Platform/PowerSystems.jl/blob/main/src/descriptors/power_system_inputs.json).
```python
python ./bin/generate_config_file.py ./user_descriptors.yaml
```
Next, edit this file with your customizations.
Note that the user-specific customizations are stored in YAML rather than JSON
to allow for easier editing. The next few sections describe changes you can
make to this YAML file. Do not edit the default JSON file.
## Per-unit conversion
`PowerSystems` defines whether it expects a column value to be per-unit system base,
per-unit device base, or natural units in `power_system_inputs.json`. If it expects a
per-unit convention that differs from your values then you can set the `unit_system` in
`user_descriptors.yaml` and `PowerSystems` will automatically convert the values. For
example, if you have a `max_active_power` value stored in natural units (MW), but
`power_system_inputs.json` specifies `unit_system: device_base`, you can enter
`unit_system: natural_units` in `user_descriptors.yaml` and `PowerSystems` will divide
the value by the value of the corresponding entry in the column identified by the
`base_reference` field in `power_system_inputs.json`. You can also override the
`base_reference` setting by adding `base_reference: My Column` to make device base
per-unit conversion by dividing the value by the entry in `My Column`. System base
per-unit conversions always divide the value by the system `base_power` value
instantiated when constructing a `System`.
`PowerSystems` provides a limited set of unit conversions. For example, if
`power_system_inputs.json` indicates that a value's unit is degrees but
your values are in radians then you can set `unit: radian` in
your YAML file. Other valid `unit` entries include `GW`, `GWh`, `MW`, `MWh`, `kW`,
and `kWh`.
# Examples
```julia
data_dir = "/data/my-data-dir"
base_power = 100.0
descriptors = "./user_descriptors.yaml"
timeseries_metadata_file = "./timeseries_pointers.json"
generator_mapping_file = "./generator_mapping.yaml"
data = PowerSystemTableData(
data_dir,
base_power,
descriptors;
timeseries_metadata_file = timeseries_metadata_file,
generator_mapping_file = generator_mapping_file,
)
sys = System(data; time_series_in_memory = true)
```
"""
function PowerSystemTableData(
directory::AbstractString,
base_power::Float64,
user_descriptor_file::AbstractString;
descriptor_file = POWER_SYSTEM_DESCRIPTOR_FILE,
generator_mapping_file = GENERATOR_MAPPING_FILE_CDM,
timeseries_metadata_file = joinpath(directory, "timeseries_pointers"),
)
files = readdir(directory)
REGEX_DEVICE_TYPE = r"(.*?)\.csv"
REGEX_IS_FOLDER = r"^[A-Za-z]+$"
data = Dict{String, Any}()
if length(files) == 0
error("No files in the folder")
else
data["base_power"] = base_power
end
encountered_files = 0
for d_file in files
try
if match(REGEX_IS_FOLDER, d_file) !== nothing
@info "Parsing csv files in $d_file ..."
d_file_data = Dict{String, Any}()
for file in readdir(joinpath(directory, d_file))
if match(REGEX_DEVICE_TYPE, file) !== nothing
@info "Parsing csv data in $file ..."
encountered_files += 1
fpath = joinpath(directory, d_file, file)
raw_data = DataFrames.DataFrame(CSV.File(fpath))
d_file_data[split(file, r"[.]")[1]] = raw_data
end
end
if length(d_file_data) > 0
data[d_file] = d_file_data
@info "Successfully parsed $d_file"
end
elseif match(REGEX_DEVICE_TYPE, d_file) !== nothing
@info "Parsing csv data in $d_file ..."
encountered_files += 1
fpath = joinpath(directory, d_file)
raw_data = DataFrames.DataFrame(CSV.File(fpath))
data[split(d_file, r"[.]")[1]] = raw_data
@info "Successfully parsed $d_file"
end
catch ex
@error "Error occurred while parsing $d_file" exception = ex
throw(ex)
end
end
if encountered_files == 0
error("No csv files or folders in $directory")
end
generator_mapping = Dict{NamedTuple, DataType}()
try
generator_mapping = get_generator_mapping(generator_mapping_file)
catch e
@error "Error loading generator mapping $(generator_mapping_file)"
rethrow(e)
end
return PowerSystemTableData(
data,
directory,
user_descriptor_file,
descriptor_file,
generator_mapping;
timeseries_metadata_file = timeseries_metadata_file,
)
end
"""
Return the custom name stored in the user descriptor file.
Throws DataFormatError if a required value is not found in the file.
"""
function get_user_field(
data::PowerSystemTableData,
category::InputCategory,
field::AbstractString,
)
if !haskey(data.user_descriptors, category)
throw(DataFormatError("Invalid category=$category"))
end
try
for item in data.user_descriptors[category]
if item["name"] == field
return item["custom_name"]
end
end
catch
(err)
if err == KeyError
msg = "Failed to find category=$category field=$field in input descriptors $err"
throw(DataFormatError(msg))
else
throw(err)
end
end
end
"""Return a vector of user-defined fields for the category."""
function get_user_fields(data::PowerSystemTableData, category::InputCategory)
if !haskey(data.user_descriptors, category)
throw(DataFormatError("Invalid category=$category"))
end
return [x["name"] for x in data.user_descriptors[category]]
end
"""Return the dataframe for the category."""
function get_dataframe(data::PowerSystemTableData, category::InputCategory)
df = get(data.category_to_df, category, DataFrames.DataFrame())
isempty(df) && @warn("Missing $category data.")
return df
end
"""
Return a NamedTuple of parameters from the descriptor file for each row of a dataframe,
making type conversions as necessary.
Refer to the PowerSystems descriptor file for field names that will be created.
"""
function iterate_rows(data::PowerSystemTableData, category; na_to_nothing = true)
df = get_dataframe(data, category)
field_infos = _get_field_infos(data, category, names(df))
Channel() do channel
for row in eachrow(df)
obj = _read_data_row(data, row, field_infos; na_to_nothing = na_to_nothing)
put!(channel, obj)
end
end
end
"""
Construct a System from [`PowerSystemTableData`](@ref) data.
!!! warning
This parser is planned for deprecation. `PowerSystems.jl` will be
moving to a database solution for handling data. There are plans to eventually include
utility functions to translate from .csv files to the database, but there will probably
be a gap in support. **Users are recommended to write their own custom Julia code to
import data from their unique data formats, rather than relying on this parsing
code.** See [How-to Build a `System` from CSV Files](@ref system_from_csv) for an example.
# Arguments
- `time_series_resolution::Union{DateTime, Nothing}=nothing`: only store time_series that match
this resolution.
- `time_series_in_memory::Bool=false`: Store time series data in memory instead of HDF5 file
- `time_series_directory=nothing`: Store time series data in directory instead of tmpfs
- `runchecks::Bool=true`: Validate struct fields.
Throws DataFormatError if time_series with multiple resolutions are detected.
- A time_series has a different resolution than others.
- A time_series has a different horizon than others.
"""
function System(
data::PowerSystemTableData;
time_series_resolution = nothing,
time_series_in_memory = false,
time_series_directory = nothing,
runchecks = true,
kwargs...,
)
sys = System(
data.base_power;
time_series_in_memory = time_series_in_memory,
time_series_directory = time_series_directory,
runchecks = runchecks,
kwargs...,
)
set_units_base_system!(sys, IS.UnitSystem.DEVICE_BASE)
loadzone_csv_parser!(sys, data)
bus_csv_parser!(sys, data)
# Services and time_series must be last.
parsers = (
(get_dataframe(data, InputCategory.BRANCH), branch_csv_parser!),
(get_dataframe(data, InputCategory.DC_BRANCH), dc_branch_csv_parser!),
(get_dataframe(data, InputCategory.GENERATOR), gen_csv_parser!),
(get_dataframe(data, InputCategory.LOAD), load_csv_parser!),
(get_dataframe(data, InputCategory.RESERVE), services_csv_parser!),
)
for (val, parser) in parsers
if !isempty(val)
parser(sys, data)
end
end
timeseries_metadata_file =
get(kwargs, :timeseries_metadata_file, getfield(data, :timeseries_metadata_file))
if !isnothing(timeseries_metadata_file)
add_time_series!(sys, timeseries_metadata_file; resolution = time_series_resolution)
end
check(sys)
return sys
end
"""
Add buses and areas to the System from the raw data.
"""
function bus_csv_parser!(sys::System, data::PowerSystemTableData)
for (ix, bus) in enumerate(iterate_rows(data, InputCategory.BUS))
name = bus.name
bus_type =
isnothing(bus.bus_type) ? nothing : get_enum_value(ACBusTypes, bus.bus_type)
voltage_limits = make_minmaxlimits(bus.voltage_limits_min, bus.voltage_limits_max)
area_name = string(get(bus, :area, "area"))
area = get_component(Area, sys, area_name)
if isnothing(area)
area = Area(area_name)
add_component!(sys, area)
end
zone = get(bus, :zone, nothing)
bus_id = isnothing(bus.bus_id) ? ix : bus.bus_id
ps_bus = ACBus(;
number = bus_id,
name = name,
available = true,
bustype = bus_type,
angle = bus.angle,
magnitude = bus.voltage,
voltage_limits = voltage_limits,
base_voltage = bus.base_voltage,
area = area,
load_zone = get_component(LoadZone, sys, string(zone)),
)
add_component!(sys, ps_bus)
# add load if the following info is nonzero
if (bus.max_active_power != 0.0) || (bus.max_reactive_power != 0.0)
load = PowerLoad(;
name = name,
available = true,
bus = ps_bus,
active_power = bus.active_power,
reactive_power = bus.reactive_power,
base_power = bus.base_power,
max_active_power = bus.max_active_power,
max_reactive_power = bus.max_reactive_power,
)
add_component!(sys, load)
end
if (bus.shunt_b != 0.0) || (bus.shunt_g != 0.0)
shunt = FixedAdmittance(;
name = name,
available = true,
bus = ps_bus,
Y = (bus.shunt_g + bus.shunt_b * im),
)
add_component!(sys, shunt)
end
end
end
function get_branch_type(
tap::Float64,
is_transformer::Union{Bool, Nothing},
)
if isnothing(is_transformer)
is_transformer = (tap != 0.0) && (tap != 1.0)
end
is_transformer || return Line
return tap == 1.0 ? Transformer2W : TapTransformer
end
"""
Add branches to the System from the raw data.
"""
function branch_csv_parser!(sys::System, data::PowerSystemTableData)
available = true
for branch in iterate_rows(data, InputCategory.BRANCH)
bus_from = get_bus(sys, branch.connection_points_from)
bus_to = get_bus(sys, branch.connection_points_to)
name = get(branch, :name, get_name(bus_from) * "_" * get_name(bus_to))
connection_points = Arc(bus_from, bus_to)
pf = branch.active_power_flow
qf = branch.reactive_power_flow
# Table Model doesn't support PhaseShifters
branch_type =
get_branch_type(
branch.tap,
get(branch, :is_transformer, nothing),
)
if branch_type == Line
b = branch.primary_shunt / 2
value = Line(;
name = name,
available = available,
active_power_flow = pf,
reactive_power_flow = qf,
arc = connection_points,
r = branch.r,
x = branch.x,
b = (from = b, to = b),
rating = branch.rate,
angle_limits = (
min = branch.min_angle_limits,
max = branch.max_angle_limits,
),
)
elseif branch_type == Transformer2W
value = Transformer2W(;
name = name,
available = available,
active_power_flow = pf,
reactive_power_flow = qf,
arc = connection_points,
r = branch.r,
x = branch.x,
primary_shunt = branch.primary_shunt,
winding_group_number = WindingGroupNumber.UNDEFINED,
rating = branch.rate,
base_power = data.base_power, # use system base power
)
elseif branch_type == TapTransformer
value = TapTransformer(;
name = name,
available = available,
active_power_flow = pf,
reactive_power_flow = qf,
arc = connection_points,
r = branch.r,
x = branch.x,
primary_shunt = branch.primary_shunt,
winding_group_number = WindingGroupNumber.UNDEFINED,
tap = branch.tap,
rating = branch.rate,
base_power = data.base_power, # use system base power
)
else
error("Unsupported branch type $branch_type")
end
add_component!(sys, value)
end
end
"""
Add DC branches to the System from raw data.
"""
function dc_branch_csv_parser!(sys::System, data::PowerSystemTableData)
function make_dc_limits(dc_branch, min, max)
min_lim = dc_branch[min]
if isnothing(dc_branch[min]) && isnothing(dc_branch[max])
throw(DataFormatError("valid limits required for $min , $max"))
elseif isnothing(dc_branch[min])
min_lim = dc_branch[max] * -1.0
end
return (min = min_lim, max = dc_branch[max])
end
for dc_branch in iterate_rows(data, InputCategory.DC_BRANCH)
available = true
bus_from = get_bus(sys, dc_branch.connection_points_from)
bus_to = get_bus(sys, dc_branch.connection_points_to)
connection_points = Arc(bus_from, bus_to)
if dc_branch.control_mode == "Power"
mw_load = dc_branch.mw_load
activepowerlimits_from = make_dc_limits(
dc_branch,
:min_active_power_limit_from,
:max_active_power_limit_from,
)
activepowerlimits_to = make_dc_limits(
dc_branch,
:min_active_power_limit_to,
:max_active_power_limit_to,
)
reactivepowerlimits_from = make_dc_limits(
dc_branch,
:min_reactive_power_limit_from,
:max_reactive_power_limit_from,
)
reactivepowerlimits_to = make_dc_limits(
dc_branch,
:min_reactive_power_limit_to,
:max_reactive_power_limit_to,
)
loss = LinearCurve(dc_branch.loss) #TODO: Can we infer this from the other data?,
value = TwoTerminalGenericHVDCLine(;
name = dc_branch.name,
available = available,
active_power_flow = dc_branch.active_power_flow,
arc = connection_points,
active_power_limits_from = activepowerlimits_from,
active_power_limits_to = activepowerlimits_to,
reactive_power_limits_from = reactivepowerlimits_from,
reactive_power_limits_to = reactivepowerlimits_to,
loss = loss,
)
else
error(
"Only control mode = Power is supported for DC Branch $(dc_branch.name) in TableData.",
)
end
add_component!(sys, value)
end
end
"""
Add generators to the System from the raw data.
"""
struct _HeatRateColumns
columns::Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Array{Symbol, 1}}}
end
struct _CostPointColumns
columns::Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Array{Symbol, 1}}}
end
function gen_csv_parser!(sys::System, data::PowerSystemTableData)
output_point_fields = Vector{Symbol}()
heat_rate_fields = Vector{Symbol}()
cost_point_fields = Vector{Symbol}()
fields = get_user_fields(data, InputCategory.GENERATOR)
for field in fields
if occursin("output_point", field)
push!(output_point_fields, Symbol(field))
elseif occursin("heat_rate_", field)
push!(heat_rate_fields, Symbol(field))
elseif occursin("cost_point_", field)
push!(cost_point_fields, Symbol(field))
end
end
@assert length(output_point_fields) > 0
if length(heat_rate_fields) > 0 && length(cost_point_fields) > 0
throw(IS.ConflictingInputsError("Heat rate and cost points are both defined"))
elseif length(heat_rate_fields) > 0
cost_colnames = _HeatRateColumns(zip(heat_rate_fields, output_point_fields))
elseif length(cost_point_fields) > 0
cost_colnames = _CostPointColumns(zip(cost_point_fields, output_point_fields))
else
throw(IS.DataFormatError("Configuration for cost terms not recognized"))
end
gen_storage = cache_storage(data::PowerSystemTableData)
for gen in iterate_rows(data, InputCategory.GENERATOR)
reservoirs = nothing # For hydro generators with reservoirs
@debug "making generator:" _group = IS.LOG_GROUP_PARSING gen.name
bus = get_bus(sys, gen.bus_id)
if isnothing(bus)
throw(DataFormatError("could not find $(gen.bus_id)"))
end
# Returns a vector of reservoirs when applicable to hydro turbines
generator, reservoirs =
make_generator(data, gen, cost_colnames, bus, gen_storage)
@debug "adding gen:" _group = IS.LOG_GROUP_PARSING generator
if !isnothing(generator)
add_component!(sys, generator)
end
if !isnothing(reservoirs)
@debug "adding reservoirs:" _group = IS.LOG_GROUP_PARSING generator
add_components!(sys, reservoirs)
end
end
return
end
function cache_storage(data::PowerSystemTableData)
storage = Dict{String, Any}()
gen_head_dict = Dict()
gen_tail_dict = Dict()
if !haskey(data.category_to_df, InputCategory.STORAGE)
return gen_head_dict, gen_tail_dict
end
for s in iterate_rows(data, InputCategory.STORAGE)
if occursin("head", normalize(s.position; casefold = true))
if !haskey(gen_head_dict, s.generator_name)
gen_head_dict[s.generator_name] = s
else
throw(DataFormatError("Duplicate head storage found for gen $s"))
end
elseif occursin("tail", normalize(s.position; casefold = true))
if !haskey(gen_tail_dict, s.generator_name)
gen_tail_dict[s.generator_name] = s
else
throw(DataFormatError("Duplicate tail storage found for gen $s"))
end
end
end
storage["head"] = gen_head_dict
storage["tail"] = gen_tail_dict
return storage
end
"""
load_csv_parser!(sys::System, data::PowerSystemTableData)
Add loads to the System from the raw load data.
"""
function load_csv_parser!(sys::System, data::PowerSystemTableData)
for rawload in iterate_rows(data, InputCategory.LOAD)
bus = get_bus(sys, rawload.bus_id)
if isnothing(bus)
throw(
DataFormatError(
"could not find bus_number=$(rawload.bus_id) for load=$(rawload.name)",
),
)
end
load = PowerLoad(;
name = rawload.name,
available = rawload.available,
bus = bus,
active_power = rawload.active_power,
reactive_power = rawload.reactive_power,
max_active_power = rawload.max_active_power,
max_reactive_power = rawload.max_reactive_power,
base_power = rawload.base_power,
)
add_component!(sys, load)
end
end
"""
loadzone_csv_parser!(sys::System, data::PowerSystemTableData)
Add branches to the System from the raw data.
"""
function loadzone_csv_parser!(sys::System, data::PowerSystemTableData)
buses = get_dataframe(data, InputCategory.BUS)
zone_column = get_user_field(data, InputCategory.BUS, "zone")
if !in(zone_column, names(buses))
@warn "Missing Data : no 'zone' information for buses, cannot create loads based on zones"
return
end
zones = unique(buses[!, zone_column])
for zone in zones
bus_numbers = Set{Int}()
active_powers = Vector{Float64}()
reactive_powers = Vector{Float64}()
for (ix, bus) in enumerate(iterate_rows(data, InputCategory.BUS))
bus_number = isnothing(bus.bus_id) ? ix : bus.bus_id
if bus.zone == zone
push!(bus_numbers, bus_number)
active_power = bus.max_active_power
push!(active_powers, active_power)
reactive_power = bus.max_reactive_power
push!(reactive_powers, reactive_power)
end
end
name = string(zone)
load_zone = LoadZone(name, sum(active_powers), sum(reactive_powers))
add_component!(sys, load_zone)
end
end
"""
Add services to the System from the raw data.
"""
function services_csv_parser!(sys::System, data::PowerSystemTableData)
bus_id_column = get_user_field(data, InputCategory.BUS, "bus_id")
bus_area_column = get_user_field(data, InputCategory.BUS, "area")
# Shortcut for data that looks like "(val1,val2,val3)"
function make_array(x)
if isnothing(x)
return x
else
y = split(strip(x, ['(', ')']), ",")
# Remove extra space at the beginning if needed
return replace.(y, r"^ *" => "")
end
end
function _add_device!(contributing_devices, device_categories, name)
component = []
for dev_category in device_categories
component_type = _get_component_type_from_category(dev_category)
components = get_components_by_name(component_type, sys, name)
if length(components) == 0
# There multiple categories, so we might not find a match in some.
continue
elseif length(components) == 1
push!(component, components[1])
else
msg = "Found duplicate names type=$component_type name=$name"
throw(DataFormatError(msg))
end
end
if length(component) > 1
msg = "Found duplicate components with name=$name"
throw(DataFormatError(msg))
elseif length(component) == 1
push!(contributing_devices, component[1])
end
end
for reserve in iterate_rows(data, InputCategory.RESERVE)
device_categories = make_array(reserve.eligible_device_categories)
device_subcategories =
make_array(get(reserve, :eligible_device_subcategories, nothing))
devices = make_array(get(reserve, :contributing_devices, nothing))
regions = make_array(reserve.eligible_regions) #TODO: rename to "area"
requirement = get(reserve, :requirement, nothing)
contributing_devices = Vector{Device}()
if isnothing(device_subcategories)
@info("Adding contributing components for $(reserve.name) by component name")
for device in devices
@assert supports_services(device)
_add_device!(contributing_devices, device_categories, device)
end
else
@info("Adding contributing generators for $(reserve.name) by category")
for gen in iterate_rows(data, InputCategory.GENERATOR)
buses = get_dataframe(data, InputCategory.BUS)
bus_ids = buses[!, bus_id_column]
gen_type =
get_generator_type(gen.fuel, gen.unit_type, data.generator_mapping)
sys_gen = get_component(gen_type, sys, gen.name)
@assert supports_services(sys_gen)
if isnothing(sys_gen)
error(
"Failed to find generator: type = $gen_type name = $(gen.name) " *
"fuel = $(gen.fuel) unit_type = $(gen.unit_type)",
)
end
area = string(
buses[bus_ids .== get_number(get_bus(sys_gen)), bus_area_column][1],
)
if gen.category in device_subcategories && area in regions
_add_device!(contributing_devices, device_categories, gen.name)
end
end
unused_categories = setdiff(
device_subcategories,
get_dataframe(data, InputCategory.GENERATOR)[
!,
get_user_field(data, InputCategory.GENERATOR, "category"),
],
)
for cat in unused_categories
@warn(
"Device category: $cat not found in generators data; adding contributing devices by category only supported for generator data"
)
end
end
if length(contributing_devices) == 0
throw(
DataFormatError(
"did not find contributing devices for service $(reserve.name)",
),
)
end
direction = get_reserve_direction(reserve.direction)
if isnothing(requirement)
service = ConstantReserve{direction}(reserve.name, true, reserve.timeframe, 0.0)
else
service = VariableReserve{direction}(
reserve.name,
true,
reserve.timeframe,
requirement,
)
end
add_service!(sys, service, contributing_devices)
end
end
function get_reserve_direction(direction::AbstractString)
if lowercase(direction) == "up"
return ReserveUp
elseif lowercase(direction) == "down"
return ReserveDown
else
throw(DataFormatError("invalid reserve direction $direction"))
end
end
"""Creates a generator of any type."""
function make_generator(
data::PowerSystemTableData,
gen,
cost_colnames,
bus,
gen_storage,
)
generator = nothing
gen_type =
get_generator_type(gen.fuel, get(gen, :unit_type, nothing), data.generator_mapping)
reservoirs = nothing
if isnothing(gen_type)
@error "Cannot recognize generator type" gen.name
elseif gen_type == ThermalStandard
generator = make_thermal_generator(data, gen, cost_colnames, bus)
elseif gen_type == ThermalMultiStart
generator = make_thermal_generator_multistart(data, gen, cost_colnames, bus)
elseif gen_type == SynchronousCondenser
generator = make_synchronous_condenser_generator(gen, bus)
elseif gen_type == HydroDispatch
generator = make_hydro_dispatch(data, gen, cost_colnames, bus)
elseif gen_type == HydroTurbine
generator, reservoirs =
make_hydro_turbine(data, gen, cost_colnames, bus, gen_storage)
elseif gen_type == HydroPumpTurbine
# For HydroPump it can only return 2 reservoirs. First is head second is tail
generator, reservoirs =
make_hydro_pump_storage(data, gen, cost_colnames, bus, gen_storage)
elseif gen_type <: RenewableGen
generator = make_renewable_generator(gen_type, data, gen, cost_colnames, bus)
elseif gen_type == EnergyReservoirStorage
head_dict = gen_storage["head"]
if !haskey(head_dict, gen.name)
throw(DataFormatError("Cannot find storage for $(gen.name) in storage.csv"))
end
storage = head_dict[gen.name]
generator = make_storage(data, gen, bus, storage)
else
@error "Skipping unsupported generator" gen.name gen_type
end
if abs(get_base_power(generator)) <= 1e-6
@warn "Generator $(summary(generator)) has base power of zero: changing device " *
"base power to match system base power, $(data.base_power)"
set_base_power!(generator, data.base_power)
end
return generator, reservoirs
end
function make_cost(
::Type{T},
data,
gen,
cost_colnames::_HeatRateColumns,
) where {T <: ThermalGen}
fuel_price = gen.fuel_price / 1000.0
# We check if there is any Quadratic or Linear Data defined. If not we fall back to create PiecewiseIncrementalCurve
quadratic_fields = (gen.heat_rate_a0, gen.heat_rate_a1, gen.heat_rate_a2)
if any(field -> field != nothing, quadratic_fields)
var_cost, fixed =
create_poly_cost(gen, ["heat_rate_a0", "heat_rate_a1", "heat_rate_a2"])
else
cost_pairs = get_cost_pairs(gen, cost_colnames)
var_cost, fixed = create_pwinc_cost(gen, cost_pairs)
end
parse_maybe_nothing(x) =
isnothing(x) ? 0.0 : (x isa Number ? Float64(x) : tryparse(Float64, x))
vom_cost = parse_maybe_nothing(getfield(gen, Symbol("variable_cost")))
vom_data = LinearCurve(vom_cost)
startup_cost, shutdown_cost = calculate_uc_cost(data, gen, fuel_price)
fuel_offtake = LinearCurve(0.0)
op_cost = ThermalGenerationCost(
FuelCurve(var_cost, UnitSystem.NATURAL_UNITS, fuel_price, fuel_offtake, vom_data),
fixed * fuel_price,
startup_cost,
shutdown_cost,
)
return op_cost
end
function make_cost(
::Type{T},
data,
gen,
cost_colnames::_CostPointColumns,
) where {T <: ThermalGen}
fuel_price = gen.fuel_price / 1000.0
cost_pairs = get_cost_pairs(gen, cost_colnames)
var_cost = create_pwl_cost(gen, cost_pairs)
startup_cost, shutdown_cost = calculate_uc_cost(data, gen, fuel_price)
parse_maybe_nothing(x) =
isnothing(x) ? 0.0 : (x isa Number ? Float64(x) : tryparse(Float64, x))
vom_cost = parse_maybe_nothing(getfield(gen, Symbol("variable_cost")))
vom_data = LinearCurve(vom_cost)
op_cost = ThermalGenerationCost(
CostCurve(var_cost, UnitSystem.NATURAL_UNITS, vom_data),
gen.fixed_cost,
startup_cost,
shutdown_cost,
)
return op_cost
end
function make_cost(
::Type{T},
data,
gen,
cost_colnames::_HeatRateColumns,
) where {T <: HydroGen}
fuel_price = gen.fuel_price / 1000.0
cost_pairs = get_cost_pairs(gen, cost_colnames)
var_cost, fixed = create_pwinc_cost(gen, cost_pairs)
op_cost = HydroGenerationCost(
FuelCurve(var_cost, UnitSystem.NATURAL_UNITS, fuel_price),
fixed * fuel_price)
return op_cost
end
function make_cost(
::Type{T},
data,
gen,
cost_colnames::_CostPointColumns,
) where {T <: HydroGen}
cost_pairs = get_cost_pairs(gen, cost_colnames)
var_cost = create_pwl_cost(gen, cost_pairs)
op_cost = HydroGenerationCost(
CostCurve(var_cost, UnitSystem.NATURAL_UNITS),
gen.fixed_cost)
return op_cost
end
function make_cost(
::Type{T},
data,
gen,
cost_colnames::_HeatRateColumns,
) where {T <: RenewableGen}
@warn "Heat rate parsing not valid for RenewableGen replacing with zero cost"
parse_maybe_nothing(x) =
isnothing(x) ? 0.0 : (x isa Number ? Float64(x) : tryparse(Float64, x))
vom_cost = parse_maybe_nothing(getfield(gen, Symbol("variable_cost")))
vom_data = LinearCurve(vom_cost)
var_cost = CostCurve(;
value_curve = LinearCurve(0.0),
power_units = UnitSystem.NATURAL_UNITS,
vom_cost = vom_data,
)
op_cost = RenewableGenerationCost(var_cost)
return op_cost
end
function make_cost(
::Type{T},
data,
gen,
cost_colnames::_CostPointColumns,
) where {T <: RenewableGen}
cost_pairs = get_cost_pairs(gen, cost_colnames)
parse_maybe_nothing(x) =
isnothing(x) ? 0.0 : (x isa Number ? Float64(x) : tryparse(Float64, x))
vom_cost = parse_maybe_nothing(getfield(gen, Symbol("variable_cost")))
vom_data = LinearCurve(vom_cost)
var_cost = CostCurve(;
value_curve = cost_pairs,
power_units = UnitSystem.NATURAL_UNITS,
vom_cost = vom_data,
)
op_cost = RenewableGenerationCost(var_cost)
return op_cost
end
function get_cost_pairs(gen::NamedTuple, cost_colnames)
base_power = gen.base_mva * gen.active_power_limits_max
vals = []
for (c, pt) in cost_colnames.columns
x = getfield(gen, pt)
y = getfield(gen, c)
if !in(nothing, [x, y])
push!(vals,
(x = tryparse(Float64, string(x)) * base_power,
y = tryparse(Float64, string(y))))
end
end
if isempty(vals)
return vals
else
last_increasing_point =
findfirst(x -> x < 0.0, [diff(getfield.(vals, :x))..., -Inf])
return vals[1:last_increasing_point]
end
end
function create_pwl_cost(
gen,
cost_pairs,
)
if length(cost_pairs) > 1
var_cost = PiecewisePointCurve(PiecewiseLinearData(cost_pairs))
elseif length(cost_pairs) == 1
# if there is only one point, use it to determine the constant $/MW cost
var_cost = LinearCurve(cost_pairs[1].y / cost_pairs[1].x)
else
@warn "$(gen.name) has no costs defined, using 0.0" cost_pairs maxlog = 5
var_cost = LinearCurve(0.0)
end
return var_cost
end
"""
create_poly_cost(gen, cost_colnames)
Return a Polynomial function cost based on the coeffiecients provided on gen.
Three supported cases,
1. If three values are passed then we have data looking like: `a2 * x^2 + a1 * x + a0`,
2. If `a1` and `a0` are passed then we have data looking like: `a1 * x + a0`,
3. If only `a1` is passed then we have data looking like: `a1 * x`.
"""
function create_poly_cost(
gen, cost_colnames,
)
fixed_cost = 0.0
parse_maybe_nothing(x) =
isnothing(x) ? nothing : (x isa Number ? Float64(x) : tryparse(Float64, x))
a2 = parse_maybe_nothing(getfield(gen, Symbol("heat_rate_a2")))
a1 = parse_maybe_nothing(getfield(gen, Symbol("heat_rate_a1")))
a0 = parse_maybe_nothing(getfield(gen, Symbol("heat_rate_a0")))
if !isnothing(a2) && (isnothing(a1) || isnothing(a0))
throw(
DataFormatError(
"All coefficients must be passed if quadratic term is passed.",
),
)
end
if !any(isnothing.([a2, a1, a0]))
@debug "QuadraticCurve created for $(gen.name)"
return QuadraticCurve(a2, a1, a0), fixed_cost
end
if all(isnothing.([a2, a0])) && !isnothing(a1)
@debug "LinearCurve created for $(gen.name)"
return LinearCurve(a1), fixed_cost
end
@debug "LinearCurve created for $(gen.name)"
return LinearCurve(a1, a0), fixed_cost
end
function create_pwinc_cost(
gen,
cost_pairs,
)
if length(cost_pairs) > 1
x_points = getfield.(cost_pairs, :x)
y_points = getfield.(cost_pairs, :y)
var_cost = PiecewiseIncrementalCurve(
first(y_points) * first(x_points),
x_points,
y_points[2:end],
)
elseif length(cost_pairs) == 1
# if there is only one point, use it to determine the constant $/MW cost
var_cost = LinearCurve(cost_pairs[1].y)
else
@warn "Unable to calculate variable cost for $(gen.name), defaulting to LinearCurve(0.0)" cost_pairs maxlog =
5
var_cost = LinearCurve(0.0)
end
return var_cost, 0.0
end
function calculate_uc_cost(data, gen, fuel_cost)
startup_cost = gen.startup_cost
if isnothing(startup_cost)
if !isnothing(gen.startup_heat_cold_cost)
startup_cost = gen.startup_heat_cold_cost * fuel_cost * 1000
else
startup_cost = 0.0
@warn "No startup_cost defined for $(gen.name), setting to $startup_cost" maxlog =
5
end
end
shutdown_cost = get(gen, :shutdown_cost, nothing)
if isnothing(shutdown_cost)
@warn "No shutdown_cost defined for $(gen.name), setting to 0.0" maxlog = 1
shutdown_cost = 0.0
end
return startup_cost, shutdown_cost
end
function make_minmaxlimits(min::Union{Nothing, Float64}, max::Union{Nothing, Float64})
if isnothing(min) && isnothing(max)
minmax = nothing
else
minmax = (min = min, max = max)
end
return minmax
end
function make_ramplimits(
gen;
ramplimcol = :ramp_limits,
rampupcol = :ramp_up,
rampdncol = :ramp_down,
)
ramp = get(gen, ramplimcol, nothing)
if !isnothing(ramp)
up = ramp
down = ramp
else
up = get(gen, rampupcol, ramp)
up = typeof(up) <: AbstractString ? tryparse(Float64, up) : up
down = get(gen, rampdncol, ramp)
down = typeof(down) <: AbstractString ? tryparse(Float64, down) : down
end
ramplimits = isnothing(up) && isnothing(down) ? nothing : (up = up, down = down)
return ramplimits
end
function make_timelimits(gen, up_column::Symbol, down_column::Symbol)
up_time = get(gen, up_column, nothing)
up_time = typeof(up_time) <: AbstractString ? tryparse(Float64, up_time) : up_time
down_time = get(gen, down_column, nothing)
down_time =
typeof(down_time) <: AbstractString ? tryparse(Float64, down_time) : down_time
timelimits =
if isnothing(up_time) && isnothing(down_time)
nothing
else
(up = up_time, down = down_time)
end
return timelimits
end
function make_reactive_params(
gen;
powerfield = :reactive_power,
minfield = :reactive_power_limits_min,
maxfield = :reactive_power_limits_max,
)
reactive_power = get(gen, powerfield, 0.0)
reactive_power_limits_min = get(gen, minfield, nothing)
reactive_power_limits_max = get(gen, maxfield, nothing)
if isnothing(reactive_power_limits_min) && isnothing(reactive_power_limits_max)
reactive_power_limits = nothing
elseif isnothing(reactive_power_limits_min)
reactive_power_limits = (min = 0.0, max = reactive_power_limits_max)
else
reactive_power_limits =
(min = reactive_power_limits_min, max = reactive_power_limits_max)
end
return reactive_power, reactive_power_limits
end
function make_synchronous_condenser_generator(
gen,
bus,
)
(reactive_power, reactive_power_limits) = make_reactive_params(gen)
active_power_limits =
(min = gen.active_power_limits_min, max = gen.active_power_limits_max)
rating = calculate_gen_rating(active_power_limits, reactive_power_limits, 1.0)
return SynchronousCondenser(;
name = gen.name,
available = gen.available,
bus = bus,
reactive_power = reactive_power,
rating = rating,
reactive_power_limits = reactive_power_limits,
base_power = gen.base_mva,
)
end
function make_thermal_generator(
data::PowerSystemTableData,
gen,
cost_colnames::Union{_CostPointColumns, _HeatRateColumns},
bus,
)
@debug "Making ThermaStandard" _group = IS.LOG_GROUP_PARSING gen.name
active_power_limits =
(min = gen.active_power_limits_min, max = gen.active_power_limits_max)
(reactive_power, reactive_power_limits) = make_reactive_params(gen)
rating = calculate_gen_rating(active_power_limits, reactive_power_limits, 1.0)
ramplimits = make_ramplimits(gen)
timelimits = make_timelimits(gen, :min_up_time, :min_down_time)
primemover = parse_enum_mapping(PrimeMovers, gen.unit_type)
fuel = parse_enum_mapping(ThermalFuels, gen.fuel)
base_power = gen.base_mva
op_cost = make_cost(ThermalStandard, data, gen, cost_colnames)
gen_must_run = isnothing(gen.must_run) ? false : gen.must_run
if !isa(gen_must_run, Bool)
gen_must_run = parse(Bool, lowercase(String(gen_must_run)))
end
return ThermalStandard(;
name = gen.name,
available = gen.available,
status = gen.status_at_start,
bus = bus,
active_power = gen.active_power,
reactive_power = reactive_power,
rating = rating,
prime_mover_type = primemover,
fuel = fuel,
active_power_limits = active_power_limits,
reactive_power_limits = reactive_power_limits,
ramp_limits = ramplimits,
time_limits = timelimits,
operation_cost = op_cost,
base_power = base_power,
must_run = gen_must_run,
)
end
function make_thermal_generator_multistart(
data::PowerSystemTableData,
gen,
cost_colnames,
bus,
)
thermal_gen = make_thermal_generator(data, gen, cost_colnames, bus)
@debug "Making ThermalMultiStart" _group = IS.LOG_GROUP_PARSING gen.name
# Get base operation cost from thermal generator
base_op_cost = get_operation_cost(thermal_gen)
# Extract time limits for hot/warm/cold starts
lag_hot =
if isnothing(gen.hot_start_time)
get_time_limits(thermal_gen).down
else
gen.hot_start_time
end
lag_warm = isnothing(gen.warm_start_time) ? 0.0 : gen.warm_start_time
lag_cold = isnothing(gen.cold_start_time) ? 0.0 : gen.cold_start_time
startup_timelimits = (hot = lag_hot, warm = lag_warm, cold = lag_cold)
start_types = sum(values(startup_timelimits) .> 0.0)
# Power trajectory for startup/shutdown ramps
startup_ramp = isnothing(gen.startup_ramp) ? 0.0 : gen.startup_ramp
shutdown_ramp = isnothing(gen.shutdown_ramp) ? 0.0 : gen.shutdown_ramp
power_trajectory = (startup = startup_ramp, shutdown = shutdown_ramp)
# Multi-start costs - use base cost as fallback if not specified
# Convert to Float64 since CSV values may be parsed as Int64
base_start_cost = get_start_up(base_op_cost)
hot_start_cost =
isnothing(gen.hot_start_cost) ? base_start_cost : Float64(gen.hot_start_cost)
warm_start_cost =
isnothing(gen.warm_start_cost) ? hot_start_cost : Float64(gen.warm_start_cost)
cold_start_cost =
isnothing(gen.cold_start_cost) ? warm_start_cost : Float64(gen.cold_start_cost)
startup_cost = (hot = hot_start_cost, warm = warm_start_cost, cold = cold_start_cost)
# Shutdown cost
base_shutdown_cost = get_shut_down(base_op_cost)
shutdown_cost =
isnothing(gen.shutdown_cost) ? base_shutdown_cost : Float64(gen.shutdown_cost)
# Create new operation cost with multi-start stages
op_cost = ThermalGenerationCost(
get_variable(base_op_cost),
get_fixed(base_op_cost),
startup_cost,
shutdown_cost,
)
return ThermalMultiStart(;
name = get_name(thermal_gen),
available = get_available(thermal_gen),
status = get_status(thermal_gen),
bus = get_bus(thermal_gen),
active_power = get_active_power(thermal_gen),
reactive_power = get_reactive_power(thermal_gen),
rating = get_rating(thermal_gen),
prime_mover_type = get_prime_mover_type(thermal_gen),
fuel = get_fuel(thermal_gen),
active_power_limits = get_active_power_limits(thermal_gen),
reactive_power_limits = get_reactive_power_limits(thermal_gen),
ramp_limits = get_ramp_limits(thermal_gen),
power_trajectory = power_trajectory,
time_limits = get_time_limits(thermal_gen),
start_time_limits = startup_timelimits,
start_types = start_types,
operation_cost = op_cost,
base_power = get_base_power(thermal_gen),
time_at_status = get_time_at_status(thermal_gen),
must_run = get_must_run(thermal_gen),
)
end
function make_hydro_dispatch(
data::PowerSystemTableData,
gen,
cost_colnames,
bus::ACBus,
)
@debug "Creating $(gen.name) as HydroDispatch" _group = IS.LOG_GROUP_PARSING
active_power_limits =
(min = gen.active_power_limits_min, max = gen.active_power_limits_max)
(reactive_power, reactive_power_limits) = make_reactive_params(gen)
rating = calculate_gen_rating(active_power_limits, reactive_power_limits, 1.0)
ramp_limits = make_ramplimits(gen)
time_limits = make_timelimits(gen, :min_up_time, :min_down_time)
base_power = gen.base_mva
operation_cost = make_cost(HydroGen, data, gen, cost_colnames)
hydro_gen = HydroDispatch(;
name = gen.name,
available = gen.available,
bus = bus,
active_power = gen.active_power,
reactive_power = reactive_power,
rating = rating,
prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type),
active_power_limits = active_power_limits,
reactive_power_limits = reactive_power_limits,
ramp_limits = ramp_limits,
time_limits = time_limits,
base_power = base_power,
operation_cost = operation_cost,
)
return hydro_gen
end
function _make_hydro_reservoirs(
data::PowerSystemTableData,
gen,
gen_storage,
tail_required::Bool,
)
if !haskey(data.category_to_df, InputCategory.STORAGE)
throw(DataFormatError("Storage information must defined in storage.csv"))
end
head_dict = gen_storage["head"]
if !haskey(head_dict, gen.name)
throw(
DataFormatError("Cannot find head storage for $(gen.name) in storage.csv"),
)
end
reservoir_data = head_dict[gen.name]
head_reservoir = HydroReservoir(;
name = string(reservoir_data.name, "_head"),
available = reservoir_data.available,
storage_level_limits = (
min = reservoir_data.min_storage_capacity,
max = reservoir_data.storage_capacity,
),
initial_level = reservoir_data.energy_level,
spillage_limits = nothing,
inflow = 1.0,
outflow = 1.0,
level_targets = reservoir_data.storage_target,
intake_elevation = 0.0,
head_to_volume_factor = LinearCurve(1.0),
operation_cost = HydroReservoirCost(),
level_data_type = ReservoirDataType.ENERGY,
)
tail_dict = gen_storage["tail"]
if !haskey(tail_dict, gen.name) && tail_required
throw(
DataFormatError("Cannot find tail storage for $(gen.name) in storage.csv"),
)
elseif !haskey(tail_dict, gen.name) && !tail_required
tail_reservoir = nothing
else
reservoir_data = tail_dict[gen.name]
tail_reservoir = HydroReservoir(;
name = string(reservoir_data.name, "_tail"),
available = reservoir_data.available,
storage_level_limits = (
min = reservoir_data.min_storage_capacity,
max = reservoir_data.storage_capacity,
),
initial_level = reservoir_data.energy_level,
spillage_limits = nothing,
inflow = 1.0,
outflow = 1.0,
level_targets = reservoir_data.storage_target,
intake_elevation = 0.0,
head_to_volume_factor = LinearCurve(1.0),
operation_cost = HydroReservoirCost(),
level_data_type = ReservoirDataType.ENERGY,
)
end
return head_reservoir, tail_reservoir
end
function make_hydro_turbine(
data::PowerSystemTableData,
gen,
cost_colnames,
bus::ACBus,
gen_storage::Dict{String, Any},
)
@debug "Creating $(gen.name) as HydroTurbine" _group = IS.LOG_GROUP_PARSING
active_power_limits =
(min = gen.active_power_limits_min, max = gen.active_power_limits_max)
(reactive_power, reactive_power_limits) = make_reactive_params(gen)
rating = calculate_gen_rating(active_power_limits, reactive_power_limits, 1.0)
ramp_limits = make_ramplimits(gen)
time_limits = make_timelimits(gen, :min_up_time, :min_down_time)
base_power = gen.base_mva
operation_cost = make_cost(HydroGen, data, gen, cost_colnames)
head_reservoir, tail_reservoir = _make_hydro_reservoirs(data, gen, gen_storage, false)
if isnothing(tail_reservoir)
reservoirs = [head_reservoir]
else
reservoirs = [head_reservoir, tail_reservoir]
end
hydro_gen = HydroTurbine(;
name = gen.name,
available = gen.available,
bus = bus,
active_power = gen.active_power,
reactive_power = reactive_power,
rating = rating,
active_power_limits = active_power_limits,
reactive_power_limits = reactive_power_limits,
base_power = base_power,
operation_cost = operation_cost,
ramp_limits = ramp_limits,
time_limits = time_limits,
outflow_limits = nothing,
)
set_downstream_turbines!(reservoirs[1], [hydro_gen])
if !isnothing(tail_reservoir)
set_upstream_turbines!(reservoirs[2], [hydro_gen])
end
return hydro_gen, reservoirs
end
function make_hydro_pump_storage(
data::PowerSystemTableData,
gen,
cost_colnames,
bus::ACBus,
gen_storage,
)
@debug "Creating $(gen.name) as HydroPumpTurbine" _group = IS.LOG_GROUP_PARSING
active_power_limits =
(min = gen.active_power_limits_min, max = gen.active_power_limits_max)
(reactive_power, reactive_power_limits) = make_reactive_params(gen)
rating = calculate_gen_rating(active_power_limits, reactive_power_limits, 1.0)
ramp_limits = make_ramplimits(gen)
time_limits = make_timelimits(gen, :min_up_time, :min_down_time)
base_power = gen.base_mva
head_reservoir, tail_reservoir = make_hydro_reservoirs(data, gen, gen_storage, true)
operation_cost = make_cost(HydroGen, data, gen, cost_colnames)
pump_active_power_limits = (
min = gen.pump_active_power_limits_min,
max = gen.pump_active_power_limits_max,
)
(pump_reactive_power, pump_reactive_power_limits) = make_reactive_params(
gen;
powerfield = :pump_reactive_power,
minfield = :pump_reactive_power_limits_min,
maxfield = :pump_reactive_power_limits_max,
)
pump_rating = calculate_gen_rating(
pump_active_power_limits,
pump_reactive_power_limits,
1.0,
)
pump_ramp_limits = make_ramplimits(
gen;
ramplimcol = :pump_ramp_limits,
rampupcol = :pump_ramp_up,
rampdncol = :pump_ramp_down,
)
pump_time_limits = make_timelimits(gen, :pump_min_up_time, :pump_min_down_time)
hydro_gen = HydroPumpTurbine(;
name = gen.name,
available = gen.available,
bus = bus,
active_power = gen.active_power,
reactive_power = reactive_power,
rating = rating,
active_power_limits = active_power_limits,
rating_pump = pump_rating,
reactive_power_limits = pump_reactive_power_limits,
active_power_limits_pump = pump_active_power_limits,
outflow_limits = nothing,
head_reservoir = head_reservoir,
tail_reservoir = tail_reservoir,
power_house_elevation = 0.0,
ramp_limits_pump = pump_ramp_limits,
time_limits_pump = pump_time_limits,
base_power = base_power,
operation_cost = operation_cost,
)
set_downstream_turbines!(head_reservoir, [hydro_gen])
set_upstream_turbines!(tail_reservoir, [hydro_gen])
return hydro_gen, [head_reservoir, tail_reservoir]
end
function make_renewable_generator(
gen_type,
data::PowerSystemTableData,
gen,
cost_colnames,
bus::ACBus,
)
@debug "Making RenewableGen" _group = IS.LOG_GROUP_PARSING gen.name
generator = nothing
active_power_limits =
(min = gen.active_power_limits_min, max = gen.active_power_limits_max)
(reactive_power, reactive_power_limits) = make_reactive_params(gen)
rating = calculate_gen_rating(active_power_limits, reactive_power_limits, 1.0)
base_power = gen.base_mva
operation_cost = make_cost(RenewableGen, data, gen, cost_colnames)
if gen_type == RenewableDispatch
@debug "Creating $(gen.name) as RenewableDispatch" _group = IS.LOG_GROUP_PARSING
generator = RenewableDispatch(;
name = gen.name,
available = gen.available,
bus = bus,
active_power = gen.active_power,
reactive_power = reactive_power,
rating = rating,
prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type),
reactive_power_limits = reactive_power_limits,
power_factor = gen.power_factor,
operation_cost = operation_cost,
base_power = base_power,
)
elseif gen_type == RenewableNonDispatch
@debug "Creating $(gen.name) as RenewableNonDispatch" _group = IS.LOG_GROUP_PARSING
generator = RenewableNonDispatch(;
name = gen.name,
available = gen.available,
bus = bus,
active_power = gen.active_power,
reactive_power = reactive_power,
rating = rating,
prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type),
power_factor = gen.power_factor,
base_power = base_power,
)
else
error("Unsupported type $gen_type")
end
return generator
end
function make_storage(data::PowerSystemTableData, gen, bus, storage)
@debug "Making Storage" _group = IS.LOG_GROUP_PARSING storage.name
input_active_power_limits = (
min = storage.input_active_power_limit_min,
max = storage.input_active_power_limit_max,
)
output_active_power_limits = (
min = storage.output_active_power_limit_min,
max = if isnothing(storage.output_active_power_limit_max)
gen.active_power_limits_max
else
storage.output_active_power_limit_max
end,
)
efficiency = (in = storage.input_efficiency, out = storage.output_efficiency)
(reactive_power, reactive_power_limits) = make_reactive_params(storage)
battery = EnergyReservoirStorage(;
name = gen.name,
available = storage.available,
bus = bus,
prime_mover_type = parse_enum_mapping(PrimeMovers, gen.unit_type),
storage_technology_type = StorageTech.OTHER_CHEM,
storage_capacity = storage.storage_capacity,
storage_level_limits = (
min = storage.min_storage_capacity / storage.storage_capacity,
max = 1.0,
),
initial_storage_capacity_level = storage.energy_level / storage.storage_capacity,
rating = storage.rating,
active_power = storage.active_power,
input_active_power_limits = input_active_power_limits,
output_active_power_limits = output_active_power_limits,
efficiency = efficiency,
reactive_power = reactive_power,
reactive_power_limits = reactive_power_limits,
base_power = storage.base_power,
operation_cost = StorageCost(),
)
return battery
end
const CATEGORY_STR_TO_COMPONENT = Dict{String, DataType}(
"ACBus" => ACBus,
"Generator" => Generator,
"Reserve" => Service,
"LoadZone" => LoadZone,
"ElectricLoad" => ElectricLoad,
"Storage" => Storage,
)
function _get_component_type_from_category(category::AbstractString)
component_type = get(CATEGORY_STR_TO_COMPONENT, category, nothing)
if isnothing(component_type)
throw(DataFormatError("unsupported category=$category"))
end
return component_type
end
function _read_config_file(file_path::String)
return open(file_path) do io
data = YAML.load(io)
# Replace keys with enums.
config_data = Dict{InputCategory, Vector}()
for (key, val) in data
# TODO: need to change user_descriptors.yaml to use reserve instead.
if key == "reserves"
key = "reserve"
end
config_data[get_enum_value(InputCategory, key)] = val
end
return config_data
end
end
"""Stores user-customized information for required dataframe columns."""
struct _FieldInfo
name::String
custom_name::String
per_unit_conversion::NamedTuple{
(:From, :To, :Reference),
Tuple{UnitSystem, UnitSystem, String},
}
unit_conversion::Union{NamedTuple{(:From, :To), Tuple{String, String}}, Nothing}
default_value::Any
# TODO unit, value ranges and options
end
function _get_field_infos(data::PowerSystemTableData, category::InputCategory, df_names)
if !haskey(data.user_descriptors, category)
throw(DataFormatError("Invalid category=$category"))
end
if !haskey(data.descriptors, category)
throw(DataFormatError("Invalid category=$category"))
end
# Cache whether PowerSystems uses a column's values as system-per-unit.
# The user's descriptors indicate that the raw data is already system-per-unit or not.
per_unit = Dict{String, IS.UnitSystem}()
unit = Dict{String, Union{String, Nothing}}()
custom_names = Dict{String, String}()
for descriptor in data.user_descriptors[category]
custom_name = descriptor["custom_name"]
if descriptor["custom_name"] in df_names
per_unit[descriptor["name"]] = get_enum_value(
IS.UnitSystem,
get(descriptor, "unit_system", "NATURAL_UNITS"),
)
unit[descriptor["name"]] = get(descriptor, "unit", nothing)
custom_names[descriptor["name"]] = custom_name
else
@warn "User-defined column name $custom_name is not in dataframe."
end
end
fields = Vector{_FieldInfo}()
for item in data.descriptors[category]
name = item["name"]
item_unit_system =
get_enum_value(IS.UnitSystem, get(item, "unit_system", "NATURAL_UNITS"))
per_unit_reference = get(item, "base_reference", "base_power")
default_value = get(item, "default_value", "required")
if default_value == "system_base_power"
default_value = data.base_power
end
if name in keys(custom_names)
custom_name = custom_names[name]
if item_unit_system == IS.UnitSystem.NATURAL_UNITS &&
per_unit[name] != IS.UnitSystem.NATURAL_UNITS
throw(DataFormatError("$name cannot be defined as $(per_unit[name])"))
end
pu_conversion = (
From = per_unit[name],
To = item_unit_system,
Reference = per_unit_reference,
)
expected_unit = get(item, "unit", nothing)
if !isnothing(expected_unit) &&
!isnothing(unit[name]) &&
expected_unit != unit[name]
unit_conversion = (From = unit[name], To = expected_unit)
else
unit_conversion = nothing
end
else
custom_name = name
pu_conversion = (
From = item_unit_system,
To = item_unit_system,
Reference = per_unit_reference,
)
unit_conversion = nothing
end
push!(
fields,
_FieldInfo(name, custom_name, pu_conversion, unit_conversion, default_value),
)
end
return fields
end
"""Reads values from dataframe row and performs necessary conversions."""
function _read_data_row(data::PowerSystemTableData, row, field_infos; na_to_nothing = true)
fields = Vector{String}()
vals = Vector()
for field_info in field_infos
if field_info.custom_name in names(row)
value = row[field_info.custom_name]
else
value = field_info.default_value
value == "required" && throw(DataFormatError("$(field_info.name) is required"))
@debug "Column $(field_info.custom_name) doesn't exist in df, enabling use of default value of $(field_info.default_value)" _group =
IS.LOG_GROUP_PARSING maxlog = 1
end
if ismissing(value)
throw(DataFormatError("$(field_info.custom_name) value missing"))
end
if na_to_nothing && value == "NA"
value = nothing
end
if !isnothing(value)
if field_info.per_unit_conversion.From == IS.UnitSystem.NATURAL_UNITS &&
field_info.per_unit_conversion.To == IS.UnitSystem.SYSTEM_BASE
@debug "convert to $(field_info.per_unit_conversion.To)" _group =
IS.LOG_GROUP_PARSING field_info.custom_name
value = value isa AbstractString ? tryparse(Float64, value) : value
value = data.base_power == 0.0 ? 0.0 : value / data.base_power
elseif field_info.per_unit_conversion.From == IS.UnitSystem.NATURAL_UNITS &&
field_info.per_unit_conversion.To == IS.UnitSystem.DEVICE_BASE
reference_idx = findfirst(
x -> x.name == field_info.per_unit_conversion.Reference,
field_infos,
)
isnothing(reference_idx) && throw(
DataFormatError(
"$(field_info.per_unit_conversion.Reference) not found in table with $(field_info.custom_name)",
),
)
reference_info = field_infos[reference_idx]
@debug "convert to $(field_info.per_unit_conversion.To) using $(reference_info.custom_name)" _group =
IS.LOG_GROUP_PARSING field_info.custom_name maxlog = 1
reference_value =
get(row, reference_info.custom_name, reference_info.default_value)
reference_value == "required" && throw(
DataFormatError(
"$(reference_info.name) is required for p.u. conversion",
),
)
value = value isa AbstractString ? tryparse(Float64, value) : value
value = reference_value == 0.0 ? 0.0 : value / reference_value
elseif field_info.per_unit_conversion.From != field_info.per_unit_conversion.To
throw(
DataFormatError(
"conversion not supported from $(field_info.per_unit_conversion.From) to $(field_info.per_unit_conversion.To) for $(field_info.custom_name)",
),
)
end
else
@debug "$(field_info.custom_name) is nothing" _group = IS.LOG_GROUP_PARSING maxlog =
1
end
# TODO: need special handling for units
if !isnothing(field_info.unit_conversion)
@debug "convert units" _group = IS.LOG_GROUP_PARSING field_info.custom_name maxlog =
1
value = convert_units!(value, field_info.unit_conversion)
end
# TODO: validate ranges and option lists
push!(fields, field_info.name)
push!(vals, value)
end
return NamedTuple{Tuple(Symbol.(fields))}(vals)
end
================================================
FILE: src/parsers/powerflowdata_data.jl
================================================
"""Container for data parsed by PowerFlowData"""
struct PowerFlowDataNetwork
data::PowerFlowData.Network
end
"""
Constructs PowerFlowDataNetwork from a raw file.
Currently Supports PSSE data files v30, v32 and v33
"""
function PowerFlowDataNetwork(file::Union{String, IO}; kwargs...)
return PowerFlowDataNetwork(PowerFlowData.parse_network(file))
end
"""
Constructs a System from PowerModelsData.
# Arguments
- `pfd_data::Union{PowerFlowDataNetwork, Union{String, IO}}`: PowerModels data object or supported
load flow case (*.m, *.raw)
# Keyword arguments
- `ext::Dict`: Contains user-defined parameters. Should only contain standard types.
- `runchecks::Bool`: Run available checks on input fields and when add_component! is called.
Throws InvalidValue if an error is found.
- `time_series_in_memory::Bool=false`: Store time series data in memory instead of HDF5.
- `config_path::String`: specify path to validation config file
- `pm_data_corrections::Bool=true` : Run the PowerModels data corrections (aka :validate in PowerModels)
- `import_all:Bool=false` : Import all fields from PTI files
# Examples
```julia
sys = System(
pm_data, config_path = "ACTIVSg25k_validation.json",
bus_name_formatter = x->string(x["name"]*"-"*string(x["index"])),
load_name_formatter = x->strip(join(x["source_id"], "_"))
)
```
"""
function System(net_data::PowerFlowDataNetwork; kwargs...)
runchecks = get(kwargs, :runchecks, true)
data = net_data.data
if length(data.buses) < 1
throw(DataFormatError("There are no buses in this file."))
end
@info "Constructing System from PowerFlowData version v$(data.caseid.rev)"
if isa(data.caseid.sbase, Missing)
error("Base power not specified in .raw file. Data parsing can not continue")
end
if isa(data.caseid.basfrq, Missing)
@warn "Frequency value missing from .raw file. Using default 60 Hz"
frequency = 60.0
else
frequency = data.caseid.basfrq
end
sys = System(data.caseid.sbase; frequency = frequency, kwargs...)
bus_number_to_bus = read_bus!(sys, data.buses, data; kwargs...)
read_loads!(sys, data.loads, data.caseid.sbase, bus_number_to_bus; kwargs...)
read_gen!(sys, data.generators, data.caseid.sbase, bus_number_to_bus; kwargs...)
read_branch!(
sys,
data.branches,
data.caseid.sbase,
bus_number_to_bus;
kwargs...,
)
read_branch!(sys, data.transformers, data.caseid.sbase, bus_number_to_bus; kwargs...)
read_shunt!(sys, data.fixed_shunts, data.caseid.sbase, bus_number_to_bus; kwargs...)
read_switched_shunt!(
sys,
data.switched_shunts,
data.caseid.sbase,
bus_number_to_bus;
kwargs...,
)
read_dcline!(
sys,
data.two_terminal_dc,
data.caseid.sbase,
bus_number_to_bus;
kwargs...,
)
read_dcline!(
sys,
data.multi_terminal_dc,
data.caseid.sbase,
bus_number_to_bus;
kwargs...,
)
read_dcline!(
sys,
data.vsc_dc,
data.caseid.sbase,
bus_number_to_bus;
kwargs...,
)
if runchecks
check(sys)
end
return sys
end
function read_bus!(
sys::System,
buses::PowerFlowData.Buses33,
data::PowerFlowData.Network;
kwargs...,
)
bus_number_to_bus = Dict{Int, ACBus}()
bus_types = instances(ACBusTypes)
for ix in eachindex(buses.i)
# d id the data dict for each bus
# d_key is bus key
bus_name = strip(buses.name[ix]) * "_$(buses.i[ix])" * "_$(buses.ide[ix])"
has_component(ACBus, sys, bus_name) && throw(
DataFormatError(
"Found duplicate bus names of $bus_name, consider formatting names with `bus_name_formatter` kwarg",
),
)
bus_number = buses.i[ix]
if isempty(data.area_interchanges)
area_name = string(buses.area[ix])
@debug "File doesn't contain area names"
else
area_ix = findfirst(data.area_interchanges.i .== buses.area[ix])
area_name = data.area_interchanges.arname[area_ix]
end
area = get_component(Area, sys, area_name)
if isnothing(area)
area = Area(area_name)
add_component!(sys, area; skip_validation = SKIP_PM_VALIDATION)
end
# TODO: LoadZones need to be created and populated here
if isempty(data.zones)
zone_name = string(buses.zone[ix])
@debug "File doesn't contain load zones"
else
zone_ix = findfirst(data.zones.i .== buses.zone[ix])
zone_name = "$(data.zones.zoname[zone_ix])_$(data.zones.i[zone_ix])"
end
zone = get_component(LoadZone, sys, zone_name)
if isnothing(zone)
zone = LoadZone(zone_name, 0.0, 0.0)
add_component!(sys, zone; skip_validation = SKIP_PM_VALIDATION)
end
zone = get_component(LoadZone, sys, zone_name)
if isnothing(zone)
zone = LoadZone(zone_name, 0.0, 0.0)
add_component!(sys, zone; skip_validation = SKIP_PM_VALIDATION)
end
bus = ACBus(
bus_number,
bus_name,
true,
bus_types[buses.ide[ix]],
clamp(buses.va[ix] * (π / 180), -π / 2, π / 2),
buses.vm[ix],
(min = buses.nvlo[ix], max = buses.nvhi[ix]),
buses.basekv[ix],
area,
zone,
)
bus_number_to_bus[bus_number] = bus
add_component!(sys, bus; skip_validation = SKIP_PM_VALIDATION)
end
# TODO: Checking for surplus Areas or LoadZones in the data which don't get populated in the sys above
# but are available in the raw file
if ~isempty(data.area_interchanges)
for area_name in data.area_interchanges.arname
area = get_component(Area, sys, area_name)
if isnothing(area)
area = Area(area_name)
add_component!(sys, area; skip_validation = SKIP_PM_VALIDATION)
end
end
end
if ~isempty(data.zones)
for (i, name) in zip(data.zones.i, data.zones.zoname)
zone_name = "$(name)_$(i)"
zone = get_component(LoadZone, sys, zone_name)
if isnothing(zone)
zone = LoadZone(zone_name, 0.0, 0.0)
add_component!(sys, zone; skip_validation = SKIP_PM_VALIDATION)
end
end
end
return bus_number_to_bus
end
function read_bus!(
sys::System,
buses::PowerFlowData.Buses30,
data::PowerFlowData.Network;
kwargs...,
)
bus_number_to_bus = Dict{Int, ACBus}()
bus_types = instances(ACBusTypes)
for ix in 1:length(buses)
# d id the data dict for each bus
# d_key is bus key
bus_name = strip(buses.name[ix]) * "_$(buses.i[ix])" * "_$(buses.ide[ix])"
has_component(ACBus, sys, bus_name) && throw(
DataFormatError(
"Found duplicate bus names of $bus_name, consider formatting names with `bus_name_formatter` kwarg",
),
)
bus_number = buses.i[ix]
if isempty(data.area_interchanges)
area_name = string(buses.area[ix])
@debug "File doesn't contain area names"
else
area_ix = data.area_interchanges.i .== buses.area[ix]
if all(.!area_ix)
error("Area numbering is incorrectly specified in PSSe file")
end
area_name = first(data.area_interchanges.arname[area_ix])
end
area = get_component(Area, sys, area_name)
if isnothing(area)
area = Area(area_name)
add_component!(sys, area; skip_validation = SKIP_PM_VALIDATION)
end
# TODO: LoadZones need to be created and populated here
bus = ACBus(
bus_number,
bus_name,
true,
bus_types[buses.ide[ix]],
clamp(buses.va[ix] * (π / 180), -π / 2, π / 2),
buses.vm[ix],
nothing, # PSSe 30 data doesn't have magnitude limits
buses.basekv[ix],
area,
)
bus_number_to_bus[bus_number] = bus
add_component!(sys, bus; skip_validation = SKIP_PM_VALIDATION)
if buses.bl[ix] > 0 || buses.gl[ix] > 0
shunt = FixedAdmittance(bus_name, true, bus, buses.gl[ix] + 1im * buses.bl[ix])
add_component!(sys, shunt; skip_validation = SKIP_PM_VALIDATION)
end
end
return bus_number_to_bus
end
function read_loads!(
sys::System,
loads::PowerFlowData.Loads,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
if isempty(loads)
@error "There are no loads in this file"
return
end
for ix in eachindex(loads.i)
bus = bus_number_to_bus[loads.i[ix]]
load_name = "load-$(get_name(bus))~$(loads.id[ix])"
if has_component(StandardLoad, sys, load_name)
throw(DataFormatError("Found duplicate load names of $(load_name)"))
end
load = StandardLoad(;
name = load_name,
available = loads.status[ix],
bus = bus,
constant_active_power = loads.pl[ix] / sys_mbase,
constant_reactive_power = loads.ql[ix] / sys_mbase,
impedance_active_power = loads.yp[ix] / sys_mbase,
impedance_reactive_power = loads.yq[ix] / sys_mbase,
current_active_power = loads.ip[ix] / sys_mbase,
current_reactive_power = loads.iq[ix] / sys_mbase,
max_constant_active_power = loads.pl[ix] / sys_mbase,
max_constant_reactive_power = loads.ql[ix] / sys_mbase,
max_impedance_active_power = loads.yp[ix] / sys_mbase,
max_impedance_reactive_power = loads.yq[ix] / sys_mbase,
max_current_active_power = loads.ip[ix] / sys_mbase,
max_current_reactive_power = loads.iq[ix] / sys_mbase,
base_power = sys_mbase,
)
add_component!(sys, load; skip_validation = SKIP_PM_VALIDATION)
end
# Populate Areas and LoadZones with peak active and reactive power
areas = get_components(Area, sys)
if ~isnothing(areas)
for area in areas
area_comps = get_components_in_aggregation_topology(StandardLoad, sys, area)
if (isempty(area_comps))
set_peak_active_power!(area, 0.0)
set_peak_reactive_power!(area, 0.0)
else
set_peak_active_power!(
area,
sum(get.(get_ext.(area_comps), "active_power_load", 0.0)),
)
set_peak_reactive_power!(
area,
sum(get.(get_ext.(area_comps), "reactive_power_load", 0.0)),
)
end
end
end
zones = get_components(LoadZone, sys)
if ~isnothing(zones)
for zone in zones
zone_comps = get_components_in_aggregation_topology(StandardLoad, sys, zone)
if (isempty(zone_comps))
set_peak_active_power!(zone, 0.0)
set_peak_reactive_power!(zone, 0.0)
else
set_peak_active_power!(
zone,
sum(get.(get_ext.(zone_comps), "active_power_load", 0.0)),
)
set_peak_reactive_power!(
zone,
sum(get.(get_ext.(zone_comps), "reactive_power_load", 0.0)),
)
end
end
end
return nothing
end
function _get_active_power_limits(
pt::Float64,
pb::Float64,
machine_base::Float64,
system_base::Float64,
)
min_p = 0.0
if pb < 0.0
@info "Min power in dataset is negative, active_power_limits minimum set to 0.0"
else
min_p = pb
end
if machine_base != system_base && pt >= machine_base
@info "Max active power limit is $(pt/machine_base) than the generator base. Check the data"
end
return (min = min_p / machine_base, max = pt / machine_base)
end
function read_gen!(
sys::System,
gens::PowerFlowData.Generators,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading generator data"
if isempty(gens)
@error "There are no generators in this file"
return
end
for ix in eachindex(gens.i)
bus = get(bus_number_to_bus, gens.i[ix], nothing)
if isnothing(bus)
error("Incorrect bus id for generator $(gens.i[ix])-$(gens.id[ix])")
end
gen_name = "gen-$(get_name(bus))~$(gens.id[ix])"
if has_component(ThermalStandard, sys, gen_name)
throw(DataFormatError("Found duplicate load names of $(gen_name)"))
end
ireg_bus_num = gens.ireg[ix] == 0 ? gens.i[ix] : gens.ireg[ix]
thermal_gen = ThermalStandard(;
name = gen_name,
available = gens.stat[ix] > 0 ? true : false,
status = gens.stat[ix] > 0 ? true : false,
bus = bus,
active_power = gens.pg[ix] / gens.mbase[ix],
reactive_power = gens.qg[ix] / gens.mbase[ix],
active_power_limits = _get_active_power_limits(
gens.pt[ix],
gens.pb[ix],
gens.mbase[ix],
sys_mbase,
),
reactive_power_limits = (
min = gens.qb[ix] / sys_mbase,
max = gens.qt[ix] / sys_mbase,
),
base_power = gens.mbase[ix],
rating = gens.mbase[ix],
ramp_limits = nothing,
time_limits = nothing,
operation_cost = ThermalGenerationCost(nothing),
ext = Dict(
"IREG" => ireg_bus_num,
"WMOD" => gens.wmod[ix],
"WPF" => gens.wpf[ix],
),
)
add_component!(sys, thermal_gen; skip_validation = SKIP_PM_VALIDATION)
end
return nothing
end
function read_branch!(
sys::System,
branches::PowerFlowData.Branches30,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading line data"
if isempty(branches)
@error "There are no lines in this file"
return
end
for ix in eachindex(branches.i)
if branches.i[ix] < 0
i_ix = abs(branches.i[ix])
@warn "Branch index $(branches.i[ix]) corrected to $i_ix"
end
if branches.j[ix] < 0
j_ix = abs(branches.i[ix])
@warn "Branch index $(branches.j[ix]) corrected to $j_ix"
end
bus_from = bus_number_to_bus[abs(branches.i[ix])]
bus_to = bus_number_to_bus[abs(branches.j[ix])]
branch_name = "line-$(get_name(bus_from))-$(get_name(bus_to))-$(branches.ckt[ix])"
max_rate = max(branches.rate_a[ix], branches.rate_b[ix], branches.rate_c[ix])
if max_rate == 0.0
max_rate = abs(1 / (branches.r[ix] + 1im * branches.x[ix])) * sys_mbase
end
branch = Line(;
name = branch_name,
available = branches.st[ix] > 0 ? true : false,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
arc = Arc(bus_from, bus_to),
r = branches.r[ix],
x = branches.x[ix],
b = (from = branches.bi[ix], to = branches.bj[ix]),
angle_limits = (min = -π / 2, max = π / 2),
rating = max_rate,
)
add_component!(sys, branch; skip_validation = SKIP_PM_VALIDATION)
end
return nothing
end
function read_branch!(
sys::System,
branches::PowerFlowData.Branches33,
sys_mbase::Float64,
rating_flag::Int8,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading line data"
if isempty(branches)
@error "There are no lines in this file"
return
end
for ix in eachindex(branches.i)
bus_from = bus_number_to_bus[branches.i[ix]]
bus_to = bus_number_to_bus[branches.j[ix]]
branch_name = "line-$(get_name(bus_from))-$(get_name(bus_to))~$(branches.ckt[ix])"
max_rate = max(branches.rate_a[ix], branches.rate_b[ix], branches.rate_c[ix])
if get_base_voltage(bus_from) != get_base_voltage(bus_to)
@warn("bad line data $branch_name. Transforming this Line to Transformer2W.")
# Method needed for NTPS to make this data into a transformer
transformer_name = "transformer-$(get_name(bus_from))-$(get_name(bus_to))~$(branches.ckt[ix])"
transformer = Transformer2W(;
name = transformer_name,
available = branches.st[ix] > 0 ? true : false,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
arc = Arc(bus_from, bus_to),
r = branches.r[ix],
x = branches.x[ix],
primary_shunt = 0.0,
winding_group_number = WindingGroupNumber(0),
rating = max_rate,
base_power = get_base_power(sys), # add system base power
ext = Dict(
"line_to_xfr" => true,
),
)
add_component!(sys, transformer; skip_validation = SKIP_PM_VALIDATION)
continue
end
rated_current = 0.0
if (rating_flag > 0)
rated_current = (max_rate / (sqrt(3) * get_base_voltage(bus_from))) * 10^3
end
branch = Line(;
name = branch_name,
available = branches.st[ix] > 0 ? true : false,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
arc = Arc(bus_from, bus_to),
r = branches.r[ix],
x = branches.x[ix],
b = (from = branches.bi[ix], to = branches.bj[ix]),
angle_limits = (min = -π / 2, max = π / 2),
rating = max_rate,
ext = Dict(
"length" => branches.len[ix],
"rated_current(A)" => rated_current,
),
)
add_component!(sys, branch; skip_validation = SKIP_PM_VALIDATION)
end
return nothing
end
function read_branch!(
sys::System,
transformers::PowerFlowData.Transformers,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading transformer data"
if isempty(transformers)
@error "There are no transformers in this file"
return
end
for ix in eachindex(transformers.i)
bus_i = bus_number_to_bus[transformers.i[ix]]
bus_j = bus_number_to_bus[transformers.j[ix]]
if transformers.k[ix] > 0
@error "Three-winding transformer from PowerFlowData inputs not implemented. Data will be ignored"
continue
else
to_from_name = "$(get_name(bus_i))-$(get_name(bus_j))"
end
if transformers.ang1[ix] != 0
@error "Phase Shifting transformer from PowerFlowData inputs not implemented. Data will be ignored"
continue
end
transformer_name = "transformer-$to_from_name-$(transformers.ckt[ix])"
if !(transformers.cz[ix] in [1, 2, 3])
@warn(
"transformer CZ value outside of valid bounds assuming the default value of 1. Given $(transformer["CZ"]), should be 1, 2 or 3",
)
transformers.cz[ix] = 1
end
if !(transformers.cw[ix] in [1, 2, 3])
@warn(
"transformer CW value outside of valid bounds assuming the default value of 1. Given $(transformer["CW"]), should be 1, 2 or 3",
)
transformers.cw[ix] = 1
end
if !(transformers.cm[ix] in [1, 2])
@warn(
"transformer CM value outside of valid bounds assuming the default value of 1. Given $(transformer["CM"]), should be 1 or 2",
)
transformers.cm[ix] = 1
end
# Unit Transformations
if transformers.cz[ix] == 1 # "for resistance and reactance in pu on system MVA base and winding voltage base"
br_r, br_x = transformers.r1_2[ix], transformers.x1_2[ix]
else # NOT "for resistance and reactance in pu on system MVA base and winding voltage base"
if transformers.cz[ix] == 3 # "for transformer load loss in watts and impedance magnitude in pu on a specified MVA base and winding voltage base."
br_r = 1e-6 * transformers.r1_2[ix] / transformers.sbase1_2[ix]
br_x = sqrt(transformers.x1_2[ix]^2 - br_r^2)
else
br_r, br_x = transformers.r1_2[ix], transformers.x1_2[ix]
end
per_unit_factor =
(
transformers.nomv1[ix]^2 /
get_base_voltage(bus_i)^2
) * (sys_mbase / transformers.sbase1_2[ix])
if per_unit_factor == 0
@warn "Per unit conversion for transformer $to_from_name couldn't be done, assuming system base instead. Check field NOMV1 is valid"
per_unit_factor = 1
end
br_r *= per_unit_factor
br_x *= per_unit_factor
end
# Zeq scaling for tap2 (see eq (4.21b) in PROGRAM APPLICATION GUIDE 1 in PSSE installation folder)
# Unit Transformations
if transformers.cw[ix] == 1 # "for off-nominal turns ratio in pu of winding bus base voltage"
br_r *= transformers.windv2[ix]^2
br_x *= transformers.windv2[ix]^2
else # NOT "for off-nominal turns ratio in pu of winding bus base voltage"
if transformers.cw[ix] == 2 # "for winding voltage in kV"
br_r *=
(
transformers.windv2[ix] /
get_base_voltage(bus_j)
)^2
br_x *=
(
transformers.windv2[ix] /
get_base_voltage(bus_j)
)^2
else # "for off-nominal turns ratio in pu of nominal winding voltage, NOMV1, NOMV2 and NOMV3."
br_r *=
(
transformers.windv2[ix] * (
transformers.nomv2[ix] /
get_base_voltage(bus_j)
)
)^2
br_x *=
(
transformers.windv2[ix] * (
transformers.nomv2[ix] /
get_base_voltage(bus_j)
)
)^2
end
end
max_rate =
max(transformers.rata1[ix], transformers.ratb1[ix], transformers.ratc1[ix])
tap_value = transformers.windv1[ix] / transformers.windv2[ix]
# Unit Transformations
if transformers.cw[ix] != 1 # NOT "for off-nominal turns ratio in pu of winding bus base voltage"
tap_value *= get_base_voltage(bus_j) / get_base_voltage(bus_i)
if transformers.cw[ix] == 3 # "for off-nominal turns ratio in pu of nominal winding voltage, NOMV1, NOMV2 and NOMV3."
tap_value *= transformers.nomv1[ix] / transformers.nomv2[ix]
end
end
transformer = TapTransformer(;
name = transformer_name,
available = transformers.stat[ix] > 0 ? true : false,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
arc = Arc(bus_i, bus_j),
r = br_r,
x = br_x,
tap = tap_value,
primary_shunt = transformers.mag2[ix],
winding_group_number = WindingGroupNumber(0),
base_power = get_base_power(sys),
rating = max_rate,
)
add_component!(sys, transformer; skip_validation = SKIP_PM_VALIDATION)
end
return nothing
end
function read_shunt!(
::System,
::Nothing,
::Float64,
::Dict{Int, ACBus};
kwargs...,
)
@debug "No data for Fixed Shunts"
return
end
function read_shunt!(
sys::System,
data::PowerFlowData.FixedShunts,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@error "FixedShunts parsing from PowerFlowData inputs not implemented. Data will be ignored"
return
end
function read_switched_shunt!(
sys::System,
::Nothing,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@debug "No data for Switched Shunts"
return
end
function read_switched_shunt!(
sys::System,
::PowerFlowData.SwitchedShunts30,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@error "SwitchedShunts parsing from PSS/e v30 files not implemented. Data will be ignored"
return
end
function read_switched_shunt!(
sys::System,
data::PowerFlowData.SwitchedShunts33,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@info "Reading line data"
@warn "All switched shunts will be converted to fixed shunts"
if isempty(data)
@error "There are no lines in this file"
return
end
@error "SwitchedShunts parsing from PSS/e v33 files not implemented. Data will be ignored"
return
end
function read_dcline!(
sys::System,
::Nothing,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@debug "No data for HVDC Line"
return
end
function read_dcline!(
sys::System,
data::PowerFlowData.TwoTerminalDCLines30,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@error "TwoTerminalDCLines parsing from PSS/e v30 files not implemented. Data will be ignored"
return
end
function read_dcline!(
sys::System,
data::PowerFlowData.TwoTerminalDCLines33,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
return
end
function read_dcline!(
sys::System,
data::PowerFlowData.VSCDCLines,
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@error "VSCDCLines parsing from PSS/e files not implemented. Data will be ignored"
return
end
function read_dcline!(
sys::System,
data::PowerFlowData.MultiTerminalDCLines{PowerFlowData.DCLineID30},
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@error "MultiTerminalDCLines parsing from PSS/e files v30 not implemented. Data will be ignored"
return
end
function read_dcline!(
sys::System,
data::PowerFlowData.MultiTerminalDCLines{PowerFlowData.DCLineID33},
sys_mbase::Float64,
bus_number_to_bus::Dict{Int, ACBus};
kwargs...,
)
@error "MultiTerminalDCLines parsing from PSS/e files v30 not implemented. Data will be ignored"
return
end
================================================
FILE: src/parsers/psse_dynamic_data.jl
================================================
# Additional constants for repeated structs
const TGOV1DU = SteamTurbineGov1
const GEN_COMPONENT_TABLE =
Dict("Machine" => 1, "Shaft" => 2, "AVR" => 3, "TurbineGov" => 4, "PSS" => 5)
const INV_COMPONENT_TABLE = Dict(
"Converter" => 1,
"ActivePowerControl" => 2,
"ReactivePowerControl" => 3,
"InnerControl" => 4,
"DCSource" => 5,
"FrequencyEstimator" => 6,
"Filter" => 7,
)
"""
Parse .dyr file into a dictionary indexed by bus number.
Each bus number key has a dictionary indexed by component type and id.
Comments in .dyr files are not supported (beginning of lines with //).
"""
function _parse_dyr_file(file::AbstractString)
dyr_text = read(file, String)
start = 1
parsed_values = Dict{Int, Dict}()
while start < length(dyr_text)
val = findnext('/', dyr_text, start)
if isnothing(val)
break
end
text = strip(dyr_text[start:(val - 1)])
if !isempty(text)
line = replace(text, "\'" => "")
line = replace(line, "," => " ")
val_array = strip.(split(line))
bus = parse(Int, val_array[1])
model = string(val_array[2])
id = string(val_array[3])
component_dict = get!(parsed_values, bus, Dict{Tuple{String, String}, Array}())
component_dict[(model, id)] = parse.(Float64, val_array[4:end])
end
start = val + 1
end
return parsed_values
end
function _parse_input_types(_v, val)
# If the parameter is a Float64, then use the value directly as the argument.
# Typically uses for the resistance that is not available in .dyr files.
if isa(_v, Float64)
if isnan(_v)
error("nan for $(_v)")
end
return _v
# If the parameter is an Int, then use the integer as the key of the value in the dictionary.
elseif isa(_v, Int)
return val[_v]
elseif _v == "NaN"
return NaN
# If the parameter is a tuple (as a string), then construct the tuple directly.
elseif isa(_v, String)
#TODO: Generalize n-length tuple
m = match(r"^\((\d+)\s*,\s*(\d+)\)$", _v)
m2 = match(r"^\((\d+)\s*,\s*(\d+),\s*(\d+)\)$", _v)
if m !== nothing
_tuple_ix = parse.(Int, m.captures)
return Tuple(val[_tuple_ix])
elseif m2 !== nothing
_tuple_ix = parse.(Int, m2.captures)
return Tuple(val[_tuple_ix])
else
error("String $(_v) not recognized for parsing")
end
else
error("invalid input value $val")
end
return
end
"""
Populate arguments in a vector for each dynamic component (except Shafts).
Returns a vector with the parameter values of the argument of each component.
"""
function _populate_args(param_map::Vector, val)
struct_args = Vector{Any}(undef, length(param_map))
_populate_args!(struct_args, param_map, val, "")
return struct_args
end
function _populate_args!(struct_args, param_map::Vector, val, ::String)
for (ix, _v) in enumerate(param_map)
parameter_value = _parse_input_types(_v, val)
if !all(isnan.(parameter_value))
struct_args[ix] = parameter_value
end
end
return
end
function _populate_args!(struct_args, param_dic::Dict, val, id::String)
param_map = param_dic[id]
_populate_args!(struct_args, param_map, val, id)
return
end
"""
Create a SingleMass shaft struct directly using the parameter mapping.
"""
function _make_shaft(param_map, val)
constructor_shaft =
(args...) -> InteractiveUtils.getfield(PowerSystems, :SingleMass)(args...)
shaft_args = _populate_args(param_map, val)
return constructor_shaft(shaft_args...)
end
function _make_source(g::StaticInjection, r::Float64, x::Float64, sys_base::Float64)
# Transform Z_source to System Base
machine_base = get_base_power(g)
r_sysbase = r * (sys_base / machine_base)
x_sysbase = x * (sys_base / machine_base)
return Source(;
name = get_name(g),
available = true,
bus = get_bus(g),
active_power = get_active_power(g),
reactive_power = get_reactive_power(g),
R_th = r_sysbase,
X_th = x_sysbase,
)
end
function _assign_missing_components!(
components_dict::Dict,
component_table,
::Type{T},
) where {T <: DynamicGenerator}
for va in values(components_dict)
if length(va) == length(keys(component_table))
if ismissing(va[component_table["AVR"]])
va[component_table["AVR"]] = AVRFixed(1.0)
end
if ismissing(va[component_table["TurbineGov"]])
va[component_table["TurbineGov"]] = TGFixed(1.0)
end
if ismissing(va[component_table["PSS"]])
va[component_table["PSS"]] = PSSFixed(0.0)
end
end
end
return
end
function _assign_missing_components!(
components_dict::Dict,
component_table,
::Type{T},
) where {T <: DynamicInverter}
for va in values(components_dict)
if length(va) == length(keys(component_table))
if ismissing(va[component_table["Converter"]])
va[component_table["Converter"]] = AverageConverter(750.0, 2.75)
end
if ismissing(va[component_table["Filter"]])
va[component_table["Filter"]] = RLFilter(0.0, 0.0)
end
if ismissing(va[component_table["FrequencyEstimator"]])
va[component_table["FrequencyEstimator"]] = FixedFrequency()
end
if ismissing(va[component_table["DCSource"]])
va[component_table["DCSource"]] = FixedDCSource(750.0)
end
end
end
return
end
"""
Parse a .dyr file directly from its name by constructing its dictionary of dictionaries.
"""
function _parse_dyr_components(dyr_file::AbstractString)
ext = splitext(dyr_file)[2]
if lowercase(ext) in [".dyr"]
data = _parse_dyr_file(dyr_file)
return _parse_dyr_components(data)
else
throw(DataFormatError("$dyr_file is not a .dyr file type"))
end
end
function _make_bus_inverters_dictionary(bus_data, inv_map, inv_keys, param_map)
bus_dict_values = Dict{String, Any}()
for (componentID, componentValues) in bus_data
# ComponentID is a tuple:
# ComponentID[1] is the PSSE name
# ComponentID[2] is the number ID of the generator/inverter
# Fill array of 7 components per inverter
# Only create if name is in the supported keys in the mapping
if componentID[1] in inv_keys
# Get the component dictionary
temp = get!(bus_dict_values, componentID[2], Dict{Any, Vector{Any}}())
components_dict = inv_map[componentID[1]]
for (inv_field, struct_as_str) in components_dict
param_vec = get!(
temp,
(inv_field, struct_as_str),
_instantiate_param_vector_size(struct_as_str, param_map),
)
params_ix = param_map[struct_as_str]
_populate_args!(param_vec, params_ix, componentValues, componentID[1])
end
end
end
return bus_dict_values
end
"""
Parse dictionary of dictionaries of data (from `_parse_dyr_file`) into a dictionary of struct components.
The function receives the parsed dictionary and constructs a dictionary indexed by bus, that contains a
dictionary with each dynamic generator and dynamic inverter components (indexed via its id).
For Generators, each dictionary indexed by id contains a vector with 5 of its components:
* Machine
* Shaft
* AVR
* TurbineGov
* PSS
For Inverters, each dictionary indexed by id contains a vector with 7 of its components:
* Converter
* ActivePowerControl
* ReactivePowerControl
* InnerControl
* DCSource
* FrequencyEstimator
* Filter
"""
function _parse_dyr_components(data::Dict)
yaml_mapping = open(PSSE_DYR_MAPPING_FILE) do io
aux = YAML.load(io)
return aux
end
# param_map contains the mapping between struct params and dyr file.
param_map = yaml_mapping["parameter_mapping"][1]
# gen_map contains all the supported structs for generators
gen_map = yaml_mapping["generator_mapping"][1]
# inv_map contains al the supported structs for inverters
inv_map = yaml_mapping["inverter_mapping"][1]
# additional_map contains all the supported structs for additional injectors
additional_map = yaml_mapping["additional_mapping"][1]
gen_keys = Set(keys(gen_map))
inv_keys = Set(keys(inv_map))
additional_keys = Set(keys(additional_map))
# dic will contain the dictionary index by bus.
# Each entry will be a dictionary, with id as keys, that contains the vector of components
system_dic = Dict{Int, Any}()
for (bus_num, bus_data) in data # bus_data is a dictionary with values per component (key)
bus_dict = Dict{String, Any}()
inverters_dict = Dict{String, Any}()
for (componentID, componentValues) in bus_data
# ComponentID is a tuple:
# ComponentID[1] is the PSSE name
# ComponentID[2] is the number ID of the generator/inverter
if componentID[1] in gen_keys
_parse_dyr_generator_components!(
bus_dict,
componentID,
componentValues,
gen_map,
param_map,
)
elseif componentID[1] in inv_keys
if isempty(inverters_dict)
# Since a single PSSe inverter component contributes to more than one PSY component
# We need to map all the other components beforehand if Inverter components are present
inverters_dict = _make_bus_inverters_dictionary(
bus_data,
inv_map,
inv_keys,
param_map,
)
end
_parse_dyr_inverter_components!(
bus_dict,
inverters_dict,
componentID,
inv_map,
)
elseif componentID[1] in additional_keys
#TODO: Make multiple dispatch for this
_parse_dera1!(
bus_dict,
componentID,
componentValues,
param_map,
bus_num,
)
else
@warn "$(componentID[1]) at bus $bus_num, id $(componentID[2]), not supported in PowerSystems.jl. Skipping data."
end
end
_assign_missing_components!(bus_dict, GEN_COMPONENT_TABLE, DynamicGenerator)
_assign_missing_components!(bus_dict, INV_COMPONENT_TABLE, DynamicInverter)
system_dic[bus_num] = bus_dict
end
return system_dic
end
"""
Parse dictionary of data (from `_parse_dyr_file`) into a dictionary of DERA1.
The function receives the parsed dictionary and constructs a dictionary indexed by bus, that contains a
dictionary with each DERA1 indexed by its id.
"""
function _parse_dera1!(
bus_dict,
componentID,
componentValues,
param_map::Dict,
bus_num::Int,
)
temp = get!(bus_dict, componentID[2], fill!(Vector{Any}(undef, 1), missing))
params_ix = param_map["AggregateDistributedGenerationA"]
constructor_dera =
(args...) ->
InteractiveUtils.getfield(PowerSystems, :AggregateDistributedGenerationA)(
args...,
)
dera1_args = _populate_args(params_ix, componentValues)
# Update name
dera1_args[1] = componentID[1] * "_" * string(bus_num) * "_" * componentID[2]
# Transform Flags to Int
dera1_args[2:7] = Int64.(dera1_args[2:7])
# Transform vl tuples to vector of tuples
dera1_args[24] = [dera1_args[24]]
dera1_args[25] = [dera1_args[25]]
dera1 = constructor_dera(dera1_args...)
temp[1] = dera1
return
end
"""
Parse dictionary of data (from `_parse_dyr_file`) into a dictionary of struct components.
The function receives the parsed dictionary and constructs a dictionary indexed by bus, that contains a
dictionary with each dynamic generator indexed by its id.
"""
function _parse_dyr_generator_components!(
bus_dict::Dict,
componentID,
componentValues,
gen_map::Dict,
param_map::Dict,
)
# Fill array of 5 components per generator
temp = get!(bus_dict, componentID[2], fill!(Vector{Any}(undef, 5), missing))
# Get the component dictionary
for (gen_field, struct_as_str) in gen_map[componentID[1]]
# Get the parameter indices w/r to componentValues
params_ix = param_map[struct_as_str]
# Construct Shaft if it appears
if occursin("Shaft", struct_as_str)
temp[2] = _make_shaft(params_ix, componentValues)
continue
end
# Construct Components
component_constructor =
(args...) ->
InteractiveUtils.getfield(PowerSystems, Symbol(struct_as_str))(args...)
if struct_as_str == "BaseMachine"
struct_args = [
0.0, # R
1e-5, # X
1.0, # eq_p
]
else
struct_args = _populate_args(params_ix, componentValues)
end
_convert_argument_types_for_gen!(struct_as_str, struct_args)
temp[GEN_COMPONENT_TABLE[gen_field]] = component_constructor(struct_args...)
end
return
end
"""
Parse dictionary of data (from `_parse_dyr_file`) into a dictionary of struct components.
The function receives the parsed dictionary and constructs a dictionary indexed by bus, that contains a
dictionary with each dynamic inverter indexed by its id.
"""
function _parse_dyr_inverter_components!(
bus_dict::Dict,
inv_dict::Dict,
componentID::NTuple{2, String},
inv_map::Dict,
)
# Needs to be extended when supporting more parsing
name_to_keys = Dict(
"REGCA1" => [("Converter", "RenewableEnergyConverterTypeA")],
"REECB1" => [("InnerControl", "RECurrentControlB")],
"REPCA1" => [
("ActivePowerControl", "ActiveRenewableControllerAB"),
("ReactivePowerControl", "ReactiveRenewableControllerAB"),
],
)
# Fill array of 7 components per inverter
temp = get!(bus_dict, componentID[2], fill!(Vector{Any}(undef, 7), missing))
for (inv_field, struct_as_str) in name_to_keys[componentID[1]]
values = inv_dict[componentID[2]][(inv_field, struct_as_str)]
_convert_argument_types!(struct_as_str, values)
component_constructor =
(args...) ->
InteractiveUtils.getfield(PowerSystems, Symbol(struct_as_str))(args...)
temp[INV_COMPONENT_TABLE[inv_field]] = component_constructor(values...)
end
return
end
"""
Construct appropiate vector size for components that collect parameters from
more than 2 PSS/E components
"""
function _instantiate_param_vector_size(str::AbstractString, param_map::Dict)
if str == "ActiveRenewableControllerAB"
return fill!(Vector{Any}(undef, 17), missing)
elseif str == "ReactiveRenewableControllerAB"
return fill!(Vector{Any}(undef, 25), missing)
elseif str == "RECurrentControlB"
return fill!(Vector{Any}(undef, 12), missing)
elseif str in keys(param_map)
return fill!(Vector{Any}(undef, length(param_map[str])), missing)
else
error("String $(str) not supported in the parser")
end
end
"""
Convert specific parameters to types that are not Float64 for
specific inverter components
"""
function _convert_argument_types!(str::AbstractString, struct_args::Vector)
if str == "ActiveRenewableControllerAB"
struct_args[1:5] .= Int.(struct_args[1:5])
struct_args[4] = string(struct_args[4])
elseif str == "ReactiveRenewableControllerAB"
struct_args[1:8] .= Int.(struct_args[1:8])
struct_args[4] = string(struct_args[4])
elseif str == "RECurrentControlB"
struct_args[1:2] .= Int.(struct_args[1:2])
elseif str == "RenewableEnergyConverterTypeA"
# No changes to struct_args
else
error("$str not defined for dynamic component arguments")
end
end
"""
Convert specific parameters to types that are not Float64 for
specific generator components
"""
function _convert_argument_types_for_gen!(str::AbstractString, struct_args::Vector)
if (str == "DEGOV1") || (str == "PIDGOV")
struct_args[1] = Int(struct_args[1])
end
return
end
"""
Add to a system already created the dynamic components.
The system should already be parsed from a .raw file.
# Examples:
```julia
dyr_file = "Example.dyr"
add_dyn_injectors!(sys, dyr_file)
```
"""
function add_dyn_injectors!(sys::System, dyr_file::AbstractString)
bus_dict_gen = _parse_dyr_components(dyr_file)
_add_dyn_injectors!(sys, bus_dict_gen)
return
end
# This function is future proofed to allow adding dynamic injector models to FACTS and other VAR control devices.
# By dispatchting on specific types, we can add more injectors in the future.
# We add new _add_dyn_injectors! methods for each new type of injector.
function _add_dyn_injectors!(sys::System, bus_dict_gen::Dict)
_add_dyn_injectors!(sys, bus_dict_gen, ThermalStandard)
_add_dyn_injectors!(sys, bus_dict_gen, SynchronousCondenser)
return
end
function _add_dyn_injectors!(::System, ::Dict, InjectorType::DataType)
error("Attaching dynamic injectors of type $InjectorType is not supported yet.")
end
function _add_dyn_injectors!(
sys::System,
bus_dict_gen::Dict,
InjectorType::Type{T},
) where {T <: Union{ThermalStandard, SynchronousCondenser}}
@info "Generators provided in .dyr, without a generator in .raw file will be skipped."
for g in get_components(InjectorType, sys)
_num = get_number(get_bus(g))
_name = get_name(g)
_id = split(_name, "-")[end]
temp_dict = get(bus_dict_gen, _num, nothing)
if temp_dict === nothing
@warn "Generator at bus $(_num), id $(_id), not found in Dynamic Data.\nVoltage Source will be used to model it."
r, x = get_ext(g)["r"], get_ext(g)["x"]
if x == 0.0
@warn "No series reactance found. Setting it to 1e-6"
x = 1e-6
end
s = _make_source(g, r, x, get_base_power(sys))
remove_component!(typeof(g), sys, _name)
add_component!(sys, s)
elseif all(.!ismissing.(temp_dict[_id]))
if length(temp_dict[_id]) == 5 # Generator has 5 components
# Obtain Machine from Dictionary
machine = temp_dict[_id][1]
# Update R,X from RSORCE and XSORCE from RAW file
r, x = get_ext(g)["r"], get_ext(g)["x"]
set_R!(machine, r)
# Obtain Shaft from dictionary
shaft = temp_dict[_id][2]
if typeof(machine) == BaseMachine
if x == 0.0
@warn "No series reactance found. Setting it to 1e-6"
x = 1e-6
end
set_Xd_p!(machine, x)
if get_H(shaft) == 0.0
@info "Machine at bus $(_num), id $(_id) has zero inertia. Modeling it as Voltage Source"
s = _make_source(g, r, x, get_base_power(sys))
remove_component!(typeof(g), sys, _name)
add_component!(sys, s)
# Don't add DynamicComponent in case of adding Source
continue
end
end
# Add Dynamic Generator
dyn_gen = DynamicGenerator(get_name(g), 1.0, temp_dict[_id]...)
add_component!(sys, dyn_gen, g)
elseif length(temp_dict[_id]) == 7 # Inverter has 7 components (6 if Outer is put together)
dyn_inv = DynamicInverter(get_name(g), 1.0, temp_dict[_id]...)
add_component!(sys, dyn_inv, g)
elseif length(temp_dict[_id]) == 1
#TODO: While we only have 1 thing (DERA1) it will work,
#TODO: but we need to generalize this for any generic dynamic injector
dyn_inj = temp_dict[_id][1]
set_name!(dyn_inj, get_name(g))
add_component!(sys, dyn_inj, g)
else
@assert false
end
else
error("Generator at bus $(_num), id $(_id), name $(_name), not supported")
end
end
end
================================================
FILE: src/parsers/psse_dynamic_mapping.yaml
================================================
######################################
######### Dynamic Generator ##########
######################################
generator_mapping:
- {
#############################
######### Machines ##########
#############################
GENROU:
{
Machine: RoundRotorQuadratic,
Shaft: RoundRotorShaft
},
GENSAL:
{
Machine: SalientPoleQuadratic,
Shaft: SalientPoleShaft
},
GENROE:
{
Machine: RoundRotorExponential,
Shaft: RoundRotorShaft
},
GENSAE:
{
Machine: SalientPoleExponential,
Shaft: SalientPoleShaft
},
GENCLS:
{
Machine: BaseMachine,
Shaft: ClsShaft
},
#############################
#### Excitation Systems #####
#############################
IEEET1:
{
AVR: IEEET1
},
ESDC1A:
{
AVR: ESDC1A
},
ESDC2A:
{
AVR: ESDC2A
},
ESAC1A:
{
AVR: ESAC1A
},
ESAC6A:
{
AVR: ESAC6A
},
EXAC1:
{
AVR: EXAC1
},
EXAC1A:
{
AVR: EXAC1A
},
EXAC2:
{
AVR: EXAC2
},
EXPIC1:
{
AVR: EXPIC1
},
ESST1A:
{
AVR: ESST1A
},
ESST4B:
{
AVR: ESST4B
},
SCRX:
{
AVR: SCRX
},
SEXS:
{
AVR: SEXS
},
EXST1:
{
AVR: EXST1
},
ESAC8B:
{
AVR: ESAC8B
},
ST6B:
{
AVR: ST6B
},
ST8C:
{
AVR: ST8C
},
#############################
#### Turbine Governors ######
#############################
GAST:
{
TurbineGov: GasTG
},
GGOV1:
{
TurbineGov: GeneralGovModel
},
HYGOV:
{
TurbineGov: HydroTurbineGov
},
IEEEG1:
{
TurbineGov: IEEETurbineGov1
},
TGOV1:
{
TurbineGov: SteamTurbineGov1
},
TGOV1DU:
{
TurbineGov: TGOV1DU
},
DEGOV1:
{
TurbineGov: DEGOV1
},
PIDGOV:
{
TurbineGov: PIDGOV
},
WPIDHY:
{
TurbineGov: WPIDHY
},
######################################
###### Power System Stabilizers ######
######################################
IEEEST:
{
PSS: IEEEST
},
STAB1:
{
PSS: STAB1
}
}
######################################
######### Dynamic Inverter ###########
######################################
inverter_mapping:
- {
#############################
######### Converter #########
#############################
REGCA1:
{
Converter: RenewableEnergyConverterTypeA
},
REECB1:
{
ActivePowerControl: ActiveRenewableControllerAB,
ReactivePowerControl: ReactiveRenewableControllerAB,
InnerControl: RECurrentControlB
},
REPCA1:
{
ActivePowerControl: ActiveRenewableControllerAB,
ReactivePowerControl: ReactiveRenewableControllerAB,
}
}
######################################
######### Additional Models ##########
######################################
additional_mapping:
- {
DERA1:
{
DynamicInjection: AggregateDistributedGenerationA
}
}
###################
##### Mapping #####
###################
parameter_mapping:
- {
##################
### Generators ###
##################
#Machines
RoundRotorQuadratic: [0.0, #R
1, #Td0_p
2, #Td0_pp
3, #Tq0_p
4, #Tq0_pp
7, #Xd
8, #Xq
9, #Xd_p
10, #Xq_p
11, #Xd_pp
12, #Xl,
'(13, 14)'], #(Se(1.0), Se(1.2))
RoundRotorExponential: [0.0, 1, 2, 3, 4, 7, 8, 9, 10, 11, 12, '(13, 14)'],
SalientPoleQuadratic: [0.0, #R
1, #Td0_p
2, #Td0_pp
3, #Tq0_pp
6, #Xd
7, #Xq
8, #Xd_p
9, #Xd_pp
10, #Xl,
'(11, 12)'], #(Se(1.0), Se(1.2))
SalientPoleExponential: [0.0, 1, 2, 3, 6, 7, 8, 9, 10, '(11, 12)'],
#Shafts
RoundRotorShaft: [5, 6],
SalientPoleShaft: [4, 5],
BaseMachine: [],
ClsShaft: [1, 2],
#AVRs
IEEET1: [1, 2, 3, '(5, 4)', 6, 7, 8, 9, 10, '(11, 13)', '(12, 14)'],
ESDC1A: [1, 2, 3, 4, 5, '(7, 6)', 8, 9, 10, 11, 12, '(13, 15)', '(14, 16)'],
ESDC2A: [1, 2, 3, 4, 5, '(7, 6)', 8, 9, 10, 11, 12, '(13, 15)', '(14, 16)'],
ESAC1A: [1, 2, 3, 4, 5, '(7, 6)', 8, 9, 10, 11, 12, 13, '(14, 16)', '(15, 17)', '(19, 18)'],
ESAC6A: [1, 2, 3, 4, 5, 6, '(8, 7)', '(10, 9)', 11, 12, 13, 14, 15, 16, 17, 18, 19, '(20, 22)','(21, 23)'],
EXAC1: [1, 2, 3, 4 , 5, '(7, 6)', 8, 9, 10, 11, 12, 13, '(14, 16)', '(15, 17)'],
EXAC1A: [1, 2, 3, 4 , 5, '(7, 6)', 8, 9, 10, 11, 12, 13, '(14, 16)', '(15, 17)'],
EXAC2: [1, 2, 3, 4 , 5, '(7, 6)', 8, '(10, 9)', 11, 12, 13, 14, 15, 16, 17, 18, 19, '(20, 22)', '(21, 23)'],
EXPIC1: [1, 2, 3, '(5, 4)', 6, 7, 8, '(10, 9)', 11, 12, 13, '(15, 14)', 16, 17, '(18, 20)', '(19, 21)', 22, 23, 24],
ESST1A: [1, 2, 3, '(5, 4)', 6, 7, 8, 9, 10, 11, '(13, 12)', '(15, 14)', 16, 17, 18, 19, 20],
ESST4B: [1, 2, 3, '(5, 4)', 6, 7, 8, '(10, 9)', 11, 12, 13, 14, 15, 16, 17],
SCRX: [1, 2, 3, 4, '(5, 6)', 7, 8],
SEXS: [1, 2, 3, 4, '(5, 6)'],
EXST1: [1, '(3, 2)', 4, 5, 6, 7, '(9, 8)', 10, 11, 12],
ESAC8B: [1, 2, 3, 4, 5, 6, 7, '(9, 8)', 10, 11, '(12, 14)', '(13, 15)'],
ST6B: [1, 2, 3, 4, 5, 6, '(8, 7)', 9, 10, 11, 12, 13, '(15, 14)', 16, 17],
ST8C: [1, 2, 3, 4, 5, 6, 7, '(9, 8)', 10, 11, '(13, 12)', 14, 15, '(17, 16)', 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28],
#TGs
GasTG: [1, 2, 3, 4, 5, 6, '(8, 7)', 9],
GeneralGovModel: [1, 2, 3, 4, '(6, 5)', 7, 8, 9, 10, '(12, 11)', 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, '(35, 34)'],
HydroTurbineGov: [1, 2, 3, 4, 5, 6, '(8, 7)', 9, 10, 11, 12],
IEEETurbineGov1: [1, 2, 3, 4, 5, 6, '(8, 7)', 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
SteamTurbineGov1: [1, 2, '(4, 3)', 5, 6, 7, 0.0, 0.0, 0.0],
TGOV1DU: [1, 2, '(4, 3)', 5, 6, 7, 8, 9, 10],
DEGOV1: [1, 2, 3, 4, 5, 6, 7, 8, 9, '(11, 10)', 12, 13],
PIDGOV: [1, 2, 3, 4, 5, 6, 7, 8, 9, '(10, 11, 13)', '(12, 14, 15)', '(17, 16)', 18, 19, '(21, 20)'],
WPIDHY: [1, 2, 3, 4, 5, 6, 7, '(9, 8)', '(11, 10)', 12, '(14, 13)', 15, '(16, 17, 19)', '(18, 20, 21)'],
#PSSs:
IEEEST: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, '(17, 16)', 18, 19],
STAB1: [1, 2, 3, 4, 5, 6, 7],
###################
#### Inverters ####
###################
#Converters
RenewableEnergyConverterTypeA: [2, 3, 4, 5, 6, 7, '(9, 8)', 10, 11, 12, '(14, 13)', 15, 1],
#ActivePowerControl
ActiveRenewableControllerAB:
{
REECB1: ['NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', '(26, 25)', '(28, 27)', 30],
REPCA1: [1, 2, 3, 4, 7, 23, 24, 25, '(26, 27)', '(29, 28)', '(31, 30)', 32, 33, 34, 'NaN', 'NaN', 'NaN']
},
#ReactivePowerControl
ReactiveRenewableControllerAB:
{
# bus, from_b, to_b, b_id, VC, Ref, PF, V, T_f, K_p, K_i, T_ft, T_fv, V_fr, R_c, X_c, K_c, e_lim, dbd, Q_lim, Tp, Qlim_in, V_lim, Kqp, Kqi
REECB1: ['NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 2, 3, 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN', 15, '(17, 16)', '(19, 18)', 20, 21],
REPCA1: [1, 2, 3, 4, 5, 6, 'NaN', 'NaN', 8, 9, 10, 11, 12, 13, 14, 15, 16, '(18, 17)', '(19, 20)', '(22, 21)', 'NaN', 'NaN', 'NaN', 'NaN', 'NaN']
},
#Inner Control
RECurrentControlB:
{
REECB1: [4, 5, '(6, 7)', 8, '(9, 10)', 11, '(13, 12)', 14, 22, 23, 24, 29]
},
# Additional Components
AggregateDistributedGenerationA: ['NaN', 1, 2, 3, 4, 5, 6, 7, 8, '(9, 10)', 11, 13, 14, 15, 16, '(17, 18)', '(20, 19)', '(22, 21)', '(24, 23)', 25, 26, 27, 28, '(29, 30)', '(31, 32)', 37, 38, 39, 40, 41, 42, 43, 44, 45, '(47, 46)',]
}
================================================
FILE: src/parsers/psse_metadata_reimport.jl
================================================
# Parse the `_export_metadata.json` file written alongside PSS/E files by PowerFlows.jl
# Currently the following mappings are used here:
# area_mapping: maps Sienna name to PSS/E number for all areas
# zone_mapping: maps Sienna name to PSS/E number for all load zones
# bus_name_mapping: maps Sienna name to PSS/E name for all buses
# bus_number_mapping: maps Sienna number to PSS/E number for all buses
# load_name_mapping: maps (Sienna bus, Sienna name) to PSS/E name for all loads
# shunt_name_mapping: maps (Sienna bus, Sienna name) to PSS/E name for all shunts
# switched_shunt_name_mapping: maps (Sienna bus, Sienna name) to PSS/E name for all switched shunts
# generator_name_mapping: maps (Sienna bus 1, Sienna bus 2, Sienna name) to PSS/E name for all generators
# xfrm_3w_name_formatter: maps (Sienna bus 1, Sienna bus 2, Sienna bus 3, Sienna name) to PSS/E name for all 3W transformers
# dcline_name_formatter: maps (Sienna bus 1, Sienna bus 2, Sienna name) to PSS/E name for all DC lines
# vscline_name_formatter: maps (Sienna bus 1, Sienna bus 2, Sienna name) to PSS/E name for all VSC lines
# branch_name_mapping: maps (Sienna bus 1, Sienna bus 2, Sienna name) to PSS/E name for all non-transformer branches
# transformer_ckt_mapping: maps (Sienna bus1, Sienna bus2, Sienna name) to PSS/E CKT field for all transformers
# Mappings are stored in the file in the Sienna -> PSS/E direction, so they need to be
# reversed for use here. Wherever a tuple is indicated above, the presentation in the file
# is of the elements joined with underscores to form a single string.
# NOTE for the moment, this feature is mostly tested in the PowerFlows.jl unit tests.
const PSSE_EXPORT_METADATA_EXTENSION = "_export_metadata.json"
reverse_dict(d::Dict) = Dict(map(reverse, collect(d)))
function split_first_rest(s::AbstractString; delim = "_")
splitted = split(s, delim)
return first(splitted), join(splitted[2:end], delim)
end
"Convert a s_bus_n_s_name => p_name dictionary to a (p_bus_n, p_name) => s_name dictionary"
deserialize_reverse_component_ids(
mapping,
bus_number_mapping,
::T,
) where {T <: Type{Int64}} =
Dict(
let
(s_bus_n, s_name) = split_first_rest(s_bus_n_s_name)
p_bus_n = bus_number_mapping[s_bus_n]
(p_bus_n, p_name) => s_name
end
for (s_bus_n_s_name, p_name) in mapping)
deserialize_reverse_component_ids(
mapping,
bus_number_mapping,
::T,
) where {T <: Type{Tuple{Int64, Int64}}} =
Dict(
let
(s_buses, s_name) = split_first_rest(s_buses_s_name)
(s_bus_1, s_bus_2) = split(s_buses, "-")
(p_bus_1, p_bus_2) = bus_number_mapping[s_bus_1], bus_number_mapping[s_bus_2]
((p_bus_1, p_bus_2), p_name) => s_name
end
for (s_buses_s_name, p_name) in mapping)
"""
Use PSS/E exporter metadata to build a function that maps component names back to their
original Sienna values.
"""
function name_formatter_from_component_ids(raw_name_mapping, bus_number_mapping, sig)
reversed_name_mapping =
deserialize_reverse_component_ids(raw_name_mapping, bus_number_mapping, sig)
function component_id_formatter(device_dict)
(p_bus_n, p_name) = device_dict["source_id"][2:3]
(p_bus_n isa Integer) || (p_bus_n = parse(Int64, p_bus_n))
new_name = reversed_name_mapping[(p_bus_n, p_name)]
return new_name
end
return component_id_formatter
end
# Assumes bus_number_mapping is 1-to-1, given by its coming from reverse_dict
function remap_bus_numbers!(sys::System, bus_number_mapping)
for bus in collect(get_components(Bus, sys))
old_number = get_number(bus)
new_number_str = get(bus_number_mapping, old_number, string(old_number))
new_number = parse(Int, new_number_str)
if new_number != old_number
# This will throw an exception if one bus's PSS/E number is another bus's
# Sienna number. That never happens because _psse_bus_numbers on the
# exporting side guarantees that bus numbers that are already compliant with
# the PSS/E spec will not be changed.
set_bus_number!(sys, bus, new_number)
end
end
end
"""
Parse an export_metadata dictionary, returning the kwargs that should be passed to the
System constructor and the bus number remapping that should be used to effect the
retransformation.
"""
function parse_export_metadata_dict(md::Dict)
bus_name_map = reverse_dict(md["bus_name_mapping"]) # PSS/E bus name -> Sienna bus name
all_branch_name_map = deserialize_reverse_component_ids(
merge(
md["branch_name_mapping"],
md["transformer_ckt_mapping"],
),
md["bus_number_mapping"],
Tuple{Int64, Int64},
)
bus_name_formatter = device_dict -> begin
bus_name = device_dict["name"]
get(bus_name_map, bus_name, bus_name)
end
gen_name_formatter = name_formatter_from_component_ids(
md["generator_name_mapping"],
md["bus_number_mapping"],
Int64,
)
load_name_formatter = name_formatter_from_component_ids(
md["load_name_mapping"],
md["bus_number_mapping"],
Int64,
)
function branch_name_formatter(
device_dict::Dict,
bus_f::ACBus,
bus_t::ACBus,
)::String
sid = device_dict["source_id"]
(p_bus_1, p_bus_2, p_name) =
(length(sid) == 6) ? [sid[2], sid[3], sid[5]] : last(sid, 3)
if sid[1] in ["switch", "breaker"]
p_name = replace(p_name, r"[@*]" => "_")
end
bus_f_name = get_name(bus_f)
bus_t_name = get_name(bus_t)
key = ((p_bus_1, p_bus_2), p_name)
def_name = "$(bus_f_name)-$(bus_t_name)-i_$(p_name)"
new_name = get(all_branch_name_map, key, def_name)
return new_name
end
function xfrm_3w_name_formatter(
device_dict::Dict,
p_bus::ACBus,
s_bus::ACBus,
t_bus::ACBus,
)::String
bus_primary = get_name(p_bus)
bus_secondary = get_name(s_bus)
bus_tertiary = get_name(t_bus)
ckt = device_dict["circuit"]
return "$(bus_primary)-$(bus_secondary)-$(bus_tertiary)-i_$(ckt)"
end
function make_switched_shunt_name_formatter(mapping, bus_number_mapping)
reversed_name_mapping = Dict{Tuple{Int, String}, String}()
for (s_bus_n_s_name, p_name) in mapping
parts = split(s_bus_n_s_name, "_")
s_bus_n = parts[1]
s_shunt_name = join(parts[2:end], "_")
p_bus_n = bus_number_mapping[s_bus_n]
reversed_name_mapping[(p_bus_n, s_shunt_name)] = p_name
end
return function (device_dict)
sid = device_dict["source_id"]
p_bus_n = sid[2]
p_name = sid[3]
get(reversed_name_mapping, (p_bus_n, p_name), "$(p_bus_n)-$(p_name)")
end
end
function make_hvdc_name_formatter(mapping)
reversed_mapping = reverse_dict(mapping)
return function (device_dict, bus_f::ACBus, bus_t::ACBus)
bus_f_name = get_name(bus_f)
bus_t_name = get_name(bus_t)
name = device_dict["name"]
key = string(bus_f_name, "-", bus_t_name, "-i_", name)
new_name = get(reversed_mapping, key, key)
return new_name
end
end
shunt_name_formatter = name_formatter_from_component_ids(
md["shunt_name_mapping"],
md["bus_number_mapping"],
Int64,
)
switched_shunt_name_formatter = make_switched_shunt_name_formatter(
md["switched_shunt_name_mapping"],
md["bus_number_mapping"],
)
dcline_name_formatter = make_hvdc_name_formatter(
md["dcline_name_mapping"],
)
vscline_name_formatter = make_hvdc_name_formatter(
md["vsc_line_name_mapping"],
)
loadzone_name_map = reverse_dict(md["zone_mapping"])
get!(loadzone_name_map, 1, "1")
loadzone_name_formatter = name -> loadzone_name_map[name]
area_name_map = reverse_dict(md["area_mapping"])
get!(area_name_map, 1, "1")
area_name_formatter = name -> area_name_map[name]
transformer_control_objective_map = md["transformer_control_objective_mapping"]
transformer_control_objective_formatter =
name -> get(transformer_control_objective_map, name, nothing)
sys_kwargs = Dict(
:area_name_formatter => area_name_formatter,
:loadzone_name_formatter => loadzone_name_formatter,
:bus_name_formatter => bus_name_formatter,
:load_name_formatter => load_name_formatter,
:shunt_name_formatter => shunt_name_formatter,
:gen_name_formatter => gen_name_formatter,
:branch_name_formatter => branch_name_formatter,
:xfrm_3w_name_formatter => xfrm_3w_name_formatter,
:switched_shunt_name_formatter => switched_shunt_name_formatter,
:transformer_control_objective_formatter =>
transformer_control_objective_formatter,
:dcline_name_formatter => dcline_name_formatter,
:vscline_name_formatter => vscline_name_formatter,
)
bus_number_mapping = reverse_dict(md["bus_number_mapping"]) # PSS/E bus name -> Sienna bus name
return sys_kwargs, bus_number_mapping
end
"Construct a System from a `.raw` file and a dictionary corresponding to the `_export_metadata.json` file"
function System(file_path::AbstractString, md::Dict; kwargs...)
sys_kwargs, bus_number_mapping = parse_export_metadata_dict(md)
sys = system_via_power_models(file_path; merge(sys_kwargs, kwargs)...)
# Remap bus numbers last because everything has been added to the system using PSS/E bus numbers
remap_bus_numbers!(sys, bus_number_mapping)
return sys
end
function system_from_psse_reimport(file_path::AbstractString; kwargs...)
md_path = joinpath(
dirname(file_path),
splitext(basename(file_path))[1] * PSSE_EXPORT_METADATA_EXTENSION,
)
if isfile(md_path)
@info "Found a PowerFlows.jl PSS/E export metadata file at $md_path, will use it to perform remapping for round trip"
md = JSON3.read(md_path, Dict)
return System(file_path, md; kwargs...)
else
@info "Did not find a PowerFlows.jl PSS/E export metadata file at $md_path, will not do any remapping"
return system_via_power_models(file_path; kwargs...)
end
end
================================================
FILE: src/plant_attribute.jl
================================================
"""
Supertype for power plant supplemental attributes that group generating units.
Concrete subtypes include [`ThermalPowerPlant`](@ref), [`HydroPowerPlant`](@ref),
[`RenewablePowerPlant`](@ref), [`CombinedCycleBlock`](@ref), and
[`CombinedCycleFractional`](@ref).
"""
abstract type PowerPlant <: SupplementalAttribute end
"""Get `internal`."""
get_internal(x::PowerPlant) = x.internal
"""
Attribute to represent [`ThermalGen`](@ref) power plants with synchronous generation.
For Combined Cycle plants consider using [`CombinedCycleBlock`](@ref).
The shaft map field is used to represent shared shafts between units.
# Arguments
- `name::String`: Name of the power plant
- `shaft_map::Dict{Int, Vector{Base.UUID}}`: Mapping of shaft numbers to unit UUIDs (multiple units can share a shaft)
- `reverse_shaft_map::Dict{Base.UUID, Int}`: Reverse mapping from unit UUID to shaft number
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems internal reference
"""
struct ThermalPowerPlant <: PowerPlant
name::String
shaft_map::Dict{Int, Vector{Base.UUID}}
reverse_shaft_map::Dict{Base.UUID, Int}
internal::InfrastructureSystemsInternal
end
# Deserialization variant: converts string-keyed dicts from JSON
function ThermalPowerPlant(
name::String,
shaft_map::Dict{String, <:Any},
reverse_shaft_map::Dict{String, <:Any},
internal::InfrastructureSystemsInternal,
)
return ThermalPowerPlant(
name,
Dict{Int, Vector{Base.UUID}}(
parse(Int, k) => Base.UUID.(v) for (k, v) in shaft_map
),
Dict{Base.UUID, Int}(Base.UUID(k) => v for (k, v) in reverse_shaft_map),
internal,
)
end
"""
ThermalPowerPlant(; name, shaft_map, reverse_shaft_map, internal)
Construct a [`ThermalPowerPlant`](@ref).
# Arguments
- `name::String`: Name of the power plant
- `shaft_map::Dict{Int, Vector{Base.UUID}}`: (default: empty dict) Mapping of shaft numbers to unit UUIDs
- `reverse_shaft_map::Dict{Base.UUID, Int}`: (default: empty dict) Reverse mapping from unit UUID to shaft number
- `internal::InfrastructureSystemsInternal`: (default: `InfrastructureSystemsInternal()`) (**Do not modify.**) PowerSystems internal reference
"""
function ThermalPowerPlant(;
name::String,
shaft_map::AbstractDict = Dict{Int, Vector{Base.UUID}}(),
reverse_shaft_map::AbstractDict = Dict{Base.UUID, Int}(),
internal::InfrastructureSystemsInternal = InfrastructureSystemsInternal(),
)
return ThermalPowerPlant(name, shaft_map, reverse_shaft_map, internal)
end
"""Get [`ThermalPowerPlant`](@ref) `name`."""
get_name(value::ThermalPowerPlant) = value.name
"""Get [`ThermalPowerPlant`](@ref) `shaft_map`."""
get_shaft_map(value::ThermalPowerPlant) = value.shaft_map
"""Get [`ThermalPowerPlant`](@ref) `reverse_shaft_map`."""
get_reverse_shaft_map(value::ThermalPowerPlant) = value.reverse_shaft_map
"""
Attribute to represent combined cycle generation by block configuration that shares heat recovery converstions.
For aggregate representations consider using [`CombinedCycleFractional`](@ref).
# Arguments
- `name::String`: Name of the combined cycle block
- `configuration::CombinedCycleConfiguration`: Configuration type of the combined cycle
- `heat_recovery_to_steam_factor::Float64`: Factor for heat recovery to steam conversion
- `hrsg_ct_map::Dict{Int, Vector{Base.UUID}}`: Mapping of HRSG numbers to CT unit UUIDs (CTs as HRSG inputs)
- `hrsg_ca_map::Dict{Int, Vector{Base.UUID}}`: Mapping of HRSG numbers to CA unit UUIDs (CAs as HRSG outputs)
- `ct_hrsg_map::Dict{Base.UUID, Vector{Int}}`: Reverse mapping from CT unit UUID to HRSG numbers (a CT can feed multiple HRSGs)
- `ca_hrsg_map::Dict{Base.UUID, Vector{Int}}`: Reverse mapping from CA unit UUID to HRSG numbers (a CA can receive from multiple HRSGs)
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems internal reference
"""
struct CombinedCycleBlock <: PowerPlant
name::String
configuration::CombinedCycleConfiguration
heat_recovery_to_steam_factor::Float64
hrsg_ct_map::Dict{Int, Vector{Base.UUID}}
hrsg_ca_map::Dict{Int, Vector{Base.UUID}}
ct_hrsg_map::Dict{Base.UUID, Vector{Int}}
ca_hrsg_map::Dict{Base.UUID, Vector{Int}}
internal::InfrastructureSystemsInternal
end
# Deserialization variant: converts string-keyed dicts from JSON
function CombinedCycleBlock(
name::String,
configuration::CombinedCycleConfiguration,
heat_recovery_to_steam_factor::Float64,
hrsg_ct_map::Dict{String, <:Any},
hrsg_ca_map::Dict{String, <:Any},
ct_hrsg_map::Dict{String, <:Any},
ca_hrsg_map::Dict{String, <:Any},
internal::InfrastructureSystemsInternal,
)
return CombinedCycleBlock(
name,
configuration,
heat_recovery_to_steam_factor,
Dict{Int, Vector{Base.UUID}}(
parse(Int, k) => Base.UUID.(v) for (k, v) in hrsg_ct_map
),
Dict{Int, Vector{Base.UUID}}(
parse(Int, k) => Base.UUID.(v) for (k, v) in hrsg_ca_map
),
Dict{Base.UUID, Vector{Int}}(Base.UUID(k) => v for (k, v) in ct_hrsg_map),
Dict{Base.UUID, Vector{Int}}(Base.UUID(k) => v for (k, v) in ca_hrsg_map),
internal,
)
end
# Deserialization variant: configuration is also serialized as a string
function CombinedCycleBlock(
name::String,
configuration::String,
heat_recovery_to_steam_factor::Float64,
hrsg_ct_map::Dict{String, <:Any},
hrsg_ca_map::Dict{String, <:Any},
ct_hrsg_map::Dict{String, <:Any},
ca_hrsg_map::Dict{String, <:Any},
internal::InfrastructureSystemsInternal,
)
return CombinedCycleBlock(
name,
IS.deserialize(CombinedCycleConfiguration, configuration),
heat_recovery_to_steam_factor,
hrsg_ct_map,
hrsg_ca_map,
ct_hrsg_map,
ca_hrsg_map,
internal,
)
end
"""
CombinedCycleBlock(; name, configuration, heat_recovery_to_steam_factor, hrsg_ct_map, hrsg_ca_map, ct_hrsg_map, ca_hrsg_map, internal)
Construct a [`CombinedCycleBlock`](@ref).
# Arguments
- `name::String`: Name of the combined cycle block
- `configuration::CombinedCycleConfiguration`: Configuration type of the combined cycle
- `heat_recovery_to_steam_factor::Float64`: (default: `0.0`) Factor for heat recovery to steam conversion
- `hrsg_ct_map::AbstractDict`: (default: empty dict) Mapping of HRSG numbers to CT unit UUIDs (CTs as HRSG inputs)
- `hrsg_ca_map::AbstractDict`: (default: empty dict) Mapping of HRSG numbers to CA unit UUIDs (CAs as HRSG outputs)
- `ct_hrsg_map::AbstractDict`: (default: empty dict) Reverse mapping from CT unit UUID to HRSG numbers
- `ca_hrsg_map::AbstractDict`: (default: empty dict) Reverse mapping from CA unit UUID to HRSG numbers
- `internal::InfrastructureSystemsInternal`: (default: `InfrastructureSystemsInternal()`) (**Do not modify.**) PowerSystems internal reference
"""
function CombinedCycleBlock(;
name,
configuration,
heat_recovery_to_steam_factor = 0.0,
hrsg_ct_map::AbstractDict = Dict{Int, Vector{Base.UUID}}(),
hrsg_ca_map::AbstractDict = Dict{Int, Vector{Base.UUID}}(),
ct_hrsg_map::AbstractDict = Dict{Base.UUID, Vector{Int}}(),
ca_hrsg_map::AbstractDict = Dict{Base.UUID, Vector{Int}}(),
internal = InfrastructureSystemsInternal(),
)
return CombinedCycleBlock(
name,
configuration,
heat_recovery_to_steam_factor,
hrsg_ct_map,
hrsg_ca_map,
ct_hrsg_map,
ca_hrsg_map,
internal,
)
end
"""Get [`CombinedCycleBlock`](@ref) `name`."""
get_name(value::CombinedCycleBlock) = value.name
"""Get [`CombinedCycleBlock`](@ref) `configuration`."""
get_configuration(value::CombinedCycleBlock) = value.configuration
"""Get [`CombinedCycleBlock`](@ref) `heat_recovery_to_steam_factor`."""
get_heat_recovery_to_steam_factor(value::CombinedCycleBlock) =
value.heat_recovery_to_steam_factor
"""Get [`CombinedCycleBlock`](@ref) `hrsg_ct_map`."""
get_hrsg_ct_map(value::CombinedCycleBlock) = value.hrsg_ct_map
"""Get [`CombinedCycleBlock`](@ref) `hrsg_ca_map`."""
get_hrsg_ca_map(value::CombinedCycleBlock) = value.hrsg_ca_map
"""Get [`CombinedCycleBlock`](@ref) `ct_hrsg_map`."""
get_ct_hrsg_map(value::CombinedCycleBlock) = value.ct_hrsg_map
"""Get [`CombinedCycleBlock`](@ref) `ca_hrsg_map`."""
get_ca_hrsg_map(value::CombinedCycleBlock) = value.ca_hrsg_map
"""
Attribute to represent combined cycle generation when each unit represents a specific configuration and aggregate heat rate.
For block-level representations consider using [`CombinedCycleBlock`](@ref).
# Arguments
- `name::String`: Name of the combined cycle fractional plant
- `configuration::CombinedCycleConfiguration`: Configuration type of the combined cycle
- `operation_exclusion_map::Dict{Int, Vector{Base.UUID}}`: Mapping of operation exclusion group numbers to unit UUIDs (only units in the same group can operate simultaneously)
- `inverse_operation_exclusion_map::Dict{Base.UUID, Int}`: Reverse mapping from unit UUID to exclusion group number
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems internal reference
"""
struct CombinedCycleFractional <: PowerPlant
name::String
configuration::CombinedCycleConfiguration
operation_exclusion_map::Dict{Int, Vector{Base.UUID}}
inverse_operation_exclusion_map::Dict{Base.UUID, Int}
internal::InfrastructureSystemsInternal
end
# Deserialization variant: converts string-keyed dicts from JSON
function CombinedCycleFractional(
name::String,
configuration::CombinedCycleConfiguration,
operation_exclusion_map::Dict{String, <:Any},
inverse_operation_exclusion_map::Dict{String, <:Any},
internal::InfrastructureSystemsInternal,
)
return CombinedCycleFractional(
name,
configuration,
Dict{Int, Vector{Base.UUID}}(
parse(Int, k) => Base.UUID.(v) for (k, v) in operation_exclusion_map
),
Dict{Base.UUID, Int}(
Base.UUID(k) => v for (k, v) in inverse_operation_exclusion_map
),
internal,
)
end
# Deserialization variant: configuration is also serialized as a string
function CombinedCycleFractional(
name::String,
configuration::String,
operation_exclusion_map::Dict{String, <:Any},
inverse_operation_exclusion_map::Dict{String, <:Any},
internal::InfrastructureSystemsInternal,
)
return CombinedCycleFractional(
name,
IS.deserialize(CombinedCycleConfiguration, configuration),
operation_exclusion_map,
inverse_operation_exclusion_map,
internal,
)
end
"""
CombinedCycleFractional(; name, configuration, operation_exclusion_map, inverse_operation_exclusion_map, internal)
Construct a [`CombinedCycleFractional`](@ref).
# Arguments
- `name::String`: Name of the combined cycle fractional plant
- `configuration::CombinedCycleConfiguration`: Configuration type of the combined cycle
- `operation_exclusion_map::AbstractDict`: (default: empty dict) Mapping of operation exclusion group numbers to unit UUIDs
- `inverse_operation_exclusion_map::AbstractDict`: (default: empty dict) Reverse mapping from unit UUID to exclusion group number
- `internal::InfrastructureSystemsInternal`: (default: `InfrastructureSystemsInternal()`) (**Do not modify.**) PowerSystems internal reference
"""
function CombinedCycleFractional(;
name,
configuration,
operation_exclusion_map::AbstractDict = Dict{Int, Vector{Base.UUID}}(),
inverse_operation_exclusion_map::AbstractDict = Dict{Base.UUID, Int}(),
internal = InfrastructureSystemsInternal(),
)
return CombinedCycleFractional(
name,
configuration,
operation_exclusion_map,
inverse_operation_exclusion_map,
internal,
)
end
"""Get [`CombinedCycleFractional`](@ref) `name`."""
get_name(value::CombinedCycleFractional) = value.name
"""Get [`CombinedCycleFractional`](@ref) `configuration`."""
get_configuration(value::CombinedCycleFractional) = value.configuration
"""Get [`CombinedCycleFractional`](@ref) `operation_exclusion_map`."""
get_operation_exclusion_map(value::CombinedCycleFractional) =
value.operation_exclusion_map
"""Get [`CombinedCycleFractional`](@ref) `inverse_operation_exclusion_map`."""
get_inverse_operation_exclusion_map(value::CombinedCycleFractional) =
value.inverse_operation_exclusion_map
"""
Attribute to represent hydro power plants with shared penstocks.
# Arguments
- `name::String`: Name of the hydro power plant
- `penstock_map::Dict{Int, Vector{Base.UUID}}`: Mapping of penstock numbers to unit UUIDs (multiple units can share a penstock)
- `reverse_penstock_map::Dict{Base.UUID, Int}`: Reverse mapping from unit UUID to penstock number
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems internal reference
"""
struct HydroPowerPlant <: PowerPlant
name::String
penstock_map::Dict{Int, Vector{Base.UUID}}
reverse_penstock_map::Dict{Base.UUID, Int}
internal::InfrastructureSystemsInternal
end
# Deserialization variant: converts string-keyed dicts from JSON
function HydroPowerPlant(
name::String,
penstock_map::Dict{String, <:Any},
reverse_penstock_map::Dict{String, <:Any},
internal::InfrastructureSystemsInternal,
)
return HydroPowerPlant(
name,
Dict{Int, Vector{Base.UUID}}(
parse(Int, k) => Base.UUID.(v) for (k, v) in penstock_map
),
Dict{Base.UUID, Int}(Base.UUID(k) => v for (k, v) in reverse_penstock_map),
internal,
)
end
"""
HydroPowerPlant(; name, penstock_map, reverse_penstock_map, internal)
Construct a [`HydroPowerPlant`](@ref).
# Arguments
- `name::String`: Name of the hydro power plant
- `penstock_map::Dict{Int, Vector{Base.UUID}}`: (default: empty dict) Mapping of penstock numbers to unit UUIDs
- `reverse_penstock_map::Dict{Base.UUID, Int}`: (default: empty dict) Reverse mapping from unit UUID to penstock number
- `internal::InfrastructureSystemsInternal`: (default: `InfrastructureSystemsInternal()`) (**Do not modify.**) PowerSystems internal reference
"""
function HydroPowerPlant(;
name::String,
penstock_map::AbstractDict = Dict{Int, Vector{Base.UUID}}(),
reverse_penstock_map::AbstractDict = Dict{Base.UUID, Int}(),
internal::InfrastructureSystemsInternal = InfrastructureSystemsInternal(),
)
return HydroPowerPlant(name, penstock_map, reverse_penstock_map, internal)
end
"""Get [`HydroPowerPlant`](@ref) `name`."""
get_name(value::HydroPowerPlant) = value.name
"""Get [`HydroPowerPlant`](@ref) `penstock_map`."""
get_penstock_map(value::HydroPowerPlant) = value.penstock_map
"""Get [`HydroPowerPlant`](@ref) `reverse_penstock_map`."""
get_reverse_penstock_map(value::HydroPowerPlant) = value.reverse_penstock_map
"""
Attribute to represent renewable power plants.
# Arguments
- `name::String`: Name of the renewable power plant
- `pcc_map::Dict{Int, Vector{Base.UUID}}`: Mapping of PCC numbers to unit UUIDs (multiple units can share a PCC)
- `reverse_pcc_map::Dict{Base.UUID, Int}`: Reverse mapping from unit UUID to PCC number
- `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems internal reference
"""
struct RenewablePowerPlant <: PowerPlant
name::String
pcc_map::Dict{Int, Vector{Base.UUID}}
reverse_pcc_map::Dict{Base.UUID, Int}
internal::InfrastructureSystemsInternal
end
# Deserialization variant: converts string-keyed dicts from JSON
function RenewablePowerPlant(
name::String,
pcc_map::Dict{String, <:Any},
reverse_pcc_map::Dict{String, <:Any},
internal::InfrastructureSystemsInternal,
)
return RenewablePowerPlant(
name,
Dict{Int, Vector{Base.UUID}}(
parse(Int, k) => Base.UUID.(v) for (k, v) in pcc_map
),
Dict{Base.UUID, Int}(Base.UUID(k) => v for (k, v) in reverse_pcc_map),
internal,
)
end
"""
RenewablePowerPlant(; name, pcc_map, reverse_pcc_map, internal)
Construct a [`RenewablePowerPlant`](@ref). This supports multiple point of common coupling (PCC) connections.
# Arguments
- `name::String`: Name of the renewable power plant
- `pcc_map::Dict{Int, Vector{Base.UUID}}`: (default: empty dict) Mapping of PCC numbers to unit UUIDs
- `reverse_pcc_map::Dict{Base.UUID, Int}`: (default: empty dict) Reverse mapping from unit UUID to PCC number
- `internal::InfrastructureSystemsInternal`: (default: `InfrastructureSystemsInternal()`) (**Do not modify.**) PowerSystems internal reference
"""
function RenewablePowerPlant(;
name::String,
pcc_map::AbstractDict = Dict{Int, Vector{Base.UUID}}(),
reverse_pcc_map::AbstractDict = Dict{Base.UUID, Int}(),
internal::InfrastructureSystemsInternal = InfrastructureSystemsInternal(),
)
return RenewablePowerPlant(name, pcc_map, reverse_pcc_map, internal)
end
"""Get [`RenewablePowerPlant`](@ref) `name`."""
get_name(value::RenewablePowerPlant) = value.name
"""Get [`RenewablePowerPlant`](@ref) `pcc_map`."""
get_pcc_map(value::RenewablePowerPlant) = value.pcc_map
"""Get [`RenewablePowerPlant`](@ref) `reverse_pcc_map`."""
get_reverse_pcc_map(value::RenewablePowerPlant) = value.reverse_pcc_map
"""
get_components_in_shaft(sys::System, plant::ThermalPowerPlant, shaft_number::Int)
Get all thermal generators connected to a specific shaft in a [`ThermalPowerPlant`](@ref).
# Arguments
- `sys::System`: The system containing the components
- `plant::ThermalPowerPlant`: The thermal power plant
- `shaft_number::Int`: The shaft number to query
# Returns
- `Vector{ThermalGen}`: Vector of thermal generators on the specified shaft
# Throws
- `ArgumentError`: If the shaft number does not exist in the plant
"""
function get_components_in_shaft(
sys::System,
plant::ThermalPowerPlant,
shaft_number::Int,
)
shaft_map = get_shaft_map(plant)
if !haskey(shaft_map, shaft_number)
throw(
IS.ArgumentError(
"Shaft number $shaft_number does not exist in plant $(get_name(plant))",
),
)
end
uuids = shaft_map[shaft_number]
all_components = get_associated_components(sys, plant; component_type = ThermalGen)
# Filter to only include components on this shaft
return filter(c -> IS.get_uuid(c) in uuids, all_components)
end
"""
get_components_in_penstock(sys::System, plant::HydroPowerPlant, penstock_number::Int)
Get all hydro generators connected to a specific penstock in a [`HydroPowerPlant`](@ref).
# Arguments
- `sys::System`: The system containing the components
- `plant::HydroPowerPlant`: The hydro power plant
- `penstock_number::Int`: The penstock number to query
# Returns
- `Vector{Union{HydroTurbine, HydroPumpTurbine}}`: Vector of hydro generators on the specified penstock
# Throws
- `ArgumentError`: If the penstock number does not exist in the plant
"""
function get_components_in_penstock(
sys::System,
plant::HydroPowerPlant,
penstock_number::Int,
)
penstock_map = get_penstock_map(plant)
if !haskey(penstock_map, penstock_number)
throw(
IS.ArgumentError(
"Penstock number $penstock_number does not exist in plant $(get_name(plant))",
),
)
end
uuids = penstock_map[penstock_number]
all_components = get_associated_components(sys, plant; component_type = HydroGen)
# Filter to only include components on this penstock
return filter(c -> IS.get_uuid(c) in uuids, all_components)
end
"""
get_components_in_pcc(sys::System, plant::RenewablePowerPlant, pcc_number::Int)
Get all renewable generators and storage devices connected to a specific PCC in a [`RenewablePowerPlant`](@ref).
# Arguments
- `sys::System`: The system containing the components
- `plant::RenewablePowerPlant`: The renewable power plant
- `pcc_number::Int`: The PCC (point of common coupling) number to query
# Returns
- `Vector{Union{RenewableGen, EnergyReservoirStorage}}`: Vector of components on the specified PCC
# Throws
- `ArgumentError`: If the PCC number does not exist in the plant
"""
function get_components_in_pcc(
sys::System,
plant::RenewablePowerPlant,
pcc_number::Int,
)
pcc_map = get_pcc_map(plant)
if !haskey(pcc_map, pcc_number)
throw(
IS.ArgumentError(
"PCC number $pcc_number does not exist in plant $(get_name(plant))",
),
)
end
uuids = pcc_map[pcc_number]
all_components = get_associated_components(sys, plant)
# Filter to only include components on this PCC
return filter(c -> IS.get_uuid(c) in uuids, all_components)
end
"""
add_supplemental_attribute!(sys::System, component::ThermalGen, attribute::ThermalPowerPlant; shaft_number::Int)
Add a thermal generator to a [`ThermalPowerPlant`](@ref) by associating it with a shaft number.
This attaches the plant as a supplemental attribute to the generator and records the
generator's UUID in the plant's shaft map.
# Arguments
- `sys::System`: The system containing the generator
- `component::ThermalGen`: The thermal generator to add to the plant
- `attribute::ThermalPowerPlant`: The thermal power plant
- `shaft_number::Int`: The shaft number to associate with the generator
"""
function add_supplemental_attribute!(
sys::System,
component::ThermalGen,
attribute::ThermalPowerPlant;
shaft_number::Int,
)
uuid = IS.get_uuid(component)
if haskey(attribute.reverse_shaft_map, uuid)
throw(
IS.ArgumentError(
"Generator $(get_name(component)) is already part of plant $(get_name(attribute))",
),
)
end
IS.add_supplemental_attribute!(sys.data, component, attribute)
if haskey(attribute.shaft_map, shaft_number)
push!(attribute.shaft_map[shaft_number], uuid)
else
attribute.shaft_map[shaft_number] = [uuid]
end
attribute.reverse_shaft_map[uuid] = shaft_number
return
end
"""
add_supplemental_attribute!(sys::System, component::Union{HydroPumpTurbine, HydroTurbine}, attribute::HydroPowerPlant; penstock_number::Int)
Add a hydro generator to a [`HydroPowerPlant`](@ref) by associating it with a penstock number.
This attaches the plant as a supplemental attribute to the generator and records the
generator's UUID in the plant's penstock map.
# Arguments
- `sys::System`: The system containing the generator
- `component::Union{HydroPumpTurbine, HydroTurbine}`: The hydro generator to add to the plant
- `attribute::HydroPowerPlant`: The hydro power plant
- `penstock_number::Int`: The penstock number to associate with the generator
"""
function add_supplemental_attribute!(
sys::System,
component::Union{HydroPumpTurbine, HydroTurbine},
attribute::HydroPowerPlant,
penstock_number::Int,
)
uuid = IS.get_uuid(component)
if haskey(attribute.reverse_penstock_map, uuid)
throw(
IS.ArgumentError(
"Generator $(get_name(component)) is already part of plant $(get_name(attribute))",
),
)
end
IS.add_supplemental_attribute!(sys.data, component, attribute)
if haskey(attribute.penstock_map, penstock_number)
push!(attribute.penstock_map[penstock_number], uuid)
else
attribute.penstock_map[penstock_number] = [uuid]
end
attribute.reverse_penstock_map[uuid] = penstock_number
return
end
"""
add_supplemental_attribute!(sys::System, component::HydroDispatch, attribute::HydroPowerPlant, args...; kwargs...)
Error-throwing overload. HydroDispatch is not supported in a HydroPowerPlant.
"""
function add_supplemental_attribute!(
::System,
::HydroDispatch,
::HydroPowerPlant,
args...;
kwargs...,
)
throw(
IS.ArgumentError(
"HydroDispatch is not supported in a HydroPowerPlant. Consider using HydroTurbine instead.",
),
)
end
"""
add_supplemental_attribute!(sys::System, component::Union{RenewableGen, EnergyReservoirStorage}, attribute::RenewablePowerPlant; pcc_number::Int=1)
Add a renewable generator or storage to a [`RenewablePowerPlant`](@ref) by associating it with a PCC number.
This attaches the plant as a supplemental attribute to the generator and records the
generator's UUID in the plant's PCC map.
# Arguments
- `sys::System`: The system containing the generator
- `component::Union{RenewableGen, EnergyReservoirStorage}`: The renewable generator or storage to add to the plant
- `attribute::RenewablePowerPlant`: The renewable power plant
- `pcc_number::Int`: (default: 1) The PCC (point of common coupling) number to associate with the generator
"""
function add_supplemental_attribute!(
sys::System,
component::Union{RenewableGen, EnergyReservoirStorage},
attribute::RenewablePowerPlant,
pcc_number::Int,
)
uuid = IS.get_uuid(component)
if haskey(attribute.reverse_pcc_map, uuid)
throw(
IS.ArgumentError(
"Component $(get_name(component)) is already part of plant $(get_name(attribute))",
),
)
end
IS.add_supplemental_attribute!(sys.data, component, attribute)
if haskey(attribute.pcc_map, pcc_number)
push!(attribute.pcc_map[pcc_number], uuid)
else
attribute.pcc_map[pcc_number] = [uuid]
end
attribute.reverse_pcc_map[uuid] = pcc_number
return
end
"""
remove_supplemental_attribute!(sys::System, component::ThermalGen, attribute::ThermalPowerPlant)
Remove a thermal generator from a [`ThermalPowerPlant`](@ref).
This removes the plant as a supplemental attribute from the generator and removes the
generator's UUID from the plant's shaft map.
# Arguments
- `sys::System`: The system containing the generator
- `component::ThermalGen`: The thermal generator to remove from the plant
- `attribute::ThermalPowerPlant`: The thermal power plant
"""
function remove_supplemental_attribute!(
sys::System,
component::ThermalGen,
attribute::ThermalPowerPlant,
)
uuid = IS.get_uuid(component)
if !haskey(attribute.reverse_shaft_map, uuid)
throw(
IS.ArgumentError(
"Generator $(get_name(component)) is not part of plant $(get_name(attribute))",
),
)
end
shaft_number = attribute.reverse_shaft_map[uuid]
filter!(x -> x != uuid, attribute.shaft_map[shaft_number])
if isempty(attribute.shaft_map[shaft_number])
delete!(attribute.shaft_map, shaft_number)
end
delete!(attribute.reverse_shaft_map, uuid)
IS.remove_supplemental_attribute!(sys.data, component, attribute)
return
end
"""
remove_supplemental_attribute!(sys::System, component::Union{HydroPumpTurbine, HydroTurbine}, attribute::HydroPowerPlant)
Remove a hydro generator from a [`HydroPowerPlant`](@ref).
This removes the plant as a supplemental attribute from the generator and removes the
generator's UUID from the plant's penstock map.
# Arguments
- `sys::System`: The system containing the generator
- `component::Union{HydroPumpTurbine, HydroTurbine}`: The hydro generator to remove from the plant
- `attribute::HydroPowerPlant`: The hydro power plant
"""
function remove_supplemental_attribute!(
sys::System,
component::Union{HydroPumpTurbine, HydroTurbine},
attribute::HydroPowerPlant,
)
uuid = IS.get_uuid(component)
if !haskey(attribute.reverse_penstock_map, uuid)
throw(
IS.ArgumentError(
"Generator $(get_name(component)) is not part of plant $(get_name(attribute))",
),
)
end
penstock_number = attribute.reverse_penstock_map[uuid]
filter!(x -> x != uuid, attribute.penstock_map[penstock_number])
if isempty(attribute.penstock_map[penstock_number])
delete!(attribute.penstock_map, penstock_number)
end
delete!(attribute.reverse_penstock_map, uuid)
IS.remove_supplemental_attribute!(sys.data, component, attribute)
return
end
"""
remove_supplemental_attribute!(sys::System, component::Union{RenewableGen, EnergyReservoirStorage}, attribute::RenewablePowerPlant)
Remove a renewable generator or storage from a [`RenewablePowerPlant`](@ref).
This removes the plant as a supplemental attribute from the generator and removes the
generator's UUID from the plant's PCC map.
# Arguments
- `sys::System`: The system containing the generator
- `component::Union{RenewableGen, EnergyReservoirStorage}`: The renewable generator or storage to remove from the plant
- `attribute::RenewablePowerPlant`: The renewable power plant
"""
function remove_supplemental_attribute!(
sys::System,
component::Union{RenewableGen, EnergyReservoirStorage},
attribute::RenewablePowerPlant,
)
uuid = IS.get_uuid(component)
if !haskey(attribute.reverse_pcc_map, uuid)
throw(
IS.ArgumentError(
"Generator $(get_name(component)) is not part of plant $(get_name(attribute))",
),
)
end
pcc_number = attribute.reverse_pcc_map[uuid]
filter!(x -> x != uuid, attribute.pcc_map[pcc_number])
if isempty(attribute.pcc_map[pcc_number])
delete!(attribute.pcc_map, pcc_number)
end
delete!(attribute.reverse_pcc_map, uuid)
IS.remove_supplemental_attribute!(sys.data, component, attribute)
return
end
"""
add_supplemental_attribute!(sys::System, component::ThermalGen, attribute::CombinedCycleBlock; hrsg_number::Int)
Add a thermal generator to a [`CombinedCycleBlock`](@ref) by associating it with an HRSG number.
Only generators with CT (combustion turbine as HRSG input) or CA (combined cycle steam part as HRSG output)
prime mover types can be added.
# Arguments
- `sys::System`: The system containing the generator
- `component::ThermalGen`: The thermal generator to add to the block (must have prime mover type CT or CA)
- `attribute::CombinedCycleBlock`: The combined cycle block
- `hrsg_number::Int`: The HRSG number to associate with the generator
"""
function add_supplemental_attribute!(
sys::System,
component::ThermalGen,
attribute::CombinedCycleBlock;
hrsg_number::Int,
)
uuid = IS.get_uuid(component)
if haskey(attribute.ct_hrsg_map, uuid) || haskey(attribute.ca_hrsg_map, uuid)
throw(
IS.ArgumentError(
"Generator $(get_name(component)) is already part of block $(get_name(attribute))",
),
)
end
prime_mover = get_prime_mover_type(component)
if prime_mover == PrimeMovers.CT
IS.add_supplemental_attribute!(sys.data, component, attribute)
if haskey(attribute.hrsg_ct_map, hrsg_number)
push!(attribute.hrsg_ct_map[hrsg_number], uuid)
else
attribute.hrsg_ct_map[hrsg_number] = [uuid]
end
attribute.ct_hrsg_map[uuid] = [hrsg_number]
elseif prime_mover == PrimeMovers.CA
IS.add_supplemental_attribute!(sys.data, component, attribute)
if haskey(attribute.hrsg_ca_map, hrsg_number)
push!(attribute.hrsg_ca_map[hrsg_number], uuid)
else
attribute.hrsg_ca_map[hrsg_number] = [uuid]
end
attribute.ca_hrsg_map[uuid] = [hrsg_number]
else
throw(
IS.ArgumentError(
"Invalid prime mover type $prime_mover for generator $(get_name(component)). Only CT and CA generators can be added to a CombinedCycleBlock.",
),
)
end
return
end
"""
remove_supplemental_attribute!(sys::System, component::ThermalGen, attribute::CombinedCycleBlock)
Remove a thermal generator from a [`CombinedCycleBlock`](@ref).
This removes the block as a supplemental attribute from the generator and removes the
generator's UUID from the block's HRSG maps.
# Arguments
- `sys::System`: The system containing the generator
- `component::ThermalGen`: The thermal generator to remove from the block
- `attribute::CombinedCycleBlock`: The combined cycle block
"""
function remove_supplemental_attribute!(
sys::System,
component::ThermalGen,
attribute::CombinedCycleBlock,
)
uuid = IS.get_uuid(component)
# Check if this is a CT (HRSG input)
if haskey(attribute.ct_hrsg_map, uuid)
hrsg_numbers = attribute.ct_hrsg_map[uuid]
for hrsg_number in hrsg_numbers
filter!(x -> x != uuid, attribute.hrsg_ct_map[hrsg_number])
if isempty(attribute.hrsg_ct_map[hrsg_number])
delete!(attribute.hrsg_ct_map, hrsg_number)
end
end
delete!(attribute.ct_hrsg_map, uuid)
# Check if this is a CA (HRSG output)
elseif haskey(attribute.ca_hrsg_map, uuid)
hrsg_numbers = attribute.ca_hrsg_map[uuid]
for hrsg_number in hrsg_numbers
filter!(x -> x != uuid, attribute.hrsg_ca_map[hrsg_number])
if isempty(attribute.hrsg_ca_map[hrsg_number])
delete!(attribute.hrsg_ca_map, hrsg_number)
end
end
delete!(attribute.ca_hrsg_map, uuid)
else
throw(
IS.ArgumentError(
"Generator $(get_name(component)) is not part of block $(get_name(attribute))",
),
)
end
IS.remove_supplemental_attribute!(sys.data, component, attribute)
return
end
"""
add_supplemental_attribute!(sys::System, component::ThermalGen, attribute::CombinedCycleFractional; exclusion_group::Int)
Add a thermal generator to a [`CombinedCycleFractional`](@ref) by associating it with an exclusion group number.
Only generators with CC (combined cycle) prime mover type can be added.
# Arguments
- `sys::System`: The system containing the generator
- `component::ThermalGen`: The thermal generator to add to the plant (must have prime mover type CC)
- `attribute::CombinedCycleFractional`: The combined cycle fractional plant
- `exclusion_group::Int`: The exclusion group number to associate with the generator
"""
function add_supplemental_attribute!(
sys::System,
component::ThermalGen,
attribute::CombinedCycleFractional;
exclusion_group::Int,
)
uuid = IS.get_uuid(component)
# Check if already in any exclusion group
for (_, uuids) in attribute.operation_exclusion_map
if uuid in uuids
throw(
IS.ArgumentError(
"Generator $(get_name(component)) is already part of plant $(get_name(attribute))",
),
)
end
end
prime_mover = get_prime_mover_type(component)
if prime_mover != PrimeMovers.CC
throw(
IS.ArgumentError(
"Invalid prime mover type $prime_mover for generator $(get_name(component)). Only CC generators can be added to a CombinedCycleFractional.",
),
)
end
IS.add_supplemental_attribute!(sys.data, component, attribute)
if haskey(attribute.operation_exclusion_map, exclusion_group)
push!(attribute.operation_exclusion_map[exclusion_group], uuid)
else
attribute.operation_exclusion_map[exclusion_group] = [uuid]
end
attribute.inverse_operation_exclusion_map[uuid] = exclusion_group
return
end
"""
remove_supplemental_attribute!(sys::System, component::ThermalGen, attribute::CombinedCycleFractional)
Remove a thermal generator from a [`CombinedCycleFractional`](@ref).
This removes the plant as a supplemental attribute from the generator and removes the
generator's UUID from the plant's exclusion maps.
# Arguments
- `sys::System`: The system containing the generator
- `component::ThermalGen`: The thermal generator to remove from the plant
- `attribute::CombinedCycleFractional`: The combined cycle fractional plant
"""
function remove_supplemental_attribute!(
sys::System,
component::ThermalGen,
attribute::CombinedCycleFractional,
)
uuid = IS.get_uuid(component)
found = false
for (group, _) in attribute.operation_exclusion_map
if uuid in attribute.operation_exclusion_map[group]
filter!(x -> x != uuid, attribute.operation_exclusion_map[group])
if isempty(attribute.operation_exclusion_map[group])
delete!(attribute.operation_exclusion_map, group)
end
found = true
break
end
end
if !found
throw(
IS.ArgumentError(
"Generator $(get_name(component)) is not part of plant $(get_name(attribute))",
),
)
end
delete!(attribute.inverse_operation_exclusion_map, uuid)
IS.remove_supplemental_attribute!(sys.data, component, attribute)
return
end
"""
get_components_in_exclusion_group(sys::System, plant::CombinedCycleFractional, exclusion_group::Int)
Get all thermal generators in a specific exclusion group of a [`CombinedCycleFractional`](@ref).
# Arguments
- `sys::System`: The system containing the components
- `plant::CombinedCycleFractional`: The combined cycle fractional plant
- `exclusion_group::Int`: The exclusion group number to query
# Returns
- `Vector{ThermalGen}`: Vector of thermal generators in the specified exclusion group
# Throws
- `ArgumentError`: If the exclusion group does not exist in the plant
"""
function get_components_in_exclusion_group(
sys::System,
plant::CombinedCycleFractional,
exclusion_group::Int,
)
exclusion_map = get_operation_exclusion_map(plant)
if !haskey(exclusion_map, exclusion_group)
throw(
IS.ArgumentError(
"Exclusion group $exclusion_group does not exist in plant $(get_name(plant))",
),
)
end
uuids = exclusion_map[exclusion_group]
all_components = get_associated_components(sys, plant; component_type = ThermalGen)
# Filter to only include components in this exclusion group
return filter(c -> IS.get_uuid(c) in uuids, all_components)
end
================================================
FILE: src/subsystems.jl
================================================
"""
Add a new subsystem to the system.
"""
function add_subsystem!(sys::System, subsystem_name::AbstractString)
_check_num_subsystems(sys)
IS.add_subsystem!(sys.data, subsystem_name)
end
"""
Return the number of subsystems stored in the system.
"""
get_num_subsystems(sys::System) = IS.get_num_subsystems(sys.data)
"""
Return an iterator of all subsystem names in the system.
"""
get_subsystems(sys::System) = IS.get_subsystems(sys.data)
"""
Remove a subsystem from the system.
Throws ArgumentError if the subsystem name is not stored.
"""
remove_subsystem!(sys::System, subsystem_name::AbstractString) =
IS.remove_subsystem!(sys.data, subsystem_name)
"""
Return true if the system has one or more subsystems.
"""
function has_subsystems(sys::System)
for _ in get_subsystems(sys)
return true
end
return false
end
"""
Add a component to a subsystem.
"""
function add_component_to_subsystem!(
sys::System,
subsystem_name::AbstractString,
component::Component,
)
IS.add_component_to_subsystem!(sys.data, subsystem_name, component)
handle_component_addition_to_subsystem!(sys, subsystem_name, component)
return
end
"""
Peforms component-type-specific postprocessing when a component is added to a subsystem.
"""
handle_component_addition_to_subsystem!(
::System,
subsystem_name::AbstractString,
::Component,
) = nothing
"""
Peforms component-type-specific postprocessing when a component is removed from a subsystem.
"""
handle_component_removal_from_subsystem!(
::System,
subsystem_name::AbstractString,
::Component,
) = nothing
function handle_component_addition_to_subsystem!(
sys::System,
subsystem_name::AbstractString,
component::StaticInjectionSubsystem,
)
for subcomponent in get_subcomponents(component)
if !is_assigned_to_subsystem(sys, subcomponent, subsystem_name)
add_component_to_subsystem!(sys, subsystem_name, subcomponent)
end
end
end
function handle_component_removal_from_subsystem!(
sys::System,
subsystem_name::AbstractString,
component::StaticInjectionSubsystem,
)
for subcomponent in get_subcomponents(component)
if is_assigned_to_subsystem(sys, subcomponent, subsystem_name)
remove_component_from_subsystem!(sys, subsystem_name, subcomponent)
end
end
end
"""
Return a Generator of all components in the subsystem.
Throws ArgumentError if the subsystem name is not stored.
"""
get_subsystem_components(sys::System, subsystem_name::AbstractString) =
IS.get_subsystem_components(sys.data, subsystem_name)
"""
Remove a component from a subsystem.
Throws ArgumentError if the subsystem name or component is not stored.
"""
function remove_component_from_subsystem!(
sys::System,
subsystem_name::AbstractString,
component::Component,
)
IS.remove_component_from_subsystem!(sys.data, subsystem_name, component)
handle_component_removal_from_subsystem!(sys, subsystem_name, component)
return
end
"""
Remove a component from all subsystems it belongs to.
"""
remove_component_from_subsystems!(
sys::System,
component::Component,
) = remove_component_from_subsystems!(sys.data, component)
"""
Return true if the component is in the subsystem.
"""
has_component(
sys::System,
subsystem_name::AbstractString,
component::Component,
) = IS.has_component(sys.data, subsystem_name, component)
"""
Return a Vector of subsystem names that contain the component.
"""
get_assigned_subsystems(
sys::System,
component::Component,
) = IS.get_assigned_subsystems(sys.data, component)
"""
Return true if the component is assigned to any subsystems.
"""
is_assigned_to_subsystem(sys::System, component::Component) =
IS.is_assigned_to_subsystem(sys.data, component)
"""
Return true if the component is assigned to the subsystem.
"""
is_assigned_to_subsystem(
sys::System,
component::Component,
subsystem_name::AbstractString,
) = IS.is_assigned_to_subsystem(sys.data, component, subsystem_name)
"""
Return the UUIDs of all components in the given subsystem.
"""
get_component_uuids(sys::System, subsystem_name::AbstractString) =
IS.get_component_uuids(sys.data, subsystem_name)
function check_subsystems(sys::System, component::Component)
_check_arc_consistency(sys, component)
_check_branch_consistency(sys, component)
_check_device_service_consistency(sys, component)
_check_subcomponent_consistency(sys, component)
_check_topological_consistency(sys, component)
return
end
function _check_num_subsystems(sys::System)
num_buses = length(sys.bus_numbers)
if get_num_subsystems(sys) >= num_buses
throw(
IS.InvalidValue(
"The number of subsystems cannot exceed the number of buses: $num_buses",
),
)
end
end
_check_arc_consistency(::System, ::Component) = nothing
_check_branch_consistency(::System, ::Component) = nothing
_check_device_service_consistency(::System, ::Component) = nothing
_check_subcomponent_consistency(::System, ::Component) = nothing
function _check_arc_consistency(sys::System, arc::Arc)
msg = "An arc must be assigned to the same subystems as its buses."
_check_subsystem_assignments(sys, arc, get_from(arc), msg; symmetric_diff = false)
_check_subsystem_assignments(sys, arc, get_to(arc), msg; symmetric_diff = false)
end
function _check_branch_consistency(sys::System, branch::Branch)
msg = "A branch must be assigned to the same subystems as its arc."
_check_subsystem_assignments(sys, branch, get_arc(branch), msg; symmetric_diff = true)
end
function _check_branch_consistency(
sys::System,
branch::ThreeWindingTransformer,
)
msg = "A branch must be assigned to the same subystems as its arc."
arcs = [
get_primary_star_arc(branch),
get_secondary_star_arc(branch),
get_tertiary_star_arc(branch),
]
for arc in arcs
_check_subsystem_assignments(sys, branch, arc, msg; symmetric_diff = true)
end
end
function _check_branch_consistency(sys::System, branch::AreaInterchange)
msg = "An area interchange must be assigned to the same subystems as its areas."
_check_subsystem_assignments(
sys,
branch,
get_from_area(branch),
msg;
symmetric_diff = false,
)
_check_subsystem_assignments(
sys,
branch,
get_to_area(branch),
msg;
symmetric_diff = false,
)
end
function _check_subcomponent_consistency(sys::System, component::StaticInjectionSubsystem)
for subcomponent in get_subcomponents(component)
_check_subsystem_assignments(
sys,
component,
subcomponent,
"StaticInjectionSubsystems and their subcomponents be assigned to the same subsystems.";
symmetric_diff = true,
)
end
end
function _check_topological_consistency(sys::System, component::Component)
for name in fieldnames(typeof(component))
val = getproperty(component, name)
if val isa Topology
_check_subsystem_assignments(
sys,
component,
val,
"A component must be assigned to at least one subsystem as its topological component(s).";
symmetric_diff = false,
)
end
end
end
function _check_device_service_consistency(sys::System, device::Device)
if !supports_services(device)
return
end
for service in get_services(device)
_check_subsystem_assignments(
sys,
device,
service,
"A service must be assigned to the same subsystems as its contributing devices.";
symmetric_diff = true,
)
end
return
end
function _check_subsystem_assignments(
sys::System,
component1::Component,
component2::Component,
message::AbstractString;
symmetric_diff::Bool,
)
subsys1 = get_assigned_subsystems(sys, component1)
subsys2 = get_assigned_subsystems(sys, component2)
diff_method = symmetric_diff ? symdiff : setdiff
diff = diff_method(subsys1, subsys2)
if !isempty(diff)
throw(
IS.InvalidValue(
message *
"$(summary(component1)): $subsys1 " *
"$(summary(component2)): $subsys2 " *
"diff: $diff",
),
)
end
end
================================================
FILE: src/utils/IO/base_checks.jl
================================================
function orderedlimits(
limits::Union{NamedTuple{(:min, :max), Tuple{Float64, Float64}}, Nothing},
limitsname::String,
)
if isa(limits, Nothing)
@info "'$limitsname' limits defined as nothing"
else
if limits.max < limits.min
throw(DataFormatError("$limitsname limits not in ascending order"))
end
end
return limits
end
"""Throws DataFormatError if the array is not in ascending order."""
function check_ascending_order(array::Array{Int}, name::AbstractString)
for (i, num) in enumerate(array)
if i > 1 && num < array[i - 1]
throw(DataFormatError("$name Numbers are not in ascending order."))
end
end
return
end
"""Checks if a PowerSystemDevice has a field or subfield name."""
function isafield(component::Component, field::Symbol)
function _wrap(t, d = [])
fn = fieldnames(typeof(t))
for n in fn
push!(d, n)
f = getfield(t, n)
if length(fieldnames(typeof(f))) > 0
_wrap(f, d)
end
end
return d
end
allfields = _wrap(component)
return field in allfields
end
================================================
FILE: src/utils/IO/branchdata_checks.jl
================================================
function sanitize_component!(line::Union{MonitoredLine, Line}, sys::System)
sanitize_angle_limits!(line)
return
end
function validate_component_with_system(line::Union{MonitoredLine, Line}, sys::System)
is_valid = true
if !check_endpoint_voltages(line)
is_valid = false
elseif !correct_rate_limits!(line, get_base_power(sys))
is_valid = false
end
return is_valid
end
function sanitize_angle_limits!(line::Union{Line, MonitoredLine})
max_limit = pi / 2
min_limit = -pi / 2
orderedlimits(line.angle_limits, "Angles")
if (line.angle_limits.max / max_limit > 3) ||
(-1 * line.angle_limits.min / max_limit > 3)
@warn "The angle limits provided is larger than 3π/2 radians.\n " *
"PowerSystems inferred the data provided in degrees and will transform it to radians" _group =
IS.LOG_GROUP_PARSING maxlog = PS_MAX_LOG
if line.angle_limits.max / max_limit >= 0.99
line.angle_limits = (
min = line.angle_limits.min,
max = min(line.angle_limits.max * (π / 180), max_limit),
)
else
line.angle_limits =
(min = line.angle_limits.min, max = min(line.angle_limits.max, max_limit))
end
if (-1 * line.angle_limits.min / max_limit > 0.99)
line.angle_limits = (
min = max(line.angle_limits.min * (π / 180), min_limit),
max = line.angle_limits.max,
)
else
line.angle_limits =
(min = max(line.angle_limits.min, min_limit), max = line.angle_limits.max)
end
else
if line.angle_limits.max >= max_limit && line.angle_limits.min <= min_limit
line.angle_limits = (min = min_limit, max = max_limit)
elseif line.angle_limits.max >= max_limit && line.angle_limits.min >= min_limit
line.angle_limits = (min = line.angle_limits.min, max = max_limit)
elseif line.angle_limits.max <= max_limit && line.angle_limits.min <= min_limit
line.angle_limits = (min = min_limit, max = line.angle_limits.max)
elseif line.angle_limits.max == 0.0 && line.angle_limits.min == 0.0
line.angle_limits = (min = min_limit, max = max_limit)
end
end
return
end
# Building Synthetic Power Transmission Networks of Many Voltage Levels, Spanning Multiple Areas
# https://scholarspace.manoa.hawaii.edu/server/api/core/bitstreams/47b28d1e-7019-415f-9a88-e1ed37556342/content
# https://www.mdpi.com/1996-1073/10/8/1233/htm
const MVA_LIMITS_LINES = Dict(
69.0 => (min = 12.0, max = 115.0),
115.0 => (min = 92.0, max = 255.0),
138.0 => (min = 141.0, max = 344.0),
161.0 => (min = 176.0, max = 410.0),
230.0 => (min = 327.0, max = 797.0),
345.0 => (min = 897.0, max = 1494.0),
500.0 => (min = 1732.0, max = 3464.0))
# Building Synthetic Power Transmission Networks of Many Voltage Levels, Spanning Multiple Areas
# https://scholarspace.manoa.hawaii.edu/server/api/core/bitstreams/47b28d1e-7019-415f-9a88-e1ed37556342/content
# https://www.mdpi.com/1996-1073/10/8/1233/htm
const MVA_LIMITS_TRANSFORMERS = Dict(
69.0 => (min = 7.0, max = 115.0),
115.0 => (min = 17.0, max = 140.0),
138.0 => (min = 15.0, max = 239.0),
161.0 => (min = 30.0, max = 276.0),
230.0 => (min = 50.0, max = 470.0),
345.0 => (min = 160.0, max = 702.0),
500.0 => (min = 150.0, max = 1383.0),
765.0 => (min = 2200.0, max = 6900.0), # This value is 3x the SIL value from https://neos-guide.org/wp-content/uploads/2022/04/line_flow_approximation.pdf
)
function check_rating_values(line::Union{Line, MonitoredLine}, basemva::Float64)
arc = get_arc(line)
vrated = get_base_voltage(get_to(arc))
voltage_levels = collect(keys(MVA_LIMITS_LINES))
closestV_ix = findmin(abs.(voltage_levels .- vrated))
closest_v_level = voltage_levels[closestV_ix[2]]
closest_rate_range = MVA_LIMITS_LINES[closest_v_level]
# Assuming that the rate is in pu
for field in [:rating, :rating_b, :rating_c]
rating_value = getfield(line, field)
if isnothing(rating_value)
@assert field ∈ [:rating_b, :rating_c]
continue
end
if (rating_value >= 2.0 * closest_rate_range.max / basemva)
@warn "$(field) $(round(rating_value*basemva; digits=2)) MW for $(get_name(line)) is 2x larger than the max expected rating $(closest_rate_range.max) MW for Line at a $(closest_v_level) kV Voltage level." _group =
IS.LOG_GROUP_PARSING maxlog = PS_MAX_LOG
elseif (rating_value >= closest_rate_range.max / basemva) ||
(rating_value <= closest_rate_range.min / basemva)
@info "$(field) $(round(rating_value*basemva; digits=2)) MW for $(get_name(line)) is outside the expected range $(closest_rate_range) MW for Line at a $(closest_v_level) kV Voltage level." _group =
IS.LOG_GROUP_PARSING maxlog = PS_MAX_LOG
end
end
return true
end
"""
Calculates the line rating based on the formula for the maximum transfer limit over an impedance
"""
function line_rating_calculation(l::Union{Line, MonitoredLine})
theta_max = max(abs(l.angle_limits.min), abs(l.angle_limits.max))
g = l.r / (l.r^2 + l.x^2)
b = -l.x / (l.r^2 + l.x^2)
y_mag = sqrt(g^2 + b^2)
from_voltage_limits = get_voltage_limits(get_arc(l).from)
to_voltage_limits = get_voltage_limits(get_arc(l).to)
fr_vmin = isnothing(from_voltage_limits) ? 0.9 : from_voltage_limits.min
to_vmin = isnothing(to_voltage_limits) ? 0.9 : from_voltage_limits.min
c_max = sqrt(fr_vmin^2 + to_vmin^2 - 2 * fr_vmin * to_vmin * cos(theta_max))
new_rate = y_mag * max(fr_vmin, to_vmin) * c_max
return new_rate
end
function correct_rate_limits!(branch::Union{Line, MonitoredLine}, basemva::Float64)
theoretical_line_rate_pu = line_rating_calculation(branch)
for field in [:rating, :rating_b, :rating_c]
rating_value = getfield(branch, field)
if isnothing(rating_value)
@assert field ∈ [:rating_b, :rating_c]
continue
end
if rating_value < 0.0
@error "PowerSystems does not support negative line rates. $(field): $(rating)"
return false
end
if rating_value == INFINITE_BOUND
@warn "Data for branch $(summary(branch)) $(field) is set to INFINITE_BOUND. \
PowerSystems will set a rate from line parameters to $(theoretical_line_rate_pu)" _group =
IS.LOG_GROUP_PARSING maxlog = PS_MAX_LOG
setfield!(branch, field, theoretical_line_rate_pu)
end
end
return check_rating_values(branch, basemva)
end
function check_endpoint_voltages(line::Union{Line, MonitoredLine})
is_valid = true
arc = get_arc(line)
from_voltage = get_base_voltage(get_from(arc))
to_voltage = get_base_voltage(get_to(arc))
percent_difference = abs(from_voltage - to_voltage) / ((from_voltage + to_voltage) / 2)
if percent_difference > BRANCH_BUS_VOLTAGE_DIFFERENCE_TOL
is_valid = false
@error "Voltage endpoints of $(get_name(line)) have more than $(BRANCH_BUS_VOLTAGE_DIFFERENCE_TOL*100)% difference, cannot create Line. /
Check if the data corresponds to transformer data."
end
return is_valid
end
const TYPICAL_XFRM_REACTANCE = (min = 0.05, max = 0.2) # per-unit
function validate_component_with_system(
xfrm::TwoWindingTransformer,
sys::System,
)
is_valid_reactance = check_transformer_reactance(xfrm)
is_valid_rating = check_rating_values(xfrm, get_base_power(sys))
return is_valid_reactance && is_valid_rating
end
function check_rating_values(
xfrm::TwoWindingTransformer,
::Float64,
)
arc = get_arc(xfrm)
v_from = get_base_voltage(get_from(arc))
v_to = get_base_voltage(get_to(arc))
vrated = maximum([v_from, v_to])
voltage_levels = collect(keys(MVA_LIMITS_TRANSFORMERS))
closestV_ix = findmin(abs.(voltage_levels .- vrated))
closest_v_level = voltage_levels[closestV_ix[2]]
closest_rate_range = MVA_LIMITS_TRANSFORMERS[closest_v_level]
device_base_power = get_base_power(xfrm)
# The rate is in device pu
for field in [:rating, :rating_b, :rating_c]
rating_value = getproperty(xfrm, field)
if isnothing(rating_value)
@assert field ∈ [:rating_b, :rating_c]
continue
end
if (rating_value * device_base_power >= 2.0 * closest_rate_range.max)
@warn "$(field) $(round(rating_value*device_base_power; digits=2)) MW for $(get_name(xfrm)) is 2x larger than the max expected rating $(closest_rate_range.max) MW for Transformer at a $(closest_v_level) kV Voltage level." _group =
IS.LOG_GROUP_PARSING maxlog = PS_MAX_LOG
elseif (rating_value * device_base_power >= closest_rate_range.max) ||
(rating_value * device_base_power <= closest_rate_range.min)
@info "$(field) $(round(rating_value*device_base_power; digits=2)) MW for $(get_name(xfrm)) is outside the expected range $(closest_rate_range) MW for Transformer at a $(closest_v_level) kV Voltage level." _group =
IS.LOG_GROUP_PARSING maxlog = PS_MAX_LOG
end
end
return true
end
function check_transformer_reactance(
xfrm::TwoWindingTransformer,
)
x_pu = getproperty(xfrm, :x)
if x_pu < TYPICAL_XFRM_REACTANCE.min
@warn "Transformer $(get_name(xfrm)) per-unit reactance $(x_pu) is lower than the typical range $(TYPICAL_XFRM_REACTANCE). \
Check if the reactance source data is correct." _group = IS.LOG_GROUP_PARSING maxlog =
PS_MAX_LOG
end
if x_pu > TYPICAL_XFRM_REACTANCE.max
@warn "Transformer $(get_name(xfrm)) per-unit reactance $(x_pu) is higher than the typical range $(TYPICAL_XFRM_REACTANCE). \
Check if the reactance source data is correct." _group = IS.LOG_GROUP_PARSING maxlog =
PS_MAX_LOG
end
return true
end
================================================
FILE: src/utils/IO/system_checks.jl
================================================
### Utility Functions needed for the construction of the Power System, mostly used for consistency checking ####
## Check that all the buses have a type defintion and that bus types are consistent with generator connections ##
function buscheck(sys::System)
buses = get_components(ACBus, sys)
for b in buses
b_type = get_bustype(b)
if isnothing(b_type)
@warn "Bus/Nodes data does not contain information to build an a network" maxlog =
10
end
end
return
end
## Slack Bus Definition ##
function slack_bus_check(buses)
slack = -9
for b in buses
if b.bustype == ACBusTypes.REF
slack = b.number
break
end
end
if slack == -9
@error "Model doesn't contain a slack bus"
end
return
end
# TODO: Check for islanded Buses
# check for minimum timediff
function minimumtimestep(time_series::Array{T}) where {T <: TimeSeriesData}
if length(time_series[1].data) > 1
timeseries = time_series[1].data
n = length(timeseries) - 1
ts = []
for i in 1:n
push!(
ts,
TimeSeries.timestamp(timeseries)[n + 1] -
TimeSeries.timestamp(timeseries)[n],
)
end
return minimum(ts)
else
ts = Dates.Dates.Minute(1)
return ts
end
end
function critical_components_check(sys::System)
critical_component_types = [ACBus, Generator, ElectricLoad]
for component_type in critical_component_types
components = get_available_components(component_type, sys)
if length(components) == 0
@warn "There are no $(component_type) Components in the System"
end
end
end
"""
adequacy_check(sys::System)
Checks the system for sum(generator ratings) >= sum(load ratings).
# Arguments
- `sys::System`: system
"""
function adequacy_check(sys::System)
gen = total_capacity_rating(sys)
load = total_load_rating(sys)
load > gen && @warn "System peak load ($load) exceeds total capacity capability ($gen)."
return
end
"""
total_load_rating(sys::System)
Sum of load ratings.
# Arguments
- `sys::System`: system
"""
function total_load_rating(sys::System)
# Assumes system is in system base
base_power = get_base_power(sys)
static_loads = get_available_components(StaticLoad, sys)
sl = isempty(static_loads) ? 0.0 : sum(get_max_active_power.(static_loads)) * base_power
@debug "System has $sl MW of StaticLoad" _group = IS.LOG_GROUP_SYSTEM_CHECKS
# Total load calculation for admittances assumes P = Real(V^2*Y) with V=1.0
fa_loads = get_available_components(FixedAdmittance, sys)
fa = isempty(fa_loads) ? 0.0 : sum(real.(1.0 .* get_Y.(fa_loads))) * base_power
@debug "System has $fa MW of FixedAdmittance" _group = IS.LOG_GROUP_SYSTEM_CHECKS
sa_loads = get_available_components(SwitchedAdmittance, sys)
sa = isempty(sa_loads) ? 0.0 : sum(real.(1.0 .* get_Y.(sa_loads))) * base_power
@debug "System has $fa MW of SwitchedAdmittance" _group = IS.LOG_GROUP_SYSTEM_CHECKS
total_load = sl + fa + sa
@debug "Total System Load: $total_load" _group = IS.LOG_GROUP_SYSTEM_CHECKS
return total_load
end
"""
total_capacity_rating(sys::System)
Sum of system generator and storage ratings.
# Arguments
- `sys::System`: system
"""
function total_capacity_rating(sys::System)
total = 0
for component_type in (Generator, Storage)
components = get_available_components(component_type, sys)
if !isempty(components)
component_total = sum(get_rating.(components)) * get_base_power(sys)
@debug "total rating for $component_type = $component_total" _group =
IS.LOG_GROUP_SYSTEM_CHECKS
total += component_total
end
end
@debug "Total System capacity: $total" _group = IS.LOG_GROUP_SYSTEM_CHECKS
return total
end
================================================
FILE: src/utils/conversion.jl
================================================
"Convert Tuple to Min Max Named Tuple"
Base.convert(::Type{MinMax}, input::Tuple{Float64, Float64}) =
(min = input[1], max = input[2])
"Convert Tuple to Up Down Named Tuple"
Base.convert(::Type{UpDown}, input::Tuple{Float64, Float64}) =
(up = input[1], down = input[2])
================================================
FILE: src/utils/generate_struct_files.jl
================================================
"""
Generate a Julia source code file for one struct from a `StructDefinition`.
Refer to `StructDefinition` and `StructField` for descriptions of the available fields.
# Arguments
- `definition::StructDefinition`: Defines the struct and all fields.
- `filename::AbstractString`: Add the struct definition to this JSON file. Defaults to
`src/descriptors/power_system_structs.json`
- `output_directory::AbstractString`: Generate the files in this directory. Defaults to
`src/models/generated`
"""
function generate_struct_file(
definition::StructDefinition;
filename = nothing,
output_directory = nothing,
)
generate_struct_files(
[definition];
filename = filename,
output_directory = output_directory,
)
end
"""
Generate Julia source code files for multiple structs from a iterable of `StructDefinition`
instances.
Refer to `StructDefinition` and `StructField` for descriptions of the available fields.
# Arguments
- `definitions`: Defines the structs and all fields.
- `filename::AbstractString`: Add the struct definition to this JSON file. Defaults to
`src/descriptors/power_system_structs.json`
- `output_directory::AbstractString`: Generate the files in this directory. Defaults to
`src/models/generated`
"""
function generate_struct_files(definitions; filename = nothing, output_directory = nothing)
if isnothing(filename)
filename = joinpath(
dirname(Base.find_package("PowerSystems")),
"descriptors",
"power_system_structs.json",
)
end
if isnothing(output_directory)
output_directory =
joinpath(dirname(Base.find_package("PowerSystems")), "models", "generated")
end
IS.generate_struct_files(
definitions;
filename = filename,
output_directory = output_directory,
)
end
================================================
FILE: src/utils/logging.jl
================================================
"""
Creates console and file loggers.
**Note:** Log messages may not be written to the file until flush() or close() is called on
the returned logger.
# Arguments
- `console_level = Logging.Error`: level for console messages
- `file_level = Logging.Info`: level for file messages
- `filename::Union{Nothing, AbstractString} = "power-systems.log"`: log file; pass nothing
to disable file logging
# Example
```julia
logger = configure_logging(console_level = Logging.Info)
@info "log message"
close(logger)
```
"""
function configure_logging(;
console_level = Logging.Error,
file_level = Logging.Info,
filename::Union{Nothing, AbstractString} = "power-systems.log",
)
return IS.configure_logging(;
console = true,
console_stream = stderr,
console_level = console_level,
file = filename !== nothing,
filename = filename,
file_level = file_level,
file_mode = "w+",
tracker = nothing,
set_global = true,
)
end
================================================
FILE: src/utils/print.jl
================================================
# "smart" summary and REPL printing
function Base.summary(sys::System)
return "System (base power $(get_base_power(sys)))"
end
function Base.show(io::IO, sys::System)
show_system_table(io, sys; backend = :auto)
if IS.get_num_components(sys) > 0
show_components_table(io, sys; backend = :auto)
end
println(io)
IS.show_time_series_data(io, sys.data; backend = :auto)
return
end
Base.show(io::IO, ::MIME"text/plain", sys::System) = show(io, sys)
function Base.summary(io::IO, tech::DeviceParameter)
print(io, "$(typeof(tech))")
end
function Base.summary(io::IO, data::OperationalCost)
field_msgs = []
for field_name in fieldnames(typeof(data))
val = getproperty(data, field_name)
# Only the most important fields
(val isa ProductionVariableCostCurve) &&
push!(field_msgs, "$(field_name): $(typeof(val))")
(val isa TimeSeriesKey) &&
push!(field_msgs, "$(field_name): time series \"$(get_name(val))\"")
end
isempty(field_msgs) && return
print(io, "$(typeof(data)) composed of ")
join(io, field_msgs, ", ")
end
function Base.show(io::IO, ::MIME"text/plain", data::OperationalCost)
print(io, "$(typeof(data)): ")
for field_name in fieldnames(typeof(data))
val = getproperty(data, field_name)
val_printout =
replace(sprint(show, "text/plain", val; context = io), "\n" => "\n ")
print(io, "\n $(field_name): $val_printout")
end
end
function Base.show(io::IO, ::MIME"text/plain", data::PowerSystemTableData)
println(io, "$(typeof(data)):")
println(io, " directory: $(data.directory)")
if !isnothing(data.timeseries_metadata_file)
println(io, " timeseries_metadata_file: $(data.timeseries_metadata_file)")
end
println(io, " base_power: $(data.base_power)")
for (field, df) in data.category_to_df
print(io, " $field: ")
println(io, "$(summary(df))")
end
end
function Base.show(io::IO, ist::Component)
print(io, IS.strip_module_name(typeof(ist)), "(")
is_first = true
for (name, field_type) in zip(fieldnames(typeof(ist)), fieldtypes(typeof(ist)))
getter_name = Symbol("get_$name")
if field_type <: InfrastructureSystemsInternal
continue
elseif hasproperty(PowerSystems, getter_name)
getter_func = getproperty(PowerSystems, getter_name)
val = getter_func(ist)
else
val = getproperty(ist, name)
end
if is_first
is_first = false
else
print(io, ", ")
end
print(io, val)
end
print(io, ")")
return
end
function Base.show(io::IO, ::MIME"text/plain", ist::Component)
default_units = false
if !has_units_setting(ist)
print(io, "\n")
@warn(
"SystemUnitSetting not defined, using NATURAL_UNITS for displaying device specification."
)
set_units_setting!(
ist,
SystemUnitsSettings(100.0, UNIT_SYSTEM_MAPPING["NATURAL_UNITS"]),
)
default_units = true
end
try
print(io, summary(ist), ":")
for name in fieldnames(typeof(ist))
obj = getproperty(ist, name)
getter_name = Symbol("get_$name")
if (obj isa InfrastructureSystemsInternal) && !default_units
print(io, "\n ")
show(io, MIME"text/plain"(), obj.units_info)
continue
elseif obj isa InfrastructureSystemsType ||
obj isa Vector{<:InfrastructureSystemsComponent}
val = summary(getproperty(ist, name))
elseif hasproperty(PowerSystems, getter_name)
getter_func = getproperty(PowerSystems, getter_name)
try
val = getter_func(ist)
catch e
@warn "$(e.msg) Printing in DEVICE_BASE instead."
val = with_units_base(ist, "DEVICE_BASE") do
getter_func(ist)
end
end
else
val = getproperty(ist, name)
end
print(io, "\n ", name, ": ", val)
end
print(
io,
"\n ",
"has_supplemental_attributes",
": ",
string(has_supplemental_attributes(ist)),
)
print(io, "\n ", "has_time_series", ": ", string(has_time_series(ist)))
finally
if default_units
set_units_setting!(ist, nothing)
end
end
return
end
"""
Show all components of the given type in a table.
# Arguments
- `sys::System`: System containing the components.
- `component_type::Type{<:Component}`: Type to display. Must be a concrete type.
- `additional_columns::Union{Dict, Vector}`: Additional columns to display.
The Dict option is a mapping of column name to function. The function must accept
a component.
The Vector option is an array of field names for the `component_type`.
Extra keyword arguments are forwarded to PrettyTables.pretty_table.
# Examples
```julia
show_components(sys, ThermalStandard)
show_components(sys, ThermalStandard, Dict("has_time_series" => x -> has_time_series(x)))
show_components(sys, ThermalStandard, [:active_power, :reactive_power])
```
"""
function show_components(
sys::System,
component_type::Type{<:Component},
additional_columns::Union{Dict, Vector} = Dict();
kwargs...,
)
show_components(stdout, sys, component_type, additional_columns; kwargs...)
return
end
function show_components(
io::IO,
sys::System,
component_type::Type{<:Component},
additional_columns::Union{Dict, Vector} = Dict();
kwargs...,
)
IS.show_components(
io,
sys.data.components,
component_type,
additional_columns;
kwargs...,
)
return
end
# The placement of the type in the argument list has been confusing for people. Support
# it both before and after the system.
show_components(
component_type::Type{<:Component},
sys::System,
additional_columns::Union{Dict, Vector} = Dict();
kwargs...,
) = show_components(sys, component_type, additional_columns; kwargs...)
show_components(
io::IO,
component_type::Type{<:Component},
sys::System,
additional_columns::Union{Dict, Vector} = Dict();
kwargs...,
) = show_components(io, sys, component_type, additional_columns; kwargs...)
"""
Show a table with the summary of time series attached to the system.
"""
function show_time_series(sys::System)
IS.show_time_series_data(stdout, sys.data)
end
================================================
FILE: src/utils/print_pt_v2.jl
================================================
function _make_backend_entry(backend::Val{T}) where {T}
return backend
end
function _make_backend_entry(backend::Symbol)
return Val(backend)
end
function _handle_kwargs(kwargs...)
kwargs = Dict{Symbol, Any}(kwargs...)
if haskey(kwargs, :stand_alone)
kwargs[:standalone] = kwargs[:stand_alone]
delete!(kwargs, :stand_alone)
end
backend_entry = pop!(kwargs, :backend, Val(:auto))
kwargs[:backend] = _make_backend_entry(backend_entry)
return kwargs
end
function show_system_table(io::IO, sys::System; kwargs...)
header = ["Property", "Value"]
num_components = get_num_components(sys)
table = [
"Name" isnothing(get_name(sys)) ? "" : get_name(sys)
"Description" isnothing(get_description(sys)) ? "" : get_description(sys)
"System Units Base" string(get_units_base(sys))
"Base Power" string(get_base_power(sys))
"Base Frequency" string(get_frequency(sys))
"Num Components" string(num_components)
]
PrettyTables.pretty_table(
io,
table;
header = header,
title = "System",
alignment = :l,
_handle_kwargs(kwargs)...,
)
return
end
function show_components_table(io::IO, sys::System; kwargs...)
header = ["Type", "Count"]
components = sys.data.components
static_types = Vector{DataType}()
dynamic_types = Vector{DataType}()
for component_type in keys(components.data)
if component_type <: DynamicInjection
push!(dynamic_types, component_type)
else
push!(static_types, component_type)
end
end
static_data = Array{Any, 2}(undef, length(static_types), length(header))
dynamic_data = Array{Any, 2}(undef, length(dynamic_types), length(header))
static_type_names = [(IS.strip_module_name(x), x) for x in static_types]
sort!(static_type_names; by = x -> x[1])
for (i, (type_name, type)) in enumerate(static_type_names)
vals = components.data[type]
static_data[i, 1] = type_name
static_data[i, 2] = length(vals)
end
if !isempty(static_types)
println(io)
PrettyTables.pretty_table(
io,
static_data;
header = header,
title = "Static Components",
alignment = :l,
_handle_kwargs(kwargs)...,
)
end
dynamic_type_names = [(IS.strip_module_name(x), x) for x in dynamic_types]
sort!(dynamic_type_names; by = x -> x[1])
for (i, (type_name, type)) in enumerate(dynamic_type_names)
vals = components.data[type]
dynamic_data[i, 1] = type_name
dynamic_data[i, 2] = length(vals)
end
if !isempty(dynamic_types)
println(io)
PrettyTables.pretty_table(
io,
dynamic_data;
header = header,
title = "Dynamic Components",
alignment = :l,
_handle_kwargs(kwargs)...,
)
end
end
function Base.show(io::IO, ::MIME"text/html", sys::System)
show_system_table(io, sys; backend = :html, stand_alone = false)
if get_num_components(sys) > 0
show_components_table(
io,
sys;
backend = Val(:html),
tf = PrettyTables.tf_html_simple,
standalone = false,
)
end
println(io)
IS.show_time_series_data(
io,
sys.data;
backend = Val(:html),
tf = PrettyTables.tf_html_simple,
standalone = false,
)
return
end
================================================
FILE: src/utils/print_pt_v3.jl
================================================
# The predefined table format recipes for HTML output got removed in PT v3.
# This is the CSS recipe copie from PT v2 for simple HTML tables.
const tf_html_simple = PrettyTables.HtmlTableFormat(;
css = """
table, td, th {
border-collapse: collapse;
font-family: sans-serif;
}
td, th {
border-bottom: 0;
padding: 4px
}
tr:nth-child(odd) {
background: #eee;
}
tr:nth-child(even) {
background: #fff;
}
tr.header {
background: #fff !important;
font-weight: bold;
}
tr.subheader {
background: #fff !important;
color: dimgray;
}
tr.headerLastRow {
border-bottom: 2px solid black;
}
th.rowNumber, td.rowNumber {
text-align: right;
}
""",
)
function show_system_table(io::IO, sys::System; kwargs...)
column_labels = ["Property", "Value"]
num_components = get_num_components(sys)
table = [
"Name" isnothing(get_name(sys)) ? "" : get_name(sys)
"Description" isnothing(get_description(sys)) ? "" : get_description(sys)
"System Units Base" string(get_units_base(sys))
"Base Power" string(get_base_power(sys))
"Base Frequency" string(get_frequency(sys))
"Num Components" string(num_components)
]
PrettyTables.pretty_table(
io,
table;
column_labels = column_labels,
title = "System",
alignment = :l,
kwargs...,
)
return
end
function show_components_table(io::IO, sys::System; kwargs...)
column_labels = ["Type", "Count"]
components = sys.data.components
static_types = Vector{DataType}()
dynamic_types = Vector{DataType}()
for component_type in keys(components.data)
if component_type <: DynamicInjection
push!(dynamic_types, component_type)
else
push!(static_types, component_type)
end
end
static_data = Array{Any, 2}(undef, length(static_types), length(column_labels))
dynamic_data = Array{Any, 2}(undef, length(dynamic_types), length(column_labels))
static_type_names = [(IS.strip_module_name(x), x) for x in static_types]
sort!(static_type_names; by = x -> x[1])
for (i, (type_name, type)) in enumerate(static_type_names)
vals = components.data[type]
static_data[i, 1] = type_name
static_data[i, 2] = length(vals)
end
if !isempty(static_types)
println(io)
PrettyTables.pretty_table(
io,
static_data;
column_labels = column_labels,
title = "Static Components",
alignment = :l,
kwargs...,
)
end
dynamic_type_names = [(IS.strip_module_name(x), x) for x in dynamic_types]
sort!(dynamic_type_names; by = x -> x[1])
for (i, (type_name, type)) in enumerate(dynamic_type_names)
vals = components.data[type]
dynamic_data[i, 1] = type_name
dynamic_data[i, 2] = length(vals)
end
if !isempty(dynamic_types)
println(io)
PrettyTables.pretty_table(
io,
dynamic_data;
column_labels = column_labels,
title = "Dynamic Components",
alignment = :l,
kwargs...,
)
end
end
function Base.show(io::IO, ::MIME"text/html", sys::System)
show_system_table(io, sys; backend = :html, stand_alone = false)
if get_num_components(sys) > 0
show_components_table(
io,
sys;
backend = :html,
table_format = tf_html_simple,
stand_alone = false,
)
end
println(io)
IS.show_time_series_data(
io,
sys.data;
backend = :html,
table_format = tf_html_simple,
stand_alone = false,
)
return
end
================================================
FILE: test/Project.toml
================================================
[deps]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
PowerSystemCaseBuilder = "f00506e0-b84f-492a-93c2-c0a9afc4364e"
PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TimeSeries = "9e3dc215-6440-5c97-bce1-76c03772f85e"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
[compat]
InfrastructureSystems = "3"
PowerSystemCaseBuilder = "^2"
julia = "^1.10"
================================================
FILE: test/common.jl
================================================
import InfrastructureSystems
mutable struct TestDevice <: Device
name::String
end
mutable struct TestRenDevice <: RenewableGen
name::String
end
mutable struct TestInjector <: StaticInjection
name::String
end
struct NonexistentComponent <: StaticInjection end
"""Return the first component of type component_type that matches the name of other."""
function get_component_by_name(sys::System, component_type, other::Component)
for component in get_components(component_type, sys)
if get_name(component) == get_name(other)
return component
end
end
error("Did not find component $component")
end
"""Return the Branch in the system that matches another by case-insensitive arc
names."""
function get_branch(sys::System, other::Branch)
for branch in get_components(Branch, sys)
if lowercase(other.arc.from.name) == lowercase(branch.arc.from.name) &&
lowercase(other.arc.to.name) == lowercase(branch.arc.to.name)
return branch
end
end
error("Did not find branch with buses $(other.arc.from.name) ", "$(other.arc.to.name)")
end
function create_rts_system(time_series_resolution = Dates.Hour(1))
data = PowerSystemTableData(RTS_GMLC_DIR, 100.0, DESCRIPTORS)
return System(data; time_series_resolution = time_series_resolution)
end
function create_system_with_dynamic_inverter()
nodes_OMIB = [
ACBus(
1, #number
"Bus 1", #Name
true, #available
"REF", #ACBusType (REF, PV, PQ)
0, #Angle in radians
1.06, #Voltage in pu
(min = 0.94, max = 1.06), #Voltage limits in pu
69,
nothing,
nothing,
), #Base voltage in kV
ACBus(
2,
"Bus 2",
true,
"PV",
0,
1.045,
(min = 0.94, max = 1.06),
69,
nothing,
nothing,
),
]
battery = EnergyReservoirStorage(;
name = "Battery",
prime_mover_type = PrimeMovers.BA,
storage_technology_type = StorageTech.OTHER_CHEM,
available = true,
bus = nodes_OMIB[2],
initial_energy = 5.0,
state_of_charge_limits = (min = 5.0, max = 100.0),
rating = 0.0275, #Value in per_unit of the system
active_power = 0.01375,
input_active_power_limits = (min = 0.0, max = 50.0),
output_active_power_limits = (min = 0.0, max = 50.0),
reactive_power = 0.0,
reactive_power_limits = (min = -50.0, max = 50.0),
efficiency = (in = 0.80, out = 0.90),
base_power = 100.0,
)
converter = AverageConverter(
138.0, #Rated Voltage
100.0,
) #Rated MVA
branch_OMIB = [
Line(
"Line1", #name
true, #available
0.0, #active power flow initial condition (from-to)
0.0, #reactive power flow initial condition (from-to)
Arc(; from = nodes_OMIB[1], to = nodes_OMIB[2]), #Connection between buses
0.01, #resistance in pu
0.05, #reactance in pu
(from = 0.0, to = 0.0), #susceptance in pu
18.046, #rate in MW
1.04,
),
] #angle limits (-min and max)
dc_source = FixedDCSource(1500.0) #Not in the original data, guessed.
filt = LCLFilter(
0.08, #Series inductance lf in pu
0.003, #Series resitance rf in pu
0.074, #Shunt capacitance cf in pu
0.2, #Series reactance rg to grid connection (#Step up transformer or similar)
0.01,
) #Series resistance lg to grid connection (#Step up transformer or similar)
pll = KauraPLL(
500.0, #ω_lp: Cut-off frequency for LowPass filter of PLL filter.
0.084, #k_p: PLL proportional gain
4.69,
) #k_i: PLL integral gain
virtual_H = VirtualInertia(
2.0, #Ta:: VSM inertia constant
400.0, #kd:: VSM damping coefficient
20.0, #kω:: Frequency droop gain in pu
2 * pi * 50.0,
) #ωb:: Rated angular frequency
Q_control = ReactivePowerDroop(
0.2, #kq:: Reactive power droop gain in pu
1000.0,
) #ωf:: Reactive power cut-off low pass filter frequency
outer_control = OuterControl(virtual_H, Q_control)
vsc = VoltageModeControl(
0.59, #kpv:: Voltage controller proportional gain
736.0, #kiv:: Voltage controller integral gain
0.0, #kffv:: Binary variable enabling the voltage feed-forward in output of current controllers
0.0, #rv:: Virtual resistance in pu
0.2, #lv: Virtual inductance in pu
1.27, #kpc:: Current controller proportional gain
14.3, #kiv:: Current controller integral gain
0.0, #kffi:: Binary variable enabling the current feed-forward in output of current controllers
50.0, #ωad:: Active damping low pass filter cut-off frequency
0.2,
) #kad:: Active damping gain
sys = System(100.0)
for bus in nodes_OMIB
add_component!(sys, bus)
end
for lines in branch_OMIB
add_component!(sys, lines)
end
add_component!(sys, battery)
test_inverter = DynamicInverter(
get_name(battery),
1.0, #ω_ref
converter, #Converter
outer_control, #OuterControl
vsc, #Voltage Source Controller
dc_source, #DC Source
pll, #Frequency Estimator
filt,
) #Output Filter
add_component!(sys, test_inverter, battery)
return sys
end
"""
Create a system with supplemental attributes with the criteria below.
- Two GeographicInfo instances each assigned to multiple components.
- Two ThermalStandards each with two ForcedOutage instances and two PlannedOutage instances.
- Each outage has time series.
"""
function create_system_with_outages()
sys = PSB.build_system(
PSITestSystems,
"c_sys5_uc";
add_forecasts = true,
)
gens = collect(get_components(ThermalStandard, sys))
gen1 = gens[1]
gen2 = gens[2]
geo1 = GeographicInfo(; geo_json = Dict("type" => "Point", "coordinates" => [1.0, 2.0]))
geo2 = GeographicInfo(; geo_json = Dict("type" => "Point", "coordinates" => [3.0, 4.0]))
begin_time_series_update(sys) do
begin_supplemental_attributes_update(sys) do
add_supplemental_attribute!(sys, gen1, geo1)
add_supplemental_attribute!(sys, gen1.bus, geo1)
add_supplemental_attribute!(sys, gen2, geo2)
add_supplemental_attribute!(sys, gen2.bus, geo2)
initial_time = Dates.DateTime("2020-01-01T00:00:00")
end_time = Dates.DateTime("2020-01-01T23:00:00")
dates = collect(initial_time:Dates.Hour(1):end_time)
fo1 = GeometricDistributionForcedOutage(;
mean_time_to_recovery = 1.0,
outage_transition_probability = 0.5,
)
fo2 = GeometricDistributionForcedOutage(;
mean_time_to_recovery = 2.0,
outage_transition_probability = 0.5,
)
po1 = PlannedOutage(; outage_schedule = "1")
po2 = PlannedOutage(; outage_schedule = "2")
add_supplemental_attribute!(sys, gen1, fo1)
add_supplemental_attribute!(sys, gen1, po1)
add_supplemental_attribute!(sys, gen2, fo2)
add_supplemental_attribute!(sys, gen2, po2)
for (i, outage) in enumerate((fo1, fo2, po1, po2))
data = collect(i:(i + 23))
ta = TimeSeries.TimeArray(dates, data, ["1"])
name = "ts_$(i)"
ts = SingleTimeSeries(; name = name, data = ta)
add_time_series!(sys, outage, ts)
end
end
end
return sys
end
function create_system_with_subsystems()
sys = PSB.build_system(
PSITestSystems,
"test_RTS_GMLC_sys";
add_forecasts = true,
time_series_read_only = false,
)
add_subsystem!(sys, "subsystem_1")
for component in iterate_components(sys)
add_component_to_subsystem!(sys, "subsystem_1", component)
end
# TODO: Replace with multiple valid subsystems
return sys
end
function test_accessors(component)
ps_type = typeof(component)
for (field_name, field_type) in zip(fieldnames(ps_type), fieldtypes(ps_type))
if field_name === :name
func = getfield(InfrastructureSystems, Symbol("get_" * string(field_name)))
_func! =
getfield(InfrastructureSystems, Symbol("set_" * string(field_name) * "!"))
else
getter_name = Symbol("get_" * string(field_name))
if !hasproperty(PowerSystems, getter_name)
continue
end
func = getfield(PowerSystems, getter_name)
if !hasmethod(func, (ps_type,))
continue
end
setter_name = Symbol("set_" * string(field_name) * "!")
# In some cases there is a getter but no setter.
if hasproperty(PowerSystems, setter_name)
_func! = getfield(PowerSystems, setter_name)
else
_func! = nothing
end
end
val = func(component)
@test val isa field_type
try
if typeof(val) == Float64 || typeof(val) == Int
if !isnan(val)
aux = val + 1
if _func! !== nothing
_func!(component, aux)
@test func(component) == aux
end
end
elseif typeof(val) == String
aux = val * "1"
if _func! !== nothing
_func!(component, aux)
@test func(component) == aux
end
elseif typeof(val) == Bool
aux = !val
if _func! !== nothing
_func!(component, aux)
@test func(component) == aux
end
else
_func! !== nothing && _func!(component, val)
end
catch MethodError
continue
end
end
end
function validate_serialization(
sys::System;
time_series_read_only = false,
runchecks = nothing,
assign_new_uuids = false,
)
if runchecks === nothing
runchecks = PSY.get_runchecks(sys)
end
test_dir = mktempdir()
orig_dir = pwd()
cd(test_dir)
try
path = joinpath(test_dir, "test_system_serialization.json")
@info "Serializing to $path"
sys_ext = get_ext(sys)
sys_ext["data"] = 5
ext_test_bus_name = ""
bus = collect(get_components(PSY.ACBus, sys))[1]
ext_test_bus_name = PSY.get_name(bus)
ext = PSY.get_ext(bus)
ext["test_field"] = 1
to_json(sys, path; force = true)
data = open(path, "r") do io
JSON3.read(io)
end
@test data["data_format_version"] == PSY.DATA_FORMAT_VERSION
sys2 = System(
path;
time_series_read_only = time_series_read_only,
runchecks = runchecks,
assign_new_uuids = assign_new_uuids,
)
isempty(get_bus_numbers(sys2)) && return false
sys_ext2 = get_ext(sys2)
sys_ext2["data"] != 5 && return false
bus = PSY.get_component(PSY.ACBus, sys2, ext_test_bus_name)
ext = PSY.get_ext(bus)
ext["test_field"] != 1 && return false
return sys2, PSY.compare_values(sys, sys2; compare_uuids = !assign_new_uuids)
finally
cd(orig_dir)
end
end
================================================
FILE: test/runtests.jl
================================================
using Test
using Logging
using DataStructures
using Dates
using LinearAlgebra
import TimeSeries
import InteractiveUtils
import JSON3
using PowerSystemCaseBuilder
import PowerSystemCaseBuilder as PSB
import InfrastructureSystems as IS
using PowerSystems
import PowerSystems: PowerSystemTableData
import PowerSystems as PSY
import Aqua
Aqua.test_unbound_args(PowerSystems)
Aqua.test_undefined_exports(PowerSystems)
Aqua.test_ambiguities(PowerSystems)
Aqua.test_stale_deps(PowerSystems)
Aqua.test_deps_compat(PowerSystems)
const BASE_DIR = dirname(dirname(Base.find_package("PowerSystems")))
const DATA_DIR = PSB.DATA_DIR
const TIME_SERIES_DIR = joinpath(DATA_DIR, "forecasts")
const MATPOWER_DIR = joinpath(DATA_DIR, "matpower")
const PSSE_RAW_DIR = joinpath(DATA_DIR, "psse_raw")
const PSSE_DYR_DIR = joinpath(DATA_DIR, "psse_dyr")
const PSSE_TEST_DIR = joinpath(DATA_DIR, "PSSE_test")
const RTS_GMLC_DIR = joinpath(DATA_DIR, "RTS_GMLC")
const TAMU_DIR = joinpath(DATA_DIR, "ACTIVSg2000")
const DESCRIPTORS = joinpath(RTS_GMLC_DIR, "user_descriptors.yaml")
const BAD_DATA = joinpath(DATA_DIR, "bad_data_for_tests")
LOG_FILE = "power-systems.log"
LOG_LEVELS = Dict(
"Debug" => Logging.Debug,
"Info" => Logging.Info,
"Warn" => Logging.Warn,
"Error" => Logging.Error,
)
include("common.jl")
include(joinpath(DATA_DIR, "psy_data", "data_5bus_pu.jl"))
include(joinpath(DATA_DIR, "psy_data", "data_14bus_pu.jl"))
"""
Copied @includetests from https://github.com/ssfrr/TestSetExtensions.jl.
Ideally, we could import and use TestSetExtensions. Its functionality was broken by changes
in Julia v0.7. Refer to https://github.com/ssfrr/TestSetExtensions.jl/pull/7.
"""
"""
Includes the given test files, given as a list without their ".jl" extensions.
If none are given it will scan the directory of the calling file and include all
the julia files.
"""
macro includetests(testarg...)
if length(testarg) == 0
tests = []
elseif length(testarg) == 1
tests = testarg[1]
else
error("@includetests takes zero or one argument")
end
quote
tests = $tests
rootfile = @__FILE__
if length(tests) == 0
tests = readdir(dirname(rootfile))
tests = filter(
f ->
startswith(f, "test_") && endswith(f, ".jl") && f != basename(rootfile),
tests,
)
else
tests = map(f -> string(f, ".jl"), tests)
end
println()
for test in tests
print(splitext(test)[1], ": ")
include(test)
println()
end
end
end
function get_logging_level_from_env(env_name::String, default)
level = get(ENV, env_name, default)
return IS.get_logging_level(level)
end
function run_tests()
logging_config_filename = get(ENV, "SIIP_LOGGING_CONFIG", nothing)
if logging_config_filename !== nothing
config = IS.LoggingConfiguration(logging_config_filename)
else
config = IS.LoggingConfiguration(;
filename = LOG_FILE,
file_level = get_logging_level_from_env("SIIP_FILE_LOG_LEVEL", "Info"),
console_level = get_logging_level_from_env("SIIP_CONSOLE_LOG_LEVEL", "Error"),
)
end
console_logger = ConsoleLogger(config.console_stream, config.console_level)
IS.open_file_logger(config.filename, config.file_level) do file_logger
levels = (Logging.Info, Logging.Warn, Logging.Error)
multi_logger =
IS.MultiLogger([console_logger, file_logger], IS.LogEventTracker(levels))
global_logger(multi_logger)
if !isempty(config.group_levels)
IS.set_group_levels!(multi_logger, config.group_levels)
end
# Testing Topological components of the schema
@time @testset "Begin PowerSystems tests" begin
@includetests ARGS
end
@test length(IS.get_log_events(multi_logger.tracker, Logging.Error)) == 0
@info IS.report_log_summary(multi_logger)
end
end
logger = global_logger()
try
run_tests()
finally
# Guarantee that the global logger is reset.
global_logger(logger)
nothing
end
================================================
FILE: test/test_base_checks.jl
================================================
@testset "Test base checks" begin
unordered = [1, 4, 2, 6]
@test_throws(
PowerSystems.DataFormatError,
PowerSystems.check_ascending_order(unordered, "test")
)
ordered = sort(unordered)
PowerSystems.check_ascending_order(ordered, "test")
end
================================================
FILE: test/test_base_power.jl
================================================
@testset "Test zero base power correction" begin
sys = @test_logs(
(:warn, r".*changing device base power to match system base power.*"),
match_mode = :any,
build_system(PSISystems, "RTS_GMLC_DA_sys"; force_build = true)
)
for comp in get_components(PSY.SynchronousCondenser, sys)
@test abs(get_base_power(comp)) > eps()
end
end
function thermal_with_base_power(bus::PSY.Bus, name::String, base_power::Float64)
return ThermalStandard(;
name = name,
available = true,
status = true,
bus = bus,
active_power = 1.0,
reactive_power = 0.0,
rating = 2.0,
active_power_limits = (min = 0, max = 2),
reactive_power_limits = (min = -2, max = 2),
ramp_limits = nothing,
operation_cost = ThermalGenerationCost(nothing),
base_power = base_power,
time_limits = nothing,
prime_mover_type = PrimeMovers.OT,
fuel = ThermalFuels.OTHER,
services = Device[],
dynamic_injector = nothing,
ext = Dict{String, Any}(),
)
end
@testset "Test adding component with zero base power" begin
sys = build_system(PSISystems, "RTS_GMLC_DA_sys")
bus = first(get_components(PSY.Bus, sys))
gen = thermal_with_base_power(bus, "Test Gen with Zero Base Power", 0.0)
@test_logs (:warn, "Invalid range") match_mode = :any add_component!(sys, gen)
gen2 = thermal_with_base_power(bus, "Test Gen with Non-Zero Base Power", 100.0)
@test_nowarn add_component!(sys, gen2)
# uncomment if we correct to non-zero base power.
#=
with_units_base(sys, "SYSTEM_BASE") do
gen_added = PSY.get_component(PSY.ThermalStandard, sys, "Test Gen with Zero Base Power")
PSY.set_reactive_power!(gen_added, 0.0)
@test !isnan(PSY.get_reactive_power(gen_added))
end
=#
end
================================================
FILE: test/test_branchchecks_testing.jl
================================================
import TimeSeries: TimeArray
@testset "Time resolution" begin
twomins = TimeArray([DateTime(today()) + Dates.Minute(i * 2) for i in 1:5], ones(5))
oneday = TimeArray([DateTime(today()) + Dates.Day(i) for i in 1:5], ones(5))
onesec = TimeArray([DateTime(today()) + Dates.Second(i) for i in 1:5], ones(5))
onehour = TimeArray([DateTime(today()) + Dates.Hour(i) for i in 1:5], ones(5))
@test PowerSystems.get_resolution(twomins) == Dates.Minute(2)
@test PowerSystems.get_resolution(oneday) == Dates.Day(1)
@test PowerSystems.get_resolution(onesec) == Dates.Second(1)
@test PowerSystems.get_resolution(onehour) == Dates.Hour(1)
end
@testset "Angle limits" begin
nodes5 = [
ACBus(
1,
"nodeA",
true,
PowerSystems.ACBusTypes.PV,
0,
1.0,
(min = 0.9, max = 1.05),
230,
nothing,
nothing,
),
ACBus(
2,
"nodeB",
true,
PowerSystems.ACBusTypes.PQ,
0,
1.0,
(min = 0.9, max = 1.05),
230,
nothing,
nothing,
),
ACBus(
3,
"nodeC",
true,
PowerSystems.ACBusTypes.PV,
0,
1.0,
(min = 0.9, max = 1.05),
230,
nothing,
nothing,
),
ACBus(
4,
"nodeD",
true,
PowerSystems.ACBusTypes.REF,
0,
1.0,
(min = 0.9, max = 1.05),
230,
nothing,
nothing,
),
ACBus(
5,
"nodeE",
true,
PowerSystems.ACBusTypes.PV,
0,
1.0,
(min = 0.9, max = 1.05),
230,
nothing,
nothing,
),
]
branches_test = [
Line(
"1",
true,
0.0,
0.0,
Arc(; from = nodes5[1], to = nodes5[2]),
0.00281,
0.0281,
(from = 0.00356, to = 0.00356),
400.0,
(min = -360.0, max = 360.0),
),
Line(
"2",
true,
0.0,
0.0,
Arc(; from = nodes5[1], to = nodes5[4]),
0.00304,
0.0304,
(from = 0.00329, to = 0.00329),
3960.0,
(min = -360.0, max = 75.0),
),
Line(
"3",
true,
0.0,
0.0,
Arc(; from = nodes5[1], to = nodes5[5]),
0.00064,
0.0064,
(from = 0.01563, to = 0.01563),
18812.0,
(min = -75.0, max = 360.0),
),
Line(
"4",
true,
0.0,
0.0,
Arc(; from = nodes5[2], to = nodes5[3]),
0.00108,
0.0108,
(from = 0.00926, to = 0.00926),
11148.0,
(min = 0.0, max = 0.0),
),
Line(
"5",
true,
0.0,
0.0,
Arc(; from = nodes5[3], to = nodes5[4]),
0.00297,
0.0297,
(from = 0.00337, to = 0.00337),
4053.0,
(min = -1.2, max = 60.0),
),
Line(
"6",
true,
0.0,
0.0,
Arc(; from = nodes5[4], to = nodes5[5]),
0.00297,
0.0297,
(from = 0.00337, to = 00.00337),
240.0,
(min = -1.17, max = 1.17),
),
]
foreach(x -> PowerSystems.sanitize_angle_limits!(x), branches_test)
@test branches_test[1].angle_limits == (min = -pi / 2, max = pi / 2)
@test branches_test[2].angle_limits == (min = -pi / 2, max = 75.0 * (π / 180))
@test branches_test[3].angle_limits == (min = -75.0 * (π / 180), max = pi / 2)
@test branches_test[4].angle_limits == (min = -pi / 2, max = pi / 2)
@test branches_test[5].angle_limits == (min = -1.2, max = 60.0 * (π / 180))
@test branches_test[6].angle_limits == (min = -1.17, max = 1.17)
bad_angle_limits = Line(
"1",
true,
0.0,
0.0,
Arc(; from = nodes5[1], to = nodes5[2]),
0.00281,
0.0281,
(from = 0.00356, to = 0.00356),
400.0,
(min = 360.0, max = -360.0),
)
@test_throws(
PowerSystems.DataFormatError,
PowerSystems.sanitize_angle_limits!(bad_angle_limits)
)
end
================================================
FILE: test/test_busnumberchecks.jl
================================================
base_dir = dirname(dirname(pathof(PowerSystems)))
@testset "Check bus index" begin
# This signature is used to capture expected error logs from parsing matpower
test_bus_index =
() -> begin
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_case5_re_sys")
@test sort([b.number for b in collect(get_components(ACBus, sys))]) ==
[1, 2, 3, 4, 10]
@test sort(
collect(
Set([b.arc.from.number for b in collect(get_components(Branch, sys))]),
),
) == [1, 2, 3, 4]
@test sort(
collect(
Set([b.arc.to.number for b in collect(get_components(Branch, sys))]),
),
) == [2, 3, 4, 10]
# TODO: add test for loadzones testing MAPPING_BUSNUMBER2INDEX
end
@test_logs min_level = Logging.Error match_mode = :any test_bus_index()
end
@testset "Test unique bus numbers" begin
# This signature is used to capture expected error logs from parsing matpower
test_bus_numbers =
() -> begin
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_case5_re_sys")
number = 100
bus1 = ACBus(;
number = number,
name = "bus100",
available = true,
bustype = ACBusTypes.PV,
angle = 1.0,
magnitude = 1.0,
voltage_limits = (min = -1.0, max = 1.0),
base_voltage = 1.0,
)
bus2 = ACBus(;
number = number,
name = "bus101",
available = true,
bustype = ACBusTypes.PV,
angle = 1.0,
magnitude = 1.0,
voltage_limits = (min = -1.0, max = 1.0),
base_voltage = 1.0,
area = nothing,
load_zone = nothing,
)
add_component!(sys, bus1)
@test_throws ArgumentError add_component!(sys, bus2)
end
@test_logs min_level = Logging.Error match_mode = :any test_bus_numbers()
end
@testset "Test unique DCBus numbers" begin
test_dcbus_numbers =
() -> begin
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_case5_re_sys")
number = 200
dcbus_defaults = (;
available = true,
magnitude = 1.0,
voltage_limits = (min = -1.0, max = 1.0),
base_voltage = 1.0,
)
dcbus1 = DCBus(; number = number, name = "dcbus200", dcbus_defaults...)
dcbus2 = DCBus(; number = number, name = "dcbus201", dcbus_defaults...)
add_component!(sys, dcbus1)
@test_throws ArgumentError add_component!(sys, dcbus2)
# Also verify that a DCBus cannot share a number with an existing ACBus
existing_ac_number = first(get_bus_numbers(sys))
dcbus3 = DCBus(;
number = existing_ac_number,
name = "dcbus_conflict",
dcbus_defaults...,
)
@test_throws ArgumentError add_component!(sys, dcbus3)
end
@test_logs min_level = Logging.Error match_mode = :any test_dcbus_numbers()
end
================================================
FILE: test/test_component_selector.jl
================================================
test_sys = PSB.build_system(PSB.PSITestSystems, "c_sys5_all_components")
gen_solitude = PSY.get_component(ThermalStandard, test_sys, "Solitude")::Component # Error if `nothing`
gen_sundance = get_component(ThermalStandard, test_sys, "Sundance")::Component
set_available!(gen_sundance, false)
gen_wind = get_component(RenewableDispatch, test_sys, "WindBusA")::Component
test_sys2 = PSB.build_system(PSB.PSISystems, "5_bus_hydro_uc_sys")
gen_sundance2 = get_component(ThermalStandard, test_sys2, "Sundance")::Component
set_available!(gen_sundance2, false)
sort_name!(x) = sort!(collect(x); by = get_name)
# NOTE we are not constraining the second type parameter
GCReturnType = IS.FlattenIteratorWrapper{<:IS.InfrastructureSystemsComponent, <:Any}
"Helper function to test the return type of `get_components` whenever we call it"
function get_components_rt(args...; kwargs...)
result = get_components(args...; kwargs...)
@test result isa GCReturnType
return result
end
@testset "Test helper functions" begin
@test subtype_to_string(ThermalStandard) == "ThermalStandard"
@test component_to_qualified_string(ThermalStandard, "Solitude") ==
"ThermalStandard__Solitude"
@test component_to_qualified_string(gen_solitude) == "ThermalStandard__Solitude"
end
@testset "Test NameComponentSelector" begin
test_gen_ent = PSY.NameComponentSelector(ThermalStandard, "Solitude", nothing)
named_test_gen_ent = PSY.NameComponentSelector(ThermalStandard, "Solitude", "SolGen")
# Equality
@test PSY.NameComponentSelector(ThermalStandard, "Solitude", nothing) == test_gen_ent
@test PSY.NameComponentSelector(ThermalStandard, "Solitude", "SolGen") ==
named_test_gen_ent
# Construction
@test make_selector(ThermalStandard, "Solitude") == test_gen_ent
@test make_selector(ThermalStandard, "Solitude"; name = "SolGen") == named_test_gen_ent
@test make_selector(gen_solitude) == test_gen_ent
# Naming
@test get_name(test_gen_ent) == "ThermalStandard__Solitude"
@test get_name(named_test_gen_ent) == "SolGen"
# Contents
@test collect(get_components_rt(make_selector(NonexistentComponent, ""), test_sys)) ==
Vector{Component}()
the_components = collect(get_components_rt(test_gen_ent, test_sys))
@test length(the_components) == 1
@test typeof(first(the_components)) == ThermalStandard
@test get_name(first(the_components)) == "Solitude"
@test collect(
get_components_rt(
get_available,
make_selector(gen_sundance),
test_sys,
),
) ==
Vector{Component}()
@test collect(get_available_components(make_selector(gen_sundance), test_sys)) ==
Vector{Component}()
@test get_component(x -> true, test_gen_ent, test_sys) ==
first(the_components)
@test isnothing(get_component(x -> false, test_gen_ent, test_sys))
@test isnothing(get_available_component(make_selector(gen_sundance), test_sys))
@test only(get_groups(test_gen_ent, test_sys)) == test_gen_ent
end
@testset "Test ListComponentSelector" begin
comp_ent_1 = make_selector(ThermalStandard, "Sundance")
comp_ent_2 = make_selector(RenewableDispatch, "WindBusA")
test_list_ent = PSY.ListComponentSelector((comp_ent_1, comp_ent_2), nothing)
named_test_list_ent = PSY.ListComponentSelector((comp_ent_1, comp_ent_2), "TwoComps")
# Equality
@test PSY.ListComponentSelector((comp_ent_1, comp_ent_2), nothing) == test_list_ent
@test PSY.ListComponentSelector((comp_ent_1, comp_ent_2), "TwoComps") ==
named_test_list_ent
# Construction
@test make_selector(comp_ent_1, comp_ent_2;) == test_list_ent
@test make_selector(comp_ent_1, comp_ent_2; name = "TwoComps") ==
named_test_list_ent
# Naming
@test get_name(test_list_ent) ==
"[ThermalStandard__Sundance, RenewableDispatch__WindBusA]"
@test get_name(named_test_list_ent) == "TwoComps"
# Contents
@test collect(get_components_rt(make_selector(), test_sys)) == Vector{Component}()
the_components = collect(get_components_rt(test_list_ent, test_sys))
@test length(the_components) == 2
@test collect(get_groups(make_selector(), test_sys)) ==
Vector{ComponentSelector}()
the_groups = collect(get_groups(test_list_ent, test_sys))
@test length(the_groups) == 2
end
@testset "Test TypeComponentSelector" begin
test_sub_ent = PSY.TypeComponentSelector(ThermalStandard, :all, nothing)
named_test_sub_ent = PSY.TypeComponentSelector(ThermalStandard, :all, "Thermals")
# Equality
@test PSY.TypeComponentSelector(ThermalStandard, :all, nothing) == test_sub_ent
@test PSY.TypeComponentSelector(ThermalStandard, :all, "Thermals") == named_test_sub_ent
# Construction
@test make_selector(ThermalStandard) == make_selector(ThermalStandard; groupby = :each)
@test make_selector(ThermalStandard; groupby = :all) == test_sub_ent
@test make_selector(ThermalStandard; groupby = :all, name = "Thermals") ==
named_test_sub_ent
@test make_selector(ThermalStandard; groupby = string) isa PSY.TypeComponentSelector
# Naming
@test get_name(test_sub_ent) == "ThermalStandard"
@test get_name(named_test_sub_ent) == "Thermals"
# Contents
answer = sort_name!(get_components_rt(ThermalStandard, test_sys))
@test collect(get_components_rt(make_selector(NonexistentComponent), test_sys)) ==
Vector{Component}()
the_components = sort_name!(get_components_rt(test_sub_ent, test_sys))
@test all(the_components .== answer)
@test !(
gen_sundance in
collect(get_components_rt(get_available, test_sub_ent, test_sys)))
@test !(gen_sundance in collect(get_available_components(test_sub_ent, test_sys)))
# Grouping inherits from `DynamicallyGroupedComponentSelector` and is tested elsewhere
end
@testset "Test TopologyComponentSelector" begin
topo1 = get_component(Area, test_sys2, "1")
topo2 = get_component(LoadZone, test_sys2, "2")
@assert !isnothing(topo1) && !isnothing(topo2) "Relies on an out-of-date `5_bus_hydro_uc_sys` definition"
test_topo_ent1 =
PSY.TopologyComponentSelector(ThermalStandard, Area, "1", :all, nothing)
test_topo_ent2 =
PSY.TopologyComponentSelector(StaticInjection, LoadZone, "2", :all, "Zone_2")
# Equality
@test PSY.TopologyComponentSelector(ThermalStandard, Area, "1", :all, nothing) ==
test_topo_ent1
@test PSY.TopologyComponentSelector(StaticInjection, LoadZone, "2", :all, "Zone_2") ==
test_topo_ent2
# Construction
@test make_selector(ThermalStandard, Area, "1") ==
make_selector(ThermalStandard, Area, "1"; groupby = :each)
@test make_selector(ThermalStandard, Area, "1"; groupby = :all) == test_topo_ent1
@test make_selector(StaticInjection, LoadZone, "2"; groupby = :all, name = "Zone_2") ==
test_topo_ent2
@test make_selector(StaticInjection, LoadZone, "2"; groupby = string) isa
PSY.TopologyComponentSelector
# Naming
@test get_name(test_topo_ent1) == "Area__1__ThermalStandard"
@test get_name(test_topo_ent2) == "Zone_2"
# Contents
empty_topo_ent = make_selector(NonexistentComponent, Area, "1")
@test collect(get_components_rt(empty_topo_ent, test_sys2)) == Vector{Component}()
nonexistent_topo_ent = make_selector(ThermalStandard, Area, "NonexistentArea")
@test collect(get_components_rt(nonexistent_topo_ent, test_sys2)) == Vector{Component}()
answers =
sort_name!.((
get_components_in_aggregation_topology(
ThermalStandard,
test_sys2,
get_component(Area, test_sys2, "1"),
),
get_components_in_aggregation_topology(
StaticInjection,
test_sys2,
get_component(LoadZone, test_sys2, "2"),
)))
for (ent, ans) in zip((test_topo_ent1, test_topo_ent2), answers)
@assert length(ans) > 0 "Relies on an out-of-date `5_bus_hydro_uc_sys` definition"
the_components = get_components_rt(ent, test_sys2)
@test all(sort_name!(the_components) .== ans)
@test Set(collect(get_components_rt(x -> true, ent, test_sys2))) ==
Set(the_components)
@test length(
collect(get_components_rt(x -> false, ent, test_sys2)),
) ==
0
end
end
@testset "Test FilterComponentSelector" begin
starts_with_s(x) = lowercase(first(get_name(x))) == 's'
test_filter_ent =
PSY.FilterComponentSelector(ThermalStandard, starts_with_s, :all, nothing)
named_test_filter_ent = PSY.FilterComponentSelector(
ThermalStandard, starts_with_s, :all, "ThermStartsWithS")
# Equality
@test PSY.FilterComponentSelector(ThermalStandard, starts_with_s, :all, nothing) ==
test_filter_ent
@test PSY.FilterComponentSelector(
ThermalStandard, starts_with_s, :all, "ThermStartsWithS") == named_test_filter_ent
# Construction
@test make_selector(starts_with_s, ThermalStandard) ==
make_selector(starts_with_s, ThermalStandard; groupby = :each)
@test make_selector(starts_with_s, ThermalStandard; groupby = :all) == test_filter_ent
@test make_selector(
starts_with_s,
ThermalStandard;
groupby = :all,
name = "ThermStartsWithS",
) == named_test_filter_ent
@test make_selector(starts_with_s, ThermalStandard; groupby = string) isa
PSY.FilterComponentSelector
# Naming
@test get_name(test_filter_ent) == "starts_with_s__ThermalStandard"
@test get_name(named_test_filter_ent) == "ThermStartsWithS"
# Contents
answer = filter(starts_with_s, collect(get_components_rt(ThermalStandard, test_sys)))
@test collect(
get_components_rt(make_selector(x -> true, NonexistentComponent), test_sys),
) ==
Vector{Component}()
@test collect(get_components_rt(make_selector(x -> false, Component), test_sys)) ==
Vector{Component}()
@test all(collect(get_components_rt(test_filter_ent, test_sys)) .== answer)
@test !(
gen_sundance in
collect(
get_components_rt(get_available, test_filter_ent, test_sys),
))
@test !(gen_sundance in collect(get_available_components(test_filter_ent, test_sys)))
end
@testset "Test RegroupedComponentSelector" begin
comp_ent_1 = make_selector(ThermalStandard, "Sundance")
comp_ent_2 = make_selector(RenewableDispatch, "WindBusA")
test_list_ent = PSY.ListComponentSelector((comp_ent_1, comp_ent_2), nothing)
test_sel = PSY.RegroupedComponentSelector(test_list_ent, :all)
# Equality
@test PSY.RegroupedComponentSelector(test_list_ent, :all) == test_sel
# Naming
@test get_name(test_sel) == get_name(test_list_ent)
# Contents
@test Set(collect(get_components_rt(test_sel, test_sys))) ==
Set(collect(get_components_rt(test_list_ent, test_sys)))
end
@testset "Test DynamicallyGroupedComponentSelector grouping" begin
# We'll use TopologyComponentSelector as the token example
@assert PSY.TopologyComponentSelector <: DynamicallyGroupedComponentSelector
all_selector = make_selector(ThermalStandard, Area, "1"; groupby = :all)
each_selector = make_selector(ThermalStandard, Area, "1"; groupby = :each)
@test make_selector(ThermalStandard, Area, "1") == each_selector
@test_throws ArgumentError make_selector(ThermalStandard, Area, "1"; groupby = :other)
# @show get_name.(get_components_rt(all_selector, test_sys2))
partition_selector = make_selector(ThermalStandard, Area, "1";
groupby = x -> occursin(" ", get_name(x)))
@test only(get_groups(all_selector, test_sys2)) == all_selector
@test Set(get_name.(get_groups(each_selector, test_sys2))) ==
Set((
component_to_qualified_string.(Ref(ThermalStandard),
get_name.(get_components_rt(each_selector, test_sys2)))
))
@test length(
collect(
get_groups(x -> length(get_name(x)) == 8, each_selector, test_sys2),
),
) == 2
@test Set(get_name.(get_groups(partition_selector, test_sys2))) ==
Set(["true", "false"])
@test length(
collect(
get_groups(x -> length(get_name(x)) == 8, partition_selector, test_sys2),
),
) == 1
# Also test briefly with something from IS
@assert PSY.TypeComponentSelector <: DynamicallyGroupedComponentSelector
@test length(
collect(
get_groups(make_selector(ThermalStandard;
groupby = x -> length(get_name(x))), test_sys),
),
) == 3
# Test proper handling of availability
sel = make_selector(ThermalStandard; groupby = :each)
@test length(get_groups(sel, test_sys2)) >
length(get_available_groups(sel, test_sys2)) ==
length(get_available_components(sel, test_sys2)) ==
length(get_available_components(ThermalStandard, test_sys2)) ==
length(get_components(get_available, ThermalStandard, test_sys2))
end
@testset "Test rebuild_selector" begin
@assert !(PSY.NameComponentSelector <: PSY.DynamicallyGroupedComponentSelector)
@assert PSY.TopologyComponentSelector <: PSY.DynamicallyGroupedComponentSelector
sel1::PSY.NameComponentSelector =
make_selector(ThermalStandard, "Component1"; name = "oldname")
sel2::PSY.TypeComponentSelector =
make_selector(ThermalStandard; groupby = :all)
sel3::PSY.TopologyComponentSelector =
make_selector(ThermalStandard, Area, "1"; groupby = :all)
# TODO include sel3 when get_components is fixed -- see below
sel4::IS.ListComponentSelector = make_selector(sel1, sel2; name = "oldname")
@test rebuild_selector(sel1; name = "newname") ==
make_selector(ThermalStandard, "Component1"; name = "newname")
@test_throws Exception rebuild_selector(sel1; groupby = :each)
@test rebuild_selector(sel2; name = "newname") ==
make_selector(ThermalStandard; name = "newname", groupby = :all)
@test rebuild_selector(sel2; name = "newname", groupby = :each) ==
make_selector(ThermalStandard; name = "newname", groupby = :each)
@test rebuild_selector(sel3; name = "newname") ==
make_selector(ThermalStandard, Area, "1"; name = "newname", groupby = :all)
@test rebuild_selector(sel3; name = "newname", groupby = :each) ==
make_selector(ThermalStandard, Area, "1"; name = "newname", groupby = :each)
@test rebuild_selector(sel4; name = "newname") ==
make_selector(sel1, sel2; name = "newname")
regrouped = rebuild_selector(sel4; name = "newname", groupby = :all)
@test Set(collect(get_components_rt(regrouped, test_sys))) ==
Set(collect(get_components_rt(sel4, test_sys)))
@test length(get_groups(regrouped, test_sys)) == 1
end
@testset "Test special cases" begin
# Can error if the `PSY.get_components` vs. `IS.get_components` stuff is not functioning correctly
agg_selectors = [make_selector(ThermalStandard, Area, "1"),
make_selector(ThermalStandard, Area, "1")]
get_components_rt(make_selector(agg_selectors...), test_sys)
end
================================================
FILE: test/test_constructors.jl
================================================
@testset "Bus Constructors" begin
tBus = ACBus(nothing)
tLoadZone = LoadZone(nothing)
bus = ACBus(
1,
"test",
true,
ACBusTypes.SLACK,
0.0,
0.0,
(min = 0.0, max = 0.0),
nothing,
nothing,
nothing,
)
@test PowerSystems.get_bustype(bus) == ACBusTypes.REF
end
@testset "Generation Constructors" begin
for T in InteractiveUtils.subtypes(PSY.OperationalCost)
isabstracttype(T) || (@test T(nothing) isa IS.InfrastructureSystemsType)
end
# TODO add concrete subtypes of ProductionVariableCostCurve?
tThermalGen = ThermalStandard(nothing)
@test tThermalGen isa PowerSystems.Component
tHydroDispatch = HydroDispatch(nothing)
@test tHydroDispatch isa PowerSystems.Component
tRenewableNonDispatch = RenewableNonDispatch(nothing)
@test tRenewableNonDispatch isa PowerSystems.Component
tRenewableDispatch = RenewableDispatch(nothing)
@test tRenewableDispatch isa PowerSystems.Component
tRenewableDispatch = RenewableDispatch(nothing)
@test tRenewableDispatch isa PowerSystems.Component
tTurbine = HydroTurbine(nothing)
@test tTurbine isa PowerSystems.Component
tReservoir = HydroReservoir(nothing)
@test tReservoir isa PowerSystems.Component
end
@testset "Source Constructors" begin
tSource = Source(nothing)
@test tSource isa PowerSystems.Component
end
@testset "Storage Constructors" begin
tStorage = EnergyReservoirStorage(nothing)
@test tStorage isa PowerSystems.Component
end
@testset "Load Constructors" begin
tPowerLoad = PowerLoad(nothing)
@test tPowerLoad isa PowerSystems.Component
tStandardLoad = StandardLoad(nothing)
@test tStandardLoad isa PowerSystems.Component
tPowerLoad = PowerLoad("init", true, ACBus(nothing), 0.0, 0.0, 100.0, 0.0, 0.0)
@test tPowerLoad isa PowerSystems.Component
tLoad = InterruptiblePowerLoad(nothing)
@test tLoad isa PowerSystems.Component
tShiftableLoad = ShiftablePowerLoad(nothing)
@test tShiftableLoad isa PowerSystems.Component
tInterruptibleStandardLoad = InterruptibleStandardLoad(nothing)
@test tInterruptibleStandardLoad isa PowerSystems.Component
end
@testset "Branch Constructors" begin
tLine = Line(nothing)
@test tLine isa PowerSystems.Component
tMonitoredLine = MonitoredLine(nothing)
@test tMonitoredLine isa PowerSystems.Component
tTwoTerminalGenericHVDCLine = TwoTerminalGenericHVDCLine(nothing)
@test tTwoTerminalGenericHVDCLine isa PowerSystems.Component
tTwoTerminalLCCLine = TwoTerminalLCCLine(nothing)
@test tTwoTerminalLCCLine isa PowerSystems.Component
tTwoTerminalVSCLine = TwoTerminalVSCLine(nothing)
@test tTwoTerminalVSCLine isa PowerSystems.Component
tTransformer2W = Transformer2W(nothing)
@test tTransformer2W isa PowerSystems.Component
tTapTransformer = TapTransformer(nothing)
@test tTapTransformer isa PowerSystems.Component
tPhaseShiftingTransformer = PhaseShiftingTransformer(nothing)
@test tPhaseShiftingTransformer isa PowerSystems.Component
tTransformer3W = Transformer3W(nothing)
@test tTransformer3W isa PowerSystems.Component
tPhaseShiftingTransformer3W = PhaseShiftingTransformer3W(nothing)
@test tPhaseShiftingTransformer3W isa PowerSystems.Component
tGenericArcImpedance = GenericArcImpedance(nothing)
@test tGenericArcImpedance isa PowerSystems.Component
end
@testset "Service Constructors" begin
tConstantReserve = ConstantReserve{ReserveUp}(nothing)
@test tConstantReserve isa PowerSystems.Service
tVariableReserve = VariableReserve{ReserveDown}(nothing)
@test tVariableReserve isa PowerSystems.Service
end
@testset "TimeSeriesData Constructors" begin
tg = RenewableNonDispatch(nothing)
data = PowerSystems.TimeSeries.TimeArray(
[DateTime("01-01-01"), DateTime("01-01-01") + Hour(1)],
[1.0, 1.0],
)
#SingleTimeSeries Tests
ts = SingleTimeSeries("scalingfactor", Hour(1), DateTime("01-01-01"), 24)
@test ts isa PowerSystems.TimeSeriesData
ts = SingleTimeSeries(; name = "scalingfactor", data = data)
@test ts isa PowerSystems.TimeSeriesData
#Probabilistic Tests
data = SortedDict(
DateTime("01-01-01") => [1.0 1.0; 2.0 2.0],
DateTime("01-01-01") + Hour(1) => [1.0 1.0; 2.0 2.0],
)
ts = Probabilistic("scalingfactor", data, [0.5, 0.5], Hour(1))
@test ts isa PowerSystems.TimeSeriesData
ts = Probabilistic(;
name = "scalingfactor",
percentiles = [1.0, 1.0],
data = data,
resolution = Hour(1),
)
@test ts isa PowerSystems.TimeSeriesData
##Scenario Tests
ts = Scenarios("scalingfactor", data, Hour(1))
@test ts isa PowerSystems.TimeSeriesData
end
================================================
FILE: test/test_cost_functions.jl
================================================
@testset "Test scope-sensitive printing of IS cost functions" begin
# Make sure the aliases get registered properly
@test sprint(show, "text/plain", QuadraticCurve) ==
"QuadraticCurve (alias for InputOutputCurve{QuadraticFunctionData})"
# Make sure there are no IS-related prefixes in the printouts
fc = FuelCurve(InputOutputCurve(IS.QuadraticFunctionData(1, 2, 3)), 4.0)
@test sprint(show, "text/plain", fc) ==
sprint(show, "text/plain", fc; context = :compact => false) ==
"FuelCurve:\n value_curve: QuadraticCurve (a type of InputOutputCurve) where function is: f(x) = 1.0 x^2 + 2.0 x + 3.0\n power_units: UnitSystem.NATURAL_UNITS = 2\n fuel_cost: 4.0\n startup_fuel_offtake: LinearCurve (a type of InputOutputCurve) where function is: f(x) = 0.0 x + 0.0\n vom_cost: LinearCurve (a type of InputOutputCurve) where function is: f(x) = 0.0 x + 0.0"
@test sprint(show, "text/plain", fc; context = :compact => true) ==
"FuelCurve with power_units UnitSystem.NATURAL_UNITS = 2, fuel_cost 4.0, startup_fuel_offtake LinearCurve(0.0, 0.0), vom_cost LinearCurve(0.0, 0.0), and value_curve:\n QuadraticCurve (a type of InputOutputCurve) where function is: f(x) = 1.0 x^2 + 2.0 x + 3.0"
end
@testset "Test MarketBidCost direct struct creation and some scalar cost_function_timeseries interface" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generator = get_component(ThermalStandard, sys, "322_CT_6")
#Update generator cost to MarketBidCost using Natural Units
powers = [22.0, 33.0, 44.0, 55.0] # MW
marginal_costs = [25.0, 26.0, 28.0] # $/MWh
initial_input = 50.0 # $/h
cc = CostCurve(
PiecewiseIncrementalCurve(
initial_input,
powers,
marginal_costs,
),
)
mbc = MarketBidCost(;
start_up = (hot = 0.0, warm = 0.0, cold = 0.0),
shut_down = 0.0,
incremental_offer_curves = cc,
)
set_operation_cost!(generator, mbc)
@test get_operation_cost(generator) isa MarketBidCost
@test get_incremental_offer_curves(generator, mbc) == cc
@test isnothing(get_decremental_offer_curves(generator, mbc))
@test get_variable_cost(generator, mbc) == cc
@test get_incremental_variable_cost(generator, mbc) == cc
@test isnothing(get_decremental_variable_cost(generator, mbc))
cc2 = CostCurve(
PiecewiseIncrementalCurve(
initial_input,
powers,
marginal_costs .* 1.5,
),
)
set_incremental_variable_cost!(sys, generator, cc2, UnitSystem.NATURAL_UNITS)
@test get_incremental_variable_cost(generator, mbc) == cc2
end
@testset "Test Make market bid curve interface" begin
mbc = make_market_bid_curve(
[0.0, 100.0, 105.0, 120.0, 130.0],
[25.0, 26.0, 28.0, 30.0],
10.0,
)
@test is_market_bid_curve(mbc)
@test is_market_bid_curve(
make_market_bid_curve(get_function_data(mbc), get_initial_input(mbc)),
)
@test_throws ArgumentError make_market_bid_curve(
[100.0, 105.0, 120.0, 130.0], [26.0, 28.0, 30.0, 40.0], 10.0)
mbc2 = make_market_bid_curve([1.0, 2.0, 3.0], [4.0, 6.0], 10.0; input_at_zero = 2.0)
@test is_market_bid_curve(mbc2)
@test is_market_bid_curve(
make_market_bid_curve(get_function_data(mbc2), get_initial_input(mbc2)),
)
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generator = get_component(ThermalStandard, sys, "322_CT_6")
market_bid = MarketBidCost(nothing)
mbc3 = make_market_bid_curve([22.0, 33.0, 44.0, 55.0], [25.0, 26.0, 28.0], 50.0)
set_incremental_offer_curves!(market_bid, mbc3)
set_start_up!(market_bid, 0.0)
set_operation_cost!(generator, market_bid)
@test get_operation_cost(generator) isa MarketBidCost
end
test_costs = Dict(
CostCurve{QuadraticCurve} =>
repeat([CostCurve(QuadraticCurve(999.0, 2.0, 1.0))], 24),
PiecewiseStepData =>
repeat(
[
PSY._make_market_bid_curve(
PiecewiseStepData([0.0, 2.0, 3.0], [4.0, 6.0]),
),
],
24,
),
PiecewiseIncrementalCurve =>
repeat(
[
make_market_bid_curve(
[1.0, 2.0, 3.0],
[4.0, 6.0],
18.0;
input_at_zero = 20.0,
),
],
24,
),
Float64 =>
collect(11.0:34.0),
PSY.StartUpStages =>
repeat([(hot = PSY.START_COST, warm = PSY.START_COST, cold = PSY.START_COST)], 24),
)
@testset "Test MarketBidCost with Quadratic Cost Timeseries" begin
# Will throw TypeErrors because market bids must be piecewise, not quadratic and service
# bids must be piecewise, not scalar
initial_time = Dates.DateTime("2020-01-01")
resolution = Dates.Hour(1)
name = "test"
horizon = 24
service_data = Dict(initial_time => rand(horizon))
data_quadratic =
SortedDict(initial_time => test_costs[CostCurve{QuadraticCurve}])
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generator = get_component(ThermalStandard, sys, "322_CT_6")
market_bid = MarketBidCost(nothing)
set_operation_cost!(generator, market_bid)
forecast_fd = IS.Deterministic(
"variable_cost",
Dict(k => get_function_data.(v) for (k, v) in pairs(data_quadratic)),
resolution,
)
power_units = UnitSystem.NATURAL_UNITS
@test_throws TypeError set_variable_cost!(sys, generator, forecast_fd, power_units)
for s in generator.services
forecast_fd = IS.Deterministic(get_name(s), service_data, resolution)
@test_throws TypeError set_service_bid!(sys, generator, s, forecast_fd, power_units)
end
end
@testset "Test MarketBidCost with PiecewiseLinearData Cost Timeseries with Service Bid Forecast" begin
initial_time = Dates.DateTime("2020-01-01")
resolution = Dates.Hour(1)
name = "test"
horizon = 24
power_units = UnitSystem.NATURAL_UNITS
data_pwl = SortedDict(initial_time => test_costs[PiecewiseStepData])
service_data = data_pwl
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generator = get_component(ThermalStandard, sys, "322_CT_6")
market_bid = MarketBidCost(nothing)
set_operation_cost!(generator, market_bid)
forecast_fd = Deterministic(
"variable_cost",
Dict(k => get_function_data.(v) for (k, v) in pairs(data_pwl)),
resolution,
)
@test_throws ArgumentError set_variable_cost!(
sys,
generator,
forecast_fd,
UnitSystem.SYSTEM_BASE,
)
set_variable_cost!(sys, generator, forecast_fd, power_units)
for s in generator.services
forecast_fd = Deterministic(
get_name(s),
Dict(k => get_function_data.(v) for (k, v) in pairs(service_data)),
resolution,
)
@test_throws ArgumentError set_service_bid!(
sys,
generator,
s,
forecast_fd,
UnitSystem.SYSTEM_BASE,
)
set_service_bid!(sys, generator, s, forecast_fd, power_units)
end
iocs = get_incremental_offer_curves(generator, market_bid)
@test isequal(
first(TimeSeries.values(iocs)),
get_function_data(first(data_pwl[initial_time])),
)
cost_forecast = get_variable_cost(generator, market_bid; start_time = initial_time)
@test isequal(first(TimeSeries.values(cost_forecast)), first(data_pwl[initial_time]))
for s in generator.services
service_cost = get_services_bid(generator, market_bid, s; start_time = initial_time)
@test isequal(
first(TimeSeries.values(service_cost)),
first(service_data[initial_time]),
)
end
end
@testset "Test MarketBidCost with PiecewiseLinearData Cost Timeseries, initial_input, and no_load_cost" begin
initial_time = Dates.DateTime("2020-01-01")
resolution = Dates.Hour(1)
name = "test"
horizon = 24
power_units = UnitSystem.NATURAL_UNITS
data_pwl = SortedDict(initial_time => test_costs[PiecewiseIncrementalCurve])
service_data = data_pwl
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generator = get_component(ThermalStandard, sys, "322_CT_6")
market_bid = MarketBidCost(nothing)
set_operation_cost!(generator, market_bid)
forecast_fd = IS.Deterministic(
"variable_cost_function_data",
Dict(k => get_function_data.(v) for (k, v) in pairs(data_pwl)),
resolution,
)
set_variable_cost!(sys, generator, forecast_fd, power_units)
forecast_ii = IS.Deterministic(
"variable_cost_initial_input",
Dict(k => get_initial_input.(get_value_curve.(v)) for (k, v) in pairs(data_pwl)),
resolution,
)
PSY.set_incremental_initial_input!(sys, generator, forecast_ii)
forecast_iaz = IS.Deterministic(
"variable_cost_input_at_zero",
Dict(k => get_input_at_zero.(get_value_curve.(v)) for (k, v) in pairs(data_pwl)),
resolution,
)
set_no_load_cost!(sys, generator, forecast_iaz)
iocs = get_incremental_offer_curves(generator, market_bid)
@test isequal(
first(TimeSeries.values(iocs)),
get_function_data(first(data_pwl[initial_time])),
)
cost_forecast = get_variable_cost(generator, market_bid; start_time = initial_time)
@test isequal(first(TimeSeries.values(cost_forecast)), first(data_pwl[initial_time]))
end
@testset "Test MarketBidCost with Decremental PiecewiseLinearData Cost Timeseries, initial_input, and no_load_cost" begin
initial_time = Dates.DateTime("2020-01-01")
resolution = Dates.Hour(1)
name = "test"
horizon = 24
power_units = UnitSystem.NATURAL_UNITS
data_pwl = SortedDict(initial_time => test_costs[PiecewiseIncrementalCurve])
service_data = data_pwl
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generator = get_component(ThermalStandard, sys, "322_CT_6")
market_bid = MarketBidCost(nothing)
set_operation_cost!(generator, market_bid)
forecast_fd = IS.Deterministic(
"decremental_variable_cost_function_data",
Dict(k => get_function_data.(v) for (k, v) in pairs(data_pwl)),
resolution,
)
set_decremental_variable_cost!(sys, generator, forecast_fd, power_units)
forecast_ii = IS.Deterministic(
"decremental_variable_cost_initial_input",
Dict(k => get_initial_input.(get_value_curve.(v)) for (k, v) in pairs(data_pwl)),
resolution,
)
PSY.set_decremental_initial_input!(sys, generator, forecast_ii)
forecast_iaz = IS.Deterministic(
"variable_cost_input_at_zero",
Dict(k => get_input_at_zero.(get_value_curve.(v)) for (k, v) in pairs(data_pwl)),
resolution,
)
set_no_load_cost!(sys, generator, forecast_iaz)
iocs = get_decremental_offer_curves(generator, market_bid)
isequal(first(TimeSeries.values(iocs)), first(data_pwl[initial_time]))
cost_forecast =
get_decremental_variable_cost(generator, market_bid; start_time = initial_time)
@test isequal(first(TimeSeries.values(cost_forecast)), first(data_pwl[initial_time]))
end
@testset "Test `MarketBidCost` with single `start_up` value" begin
cost = MarketBidCost(0.0, 1.0, 2.0)
@test get_start_up(cost) == (hot = 1.0, warm = 0.0, cold = 0.0)
set_start_up!(cost, 2.0)
@test get_start_up(cost) == (hot = 2.0, warm = 0.0, cold = 0.0)
end
@testset "Test ReserveDemandCurve with Cost Timeseries" begin
initial_time = Dates.DateTime("2020-01-01")
resolution = Dates.Hour(1)
other_time = initial_time + resolution
name = "test"
horizon = 24
data_pwl = SortedDict(initial_time => test_costs[PiecewiseStepData],
other_time => test_costs[PiecewiseStepData])
sys = System(100.0)
reserve = ReserveDemandCurve{ReserveUp}(nothing)
add_component!(sys, reserve)
forecast_fd = IS.Deterministic(
"variable_cost",
Dict(k => get_function_data.(v) for (k, v) in pairs(data_pwl)),
resolution,
)
set_variable_cost!(sys, reserve, forecast_fd)
cost_forecast = get_variable_cost(reserve; start_time = initial_time)
@test isequal(first(TimeSeries.values(cost_forecast)), first(data_pwl[initial_time]))
end
@testset "Test ReserveDemandCurve with Time Varying PWL Cost" begin
initial_time = Dates.DateTime("2020-01-01")
resolution = Dates.Hour(1)
other_time = initial_time + resolution
# Create time varying PWL cost data using PiecewiseIncrementalCurve
data_pwl_incremental = SortedDict(
initial_time => test_costs[PiecewiseIncrementalCurve],
other_time => test_costs[PiecewiseIncrementalCurve],
)
# Create system and reserve product
sys = System(100.0)
reserve = ReserveDemandCurve{ReserveUp}(
nothing, # variable - will be set via set_variable_cost!
"TestReserveProduct",
true,
10.0, # time_frame
3600.0, # sustained_time
1.0, # max_participation_factor
0.0, # deployed_fraction
)
add_component!(sys, reserve)
# Attach time varying cost to the reserve product
forecast_fd = IS.Deterministic(
"variable_cost",
Dict(k => get_function_data.(v) for (k, v) in pairs(data_pwl_incremental)),
resolution,
)
set_variable_cost!(sys, reserve, forecast_fd)
# Retrieve and verify the time varying cost data
cost_forecast = get_variable_cost(reserve; start_time = initial_time)
retrieved_curve = first(TimeSeries.values(cost_forecast))
original_curve = first(data_pwl_incremental[initial_time])
# Compare function data (x and y coordinates)
@test get_function_data(retrieved_curve) == get_function_data(original_curve)
# Verify we can retrieve cost at the second time point
cost_forecast_second = get_variable_cost(reserve; start_time = other_time)
retrieved_curve_second = first(TimeSeries.values(cost_forecast_second))
original_curve_second = first(data_pwl_incremental[other_time])
# Compare function data
@test get_function_data(retrieved_curve_second) ==
get_function_data(original_curve_second)
# Verify the reserve has the time series attached
@test has_time_series(reserve)
@test length(get_time_series_keys(reserve)) == 1
end
@testset "Test fuel cost (scalar and time series)" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generators = collect(get_components(ThermalStandard, sys))
generator = get_component(ThermalStandard, sys, "322_CT_6")
op_cost = get_operation_cost(generator)
value_curve = get_value_curve(get_variable(op_cost))
set_variable!(op_cost, FuelCurve(value_curve, 0.0))
@test get_fuel_cost(generator) == 0.0
@test_throws ArgumentError get_fuel_cost(generator; len = 2)
set_fuel_cost!(sys, generator, 1.23)
@test get_fuel_cost(generator) == 1.23
initial_time = Dates.DateTime("2020-01-01")
resolution = Dates.Hour(1)
horizon = 24
data_float = SortedDict(initial_time => test_costs[Float64])
forecast_fd = IS.Deterministic("fuel_cost", data_float, resolution)
set_fuel_cost!(sys, generator, forecast_fd)
fuel_forecast = get_fuel_cost(generator; start_time = initial_time)
@test first(TimeSeries.values(fuel_forecast)) == first(data_float[initial_time])
fuel_forecast = get_fuel_cost(generator) # missing start_time filled in with initial time
@test first(TimeSeries.values(fuel_forecast)) == first(data_float[initial_time])
end
@testset "Test MarketBidCost no-load cost (single number and time series)" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generators = collect(get_components(ThermalStandard, sys))
generator = get_component(ThermalStandard, sys, "322_CT_6")
market_bid = MarketBidCost(nothing)
set_operation_cost!(generator, market_bid)
op_cost = get_operation_cost(generator)
@test get_no_load_cost(generator, op_cost) === nothing
set_no_load_cost!(sys, generator, 1.23)
@test get_no_load_cost(generator, op_cost) == 1.23
initial_time = Dates.DateTime("2020-01-01")
resolution = Dates.Hour(1)
horizon = 24
data_float = SortedDict(initial_time => test_costs[Float64])
forecast_fd = IS.Deterministic("no_load_cost", data_float, resolution)
set_no_load_cost!(sys, generator, forecast_fd)
@test first(TimeSeries.values(get_no_load_cost(generator, op_cost))) ==
first(data_float[initial_time])
end
@testset "Test MarketBidCost startup cost (single number, tuple, and time series)" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generators = collect(get_components(ThermalStandard, sys))
generator = get_component(ThermalStandard, sys, "322_CT_6")
market_bid = MarketBidCost(nothing)
set_operation_cost!(generator, market_bid)
op_cost = get_operation_cost(generator)
@test get_start_up(op_cost) ==
(hot = PSY.START_COST, warm = PSY.START_COST, cold = PSY.START_COST)
@test get_start_up(generator, op_cost) ==
(hot = PSY.START_COST, warm = PSY.START_COST, cold = PSY.START_COST)
set_start_up!(sys, generator, 3.14)
@test get_start_up(op_cost) == (hot = 3.14, warm = 0.0, cold = 0.0)
@test get_start_up(generator, op_cost) == (hot = 3.14, warm = 0.0, cold = 0.0)
set_start_up!(sys, generator, (hot = 1.23, warm = 2.34, cold = 3.45))
@test get_start_up(op_cost) == (hot = 1.23, warm = 2.34, cold = 3.45)
@test get_start_up(generator, op_cost) == (hot = 1.23, warm = 2.34, cold = 3.45)
initial_time = Dates.DateTime("2020-01-01")
resolution = Dates.Hour(1)
horizon = 24
data_sus = SortedDict(initial_time => test_costs[PSY.StartUpStages])
forecast_fd = IS.Deterministic(
"start_up",
Dict(k => Tuple.(v) for (k, v) in pairs(data_sus)),
resolution,
)
set_start_up!(sys, generator, forecast_fd)
@test first(TimeSeries.values(get_start_up(generator, op_cost))) ==
first(data_sus[initial_time])
end
@testset "Test MarketBidCost shutdown cost (single number and time series)" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generators = collect(get_components(ThermalStandard, sys))
generator = get_component(ThermalStandard, sys, "322_CT_6")
market_bid = MarketBidCost(nothing)
set_operation_cost!(generator, market_bid)
op_cost = get_operation_cost(generator)
@test get_shut_down(op_cost) == 0.0
@test get_shut_down(generator, op_cost) == 0.0
set_shut_down!(sys, generator, 3.14)
@test get_shut_down(op_cost) == 3.14
@test get_shut_down(generator, op_cost) == 3.14
initial_time = Dates.DateTime("2020-01-01")
resolution = Dates.Hour(1)
horizon = 24
data_float = SortedDict(initial_time => test_costs[Float64])
forecast_fd = IS.Deterministic("fuel_cost", data_float, resolution)
set_shut_down!(sys, generator, forecast_fd)
@test first(TimeSeries.values(get_shut_down(generator, op_cost))) ==
first(data_float[initial_time])
end
function build_iec_sys()
sys = PSB.build_system(PSITestSystems, "c_sys5_uc")
source = Source(;
name = "source",
available = true,
bus = get_component(ACBus, sys, "nodeC"),
active_power = 0.0,
reactive_power = 0.0,
active_power_limits = (min = -2.0, max = 2.0),
reactive_power_limits = (min = -2.0, max = 2.0),
R_th = 0.01,
X_th = 0.02,
internal_voltage = 1.0,
internal_angle = 0.0,
base_power = 100.0,
)
source2 = Source(;
name = "source2",
available = true,
bus = get_component(ACBus, sys, "nodeD"),
active_power = 0.0,
reactive_power = 0.0,
active_power_limits = (min = -2.0, max = 2.0),
reactive_power_limits = (min = -2.0, max = 2.0),
R_th = 0.01,
X_th = 0.02,
internal_voltage = 1.0,
internal_angle = 0.0,
base_power = 100.0,
)
import_curve = make_import_curve(;
power = [0.0, 100.0, 105.0, 120.0, 200.0],
price = [5.0, 10.0, 20.0, 40.0],
)
import_curve2 = make_import_curve(;
power = 200.0,
price = 25.0,
)
export_curve = make_export_curve(;
power = [0.0, 100.0, 105.0, 120.0, 200.0],
price = [40.0, 20.0, 10.0, 5.0],
)
export_curve2 = make_export_curve(;
power = 200.0,
price = 45.0,
)
ie_cost = ImportExportCost(;
import_offer_curves = import_curve,
export_offer_curves = export_curve,
)
ie_cost2 = ImportExportCost(;
import_offer_curves = import_curve2,
export_offer_curves = export_curve2,
)
set_operation_cost!(source, ie_cost)
set_operation_cost!(source2, ie_cost2)
add_component!(sys, source)
add_component!(sys, source2)
return sys,
source,
source2,
import_curve,
import_curve2,
export_curve,
export_curve2,
ie_cost,
ie_cost2
end
@testset "ImportExportCost basic methods" begin
sys,
source,
source2,
import_curve,
import_curve2,
export_curve,
export_curve2,
ie_cost,
ie_cost2 =
build_iec_sys()
@test PowerSystems.is_import_export_curve(import_curve)
@test PowerSystems.is_import_export_curve(import_curve2)
@test PowerSystems.is_import_export_curve(export_curve)
@test PowerSystems.is_import_export_curve(export_curve2)
@test get_operation_cost(source) isa ImportExportCost
@test get_operation_cost(source2) isa ImportExportCost
end
@testset "ImportExportCost cost_function_timeseries scalar" begin
sys,
source,
source2,
import_curve,
import_curve2,
export_curve,
export_curve2,
ie_cost,
ie_cost2 =
build_iec_sys()
@test get_import_offer_curves(source, ie_cost) == import_curve
@test get_export_offer_curves(source, ie_cost) == export_curve
@test get_import_variable_cost(source, ie_cost) == import_curve
@test get_export_variable_cost(source, ie_cost) == export_curve
end
@testset "ImportExportCost cost_function_timeseries time series" begin
initial_time = Dates.DateTime("2024-01-01")
resolution = Dates.Hour(1)
other_time = initial_time + resolution
name = "test"
horizon = 24
sys,
source,
source2,
import_curve,
import_curve2,
export_curve,
export_curve2,
ie_cost,
ie_cost2 =
build_iec_sys()
import_fd_array = repeat(
[
make_import_curve(;
power = [0.0, 100.0, 105.0, 120.0, 200.0],
price = [5.0, 10.0, 20.0, 40.0])], 24)
export_fd_array = repeat(
[
make_export_curve(;
power = [0.0, 100.0, 105.0, 120.0, 200.0],
price = [40.0, 20.0, 10.0, 5.0])], 24)
import_sd = SortedDict(initial_time => import_fd_array,
other_time => import_fd_array)
export_sd = SortedDict(initial_time => export_fd_array,
other_time => export_fd_array)
import_curve = IS.Deterministic(
"import_variable_cost",
Dict(k => get_function_data.(v) for (k, v) in pairs(import_sd)),
resolution,
)
export_curve = IS.Deterministic(
"export_variable_cost",
Dict(k => get_function_data.(v) for (k, v) in pairs(export_sd)),
resolution,
)
set_import_variable_cost!(sys, source, import_curve, UnitSystem.NATURAL_UNITS)
set_export_variable_cost!(sys, source, export_curve, UnitSystem.NATURAL_UNITS)
iocs = get_import_offer_curves(source, ie_cost)
@test isequal(
first(TimeSeries.values(iocs)),
get_function_data(first(import_sd[initial_time])),
)
cost_forecast_i = get_import_variable_cost(source, ie_cost; start_time = initial_time)
@test isequal(first(TimeSeries.values(cost_forecast_i)), first(import_sd[initial_time]))
eocs = get_export_offer_curves(source, ie_cost)
@test isequal(
first(TimeSeries.values(eocs)),
get_function_data(first(export_sd[initial_time])),
)
cost_forecast_e = get_export_variable_cost(source, ie_cost; start_time = initial_time)
@test isequal(first(TimeSeries.values(cost_forecast_e)), first(export_sd[initial_time]))
end
@testset "Test HydroReservoirCost getters and setters" begin
cost = HydroReservoirCost(;
level_shortage_cost = 1.0,
level_surplus_cost = 2.0,
spillage_cost = 3.0,
)
@test get_level_shortage_cost(cost) == 1.0
@test get_level_surplus_cost(cost) == 2.0
@test get_spillage_cost(cost) == 3.0
set_level_shortage_cost!(cost, 10.0)
@test get_level_shortage_cost(cost) == 10.0
@test get_level_surplus_cost(cost) == 2.0
@test get_spillage_cost(cost) == 3.0
set_level_surplus_cost!(cost, 20.0)
@test get_level_surplus_cost(cost) == 20.0
@test get_level_shortage_cost(cost) == 10.0
@test get_spillage_cost(cost) == 3.0
set_spillage_cost!(cost, 30.0)
@test get_spillage_cost(cost) == 30.0
@test get_level_shortage_cost(cost) == 10.0
@test get_level_surplus_cost(cost) == 20.0
end
================================================
FILE: test/test_devices.jl
================================================
@testset "Test special accessors" begin
cdmsys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
th = first(get_components(ThermalStandard, cdmsys))
re = first(get_components(RenewableDispatch, cdmsys))
@test get_max_active_power(th) == get_active_power_limits(th).max
@test get_max_active_power(re) <= get_rating(re)
@test isa(get_max_reactive_power(re), Float64)
@test_throws MethodError get_max_active_power(TestDevice("foo"))
@test_throws ArgumentError get_max_active_power(TestInjector("foo"))
@test_throws ArgumentError get_max_active_power(TestRenDevice("foo"))
end
@testset "Test Remove Area with Interchanges" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
area1 = get_component(Area, sys, "1")
area2 = get_component(Area, sys, "2")
area3 = get_component(Area, sys, "3")
area_interchange12 = AreaInterchange(;
name = "interchange_a1_a2",
available = true,
active_power_flow = 0.0,
from_area = area1,
to_area = area2,
flow_limits = (from_to = 100.0, to_from = 100.0),
)
area_interchange13 = AreaInterchange(;
name = "interchange_a1_a3",
available = true,
active_power_flow = 0.0,
from_area = area1,
to_area = area3,
flow_limits = (from_to = 100.0, to_from = 100.0),
)
add_component!(sys, area_interchange12)
add_component!(sys, area_interchange13)
@test_throws ArgumentError remove_component!(sys, area1)
remove_component!(sys, area_interchange12)
remove_component!(sys, area_interchange13)
remove_component!(sys, area1)
@test get_component(Area, sys, "1") === nothing
end
@testset "Test Shiftable Power Loads and Interruptible PowerLoads" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
buses = collect(get_components(ACBus, sys))
add_component!(
sys,
InterruptiblePowerLoad(
"IloadBus",
true,
buses[1],
0.10,
0.0,
0.10,
0.0,
100.0,
LoadCost(CostCurve(LinearCurve(150.0)), 2400.0),
),
)
add_component!(
sys,
ShiftablePowerLoad(
"ShiftableLoadBus4",
true,
buses[2],
0.10,
(min = 0.03, max = 0.10),
0.0,
0.10,
0.0,
100.0,
24,
LoadCost(CostCurve(LinearCurve(150.0)), 2400.0),
),
)
dir_path = mktempdir()
to_json(sys, joinpath(dir_path, "test_RTS_GMLC_sys.json"))
sys2 = System(joinpath(dir_path, "test_RTS_GMLC_sys.json"))
@test get_active_power(get_component(ShiftablePowerLoad, sys2, "ShiftableLoadBus4")) ==
0.10
@test get_active_power(get_component(InterruptiblePowerLoad, sys2, "IloadBus")) == 0.10
@test get_active_power_limits(
get_component(ShiftablePowerLoad, sys2, "ShiftableLoadBus4"),
).min == 0.03
@test get_active_power_limits(
get_component(ShiftablePowerLoad, sys2, "ShiftableLoadBus4"),
).max == 0.10
end
================================================
FILE: test/test_dynamic_generator.jl
================================================
nodes_OMIB = [
ACBus(
1, #number
"Bus 1", #Name
true, #available
"REF", #BusType (REF, PV, PQ)
0, #Angle in radians
1.06, #Voltage in pu
(min = 0.94, max = 1.06), #Voltage limits in pu
69,
nothing,
nothing,
), #Base voltage in kV
ACBus(2, "Bus 2", true, "PV", 0, 1.045, (min = 0.94, max = 1.06), 69, nothing, nothing),
]
static_gen = ThermalStandard(;
name = "TestGen",
available = true,
status = true,
bus = nodes_OMIB[2],
active_power = 0.40,
reactive_power = 0.010,
rating = 0.5,
prime_mover_type = PrimeMovers.ST,
fuel = ThermalFuels.COAL,
active_power_limits = (min = 0.0, max = 0.40),
reactive_power_limits = (min = -0.30, max = 0.30),
time_limits = nothing,
ramp_limits = nothing,
operation_cost = ThermalGenerationCost(
CostCurve(LinearCurve(1400.0)),
0.0,
4.0,
2.0,
),
base_power = 1.0,
)
branch_OMIB = [
Line(
"Line1", #name
true, #available
0.0, #active power flow initial condition (from-to)
0.0, #reactive power flow initial condition (from-to)
Arc(; from = nodes_OMIB[1], to = nodes_OMIB[2]), #Connection between buses
0.01, #resistance in pu
0.05, #reactance in pu
(from = 0.0, to = 0.0), #susceptance in pu
1.14, #rate in MW
1.04,
),
] #angle limits (-min and max)
@testset "Dynamic Machines" begin
Basic = BaseMachine(; R = 0.0, Xd_p = 0.2995, eq_p = 1.05)
@test Basic isa PowerSystems.DynamicComponent
GENROU = RoundRotorQuadratic(;
R = 0.0,
Td0_p = 7.4,
Td0_pp = 0.03,
Tq0_p = 0.06,
Tq0_pp = 0.033,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xq_p = 0.646,
Xd_pp = 0.23,
Xl = 0.1,
Se = (0.1, 0.5),
)
@test GENROU isa PowerSystems.DynamicComponent
GENROE = RoundRotorExponential(;
R = 0.0,
Td0_p = 7.4,
Td0_pp = 0.03,
Tq0_p = 0.06,
Tq0_pp = 0.033,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xq_p = 0.646,
Xd_pp = 0.23,
Xl = 0.1,
Se = (0.1, 0.5),
)
@test GENROE isa PowerSystems.DynamicComponent
GENSAL = SalientPoleQuadratic(;
R = 0.0,
Td0_p = 7.4,
Td0_pp = 0.03,
Tq0_pp = 0.033,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xd_pp = 0.23,
Xl = 0.1,
Se = (0.1, 0.5),
)
@test GENSAL isa PowerSystems.DynamicComponent
GENSAE = SalientPoleExponential(;
R = 0.0,
Td0_p = 7.4,
Td0_pp = 0.03,
Tq0_pp = 0.033,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xd_pp = 0.23,
Xl = 0.1,
Se = (0.1, 0.5),
)
@test GENSAE isa PowerSystems.DynamicComponent
oneDoneQ = OneDOneQMachine(;
R = 0.0,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xq_p = 0.04,
Td0_p = 7.4,
Tq0_p = 0.033,
)
@test oneDoneQ isa PowerSystems.DynamicComponent
SauerPai = SauerPaiMachine(;
R = 0.0,
Xd = 0.920,
Xq = 0.130,
Xd_p = 0.300,
Xq_p = 0.228,
Xd_pp = 0.220,
Xq_pp = 0.290,
Xl = 0.1,
Td0_p = 5.2,
Tq0_p = 0.85,
Td0_pp = 0.029,
Tq0_pp = 0.034,
)
@test SauerPai isa PowerSystems.DynamicComponent
AndersonFouad = AndersonFouadMachine(;
R = 0.0,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xq_p = 0.646,
Xd_pp = 0.23,
Xq_pp = 0.4,
Td0_p = 7.4,
Tq0_p = 0.01, #Data not available in Milano: Used 0.01
Td0_pp = 0.03,
Tq0_pp = 0.033,
)
@test AndersonFouad isa PowerSystems.DynamicComponent
KundurMachine = SimpleFullMachine(;
R = 0.003, #Example 3.1 and 4.1 of Kundur
R_f = 0.0006,
R_1d = 0.0284, #RD in Machowski
R_1q = 0.0062, #RQ on Machowski
L_d = 1.81,
L_q = 1.76,
L_ad = 1.66, #k*M_f or k*M_D in Machowski
L_aq = 1.61, #k*M_Q in Machowski
L_f1d = 1.66, #L_fD in Machowski. Assumed to be equal to L_ad
L_ff = 1.825,
L_1d = 0.1713, #L_D in Machowski
L_1q = 0.7525, #L_Q in Machowski
)
@test KundurMachine isa PowerSystems.DynamicComponent
KundurFullMachine = FullMachine(;
R = 0.003, #Example 3.1 and 4.1 of Kundur
R_f = 0.0006,
R_1d = 0.0284, #RD in Machowski
R_1q = 0.0062, #RQ on Machowski
L_d = 1.81,
L_q = 1.76,
L_ad = 1.66, #k*M_f or k*M_D in Machowski
L_aq = 1.61, #k*M_Q in Machowski
L_f1d = 1.66, #L_fD in Machowski. Assumed to be equal to L_ad
L_ff = 1.825,
L_1d = 0.1713, #L_D in Machowski
L_1q = 0.7525, #L_Q in Machowski
)
@test KundurFullMachine isa PowerSystems.DynamicComponent
Mach2_benchmark = OneDOneQMachine(;
R = 0.0,
Xd = 1.3125,
Xq = 1.2578,
Xd_p = 0.1813,
Xq_p = 0.25,
Td0_p = 5.89,
Tq0_p = 0.6,
)
@test Mach2_benchmark isa PowerSystems.DynamicComponent
end
################ Shaft Data #####################
@testset "Dynamic Shaft" begin
BaseShaft = SingleMass(; H = 5.148, D = 2.0)
@test BaseShaft isa PowerSystems.DynamicComponent
FiveShaft = FiveMassShaft(;
H = 5.148,
H_hp = 0.3348,
H_ip = 0.7306,
H_lp = 0.8154,
H_ex = 0.0452,
D = 2.0,
D_hp = 0.5180,
D_ip = 0.2240,
D_lp = 0.2240,
D_ex = 0.1450,
D_12 = 0.0518,
D_23 = 0.0224,
D_34 = 0.0224,
D_45 = 0.0145,
K_hp = 33.07,
K_ip = 28.59,
K_lp = 44.68,
K_ex = 21.984,
)
@test FiveShaft isa PowerSystems.DynamicComponent
end
################# PSS Data #####################
@testset "Dynamic PSS" begin
no_pss = PSSFixed(; V_pss = 0.0)
@test no_pss isa PowerSystems.DynamicComponent
end
################ TG Data #####################
@testset "Dynamic Turbine Governor Constructors" begin
fixed_tg = TGFixed(; efficiency = 1.0)
@test fixed_tg isa PowerSystems.DynamicComponent
typeI_tg = TGTypeI(;
R = 0.02,
Ts = 0.1,
Tc = 0.45,
T3 = 0.0,
T4 = 0.0,
T5 = 50.0,
valve_position_limits = (min = 0.3, max = 1.2),
)
@test typeI_tg isa PowerSystems.DynamicComponent
@test get_frequency_droop(typeI_tg) == 0.02
typeII_tg = TGTypeII(; R = 0.05, T1 = 0.3, T2 = 0.1, τ_limits = (min = 0.1, max = 1.0))
@test typeII_tg isa PowerSystems.DynamicComponent
@test get_frequency_droop(typeII_tg) == 0.05
gast_tg = GasTG(;
R = 0.05,
T1 = 0.40,
T2 = 0.10,
T3 = 2.0,
AT = 1.0,
Kt = 2.0,
V_lim = (0.417, 0.8),
D_turb = 0.0,
)
@test gast_tg isa PowerSystems.DynamicComponent
@test get_frequency_droop(gast_tg) == 0.05
degov_tg = PSY.DEGOV(;
T1 = 0.0,
T2 = 0.0,
T3 = 0.0,
K = 18.0,
T4 = 12.0,
T5 = 5.0,
T6 = 0.2,
Td = 0.0,
P_ref = 0.0,
)
@test degov_tg isa PowerSystems.DynamicComponent
@test get_frequency_droop(degov_tg) == (1/18.0)
end
################ AVR Data #####################
@testset "Dynamic AVR Constructors" begin
proportional_avr = AVRSimple(; Kv = 5000.0)
@test proportional_avr isa PowerSystems.DynamicComponent
fixed_avr = AVRFixed(; Vf = 1.05, V_ref = 1.0)
@test fixed_avr isa PowerSystems.DynamicComponent
typeI_avr = AVRTypeI(;
Ka = 200.0,
Ke = 1.0,
Kf = 0.0012,
Ta = 0.02,
Te = 0.19,
Tf = 1.0,
Tr = 0.001,
Va_lim = (0.0, 0.0),
Ae = 0.0006,
Be = 0.9,
)
@test typeI_avr isa PowerSystems.DynamicComponent
ac1a_avr = ESAC1A(;
Tr = 0.0,
Tb = 0.0,
Tc = 0.0,
Ka = 200,
Ta = 0.5,
Va_lim = (-7.0, 7.0),
Te = 1.333,
Kf = 0.02,
Tf = 0.8,
Kc = 0.0,
Kd = 0.0,
Ke = 1.0,
E_sat = (0.0, 0.0),
Se = (0.0, 0.0),
Vr_lim = (-99.0, 99.0),
)
@test ac1a_avr isa PowerSystems.DynamicComponent
mod_ac1a_avr = EXAC1(;
Tr = 0.0,
Tb = 0.0,
Tc = 0.0,
Ka = 400,
Ta = 0.5,
Vr_lim = (-5.2477, 5.2477),
Te = 1.1,
Kf = 0.035,
Tf = 1.0,
Kc = 0.2469,
Kd = 0.5,
Ke = 1.0,
E_sat = (2.707, 3.6102),
Se = (0.0366, 0.1831),
)
@test mod_ac1a_avr isa PowerSystems.DynamicComponent
st1a_avr = ESST1A(;
UEL_flags = 1,
PSS_flags = 1,
Tr = 0.0,
Vi_lim = (-99.0, 99.0),
Tc = 2.5,
Tb = 13.25,
Tc1 = 0.0,
Tb1 = 0.0,
Ka = 200.0,
Ta = 0.1,
Va_lim = (-9.5, 9.5),
Vr_lim = (-9.5, 9.5),
Kc = 0.0,
Kf = 0.0,
Tf = 1.0,
K_lr = 0.0,
I_lr = 999.0,
)
@test st1a_avr isa PowerSystems.DynamicComponent
gen2_avr_benchmark = AVRTypeII(;
K0 = 20.0,
T1 = 0.2,
T2 = 0.063,
T3 = 0.35,
T4 = 0.01,
Te = 0.314,
Tr = 0.001,
Va_lim = (-5.0, 5.0),
Ae = 0.0039,
Be = 1.555,
)
@test gen2_avr_benchmark isa PowerSystems.DynamicComponent
end
######################### Generators ########################
@testset "Dynamic Generators" begin
#Components for the test
Basic = BaseMachine(; R = 0.0, Xd_p = 0.2995, eq_p = 1.05)
BaseShaft = SingleMass(; H = 5.148, D = 2.0)
fixed_avr = AVRFixed(; Vf = 1.05, V_ref = 1.0)
proportional_avr = AVRSimple(; Kv = 5000.0)
sexs_avr = SEXS(; Ta_Tb = 0.1, Tb = 10.0, K = 100.0, Te = 0.1, V_lim = (-4.0, 5.0))
fixed_tg = TGFixed(; efficiency = 1.0)
typeI_tg = TGTypeI(;
R = 0.02,
Ts = 0.1,
Tc = 0.45,
T3 = 0.0,
T4 = 0.0,
T5 = 50.0,
valve_position_limits = (min = 0.3, max = 1.2),
)
no_pss = PSSFixed(; V_pss = 0.0)
oneDoneQ = OneDOneQMachine(;
R = 0.0,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xq_p = 0.04,
Td0_p = 7.4,
Tq0_p = 0.033,
)
Gen1AVR = DynamicGenerator(;
name = get_name(static_gen),
ω_ref = 1.0,
machine = Basic,
shaft = BaseShaft,
avr = proportional_avr,
prime_mover = fixed_tg,
pss = no_pss,
)
@test Gen1AVR isa PowerSystems.Component
Gen1AVRnoAVR = DynamicGenerator(;
name = get_name(static_gen),
ω_ref = 1.0,
machine = Basic,
shaft = BaseShaft,
avr = fixed_avr,
prime_mover = fixed_tg,
pss = no_pss,
)
@test Gen1AVRnoAVR isa PowerSystems.Component
Gen2AVRnoAVR = DynamicGenerator(;
name = get_name(static_gen),
ω_ref = 1.0,
machine = oneDoneQ,
shaft = BaseShaft,
avr = fixed_avr,
prime_mover = fixed_tg,
pss = no_pss,
)
@test Gen2AVRnoAVR isa PowerSystems.Component
Gen2AVR = DynamicGenerator(;
name = get_name(static_gen),
ω_ref = 1.0,
machine = oneDoneQ,
shaft = BaseShaft,
avr = proportional_avr,
prime_mover = fixed_tg,
pss = no_pss,
)
@test Gen2AVR isa PowerSystems.Component
Gen3AVR = DynamicGenerator(;
name = get_name(static_gen),
ω_ref = 1.0,
machine = oneDoneQ,
shaft = BaseShaft,
avr = sexs_avr,
prime_mover = fixed_tg,
pss = no_pss,
)
@test Gen3AVR isa PowerSystems.Component
Gen4AVR = DynamicGenerator(;
name = get_name(static_gen),
ω_ref = 1.0,
machine = oneDoneQ,
shaft = BaseShaft,
avr = sexs_avr,
prime_mover = typeI_tg,
pss = no_pss,
)
@test get_frequency_droop(Gen4AVR) == 0.02
sys = System(100.0)
for bus in nodes_OMIB
add_component!(sys, bus)
end
for lines in branch_OMIB
add_component!(sys, lines)
end
# Names must be the same.
Gen1AVR.name = "bad_name"
@test_throws ArgumentError add_component!(sys, Gen1AVR, static_gen)
Gen1AVR.name = get_name(static_gen)
# static_injector must be passed.
@test_throws ArgumentError add_component!(sys, Gen1AVR)
# static_injector must be attached to the system.
@test_throws ArgumentError add_component!(sys, Gen1AVR, static_gen)
add_component!(sys, static_gen)
@test isnothing(get_dynamic_injector(static_gen))
add_component!(sys, Gen1AVR, static_gen)
dynamics = collect(get_components(DynamicGenerator, sys))
@test length(dynamics) == 1
@test dynamics[1] == Gen1AVR
@test get_dynamic_injector(static_gen) == Gen1AVR
@test get_base_power(static_gen) == get_base_power(Gen1AVR)
@test PSY.compare_values(static_gen, deepcopy(static_gen))
remove_component!(sys, Gen1AVR)
@test isnothing(get_dynamic_injector(static_gen))
add_component!(sys, Gen2AVR, static_gen)
@test get_dynamic_injector(static_gen) === Gen2AVR
@test get_base_power(static_gen) == get_base_power(Gen2AVR)
set_base_power!(static_gen, 1234.5)
@test get_base_power(static_gen) == 1234.5
@test PSY.get_system_base_power(static_gen) == get_base_power(sys)
# Rule: Can't set the pair injector if the current injector is already set.
@test_throws ArgumentError set_dynamic_injector!(static_gen, Gen1AVR)
# Rule: Can't remove a static injector if it is attached to a dynamic injector.
@test_throws ArgumentError remove_component!(sys, static_gen)
#Rule: Can't add saturation if Se(1.2) <= Se(1.0)
@test_throws IS.ConflictingInputsError PSY.get_quadratic_saturation((0.5, 0.1))
@test_throws IS.ConflictingInputsError PSY.get_quadratic_saturation((0.1, 0.1))
@test_throws IS.ConflictingInputsError PSY.get_avr_saturation((0.2, 0.1), (0.1, 0.1))
@test length(collect(get_dynamic_components(Gen2AVR))) == 5
remove_component!(sys, Gen2AVR)
@test isnothing(get_dynamic_injector(static_gen))
add_component!(sys, Gen3AVR, static_gen)
retrieved_gen = collect(get_components(DynamicGenerator, sys))
orig_dir = pwd()
temp_dir = mktempdir()
cd(temp_dir)
to_json(sys, "sys.json")
sys2 = System("sys.json")
serialized_gen = collect(get_components(DynamicGenerator, sys2))
@test get_name(retrieved_gen[1]) == get_name(serialized_gen[1])
cd(orig_dir)
end
@testset "Replace Dynamic Injector" begin
nodes = [
ACBus(
1,
"Bus 1",
true,
"REF",
0,
1.06,
(min = 0.94, max = 1.06),
69,
nothing,
nothing,
),
ACBus(
2,
"Bus 2",
true,
"PV",
0,
1.045,
(min = 0.94, max = 1.06),
69,
nothing,
nothing,
),
]
static = ThermalStandard(;
name = "ReplaceTestGen",
available = true,
status = true,
bus = nodes[2],
active_power = 0.40,
reactive_power = 0.010,
rating = 0.5,
prime_mover_type = PrimeMovers.ST,
fuel = ThermalFuels.COAL,
active_power_limits = (min = 0.0, max = 0.40),
reactive_power_limits = (min = -0.30, max = 0.30),
time_limits = nothing,
ramp_limits = nothing,
operation_cost = ThermalGenerationCost(
CostCurve(LinearCurve(1400.0)),
0.0,
4.0,
2.0,
),
base_power = 1.0,
)
branches = [
Line(
"ReplaceLine1",
true,
0.0,
0.0,
Arc(; from = nodes[1], to = nodes[2]),
0.01,
0.05,
(from = 0.0, to = 0.0),
1.14,
(min = -0.7, max = 0.7),
),
]
Basic = BaseMachine(; R = 0.0, Xd_p = 0.2995, eq_p = 1.05)
BaseShaft = SingleMass(; H = 5.148, D = 2.0)
fixed_avr = AVRFixed(; Vf = 1.05, V_ref = 1.0)
proportional_avr = AVRSimple(; Kv = 5000.0)
fixed_tg = TGFixed(; efficiency = 1.0)
no_pss = PSSFixed(; V_pss = 0.0)
oneDoneQ = OneDOneQMachine(;
R = 0.0,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xq_p = 0.04,
Td0_p = 7.4,
Tq0_p = 0.033,
)
Gen1 = DynamicGenerator(;
name = get_name(static),
ω_ref = 1.0,
machine = Basic,
shaft = BaseShaft,
avr = proportional_avr,
prime_mover = fixed_tg,
pss = no_pss,
)
Gen2 = DynamicGenerator(;
name = get_name(static),
ω_ref = 1.0,
machine = oneDoneQ,
shaft = BaseShaft,
avr = fixed_avr,
prime_mover = fixed_tg,
pss = no_pss,
)
sys = System(100.0)
for bus in nodes
add_component!(sys, bus)
end
for line in branches
add_component!(sys, line)
end
add_component!(sys, static)
add_component!(sys, Gen1, static)
@test get_dynamic_injector(static) === Gen1
# Replace the dynamic injector
replace_dynamic_injector!(sys, static, Gen2)
@test get_dynamic_injector(static) === Gen2
@test get_base_power(static) == get_base_power(Gen2)
# Old dynamic injector should be removed from the system
@test length(collect(get_components(DynamicGenerator, sys))) == 1
# Error: static injector has no dynamic injector
remove_component!(sys, Gen2)
@test isnothing(get_dynamic_injector(static))
@test_throws ArgumentError replace_dynamic_injector!(sys, static, Gen1)
# Error: name mismatch
add_component!(sys, Gen1, static)
bad_name_gen = DynamicGenerator(;
name = "wrong_name",
ω_ref = 1.0,
machine = BaseMachine(; R = 0.0, Xd_p = 0.2995, eq_p = 1.05),
shaft = SingleMass(; H = 5.148, D = 2.0),
avr = AVRSimple(; Kv = 5000.0),
prime_mover = TGFixed(; efficiency = 1.0),
pss = PSSFixed(; V_pss = 0.0),
)
@test_throws ArgumentError replace_dynamic_injector!(sys, static, bad_name_gen)
end
@testset "Generic DER (DERD)" begin
#valid (non-default) Qref_Flag
derd = GenericDER(;
name = "init",
Qref_Flag = 2,
PQ_Flag = 0,
Gen_Flag = 0,
PerOp_Flag = 0,
Recon_Flag = 0,
Trv = 0,
VV_pnts = (V1 = 0.0, V2 = 0.0, V3 = 0.0, V4 = 0.0),
Q_lim = (min = 0.0, max = 0.0),
Tp = 0,
e_lim = (min = 0.0, max = 0.0),
Kpq = 0,
Kiq = 0,
Iqr_lim = (min = 0.0, max = 0.0),
I_max = 0,
Tg = 0,
kWh_Cap = 0,
SOC_ini = 0,
SOC_lim = (min = 0.0, max = 0.0),
Trf = 0,
fdbd_pnts = (fdbd1 = 0.0, fdbd2 = 0.0),
D_dn = 0,
D_up = 0,
fe_lim = (min = 0.0, max = 0.0),
Kpp = 0,
Kip = 0,
P_lim = (min = 0.0, max = 0.0),
dP_lim = (min = 0.0, max = 0.0),
T_pord = 0,
rrpwr = 0,
VRT_pnts = (vrt1 = 0.0, vrt2 = 0.0, vrt3 = 0.0, vrt4 = 0.0, vrt5 = 0.0),
TVRT_pnts = (tvrt1 = 0.0, tvrt2 = 0.0, tvrt3 = 0.0),
tV_delay = 0,
VES_lim = (min = 0.0, max = 0.0),
FRT_pnts = (frt1 = 0.0, frt2 = 0.0, frt3 = 0.0, frt4 = 0.0),
TFRT_pnts = (tfrt1 = 0.0, tfrt2 = 0.0),
tF_delay = 0,
FES_lim = (min = 0.0, max = 0.0),
Pfa_ref = 0,
Q_ref = 0,
P_ref = 0,
base_power = 0,
ext = Dict{String, Any}(),
)
@test derd isa PowerSystems.Component
#invalid Qref_Flag
@test_throws ErrorException GenericDER(
name = "init",
Qref_Flag = 4,
PQ_Flag = 0,
Gen_Flag = 0,
PerOp_Flag = 0,
Recon_Flag = 0,
Trv = 0,
VV_pnts = (V1 = 0.0, V2 = 0.0, V3 = 0.0, V4 = 0.0),
Q_lim = (min = 0.0, max = 0.0),
Tp = 0,
e_lim = (min = 0.0, max = 0.0),
Kpq = 0,
Kiq = 0,
Iqr_lim = (min = 0.0, max = 0.0),
I_max = 0,
Tg = 0,
kWh_Cap = 0,
SOC_ini = 0,
SOC_lim = (min = 0.0, max = 0.0),
Trf = 0,
fdbd_pnts = (fdbd1 = 0.0, fdbd2 = 0.0),
D_dn = 0,
D_up = 0,
fe_lim = (min = 0.0, max = 0.0),
Kpp = 0,
Kip = 0,
P_lim = (min = 0.0, max = 0.0),
dP_lim = (min = 0.0, max = 0.0),
T_pord = 0,
rrpwr = 0,
VRT_pnts = (vrt1 = 0.0, vrt2 = 0.0, vrt3 = 0.0, vrt4 = 0.0, vrt5 = 0.0),
TVRT_pnts = (tvrt1 = 0.0, tvrt2 = 0.0, tvrt3 = 0.0),
tV_delay = 0,
VES_lim = (min = 0.0, max = 0.0),
FRT_pnts = (frt1 = 0.0, frt2 = 0.0, frt3 = 0.0, frt4 = 0.0),
TFRT_pnts = (tfrt1 = 0.0, tfrt2 = 0.0),
tF_delay = 0,
FES_lim = (min = 0.0, max = 0.0),
Pfa_ref = 0,
Q_ref = 0,
P_ref = 0,
base_power = 0,
ext = Dict{String, Any}(),
)
sys = System(100.0)
bus = ACBus(nothing)
add_component!(sys, bus)
static_injector = ThermalStandard(nothing)
static_injector.bus = bus
add_component!(sys, static_injector)
add_component!(sys, derd, static_injector)
DERDs = collect(get_components(GenericDER, sys))
@test length(DERDs) == 1
end
@testset "Aggregate Distributed Generation" begin
#valid (non-default) Freq_Flag
dera = AggregateDistributedGenerationA(;
name = "init",
Pf_Flag = 0,
Freq_Flag = 1,
PQ_Flag = 0,
Gen_Flag = 0,
Vtrip_Flag = 0,
Ftrip_Flag = 0,
T_rv = 0,
Trf = 0,
dbd_pnts = (0.0, 0.0),
K_qv = 0,
Tp = 0,
T_iq = 0,
D_dn = 0,
D_up = 0,
fdbd_pnts = (0.0, 0.0),
fe_lim = (min = 0.0, max = 0.0),
P_lim = (min = 0.0, max = 0.0),
dP_lim = (min = 0.0, max = 0.0),
Tpord = 0,
Kpg = 0,
Kig = 0,
I_max = 0,
vl_pnts = [(0.0, 0.0), (0.0, 0.0)],
vh_pnts = [(0.0, 0.0), (0.0, 0.0)],
Vrfrac = 0,
fl = 0,
fh = 0,
tfl = 0,
tfh = 0,
Tg = 0,
rrpwr = 0,
Tv = 0,
Vpr = 0,
Iq_lim = (min = 0.0, max = 0.0),
V_ref = 0,
Pfa_ref = 0,
Q_ref = 0,
P_ref = 0,
base_power = 0,
ext = Dict{String, Any}(),
)
@test dera isa PowerSystems.Component
#invalid Freq_Flag
@test_throws ErrorException AggregateDistributedGenerationA(
name = "init",
Pf_Flag = 0,
Freq_Flag = 2,
PQ_Flag = 0,
Gen_Flag = 0,
Vtrip_Flag = 0,
Ftrip_Flag = 0,
T_rv = 0,
Trf = 0,
dbd_pnts = (0.0, 0.0),
K_qv = 0,
Tp = 0,
T_iq = 0,
D_dn = 0,
D_up = 0,
fdbd_pnts = (0.0, 0.0),
fe_lim = (min = 0.0, max = 0.0),
P_lim = (min = 0.0, max = 0.0),
dP_lim = (min = 0.0, max = 0.0),
Tpord = 0,
Kpg = 0,
Kig = 0,
I_max = 0,
vl_pnts = [(0.0, 0.0), (0.0, 0.0)],
vh_pnts = [(0.0, 0.0), (0.0, 0.0)],
Vrfrac = 0,
fl = 0,
fh = 0,
tfl = 0,
tfh = 0,
Tg = 0,
rrpwr = 0,
Tv = 0,
Vpr = 0,
Iq_lim = (min = 0.0, max = 0.0),
V_ref = 0,
Pfa_ref = 0,
Q_ref = 0,
P_ref = 0,
base_power = 0,
ext = Dict{String, Any}(),
)
sys = System(100.0)
bus = ACBus(nothing)
add_component!(sys, bus)
static_injector = ThermalStandard(nothing)
static_injector.bus = bus
add_component!(sys, static_injector)
add_component!(sys, dera, static_injector)
DERAs = collect(get_components(AggregateDistributedGenerationA, sys))
@test length(DERAs) == 1
end
@testset "Forward functions" begin
GENROU = RoundRotorQuadratic(;
R = 0.0,
Td0_p = 7.4,
Td0_pp = 0.03,
Tq0_p = 0.06,
Tq0_pp = 0.033,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xq_p = 0.646,
Xd_pp = 0.23,
Xl = 0.1,
Se = (0.1, 0.5),
)
test_accessors(GENROU)
GENROE = RoundRotorExponential(;
R = 0.0,
Td0_p = 7.4,
Td0_pp = 0.03,
Tq0_p = 0.06,
Tq0_pp = 0.033,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xq_p = 0.646,
Xd_pp = 0.23,
Xl = 0.1,
Se = (0.1, 0.5),
)
test_accessors(GENROE)
GENSAL = SalientPoleQuadratic(;
R = 0.0,
Td0_p = 7.4,
Td0_pp = 0.03,
Tq0_pp = 0.033,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xd_pp = 0.23,
Xl = 0.1,
Se = (0.1, 0.5),
)
test_accessors(GENSAL)
GENSAE = SalientPoleExponential(;
R = 0.0,
Td0_p = 7.4,
Td0_pp = 0.03,
Tq0_pp = 0.033,
Xd = 0.8979,
Xq = 0.646,
Xd_p = 0.2995,
Xd_pp = 0.23,
Xl = 0.1,
Se = (0.1, 0.5),
)
test_accessors(GENSAE)
#Test GENROU
@test get_R(GENROU) == 0.0
@test get_Td0_p(GENROU) == 7.4
@test get_Td0_pp(GENROU) == 0.03
@test get_Tq0_p(GENROU) == 0.06
@test get_Tq0_pp(GENROU) == 0.033
@test get_Xd(GENROU) == 0.8979
@test get_Xq(GENROU) == 0.646
@test get_Xd_p(GENROU) == 0.2995
@test get_Xq_p(GENROU) == 0.646
@test get_Xd_pp(GENROU) == 0.23
@test get_Xl(GENROU) == 0.1
@test get_Se(GENROU) == (0.1, 0.5)
@test get_states(GENROU) == [:eq_p, :ed_p, :ψ_kd, :ψ_kq]
@test get_n_states(GENROU) == 4
@test get_saturation_coeffs(GENROU)[1] == 0.8620204102886728
@test get_saturation_coeffs(GENROU)[2] == 5.252551286084109
#Test GENROE
@test get_R(GENROE) == 0.0
@test get_Td0_p(GENROE) == 7.4
@test get_Td0_pp(GENROE) == 0.03
@test get_Tq0_p(GENROE) == 0.06
@test get_Tq0_pp(GENROE) == 0.033
@test get_Xd(GENROE) == 0.8979
@test get_Xq(GENROE) == 0.646
@test get_Xd_p(GENROE) == 0.2995
@test get_Xq_p(GENROE) == 0.646
@test get_Xd_pp(GENROE) == 0.23
@test get_Xl(GENROE) == 0.1
@test get_Se(GENROE) == (0.1, 0.5)
@test get_states(GENROE) == [:eq_p, :ed_p, :ψ_kd, :ψ_kq]
@test get_n_states(GENROE) == 4
@test abs(get_saturation_coeffs(GENROE)[1] - 8.827469119589406) <= 1e-6
@test abs(get_saturation_coeffs(GENROE)[2] - 0.1) <= 1e-6
#Test GENSAL
@test get_R(GENSAL) == 0.0
@test get_Td0_p(GENSAL) == 7.4
@test get_Td0_pp(GENSAL) == 0.03
@test get_Tq0_pp(GENSAL) == 0.033
@test get_Xd(GENSAL) == 0.8979
@test get_Xq(GENSAL) == 0.646
@test get_Xd_p(GENSAL) == 0.2995
@test get_Xd_pp(GENSAL) == 0.23
@test get_Xl(GENSAL) == 0.1
@test get_Se(GENSAL) == (0.1, 0.5)
@test get_states(GENSAL) == [:eq_p, :ψ_kd, :ψq_pp]
@test get_n_states(GENSAL) == 3
@test get_saturation_coeffs(GENSAL)[1] == 0.8620204102886728
@test get_saturation_coeffs(GENSAL)[2] == 5.252551286084109
#Test GENSAE
@test get_R(GENSAE) == 0.0
@test get_Td0_p(GENSAE) == 7.4
@test get_Td0_pp(GENSAE) == 0.03
@test get_Tq0_pp(GENSAE) == 0.033
@test get_Xd(GENSAE) == 0.8979
@test get_Xq(GENSAE) == 0.646
@test get_Xd_p(GENSAE) == 0.2995
@test get_Xd_pp(GENSAE) == 0.23
@test get_Xl(GENSAE) == 0.1
@test get_Se(GENSAE) == (0.1, 0.5)
@test get_states(GENSAE) == [:eq_p, :ψ_kd, :ψq_pp]
@test get_n_states(GENSAE) == 3
@test abs(get_saturation_coeffs(GENSAE)[1] - 8.827469119589406) <= 1e-6
@test abs(get_saturation_coeffs(GENSAE)[2] - 0.1) <= 1e-6
end
================================================
FILE: test/test_dynamic_inverter.jl
================================================
@testset "Inverter Components" begin
converter = AverageConverter(690.0, 2750000.0) #S_rated goes in Watts
@test converter isa PowerSystems.DynamicComponent
dc_source = FixedDCSource(600.0) #Not in the original data, guessed.
@test dc_source isa PowerSystems.DynamicComponent
filter = LCLFilter(0.08, 0.003, 0.074, 0.2, 0.01)
@test filter isa PowerSystems.DynamicComponent
pll = KauraPLL(500.0, 0.084, 4.69)
@test pll isa PowerSystems.DynamicComponent
reduced_pll = ReducedOrderPLL(500.0, 0.084, 4.69)
@test reduced_pll isa PowerSystems.DynamicComponent
virtual_H = VirtualInertia(2.0, 400.0, 20.0, 2 * pi * 50.0)
@test virtual_H isa PowerSystems.DeviceParameter
P_control = ActivePowerDroop(0.2, 1000.0)
@test P_control isa PowerSystems.DeviceParameter
P_control_PI = ActivePowerPI(2.0, 20.0, 50.0)
@test P_control_PI isa PowerSystems.DeviceParameter
P_VOC = ActiveVirtualOscillator(0.0033, pi / 4)
@test P_VOC isa PowerSystems.DeviceParameter
Q_control = ReactivePowerDroop(0.2, 1000.0)
@test Q_control isa PowerSystems.DeviceParameter
Q_control_PI = ReactivePowerPI(2.0, 20.0, 50.0)
@test Q_control_PI isa PowerSystems.DeviceParameter
Q_VOC = ReactiveVirtualOscillator(0.0796)
@test Q_VOC isa PowerSystems.DeviceParameter
outer_control = OuterControl(virtual_H, Q_control)
@test outer_control isa PowerSystems.DynamicComponent
test_accessors(outer_control)
outer_control_droop = OuterControl(P_control, Q_control)
@test outer_control_droop isa PowerSystems.DynamicComponent
test_accessors(outer_control_droop)
outer_control_PI = OuterControl(P_control_PI, Q_control_PI)
@test outer_control_PI isa PowerSystems.DynamicComponent
test_accessors(outer_control_PI)
outer_control_VOC = OuterControl(P_VOC, Q_VOC)
@test outer_control_PI isa PowerSystems.DynamicComponent
test_accessors(outer_control_PI)
vsc = VoltageModeControl(0.59, 736.0, 0.0, 0.0, 0.2, 1.27, 14.3, 0.0, 50.0, 0.2)
@test vsc isa PowerSystems.DynamicComponent
vsc2 = VoltageModeControl(0.59, 736.0, 0.0, 0.0, 0.2, 1.27, 14.3, 0.0, 50.0, 0.2)
@test vsc2 isa PowerSystems.DynamicComponent
vsc3 = CurrentModeControl(1.27, 14.3, 0.0)
@test vsc3 isa PowerSystems.DynamicComponent
BESS_source = ZeroOrderBESS(
(sqrt(8) / sqrt(3)) * 690.0,
(sqrt(3) / sqrt(8)) * 2750000.0,
370.0,
0.001,
4.63,
3200.0,
0.6,
4.0,
0.39,
10.34,
1.08,
)
@test BESS_source isa PowerSystems.DynamicComponent
end
@testset "Dynamic Inverter" begin
sys = PSB.build_system(PSB.PSYTestSystems, "dynamic_inverter_sys")
inverters = collect(get_components(DynamicInverter, sys))
@test length(inverters) == 1
test_inverter = inverters[1]
@test test_inverter isa PowerSystems.Component
test_accessors(test_inverter)
end
@testset "Dynamic Inverter Limiters" begin
converter = AverageConverter(690.0, 2750000.0) #S_rated goes in Watts
dc_source = FixedDCSource(600.0) #Not in the original data, guessed.
filt = LCLFilter(0.08, 0.003, 0.074, 0.2, 0.01)
pll = KauraPLL(500.0, 0.084, 4.69)
virtual_H = VirtualInertia(2.0, 400.0, 20.0, 2 * pi * 50.0)
Q_control = ReactivePowerDroop(0.2, 1000.0)
outer_control = OuterControl(virtual_H, Q_control)
vsc = VoltageModeControl(0.59, 736.0, 0.0, 0.0, 0.2, 1.27, 14.3, 0.0, 50.0, 0.2)
inverter = DynamicInverter(
"TestInverter",
1.0,
converter,
outer_control,
vsc,
dc_source,
pll,
filt,
)
@test inverter isa PowerSystems.Component
test_accessors(inverter)
inv_magnitude = DynamicInverter(;
name = "TestInverter",
ω_ref = 1.0,
converter = converter,
outer_control = outer_control,
inner_control = vsc,
dc_source = dc_source,
freq_estimator = pll,
filter = filt,
limiter = MagnitudeOutputCurrentLimiter(; I_max = 1.0),
)
@test inv_magnitude isa PowerSystems.Component
test_accessors(inv_magnitude)
inv_inst = DynamicInverter(;
name = "TestInverter",
ω_ref = 1.0,
converter = converter,
outer_control = outer_control,
inner_control = vsc,
dc_source = dc_source,
freq_estimator = pll,
filter = filt,
limiter = InstantaneousOutputCurrentLimiter(;
Id_max = 1.0 / sqrt(2),
Iq_max = 1.0 / sqrt(2),
),
)
@test inv_inst isa PowerSystems.Component
test_accessors(inv_inst)
inv_priority = DynamicInverter(;
name = "TestInverter",
ω_ref = 1.0,
converter = converter,
outer_control = outer_control,
inner_control = vsc,
dc_source = dc_source,
freq_estimator = pll,
filter = filt,
limiter = PriorityOutputCurrentLimiter(; I_max = 1.0, ϕ_I = 0.1),
)
@test inv_priority isa PowerSystems.Component
test_accessors(inv_priority)
end
@testset "Generic Renewable Models" begin
converter_regca1 = RenewableEnergyConverterTypeA(;
T_g = 0.02,
Rrpwr = 10.0,
Brkpt = 0.9,
Zerox = 0.4,
Lvpl1 = 1.22,
Vo_lim = 1.2,
Lv_pnts = (0.5, 0.9),
Io_lim = -1.3,
T_fltr = 0.2,
K_hv = 0.0,
Iqr_lims = (-100.0, 100.0),
Accel = 0.7,
Lvpl_sw = 0,
)
@test converter_regca1 isa PowerSystems.DynamicComponent
filt_current = RLFilter(; rf = 0.0, lf = 0.1)
@test filt_current isa PowerSystems.DynamicComponent
inner_ctrl_typeB = RECurrentControlB(;
Q_Flag = 0,
PQ_Flag = 0,
Vdip_lim = (-99.0, 99.0),
T_rv = 0.02,
dbd_pnts = (-1.0, 1.0),
K_qv = 0.0,
Iqinj_lim = (-1.1, 1.1),
V_ref0 = 0.0,
K_vp = 10.0,
K_vi = 60.0,
T_iq = 0.02,
I_max = 1.11,
)
@test inner_ctrl_typeB isa PowerSystems.DynamicComponent
# Creates 2^5 = 32 combinations of flags for an outer control
for (F_flag, VC_flag, R_flag, PF_flag, V_flag) in
reverse.(Iterators.product(fill(0:1, 5)...))[:]
P_control_typeAB = ActiveRenewableControllerAB(;
bus_control = 0,
from_branch_control = 0,
to_branch_control = 0,
branch_id_control = "0",
Freq_Flag = F_flag,
K_pg = 1.0,
K_ig = 0.05,
T_p = 0.25,
fdbd_pnts = (-1.0, 1.0),
fe_lim = (-99.0, 99.0),
P_lim = (0.0, 1.2),
T_g = 0.1,
D_dn = 0.0,
D_up = 0.0,
dP_lim = (-99.0, 99.0),
P_lim_inner = (0.0, 1.2),
T_pord = 0.02,
)
Q_control_typeAB = ReactiveRenewableControllerAB(;
bus_control = 0,
from_branch_control = 0,
to_branch_control = 0,
branch_id_control = "0",
VC_Flag = VC_flag,
Ref_Flag = R_flag,
PF_Flag = PF_flag,
V_Flag = V_flag,
T_fltr = 0.02,
K_p = 18.0,
K_i = 5.0,
T_ft = 0.0,
T_fv = 0.05,
V_frz = 0.0,
R_c = 0.0,
X_c = 0.0,
K_c = 0.0,
e_lim = (-0.1, 0.1),
dbd_pnts = (-1.0, 1.0),
Q_lim = (-0.43, 0.43),
T_p = 0.0,
Q_lim_inner = (-0.44, 0.44),
V_lim = (0.9, 1.05),
K_qp = 0.0,
K_qi = 0.01,
)
@test P_control_typeAB isa PowerSystems.DeviceParameter
@test Q_control_typeAB isa PowerSystems.DeviceParameter
outer_control_typeAB = OuterControl(P_control_typeAB, Q_control_typeAB)
@test outer_control_typeAB isa PowerSystems.DynamicComponent
test_accessors(outer_control_typeAB)
end
end
================================================
FILE: test/test_dynamic_loads.jl
================================================
@testset "Induction Motor" begin
#valid (non-default) A and B
im = SingleCageInductionMachine(;
name = "init",
R_s = 0.0,
R_r = 0.018,
X_ls = 0.1,
X_lr = 0.18,
X_m = 3.2,
H = 0.5,
A = 0.2,
B = 0.0,
base_power = 100.0,
)
@test im isa PowerSystems.Component
#invalid A, B or C
@test_throws ErrorException SingleCageInductionMachine(
name = "init",
R_s = 0.0,
R_r = 0.018,
X_ls = 0.1,
X_lr = 0.18,
X_m = 3.2,
H = 0.5,
A = 0.2,
B = 0.9,
base_power = 100.0,
)
sys = System(100.0)
bus = ACBus(nothing)
add_component!(sys, bus)
static_load = PowerLoad(nothing)
static_load.bus = bus
add_component!(sys, static_load)
add_component!(sys, im, static_load)
IMs = collect(get_components(SingleCageInductionMachine, sys))
@test length(IMs) == 1
im = SimplifiedSingleCageInductionMachine(;
name = "init",
R_s = 0.0,
R_r = 0.018,
X_ls = 0.1,
X_lr = 0.18,
X_m = 3.2,
H = 0.5,
A = 0.2,
B = 0.0,
base_power = 100.0,
)
@test im isa PowerSystems.Component
#invalid A, B or C
@test_throws ErrorException SimplifiedSingleCageInductionMachine(
name = "init",
R_s = 0.0,
R_r = 0.018,
X_ls = 0.1,
X_lr = 0.18,
X_m = 3.2,
H = 0.5,
A = 0.2,
B = 0.9,
base_power = 100.0,
)
sys = System(100.0)
bus = ACBus(nothing)
add_component!(sys, bus)
static_load = PowerLoad(nothing)
static_load.bus = bus
add_component!(sys, static_load)
add_component!(sys, im, static_load)
IMs = collect(get_components(SimplifiedSingleCageInductionMachine, sys))
@test length(IMs) == 1
end
@testset "Active Constant Power Load Model" begin
#valid model
al = ActiveConstantPowerLoad(;
name = "init",
r_load = 70.0,
c_dc = 2040e-6,
rf = 0.1,
lf = 2.3e-3,
cf = 8.8e-6,
rg = 0.03,
lg = 0.93e-3,
kp_pll = 0.4,
ki_pll = 4.69,
kpv = 0.5,
kiv = 150.0,
kpc = 15.0,
kic = 30000.0,
base_power = 100.0,
)
@test al isa PowerSystems.Component
sys = System(100.0)
bus = ACBus(nothing)
add_component!(sys, bus)
static_load = PowerLoad(nothing)
static_load.bus = bus
add_component!(sys, static_load)
add_component!(sys, al, static_load)
ALs = collect(get_components(ActiveConstantPowerLoad, sys))
@test length(ALs) == 1
end
@testset "Dynamic Exponential Load Model" begin
#valid model
al = DynamicExponentialLoad(;
name = "init",
a = 1.0,
b = 1.0,
α = 1.2,
β = 1.2,
T_p = 3.0,
T_q = 3.0,
)
@test al isa PowerSystems.Component
sys = System(100.0)
bus = ACBus(nothing)
add_component!(sys, bus)
static_load = PowerLoad(nothing)
static_load.bus = bus
add_component!(sys, static_load)
add_component!(sys, al, static_load)
ALs = collect(get_components(DynamicExponentialLoad, sys))
@test length(ALs) == 1
end
================================================
FILE: test/test_dynamics_source.jl
================================================
# Non functional system data. This code is just for testing.
# Do not copy paste this code.
@testset "Test Dynamic Source" begin
sys = System(100.0)
bus = ACBus(nothing)
set_bustype!(bus, ACBusTypes.SLACK)
add_component!(sys, bus)
source = Source(nothing)
set_bus!(source, bus)
add_component!(sys, source)
pvs = PeriodicVariableSource(nothing)
add_component!(sys, pvs, source)
@test get_components(PeriodicVariableSource, sys) !== nothing
end
@testset "Test Dynamic Source" begin
sys = System(100.0)
bus = ACBus(nothing)
set_bustype!(bus, ACBusTypes.REF)
add_component!(sys, bus)
source = Source(nothing)
set_bus!(source, bus)
add_component!(sys, source)
pvs = PeriodicVariableSource(nothing)
add_component!(sys, pvs, source)
@test get_components(PeriodicVariableSource, sys) !== nothing
sys2, result = validate_serialization(sys)
@test result
end
================================================
FILE: test/test_generate_structs.jl
================================================
@testset "Test generated structs" begin
descriptor_file =
joinpath(@__DIR__, "..", "src", "descriptors", "power_system_structs.json")
existing_dir = joinpath(@__DIR__, "..", "src", "models", "generated")
@test IS.test_generated_structs(descriptor_file, existing_dir)
end
@testset "Test generated structs from StructDefinition" begin
orig_descriptor_file =
joinpath(@__DIR__, "..", "src", "descriptors", "power_system_structs.json")
output_directory = mktempdir()
descriptor_file = joinpath(output_directory, "power_system_structs.json")
cp(orig_descriptor_file, descriptor_file)
# This is necessary in cases where the package has been added through a GitHub branch
# where all source files are read-only.
chmod(descriptor_file, 0o644)
new_struct = StructDefinition(;
struct_name = "MyThermalStandard",
docstring = "Custom ThermalStandard",
supertype = "ThermalGen",
is_component = true,
fields = [
StructField(; name = "name", data_type = String, comment = "name"),
StructField(;
name = "active_power",
data_type = Float64,
valid_range = "active_power_limits",
validation_action = "warn",
null_value = 0.0,
comment = "active power",
needs_conversion = true,
),
StructField(;
name = "active_power_limits",
needs_conversion = true,
data_type = "NamedTuple{(:min, :max), Tuple{Float64, Float64}}",
null_value = "(min=0.0, max=0.0)",
),
StructField(;
name = "rating",
data_type = Float64,
valid_range = Dict("min" => 0.0, "max" => nothing),
validation_action = "error",
comment = "Thermal limited MVA Power Output of the unit. <= Capacity",
),
],
)
redirect_stdout(devnull) do
generate_struct_file(
new_struct;
filename = descriptor_file,
output_directory = output_directory,
)
end
data = open(descriptor_file, "r") do io
JSON3.read(io, Dict)
end
@test data["auto_generated_structs"][end]["struct_name"] == "MyThermalStandard"
@test isfile(joinpath(output_directory, "MyThermalStandard.jl"))
end
================================================
FILE: test/test_hybrid_system.jl
================================================
@testset "Hybrid System tests" begin
test_sys = PSB.build_system(PSB.PSITestSystems, "c_sys14"; add_forecasts = false)
h_sys = HybridSystem(;
name = "Test H",
available = true,
status = true,
bus = get_component(ACBus, test_sys, "Bus 1"),
active_power = 1.0,
reactive_power = 1.0,
thermal_unit = ThermalStandard(nothing),
electric_load = PowerLoad(nothing),
storage = EnergyReservoirStorage(nothing),
renewable_unit = RenewableDispatch(nothing),
base_power = 100.0,
operation_cost = MarketBidCost(nothing),
)
add_component!(test_sys, h_sys)
initial_time = Dates.DateTime("2020-09-01")
resolution = Dates.Hour(1)
other_time = initial_time + resolution
name = "test"
horizon = 24
data = Dict(initial_time => ones(horizon), other_time => 5.0 * ones(horizon))
forecast = Deterministic(name, data, resolution)
add_time_series!(test_sys, h_sys, forecast)
ts = get_time_series(Deterministic, h_sys, "test")
@test isa(ts, Deterministic)
end
@testset "Hybrid System from parsed files" begin
sys = PSB.build_system(
PSB.PSITestSystems,
"test_RTS_GMLC_sys_with_hybrid";
add_forecasts = true,
)
hybrids = collect(get_components(HybridSystem, sys))
@test length(hybrids) == 1
h_sys = hybrids[1]
electric_load = nothing
thermal_unit = nothing
subcomponents = collect(get_subcomponents(h_sys))
@test length(subcomponents) == 4
expected_time_series_names = Set{String}()
num_time_series = 0
for subcomponent in subcomponents
@test !PSY.is_attached(subcomponent, sys)
@test IS.is_attached(subcomponent, sys.data.masked_components)
if subcomponent isa PowerLoad
electric_load = subcomponent
elseif subcomponent isa ThermalStandard
thermal_unit = subcomponent
end
for ts in get_time_series_multiple(subcomponent)
push!(
expected_time_series_names,
PSY.make_subsystem_time_series_name(subcomponent, ts),
)
num_time_series += 1
end
end
@test electric_load !== nothing
@test thermal_unit !== nothing
sts = collect(get_time_series_multiple(h_sys; type = SingleTimeSeries))
forecasts =
collect(get_time_series_multiple(h_sys; type = DeterministicSingleTimeSeries))
@test length(sts) == 2
@test length(forecasts) == 2
@test issubset((get_name(x) for x in sts), expected_time_series_names)
@test issubset((get_name(x) for x in forecasts), expected_time_series_names)
@test get_time_series(SingleTimeSeries, electric_load, "max_active_power") isa
SingleTimeSeries
@test get_time_series(Deterministic, electric_load, "max_active_power") isa
DeterministicSingleTimeSeries
@test !has_time_series(thermal_unit)
@test has_time_series(electric_load)
remove_time_series!(
sys,
DeterministicSingleTimeSeries,
electric_load,
"max_active_power",
)
@test !has_time_series(electric_load, DeterministicSingleTimeSeries, "max_active_power")
# Can't set the units when the HybridSystem is attached to system.
@test_throws ArgumentError PSY.set_thermal_unit!(h_sys, thermal_unit)
end
@testset "Hybrid System from unattached subcomponents" begin
sys = PSB.build_system(PSB.PSITestSystems, "test_RTS_GMLC_sys"; add_forecasts = false)
thermal_unit = first(get_components(ThermalStandard, sys))
bus = get_bus(thermal_unit)
electric_load = first(get_components(PowerLoad, sys))
storage = first(get_components(EnergyReservoirStorage, sys))
renewable_unit = first(get_components(RenewableDispatch, sys))
for subcomponent in (thermal_unit, electric_load, storage, renewable_unit)
remove_component!(sys, subcomponent)
end
name = "Test H"
h_sys = HybridSystem(;
name = name,
available = true,
status = true,
bus = bus,
active_power = 1.0,
reactive_power = 1.0,
thermal_unit = thermal_unit,
electric_load = electric_load,
storage = storage,
renewable_unit = renewable_unit,
base_power = 100.0,
operation_cost = MarketBidCost(nothing),
)
add_component!(sys, h_sys)
for subcomponent in (thermal_unit, electric_load, storage, renewable_unit)
@test !PSY.is_attached(subcomponent, sys)
@test !has_time_series(subcomponent)
@test IS.is_attached(subcomponent, sys.data.masked_components)
end
@test length(IS.get_masked_components(Component, sys.data)) == 4
# Add time series for a subcomponent.
initial_time = Dates.DateTime("2020-09-01")
resolution = Dates.Hour(1)
other_time = initial_time + resolution
name = "test"
horizon = 24
data = Dict(initial_time => rand(horizon), other_time => 5.0 * ones(horizon))
forecast = Deterministic(name, data, resolution)
add_time_series!(sys, thermal_unit, forecast)
@test get_time_series(Deterministic, thermal_unit, name) isa Deterministic
copy_subcomponent_time_series!(h_sys, thermal_unit)
@test get_time_series(
Deterministic,
h_sys,
PSY.make_subsystem_time_series_name(thermal_unit, forecast),
) isa Deterministic
end
@testset "get_fuel_cost for HybridSystem delegates to thermal subunit" begin
# Hybrid with thermal: get_fuel_cost delegates to thermal subunit
sys = PSB.build_system(PSB.PSITestSystems, "c_sys5_uc"; add_forecasts = false)
thermal = first(get_components(ThermalStandard, sys))
# Ensure thermal has ThermalGenerationCost with FuelCurve
fc = FuelCurve(InputOutputCurve(IS.QuadraticFunctionData(1, 2, 3)), 2.5)
set_operation_cost!(thermal, ThermalGenerationCost(fc, 0.0, 0.0, 0.0))
expected_fuel_cost = get_fuel_cost(thermal)
bus = get_bus(thermal)
remove_component!(sys, thermal)
h_sys = HybridSystem(;
name = "HybridWithThermal",
available = true,
status = true,
bus = bus,
active_power = 1.0,
reactive_power = 0.0,
thermal_unit = thermal,
electric_load = nothing,
storage = nothing,
renewable_unit = nothing,
base_power = 100.0,
operation_cost = MarketBidCost(nothing),
)
add_component!(sys, h_sys)
@test get_fuel_cost(h_sys) == expected_fuel_cost
end
@testset "get_fuel_cost for HybridSystem without thermal throws" begin
sys = PSB.build_system(PSB.PSITestSystems, "c_sys14"; add_forecasts = false)
bus = get_component(ACBus, sys, "Bus 1")
h_sys = HybridSystem(;
name = "HybridNoThermal",
available = true,
status = true,
bus = bus,
active_power = 1.0,
reactive_power = 0.0,
thermal_unit = nothing,
electric_load = nothing,
storage = nothing,
renewable_unit = nothing,
base_power = 100.0,
operation_cost = MarketBidCost(nothing),
)
add_component!(sys, h_sys)
@test_throws ArgumentError get_fuel_cost(h_sys)
end
================================================
FILE: test/test_hydro_reservoir.jl
================================================
@testset "Test Hydro Turbine constructors" begin
turbine = HydroTurbine(; name = "TestTurbine",
available = true,
bus = ACBus(nothing),
active_power = 0.0,
reactive_power = 0.0,
rating = 1,
base_power = 100,
active_power_limits = (min = 0, max = 1),
reactive_power_limits = nothing,
outflow_limits = nothing,
powerhouse_elevation = 0.0,
ramp_limits = nothing,
time_limits = nothing,
)
set_powerhouse_elevation!(turbine, 10.0)
@test get_powerhouse_elevation(turbine) == 10.0
end
@testset "Test Hydro Reservoir constructors and getters" begin
reservoir = HydroReservoir(;
name = "init",
available = false,
initial_level = 1.0,
storage_level_limits = (min = 0.0, max = 1.0),
spillage_limits = nothing,
inflow = 0.0,
outflow = 0.0,
level_targets = 0.0,
intake_elevation = 0.0,
head_to_volume_factor = LinearCurve(0.0),
)
@test get_storage_level_limits(reservoir) == (min = 0.0, max = 1.0)
@test get_initial_level(reservoir) == 1.0
@test get_level_data_type(reservoir) == ReservoirDataType.USABLE_VOLUME
@test get_inflow(reservoir) == 0.0
@test get_outflow(reservoir) == 0.0
@test get_intake_elevation(reservoir) == 0.0
@test get_head_to_volume_factor(reservoir) == LinearCurve(0.0)
set_intake_elevation!(reservoir, 10.0)
@test get_intake_elevation(reservoir) == 10.0
end
@testset "Test Hydro Reservoir constructors and setters" begin
reservoir = HydroReservoir(nothing)
@test set_storage_level_limits!(reservoir, (min = 0.0, max = 0.0)) ==
(min = 0.0, max = 0.0)
@test set_level_data_type!(reservoir, ReservoirDataType.HEAD) == ReservoirDataType.HEAD
@test set_inflow!(reservoir, 10.0) == 10.0
@test set_outflow!(reservoir, 10.0) == 10.0
end
@testset "Test single `HydroTurbine` with single `HydroReservoir`" begin
sys = System(100.0)
bus = nodes5()[4]
bus.name = "bus1"
bus.number = 1
add_component!(sys, bus)
reservoir = HydroReservoir(nothing)
add_component!(sys, reservoir)
turbine = HydroTurbine(nothing)
turbine.bus = bus
add_component!(sys, turbine)
set_downstream_turbine!(reservoir, turbine)
@test !has_upstream_turbine(reservoir)
@test has_downstream_turbine(reservoir)
@test !has_upstream_turbine(reservoir, turbine)
@test has_downstream_turbine(reservoir, turbine)
@test length(get_components(HydroTurbine, sys)) == 1
@test length(get_connected_head_reservoirs(sys, turbine)) == 1
remove_turbine!(reservoir, turbine)
@test_throws ArgumentError remove_turbine!(reservoir, turbine)
@test !has_downstream_turbine(reservoir)
@test !has_downstream_turbine(reservoir, turbine)
@test length(get_connected_head_reservoirs(sys, turbine)) == 0
remove_component!(sys, turbine)
@test_throws ArgumentError get_connected_head_reservoirs(sys, turbine)
_, result = validate_serialization(sys)
@test result
end
@testset "Test multiple `HydroTurbine` with single `HydroReservoir`" begin
sys = System(100.0)
bus = nodes5()[4]
bus.name = "bus1"
bus.number = 1
add_component!(sys, bus)
hydro_reservoir = HydroReservoir(nothing)
add_component!(sys, hydro_reservoir)
turbines = []
for i in 1:5
turbine = HydroTurbine(nothing)
turbine.name = "Turbine" * string(i)
turbine.bus = bus
add_component!(sys, turbine)
push!(turbines, turbine)
end
set_downstream_turbines!(hydro_reservoir, turbines)
collected_turbines = collect(get_components(HydroTurbine, sys))
@test length(turbines) == length(collected_turbines)
@test !has_upstream_turbine(hydro_reservoir)
@test has_downstream_turbine(hydro_reservoir)
@test length(get_downstream_turbines(hydro_reservoir)) == 5
@test isempty(get_upstream_turbines(hydro_reservoir))
mapping = get_turbine_head_reservoirs_mapping(sys)
@test mapping isa TurbineConnectedDevicesMapping
@test length(get_connected_head_reservoirs(sys, turbines[1])) == 1
_, result = validate_serialization(sys)
@test result
remove_turbine!(hydro_reservoir, turbines[1])
@test length(get_downstream_turbines(hydro_reservoir)) == 4
clear_turbines!(hydro_reservoir)
@test isempty(get_downstream_turbines(hydro_reservoir))
end
@testset "Test single `HydroTurbine` with multiple `HydroReservoir`" begin
sys = System(100.0)
bus = nodes5()[4]
bus.name = "bus1"
bus.number = 1
add_component!(sys, bus)
hydro_reservoir_01 = HydroReservoir(nothing)
hydro_reservoir_02 = HydroReservoir(nothing)
hydro_reservoir_02.name = "reservoir02"
add_component!(sys, hydro_reservoir_01)
add_component!(sys, hydro_reservoir_02)
turbine = HydroTurbine(nothing)
turbine.bus = bus
add_component!(sys, turbine)
set_downstream_turbine!(hydro_reservoir_01, turbine)
set_downstream_turbine!(hydro_reservoir_02, turbine)
@test length(get_connected_head_reservoirs(sys, turbine)) == 2
@test isempty(get_connected_tail_reservoirs(sys, turbine))
_, result = validate_serialization(sys)
@test result
end
================================================
FILE: test/test_internal.jl
================================================
import UUIDs
"""Recursively validates that the object and fields have UUIDs."""
function validate_uuids(obj::T) where {T}
if !(obj isa Component)
return true
end
result = true
if !(IS.get_uuid(obj) isa Base.UUID)
result = false
@error "object does not have a UUID" obj
end
for fieldname in fieldnames(T)
val = getfield(obj, fieldname)
if !validate_uuids(val)
result = false
end
end
return result
end
function validate_uuids(obj::T) where {T <: AbstractArray}
result = true
for elem in obj
if !validate_uuids(elem)
result = false
end
end
return result
end
function validate_uuids(obj::T) where {T <: AbstractDict}
result = true
for elem in values(obj)
if !validate_uuids(elem)
result = false
end
end
return result
end
@testset "Test internal values" begin
sys_rts = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
@test validate_uuids(sys_rts)
end
================================================
FILE: test/test_logging.jl
================================================
TEST_MSG = "test log message"
@testset "Test configure_logging" begin
# Verify logging to a file.
logfile = "testlog.txt"
isfile(logfile) && rm(logfile)
orig_logger = global_logger()
try
logger = configure_logging(;
console_level = Logging.Warn,
file_level = Logging.Debug,
filename = logfile,
)
with_logger(logger) do
@info TEST_MSG
end
close(logger)
@test isfile(logfile)
lines = readlines(logfile)
@test length(lines) == 2 # two lines per message
@test occursin(TEST_MSG, lines[1])
finally
rm(logfile)
global_logger(orig_logger)
end
# Verify logging with no file.
try
logger = configure_logging(;
console_level = Logging.Warn,
file_level = Logging.Info,
filename = nothing,
)
with_logger(logger) do
@info TEST_MSG
end
close(logger)
@test !isfile(logfile)
finally
global_logger(orig_logger)
end
end
================================================
FILE: test/test_outages.jl
================================================
@testset "Test outages" begin
sys = create_system_with_outages()
gens = collect(get_components(ThermalStandard, sys))
gen1 = gens[1]
gen2 = gens[2]
@test length(get_supplemental_attributes(Outage, sys)) == 4
forced_outages =
collect(get_supplemental_attributes(GeometricDistributionForcedOutage, sys))
@test length(forced_outages) == 2
@test get_supplemental_attribute(sys, IS.get_uuid(forced_outages[1])) ==
forced_outages[1]
planned_outages = collect(get_supplemental_attributes(PlannedOutage, sys))
@test length(planned_outages) == 2
@test get_supplemental_attribute(sys, IS.get_uuid(planned_outages[1])) ==
planned_outages[1]
geos = get_supplemental_attributes(GeographicInfo, sys)
for geo in geos
@test length(get_associated_components(sys, geo)) == 2
@test length(
get_associated_components(sys, geo; component_type = ThermalStandard),
) == 1
# This method is deprecated for now...will be deleted later.
@test length(get_components(sys, geo)) == 2
end
associated_components = get_associated_components(sys, GeographicInfo)
@test length(associated_components) == 4
@test Set([typeof(x) for x in associated_components]) == Set([ACBus, ThermalStandard])
associated_components =
get_associated_components(sys, GeographicInfo; component_type = ThermalGen)
@test length(associated_components) == 2
for gen in (gen1, gen2)
for type in (GeometricDistributionForcedOutage, PlannedOutage, GeographicInfo)
attributes = get_supplemental_attributes(type, gen)
@test length(attributes) == 1
uuid = IS.get_uuid(attributes[1])
get_supplemental_attribute(sys, uuid)
get_supplemental_attribute(gen, uuid)
@test get_supplemental_attribute(gen, uuid) ==
get_supplemental_attribute(sys, uuid)
end
end
@test length(
get_supplemental_attributes(
x -> get_mean_time_to_recovery(x) == 2.0,
GeometricDistributionForcedOutage,
sys,
),
) == 1
@test length(
get_supplemental_attributes(
x -> get_mean_time_to_recovery(x) == 2.0,
GeometricDistributionForcedOutage,
gen1,
),
) == 0
@test length(
get_supplemental_attributes(
x -> get_mean_time_to_recovery(x) == 2.0,
GeometricDistributionForcedOutage,
gen2,
),
) == 1
@test length(
get_supplemental_attributes(x -> get_outage_schedule(x) == "1", PlannedOutage, sys),
) == 1
@test length(
get_supplemental_attributes(
x -> get_outage_schedule(x) == "1",
PlannedOutage,
gen1,
),
) == 1
@test length(
get_supplemental_attributes(
x -> get_outage_schedule(x) == "1",
PlannedOutage,
gen2,
),
) == 0
planned_outages = collect(get_supplemental_attributes(PlannedOutage, gen2))
@test !isempty(planned_outages)
for outage in planned_outages
ts_keys = get_time_series_keys(outage)
@test !isempty(ts_keys)
for key in ts_keys
remove_time_series!(sys, key.time_series_type, outage, key.name)
end
@test isempty(get_time_series_keys(outage))
end
end
@testset "Test get_component_supplemental_attribute_pairs" begin
sys = create_system_with_outages()
# This function is properly tested in InfrastructureSystems.
for (gen, outage) in get_component_supplemental_attribute_pairs(
ThermalStandard,
GeometricDistributionForcedOutage,
sys,
)
@test gen isa ThermalStandard
@test outage isa GeometricDistributionForcedOutage
end
end
@testset "Test get_supplemental_attributes with component type" begin
# the create_system_with_outages function creates a system with only ThermalStandard
# components, so we need a different system for this test.
c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat")
renewables = collect(get_components(PSY.RenewableDispatch, c_sys5_bat))
thermals = collect(get_components(PSY.ThermalStandard, c_sys5_bat))
attr1 = IS.TestSupplemental(; value = 1.0)
attr2 = IS.TestSupplemental(; value = 2.0)
geo_attr1 = IS.GeographicInfo()
geo_attr2 = IS.GeographicInfo(; geo_json = Dict{String, Any}("foo" => 5))
comp_to_attributes = Dict{PSY.Component, Vector{IS.SupplementalAttribute}}(
renewables[1] => [geo_attr1],
renewables[2] => [geo_attr1, attr1],
thermals[1] => [geo_attr2],
thermals[2] => [geo_attr2, attr2],
thermals[3] => [geo_attr1],
)
for (comp, attrs) in comp_to_attributes
for attr in attrs
add_supplemental_attribute!(c_sys5_bat, comp, attr)
end
end
renewable_attrs =
get_associated_supplemental_attributes(c_sys5_bat, PSY.RenewableDispatch)
@test length(renewable_attrs) == 2 && geo_attr1 in renewable_attrs &&
attr1 in renewable_attrs
thermal_attrs = get_associated_supplemental_attributes(c_sys5_bat, PSY.ThermalStandard)
@test length(thermal_attrs) == 3 && geo_attr2 in thermal_attrs &&
attr2 in thermal_attrs && geo_attr1 in thermal_attrs
thermal_geo_attrs = get_associated_supplemental_attributes(
c_sys5_bat,
PSY.ThermalStandard;
attribute_type = IS.GeographicInfo,
)
@test length(thermal_geo_attrs) == 2 && geo_attr1 in thermal_geo_attrs &&
geo_attr2 in thermal_geo_attrs
end
@testset "Test remove_supplemental_attributes! by type" begin
sys = create_system_with_outages()
# Verify initial state
@test length(get_supplemental_attributes(GeometricDistributionForcedOutage, sys)) == 2
@test length(get_supplemental_attributes(PlannedOutage, sys)) == 2
@test length(get_supplemental_attributes(GeographicInfo, sys)) == 2
# Remove all GeometricDistributionForcedOutage attributes
remove_supplemental_attributes!(GeometricDistributionForcedOutage, sys)
@test length(get_supplemental_attributes(GeometricDistributionForcedOutage, sys)) == 0
# Other types should be unaffected
@test length(get_supplemental_attributes(PlannedOutage, sys)) == 2
@test length(get_supplemental_attributes(GeographicInfo, sys)) == 2
# Remove all PlannedOutage attributes
remove_supplemental_attributes!(PlannedOutage, sys)
@test length(get_supplemental_attributes(PlannedOutage, sys)) == 0
@test length(get_supplemental_attributes(GeographicInfo, sys)) == 2
# Remove all GeographicInfo attributes
remove_supplemental_attributes!(GeographicInfo, sys)
@test length(get_supplemental_attributes(GeographicInfo, sys)) == 0
end
================================================
FILE: test/test_parse_dynamics.jl
================================================
@testset "2-area, 11-bus, 4-generator benchmark system Parsing " begin
test_dir = mktempdir()
ger4_raw_file = joinpath(PSSE_RAW_DIR, "Benchmark_4ger_33_2015.RAW")
ger4_dyr_file = joinpath(PSSE_DYR_DIR, "Benchmark_4ger_33_2015.dyr")
sys = PSB.build_system(PSYTestSystems, "psse_Benchmark_4ger_33_2015_sys")
@test_throws PSY.DataFormatError System(ger4_raw_file, ger4_raw_file)
@test_throws PSY.DataFormatError System(ger4_dyr_file, ger4_raw_file)
dyn_injectors = get_components(DynamicInjection, sys)
@test length(dyn_injectors) == 4
for g in dyn_injectors
m = PSY.get_machine(g)
@test typeof(m) <: RoundRotorExponential
end
path = joinpath(test_dir, "test_dyn_system_serialization.json")
to_json(sys, path)
parsed_sys = System(path)
dyn_injectors = get_components(DynamicInjection, parsed_sys)
@test length(dyn_injectors) == 4
for g in dyn_injectors
m = PSY.get_machine(g)
@test typeof(m) <: RoundRotorExponential
end
end
@testset "2-area, 11-bus, 4-generator with renewables benchmark system Parsing " begin
test_dir = mktempdir()
sys = PSB.build_system(PSYTestSystems, "psse_renewable_parsing_1")
dyn_injectors = get_components(DynamicInjection, sys)
@test length(dyn_injectors) == 5
for g in dyn_injectors
if isa(g, DynamicGenerator)
m = PSY.get_machine(g)
@test typeof(m) <: RoundRotorExponential
elseif isa(g, DynamicInverter)
ic = PSY.get_inner_control(g)
@test typeof(ic) <: RECurrentControlB
else
@error("Generator $g not supported")
end
end
path = joinpath(test_dir, "test_dyn_system_serialization.json")
to_json(sys, path)
parsed_sys = System(path)
dyn_injectors = get_components(DynamicInjection, parsed_sys)
@test length(dyn_injectors) == 5
for g in dyn_injectors
if isa(g, DynamicGenerator)
m = PSY.get_machine(g)
@test typeof(m) <: RoundRotorExponential
elseif isa(g, DynamicInverter)
ic = PSY.get_inner_control(g)
@test typeof(ic) <: RECurrentControlB
else
@error("Generator $g not supported")
end
end
end
@testset "240 Bus WECC system Parsing " begin
test_dir = mktempdir()
sys = PSB.build_system(PSYTestSystems, "psse_240_parsing_sys")
dyn_injectors = get_components(DynamicInjection, sys)
@test length(dyn_injectors) == 146
for g in dyn_injectors
if isa(g, DynamicGenerator)
m = PSY.get_machine(g)
@test typeof(m) <: RoundRotorQuadratic
elseif isa(g, DynamicInverter)
ic = PSY.get_inner_control(g)
@test typeof(ic) <: RECurrentControlB
else
@error("Generator $g not supported")
end
end
path = joinpath(test_dir, "test_dyn_system_serialization.json")
to_json(sys, path)
parsed_sys = System(path)
dyn_injectors = get_components(DynamicInjection, parsed_sys)
@test length(dyn_injectors) == 146
for g in dyn_injectors
if isa(g, DynamicGenerator)
m = PSY.get_machine(g)
@test typeof(m) <: RoundRotorQuadratic
elseif isa(g, DynamicInverter)
ic = PSY.get_inner_control(g)
@test typeof(ic) <: RECurrentControlB
else
@error("Generator $g not supported")
end
end
all_gens = collect(get_components(ThermalStandard, sys))
sort!(all_gens, by = get_name)
static_injector = first(all_gens)
@test get_frequency_droop(static_injector) ==
static_injector.dynamic_injector.prime_mover.R
end
@testset "GENCLS dyr parsing" begin
threebus_raw_file = joinpath(PSSE_TEST_DIR, "ThreeBusNetwork.raw")
gencls_dyr_file = joinpath(PSSE_TEST_DIR, "TestGENCLS.dyr")
nogencls_dyr_file = joinpath(PSSE_TEST_DIR, "Test-NoCLS.dyr")
sexs_dyr_file = joinpath(PSSE_TEST_DIR, "Test_SEXS.dyr")
sys_gencls = PSB.build_system(PSYTestSystems, "psse_3bus_gen_cls_sys")
sys_nogencls = PSB.build_system(PSYTestSystems, "psse_3bus_no_cls_sys")
sys_sexs = PSB.build_system(PSYTestSystems, "psse_3bus_SEXS_sys")
#Check that generator at bus 102 (H = 0) is a Source, and not ThermalStandard.
@test isnothing(get_component(ThermalStandard, sys_gencls, "generator-102-1"))
@test typeof(get_component(StaticInjection, sys_gencls, "generator-102-1")) <: Source
#Check that generator at bus 102 (not provided in dyr data) is a Source.
@test isnothing(get_component(ThermalStandard, sys_nogencls, "generator-102-1"))
@test typeof(get_component(StaticInjection, sys_nogencls, "generator-102-1")) <: Source
#Check Parameters of GENROE raw file
genroe_gen = get_component(DynamicInjection, sys_gencls, "generator-101-1")
m = PSY.get_machine(genroe_gen)
s = PSY.get_shaft(genroe_gen)
@test typeof(m) <: RoundRotorExponential
@test get_R(m) == 0.0
@test get_Td0_p(m) == 8.0
@test get_Td0_pp(m) == 0.03
@test get_Tq0_p(m) == 0.4
@test get_Tq0_pp(m) == 0.05
@test get_Xd(m) == 1.8
@test get_Xq(m) == 1.7
@test get_Xd_p(m) == 0.3
@test get_Xd_pp(m) == 0.25
@test get_Xl(m) == 0.2
@test get_H(s) == 6.5
@test get_D(s) == 0.0
#Check Parameters of other GENCLS file
gencls_gen = get_component(DynamicInjection, sys_gencls, "generator-103-1")
m = PSY.get_machine(gencls_gen)
s = PSY.get_shaft(gencls_gen)
@test typeof(m) <: BaseMachine
@test get_R(m) == 0.0
@test get_Xd_p(m) == 0.2
@test get_H(s) == 3.1
@test get_D(s) == 2.0
#Check Parameters of other GENCLS file
gencls_gen = get_component(DynamicInjection, sys_nogencls, "generator-103-1")
m = PSY.get_machine(gencls_gen)
s = PSY.get_shaft(gencls_gen)
@test typeof(m) <: BaseMachine
@test get_R(m) == 0.0
@test get_Xd_p(m) == 0.2
@test get_H(s) == 3.1
@test get_D(s) == 2.0
#Check Parameters of SEXS file
genroe_sexs = get_component(DynamicInjection, sys_sexs, "generator-101-1")
a = PSY.get_avr(genroe_sexs)
@test typeof(a) <: AVR
@test get_Ta_Tb(a) == 0.4
@test get_Tb(a) == 5.0
@test get_K(a) == 20.0
@test get_Te(a) == 1.0
E_min, E_max = get_V_lim(a)
@test E_min == -50.0
@test E_max == 50.0
end
@testset "2000-Bus Parsing" begin
test_dir = mktempdir()
sys = build_system(PSSEParsingTestSystems, "psse_ACTIVSg2000_sys")
for g in get_components(ThermalStandard, sys)
if isnothing(get_dynamic_injector(g))
@error "ThermalStandard $(get_name(g)) should have a dynamic injector"
end
@test !isnothing(get_dynamic_injector(g))
end
for g in get_components(SynchronousCondenser, sys)
if isnothing(get_dynamic_injector(g))
@error "SynchronousCondenser $(get_name(g)) should have a dynamic injector"
end
@test !isnothing(get_dynamic_injector(g))
end
path = joinpath(test_dir, "test_dyn_system_serialization_2000.json")
to_json(sys, path)
parsed_sys = System(path)
dyn_injectors = get_components(DynamicInjection, parsed_sys)
@test length(dyn_injectors) == 435
for g in get_components(ThermalStandard, parsed_sys)
@test !isnothing(get_dynamic_injector(g))
end
end
================================================
FILE: test/test_parse_matpower.jl
================================================
# TODO: Reviewers: Is this a correct list of keys to verify?
POWER_MODELS_KEYS = [
"baseMVA",
"branch",
"bus",
"dcline",
"gen",
"load",
"name",
"per_unit",
"shunt",
"source_type",
"source_version",
"storage",
]
badfiles = Dict("case30.m" => PSY.InvalidValue)
voltage_inconsistent_files = ["RTS_GMLC_original.m", "case5_re.m", "case5_re_uc.m"]
error_log_files = ["ACTIVSg2000.m", "case_ACTIVSg10k.m"]
@testset "Parse Matpower data files" begin
files = [x for x in readdir(joinpath(MATPOWER_DIR)) if splitext(x)[2] == ".m"]
if length(files) == 0
@error "No test files in the folder"
end
for f in files
@info "Parsing $f..."
path = joinpath(MATPOWER_DIR, f)
if f in voltage_inconsistent_files
continue
else
pm_dict = PowerSystems.parse_file(path)
end
for key in POWER_MODELS_KEYS
@test haskey(pm_dict, key)
end
@info "Successfully parsed $path to PowerModels dict"
if f in keys(badfiles)
@test_logs(
(:error, r"cannot create Line"),
match_mode = :any,
@test_throws(badfiles[f], System(PowerSystems.PowerModelsData(pm_dict)))
)
else
sys = System(PowerSystems.PowerModelsData(pm_dict))
@info "Successfully parsed $path to System struct"
end
end
end
@testset "Parse PowerModel Matpower data files" begin
files = [
x for x in readdir(MATPOWER_DIR) if
splitext(x)[2] == ".m"
]
if length(files) == 0
@error "No test files in the folder"
end
for f in files
@info "Parsing $f..."
path = joinpath(MATPOWER_DIR, f)
if f in voltage_inconsistent_files
continue
else
pm_dict = PowerSystems.parse_file(path)
end
for key in POWER_MODELS_KEYS
@test haskey(pm_dict, key)
end
@info "Successfully parsed $path to PowerModels dict"
if f in keys(badfiles)
@test_logs(
(:error, r"cannot create Line"),
match_mode = :any,
@test_throws(badfiles[f], System(PowerSystems.PowerModelsData(pm_dict)))
)
else
sys = System(PowerSystems.PowerModelsData(pm_dict))
@info "Successfully parsed $path to System struct"
end
end
end
@testset "Parse Matpower files with voltage inconsistencies" begin
test_parse = (path) -> begin
pm_dict = PowerSystems.parse_file(path)
for key in POWER_MODELS_KEYS
@test haskey(pm_dict, key)
end
@info "Successfully parsed $path to PowerModels dict"
sys = System(PowerSystems.PowerModelsData(pm_dict))
@info "Successfully parsed $path to System struct"
@test isa(sys, System)
end
for f in voltage_inconsistent_files
@info "Parsing $f..."
path = joinpath(BAD_DATA, f)
@test_logs (:error,) match_mode = :any test_parse(path)
end
end
================================================
FILE: test/test_parse_psse.jl
================================================
@testset "PSSE Parsing" begin
files = readdir(PSSE_RAW_DIR)
if length(files) == 0
error("No test files in the folder")
end
for f in files[1:1]
@info "Parsing $f ..."
pm_data = PowerSystems.PowerModelsData(joinpath(PSSE_RAW_DIR, f))
@info "Successfully parsed $f to PowerModelsData"
sys = System(pm_data)
for g in get_components(Generator, sys)
@test haskey(get_ext(g), "r")
@test haskey(get_ext(g), "x")
end
@info "Successfully parsed $f to System struct"
end
# Test bad input
pm_data = PowerSystems.PowerModelsData(joinpath(PSSE_RAW_DIR, files[1]))
pm_data.data["bus"] = Dict{String, Any}()
@test_throws PowerSystems.DataFormatError System(pm_data)
end
@testset "PSSE Component Parsing" begin
@info "Testing Load Parsing"
mp_sys = build_system(MatpowerTestSystems, "matpower_case24_sys")
@test get_active_power(get_component(PowerLoad, mp_sys, "bus14")) == 1.94
@test get_max_reactive_power(get_component(PowerLoad, mp_sys, "bus14")) == 0.39
@test get_conformity(get_component(PowerLoad, mp_sys, "bus14")) ==
LoadConformity.CONFORMING
sys = build_system(PSYTestSystems, "psse_240_parsing_sys") # current/imedance_power read in natural units during parsing
@test get_current_active_power(get_component(StandardLoad, sys, "load10021")) == 2.2371
@test get_impedance_reactive_power(get_component(StandardLoad, sys, "load10021")) ==
-5.83546
@test get_conformity(get_component(StandardLoad, sys, "load10021")) ==
LoadConformity.CONFORMING
sys2 = build_system(PSYTestSystems, "psse_Benchmark_4ger_33_2015_sys") # Constant_active/reactive_power read in pu during parsing
@test get_constant_active_power(get_component(StandardLoad, sys2, "load71")) == 9.67
@test get_constant_reactive_power(get_component(StandardLoad, sys2, "load71")) == 1.0
@test get_conformity(get_component(StandardLoad, sys2, "load71")) ==
LoadConformity.CONFORMING
@info "Testing ZIP Load Parsing"
wecc_sys = build_system(PSYTestSystems, "psse_240_parsing_sys")
test_load1 = get_component(StandardLoad, wecc_sys, "load24091")
impedance_q = get_impedance_reactive_power(test_load1)
# Negative for capacitive loads
@test impedance_q < 0
@test isapprox(impedance_q, -0.75; atol = 1e-4)
test_load2 = get_component(StandardLoad, wecc_sys, "load10031")
impedance_q = get_impedance_reactive_power(test_load2)
# Positive for inductance loads
@test impedance_q > 0
@test isapprox(impedance_q, 3.873; atol = 1e-3)
@info "Testing Generator Parsing"
@test get_status(get_component(ThermalStandard, sys, "generator-2438-ND")) == 0
@test get_available(get_component(ThermalStandard, sys, "generator-2438-ND")) == 0
@test get_status(get_component(ThermalStandard, sys, "generator-2438-EG")) == 1
@test get_available(get_component(ThermalStandard, sys, "generator-2438-EG")) == 1
sys3 = build_system(PSSEParsingTestSystems, "psse_ACTIVSg2000_sys")
sys4 = build_system(PSSEParsingTestSystems, "pti_frankenstein_70_sys")
base_dir = string(dirname(@__FILE__))
file_dir = joinpath(base_dir, "test_data", "5circuit_3w.raw")
sys5 = System(file_dir)
@info "Testing Three-Winding Transformer Parsing"
@test isnothing(get_component(Transformer3W, sys3, "1"))
@test haskey(
get_ext(get_component(Transformer2W, sys3, "DALLAS 1 3-DALLAS 1 0-i_1")),
"psse_name",
)
@test get_available(
get_component(Transformer3W, sys4, "FAV PLACE 07-FAV SPOT 06-FAV SPOT 03-i_1"),
) == true
tw3s = get_components(Transformer3W, sys4)
@test length(tw3s) == 1
tw3 = only(tw3s)
@test isapprox(get_b(tw3), 0.0036144)
@test get_primary_turns_ratio(tw3) == 1.5
@test get_rating(tw3) == 0.0
@test get_available(
get_component(Transformer3W, sys5, "FAV SPOT 01-FAV SPOT 02-FAV SPOT 03-i_A"),
) == false
@test get_r_primary(
get_component(Transformer3W, sys5, "FAV SPOT 01-FAV SPOT 02-FAV SPOT 03-i_C"),
) == 0.00225
@test haskey(
get_ext(
get_component(Transformer3W, sys5, "FAV SPOT 01-FAV SPOT 02-FAV SPOT 03-i_C"),
),
"psse_name",
)
@test length(get_components(Transformer3W, sys5)) == 5
@info "Testing Phase Shifting Three-Winding Transformer Parsing"
sys_pst3w = build_system(PSSEParsingTestSystems, "pti_case14_with_pst3w_sys")
pst3w_1, pst3w_2 = sort(
collect(get_components(PhaseShiftingTransformer3W, sys_pst3w)),
by = get_name,
)
@test get_available(pst3w_1) == true
@test get_available(pst3w_2) == true
@test isapprox(get_α_primary(pst3w_1), -0.5236; atol = 1e-4)
@test isapprox(get_α_secondary(pst3w_1), 2.6179; atol = 1e-4)
@test isapprox(get_α_tertiary(pst3w_1), -1.3962; atol = 1e-4)
@test isapprox(get_α_primary(pst3w_2), 1.0471; atol = 1e-4)
@test isapprox(get_α_secondary(pst3w_2), 0.0; atol = 1e-4)
@test isapprox(get_α_tertiary(pst3w_2), -2.0943; atol = 1e-4)
@test length(get_components(PhaseShiftingTransformer3W, sys_pst3w)) == 2
@info "Testing Switched Shunt Parsing"
@test get_available(get_component(SwitchedAdmittance, sys3, "1030-9")) == false
@test only(
get_Y_increase(get_component(SwitchedAdmittance, sys3, "3147-42")),
).im ==
0.35
@test get_admittance_limits(
get_component(SwitchedAdmittance, sys3, "3147-42"),
).min ==
1.03
@test only(
get_number_of_steps(
get_component(SwitchedAdmittance, sys3, "7075-119"),
),
) ==
1
@test only(
get_Y_increase(get_component(SwitchedAdmittance, sys3, "7075-119")),
).im ==
3.425
@test get_available(get_component(SwitchedAdmittance, sys4, "1005-2")) ==
true
@test get_Y(get_component(SwitchedAdmittance, sys4, "1005-2")) == 0.06im
@test get_admittance_limits(
get_component(SwitchedAdmittance, sys4, "1005-2"),
).max ==
1.045
@test only(
get_Y_increase(get_component(SwitchedAdmittance, sys4, "1005-2")),
).im == 0.06
@test length(get_components(SwitchedAdmittance, sys4)) == 2
@test get_available(get_component(SwitchedAdmittance, sys4, "1003-1")) ==
true
@test get_Y(get_component(SwitchedAdmittance, sys4, "1003-1")) == 0.038im
@test get_admittance_limits(
get_component(SwitchedAdmittance, sys4, "1003-1"),
).min ==
0.95
@info "Testing VSC Parser"
vsc = only(get_components(TwoTerminalVSCLine, sys4))
@test get_active_power_flow(vsc) == -0.2
@test get_dc_setpoint_to(vsc) == -20.0
@info "Testing Load Zone Formatter"
PSB.clear_serialized_systems("psse_Benchmark_4ger_33_2015_sys")
sys3 = build_system(
PSYTestSystems,
"psse_Benchmark_4ger_33_2015_sys";
loadzone_name_formatter = x -> string(3 * x),
)
lz_original = only(get_components(LoadZone, sys2))
lz_new = only(get_components(LoadZone, sys3))
@test parse(Int, get_name(lz_new)) == 3 * parse(Int, get_name(lz_original))
end
@testset "PSSE FACTS Control Devices Parsing" begin
sys = build_system(PSSEParsingTestSystems, "pti_case14_sys")
bus2 = get_component(ACBus, sys, "Bus 2 HV")
facts_1 = FACTSControlDevice(;
name = "FACTS 1",
available = true,
bus = bus2,
control_mode = 1,
max_shunt_current = 9999.0,
reactive_power_required = 100.0,
voltage_setpoint = 1.0,
)
add_component!(sys, facts_1)
facts = only(get_components(FACTSControlDevice, sys))
@test get_available(facts) == true
@test get_voltage_setpoint(facts) == 1.0
@test get_max_shunt_current(facts) == 9999.0
@test get_reactive_power_required(facts) > 0
@test get_control_mode(facts) == FACTSOperationModes.NML
end
@testset "PSSE Generators as Synchronous Condensers" begin
sys = build_system(PSSEParsingTestSystems, "pti_case11_with_synchronous_condensers_sys")
sc_gen1 = collect(get_components(SynchronousCondenser, sys))[1]
@test !hasproperty(sc_gen1, :active_power)
@test get_rating(sc_gen1) >= 0.0
@test get_reactive_power(sc_gen1) != 0.0
@test get_available(sc_gen1) == true
@test get_bustype(get_bus(sc_gen1)) == ACBusTypes.PV
end
@testset "PSSE Switches & Breakers Parsing" begin
sys = build_system(PSSEParsingTestSystems, "pti_case24_sys")
line1 = first(get_components(Line, sys))
sw_1 = DiscreteControlledACBranch(;
name = "SWITCH 1",
available = true,
arc = line1.arc,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
r = 0.0,
x = line1.x,
rating = line1.rating,
discrete_branch_type = 0,
branch_status = 1,
)
add_component!(sys, sw_1)
line2 = get_component(Line, sys, "15-16-i_1")
br_1 = DiscreteControlledACBranch(;
name = "BREAKER 1",
available = true,
arc = line2.arc,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
r = 0.0,
x = line2.x,
rating = line2.rating,
discrete_branch_type = 1,
branch_status = 1,
)
add_component!(sys, br_1)
line3 = get_component(Line, sys, "20-23-i_1")
otr_1 = DiscreteControlledACBranch(;
name = "OTHER 1",
available = true,
arc = line3.arc,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
r = line3.r,
x = line3.x,
rating = line3.rating,
discrete_branch_type = 2,
branch_status = 1,
)
add_component!(sys, otr_1)
switch = get_component(DiscreteControlledACBranch, sys, "SWITCH 1")
breaker = get_component(DiscreteControlledACBranch, sys, "BREAKER 1")
other = get_component(DiscreteControlledACBranch, sys, "OTHER 1")
@test get_available(switch) == true
@test get_available(breaker) == true
@test get_available(other) == true
@test get_discrete_branch_type(switch) == DiscreteControlledBranchType.SWITCH
@test get_discrete_branch_type(breaker) == DiscreteControlledBranchType.BREAKER
@test get_branch_status(switch) == DiscreteControlledBranchStatus.CLOSED
@test get_branch_status(other) == DiscreteControlledBranchStatus.CLOSED
end
@testset "PSSE default branch name counter" begin
sys = build_system(PSSEParsingTestSystems, "pti_case24_sys")
buses = collect(get_components(ACBus, sys))
bus_f = buses[1]
bus_t = buses[2]
branch_pair_counts = Dict{Tuple{String, String}, Int}()
d1 = Dict{String, Any}("source_id" => Any["transformer", 1, 2, 0, " 1", 0])
d2 = Dict{String, Any}("source_id" => Any["transformer", 1, 2, 0, "1 ", 0])
n1 =
PowerSystems._get_pm_branch_name_with_counter!(d1, bus_f, bus_t, branch_pair_counts)
n2 =
PowerSystems._get_pm_branch_name_with_counter!(d2, bus_f, bus_t, branch_pair_counts)
@test n1 != n2
@test endswith(n1, "-i_1")
@test endswith(n2, "-i_2")
end
@testset "PSSE LCC Parsing" begin
sys = build_system(PSSEParsingTestSystems, "pti_two_terminal_hvdc_test_sys")
lccs = get_components(TwoTerminalLCCLine, sys)
@test length(lccs) == 1
lcc = only(lccs)
@test get_transfer_setpoint(lcc) == 20.0
@test get_active_power_flow(lcc) == 0.2
@test isapprox(get_rectifier_delay_angle_limits(lcc).max, pi / 2)
@test isapprox(get_inverter_extinction_angle_limits(lcc).max, pi / 2)
@test get_power_mode(lcc)
end
@testset "PSSE Impedance Correction Table Parsing" begin
base_dir = string(dirname(@__FILE__))
file_dir = joinpath(base_dir, "test_data", "modified_14bus_system.raw")
sys = System(file_dir)
tr2w_1 = get_component(Transformer2W, sys, "BUS 110-BUS 109-i_1")
suppl_attr_tr2w_1 = only(get_supplemental_attributes(tr2w_1))
@test get_table_number(suppl_attr_tr2w_1) == 3
@test get_points(get_impedance_correction_curve(suppl_attr_tr2w_1))[1] ==
(x = -24.1, y = 1.27)
@test get_points(get_impedance_correction_curve(suppl_attr_tr2w_1))[end] ==
(x = 24.1, y = 1.27)
@test get_transformer_winding(suppl_attr_tr2w_1) == WindingCategory.TR2W_WINDING
@test get_transformer_control_mode(suppl_attr_tr2w_1) ==
ImpedanceCorrectionTransformerControlMode.PHASE_SHIFT_ANGLE
tr2w_2 = get_component(Transformer2W, sys, "BUS 109-BUS 104-i_1")
suppl_attr_tr2w_2 = only(get_supplemental_attributes(tr2w_2))
@test get_table_number(suppl_attr_tr2w_2) == 4
@test get_points(get_impedance_correction_curve(suppl_attr_tr2w_2))[1] ==
(x = 0.88, y = 1.093)
@test get_points(get_impedance_correction_curve(suppl_attr_tr2w_2))[end] ==
(x = 1.17, y = 0.916)
@test get_transformer_winding(suppl_attr_tr2w_2) == WindingCategory.TR2W_WINDING
@test get_transformer_control_mode(suppl_attr_tr2w_2) ==
ImpedanceCorrectionTransformerControlMode.TAP_RATIO
tr2w_3 = get_component(Transformer2W, sys, "BUS 106-BUS 105-i_1")
suppl_attr_tr2w_3 = only(get_supplemental_attributes(tr2w_3))
@test get_table_number(suppl_attr_tr2w_3) == 7
@test get_points(get_impedance_correction_curve(suppl_attr_tr2w_3))[1] ==
(x = -45.0, y = 2.073)
@test get_points(get_impedance_correction_curve(suppl_attr_tr2w_3))[end] ==
(x = 45.0, y = 2.073)
@test get_transformer_winding(suppl_attr_tr2w_3) == WindingCategory.TR2W_WINDING
@test get_transformer_control_mode(suppl_attr_tr2w_3) ==
ImpedanceCorrectionTransformerControlMode.PHASE_SHIFT_ANGLE
tr3w_1 = get_component(Transformer3W, sys, "BUS 109-BUS 104-BUS 107-i_1")
suppl_attr_tr3w_1 = collect(get_supplemental_attributes(tr3w_1))
filtered_tertiary_tr3w_1 = only(
filter(
x -> get_transformer_winding(x) == WindingCategory.TERTIARY_WINDING,
suppl_attr_tr3w_1,
),
)
@test get_table_number(filtered_tertiary_tr3w_1) == 4
@test get_points(get_impedance_correction_curve(filtered_tertiary_tr3w_1))[1] ==
(x = 0.88, y = 1.093)
@test get_points(get_impedance_correction_curve(filtered_tertiary_tr3w_1))[end] ==
(x = 1.17, y = 0.916)
@test get_transformer_control_mode(filtered_tertiary_tr3w_1) ==
ImpedanceCorrectionTransformerControlMode.TAP_RATIO
filtered_secondary_tr3w_2 = only(
filter(
x -> get_transformer_winding(x) == WindingCategory.SECONDARY_WINDING,
suppl_attr_tr3w_1,
),
)
@test get_table_number(filtered_secondary_tr3w_2) == 8
@test get_points(get_impedance_correction_curve(filtered_secondary_tr3w_2))[1] ==
(x = -60.0, y = 1.5718)
@test get_points(get_impedance_correction_curve(filtered_secondary_tr3w_2))[end] ==
(x = 60.0, y = 1.5718)
@test get_transformer_control_mode(filtered_secondary_tr3w_2) ==
ImpedanceCorrectionTransformerControlMode.PHASE_SHIFT_ANGLE
tr3w_2 = get_component(Transformer3W, sys, "BUS 113-BUS 110-BUS 114-i_1")
suppl_attr_tr3w_2 = collect(get_supplemental_attributes(tr3w_2))
filtered_primary_tr3w_2 = only(
filter(
x -> get_transformer_winding(x) == WindingCategory.PRIMARY_WINDING,
suppl_attr_tr3w_2,
),
)
@test get_table_number(filtered_primary_tr3w_2) == 9
@test get_points(get_impedance_correction_curve(filtered_primary_tr3w_2))[1] ==
(x = -40.0, y = 1.4)
@test get_points(get_impedance_correction_curve(filtered_primary_tr3w_2))[end] ==
(x = 40.0, y = 1.4)
@test get_transformer_control_mode(filtered_primary_tr3w_2) ==
ImpedanceCorrectionTransformerControlMode.PHASE_SHIFT_ANGLE
end
@testset "PSSE System Serialization/Desearialization" begin
original_sys =
build_system(PSSEParsingTestSystems, "pti_case30_sys"; force_build = true)
serialize_sys_path = joinpath(tempdir(), "test_system.json")
to_json(original_sys, serialize_sys_path; force = true)
deserialized_sys = System(serialize_sys_path)
@test get_base_power(original_sys) == get_base_power(deserialized_sys)
@test get_frequency(original_sys) == get_frequency(deserialized_sys)
@test get_num_components(original_sys) ==
get_num_components(deserialized_sys)
gen1_names = sort(get_name.(get_components(ThermalStandard, original_sys)))
gen2_names = sort(get_name.(get_components(ThermalStandard, deserialized_sys)))
@test gen1_names == gen2_names
sa1_y = get_Y.(get_components(SwitchedAdmittance, original_sys))
sa2_y = get_Y.(get_components(SwitchedAdmittance, deserialized_sys))
@test sa1_y == sa2_y
@test IS.compare_values(original_sys, deserialized_sys)
end
@testset "PSSE transformer tap position correction testing" begin
sys = build_system(
PSSEParsingTestSystems,
"psse_14_tap_correction_test_system";
force_build = true,
)
#test 2W correction matches PSSE
trf = get_component(TapTransformer, sys, "BUS 104-BUS 107-i_1")
tap = get_tap(trf)
@test isapprox(tap, 0.979937; atol = 1e-6)
#test 3W correction matches PSSE
trf_3w = get_component(Transformer3W, sys, "BUS 109-BUS 104-BUS 107-i_1")
tap1 = get_primary_turns_ratio(trf_3w)
tap2 = get_secondary_turns_ratio(trf_3w)
tap3 = get_tertiary_turns_ratio(trf_3w)
@test isapprox(tap1, 0.98750; atol = 1e-6)
@test isapprox(tap2, 0.97500; atol = 1e-6)
@test isapprox(tap3, 0.96250; atol = 1e-6)
sys2 = build_system(
PSSEParsingTestSystems,
"pti_case8_voltage_winding_correction_sys";
force_build = true,
)
trf_3w_v = get_component(Transformer3W, sys2, "NODE F-NODE G-NODE D-i_1")
@test get_available_primary(trf_3w_v) == true
@test get_available_secondary(trf_3w_v) == true
@test get_available_tertiary(trf_3w_v) == true
#test 3W correction matches PSSE
tap1 = get_primary_turns_ratio(trf_3w_v)
tap2 = get_secondary_turns_ratio(trf_3w_v)
tap3 = get_tertiary_turns_ratio(trf_3w_v)
@test isapprox(tap1, 0.988; atol = 1e-6)
@test isapprox(tap2, 0.9807518; atol = 1e-6)
@test isapprox(tap3, 0.992; atol = 1e-6)
sys3 = build_system(
PSSEParsingTestSystems,
"pti_case10_voltage_winding_correction_sys";
force_build = true,
)
trf_3w_v1 = get_component(Transformer3W, sys3, "BUS 108-BUS 110-BUS 109-i_1")
tap1 = get_primary_turns_ratio(trf_3w_v1)
tap2 = get_secondary_turns_ratio(trf_3w_v1)
tap3 = get_tertiary_turns_ratio(trf_3w_v1)
@test isapprox(tap1, 1.05; atol = 1e-6)
@test isapprox(tap2, 0.956; atol = 1e-6)
@test isapprox(tap3, 0.95625; atol = 1e-6)
trf_3w_v2 = get_component(Transformer3W, sys3, "BUS 104-BUS 109-BUS 111-i_1")
tap1 = get_primary_turns_ratio(trf_3w_v2)
tap2 = get_secondary_turns_ratio(trf_3w_v2)
tap3 = get_tertiary_turns_ratio(trf_3w_v2)
@test isapprox(tap1, 1.0; atol = 1e-6)
@test isapprox(tap2, 1.0; atol = 1e-6)
@test isapprox(tap3, 1.0; atol = 1e-6)
trf_3w_v3 = get_component(Transformer3W, sys3, "BUS 102-BUS 104-BUS 103-i_1")
tap1 = get_primary_turns_ratio(trf_3w_v3)
tap2 = get_secondary_turns_ratio(trf_3w_v3)
tap3 = get_tertiary_turns_ratio(trf_3w_v3)
@test isapprox(tap1, 1.0250; atol = 1e-6)
@test isapprox(tap2, 0.9256; atol = 1e-6)
@test isapprox(tap3, 0.9150; atol = 1e-6)
end
@testset "PSSE isolated bus handling (unavailable vs topologically isolated)" begin
sys = @test_logs (:error,) min_level = Logging.Error match_mode = :any build_system(
PSSEParsingTestSystems,
"isolated_bus_test_system";
force_build = true,
)
@test length(get_components(x -> get_available(x), ACBus, sys)) == 2 #Bus 1 and 2
@test length(get_components(x -> get_available(x), StandardLoad, sys)) == 1 # Load at Bus 2
@test length(get_components(x -> get_available(x), SwitchedAdmittance, sys)) == 0
@test length(get_components(x -> get_available(x), Generator, sys)) == 2 #Gens at Bus 1 and 2
@test length(get_components(x -> get_available(x), Branch, sys)) == 1
@test length(get_components(x -> get_available(x), TapTransformer, sys)) == 0
@test length(get_components(x -> get_bustype(x) == ACBusTypes.ISOLATED, ACBus, sys)) ==
14
@test length(get_components(x -> get_bustype(x) == ACBusTypes.REF, ACBus, sys)) == 1
@test length(get_components(x -> get_bustype(x) == ACBusTypes.PV, ACBus, sys)) == 1
@test length(get_components(x -> get_bustype(x) == ACBusTypes.PQ, ACBus, sys)) == 0
end
@testset "Test PSSE interruptible loads parsing" begin
sys = build_system(
PSSEParsingTestSystems,
"pti_case14_with_interruptible_loads_sys";
force_build = true,
)
all_isl = collect(get_components(InterruptibleStandardLoad, sys))
sort!(all_isl, by = get_name)
isl = first(all_isl) # should be named "load10LD"
@test length(all_isl) == 4
@test get_available(isl) == true
@test isl isa InterruptibleStandardLoad
@test get_constant_active_power(isl) == 0.11485
@test get_max_active_power(isl) == 0.11485
end
@testset "Test conversion zero impedance branch to switch" begin
sys = build_system(
PSSEParsingTestSystems,
"psse_14_zero_impedance_branch_test_system";
force_build = true,
)
@test length(get_components(DiscreteControlledACBranch, sys)) == 6
@test length(
get_components(x -> get_r(x) == get_x(x) == 0.0, DiscreteControlledACBranch, sys),
) == 4
end
@testset "Test threshold setting for zero impedance 3WT winding" begin
sys = build_system(
PSSEParsingTestSystems,
"psse_4_zero_impedance_3wt_test_system";
force_build = true,
)
trf_3w = collect(get_components(Transformer3W, sys))[1]
@test get_available(trf_3w) == true
@test get_available_tertiary(trf_3w) == true
@test get_x_tertiary(trf_3w) == 1e-4
end
@testset "Test GeoJSON RFC 7946 Compliance" begin
# Test that GeographicInfo uses proper GeoJSON Point format
# According to RFC 7946, section 3.1.2, a Point should have:
# {"type": "Point", "coordinates": [longitude, latitude]}
# Create a simple test using the common.jl helper
sys = System(100.0)
bus1 = ACBus(;
number = 1,
name = "test_bus",
available = true,
bustype = ACBusTypes.REF,
angle = 0.0,
magnitude = 1.0,
voltage_limits = (min = 0.9, max = 1.1),
base_voltage = 230.0,
)
add_component!(sys, bus1)
# Create GeographicInfo with proper GeoJSON format
geo = IS.GeographicInfo(;
geo_json = Dict("type" => "Point", "coordinates" => [-105.0, 40.0]),
)
add_supplemental_attribute!(sys, bus1, geo)
# Retrieve and verify the GeoJSON format
geo_attrs = get_supplemental_attributes(IS.GeographicInfo, sys)
@test length(geo_attrs) == 1
retrieved_geo = first(geo_attrs)
geo_json = IS.get_geo_json(retrieved_geo)
# Verify RFC 7946 compliance
@test haskey(geo_json, "type")
@test geo_json["type"] == "Point"
@test haskey(geo_json, "coordinates")
@test isa(geo_json["coordinates"], Vector)
@test length(geo_json["coordinates"]) == 2
@test geo_json["coordinates"][1] == -105.0 # longitude
@test geo_json["coordinates"][2] == 40.0 # latitude
# Verify old format is NOT present
@test !haskey(geo_json, "x")
@test !haskey(geo_json, "y")
end
================================================
FILE: test/test_plant_attributes.jl
================================================
using Test
using PowerSystems
using InfrastructureSystems
import InfrastructureSystems as IS
import JSON3
import PowerSystemCaseBuilder as PSB
const PSY = PowerSystems
include("common.jl")
@testset "Test plant attributes" begin
@testset "ThermalPowerPlant construction and basic accessors" begin
plant = ThermalPowerPlant(name = "Coal Plant A")
@test get_name(plant) == "Coal Plant A"
end
@testset "HydroPowerPlant construction and basic accessors" begin
plant = HydroPowerPlant(name = "Hydro Dam 1")
@test get_name(plant) == "Hydro Dam 1"
end
@testset "RenewablePowerPlant construction and basic accessors" begin
plant = RenewablePowerPlant(name = "Wind Farm A")
@test get_name(plant) == "Wind Farm A"
end
@testset "CombinedCycleBlock construction and basic accessors" begin
cc_block = CombinedCycleBlock(
name = "CC Block 1",
configuration = CombinedCycleConfiguration.SingleShaftCombustionSteam,
heat_recovery_to_steam_factor = 0.85,
)
@test get_name(cc_block) == "CC Block 1"
@test get_configuration(cc_block) ==
CombinedCycleConfiguration.SingleShaftCombustionSteam
@test get_heat_recovery_to_steam_factor(cc_block) == 0.85
end
@testset "Add and remove ThermalGen to/from ThermalPowerPlant" begin
sys = System(100.0)
# Create buses
bus1 = ACBus(nothing)
bus1.name = "bus1"
bus1.number = 1
bus1.bustype = ACBusTypes.REF
add_component!(sys, bus1)
bus2 = ACBus(nothing)
bus2.name = "bus2"
bus2.number = 2
add_component!(sys, bus2)
# Create thermal generators
gen1 = ThermalStandard(nothing)
gen1.bus = bus1
gen1.name = "thermal_gen1"
add_component!(sys, gen1)
gen2 = ThermalStandard(nothing)
gen2.bus = bus2
gen2.name = "thermal_gen2"
add_component!(sys, gen2)
# Create thermal power plant
plant = ThermalPowerPlant(name = "Coal Plant")
# Add generators to plant with shaft numbers
add_supplemental_attribute!(sys, gen1, plant; shaft_number = 1)
add_supplemental_attribute!(sys, gen2, plant; shaft_number = 2)
# Verify shaft mappings
shaft_map = get_shaft_map(plant)
@test length(shaft_map) == 2
@test length(shaft_map[1]) == 1
@test length(shaft_map[2]) == 1
@test shaft_map[1][1] == IS.get_uuid(gen1)
@test shaft_map[2][1] == IS.get_uuid(gen2)
# Verify reverse mappings
reverse_map = get_reverse_shaft_map(plant)
@test reverse_map[IS.get_uuid(gen1)] == 1
@test reverse_map[IS.get_uuid(gen2)] == 2
# Verify supplemental attributes are attached
@test has_supplemental_attributes(gen1)
@test has_supplemental_attributes(gen2)
attrs1 = get_supplemental_attributes(ThermalPowerPlant, gen1)
@test length(collect(attrs1)) == 1
@test collect(attrs1)[1] == plant
# Test multiple generators on same shaft
gen3 = ThermalStandard(nothing)
gen3.bus = bus1
gen3.name = "thermal_gen3"
add_component!(sys, gen3)
add_supplemental_attribute!(sys, gen3, plant; shaft_number = 1)
@test length(shaft_map[1]) == 2
@test shaft_map[1][2] == IS.get_uuid(gen3)
# Remove generator from plant
remove_supplemental_attribute!(sys, gen1, plant)
@test !haskey(reverse_map, IS.get_uuid(gen1))
@test length(shaft_map[1]) == 1
@test shaft_map[1][1] == IS.get_uuid(gen3)
# Remove last generator from shaft
remove_supplemental_attribute!(sys, gen3, plant)
@test !haskey(shaft_map, 1)
@test !haskey(reverse_map, IS.get_uuid(gen3))
# Test error when removing non-existent generator
@test_throws IS.ArgumentError remove_supplemental_attribute!(sys, gen1, plant)
end
@testset "Get components in shaft" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
# Create thermal generators
gen1 = ThermalStandard(nothing)
gen1.bus = bus
gen1.name = "gen1"
add_component!(sys, gen1)
gen2 = ThermalStandard(nothing)
gen2.bus = bus
gen2.name = "gen2"
add_component!(sys, gen2)
gen3 = ThermalStandard(nothing)
gen3.bus = bus
gen3.name = "gen3"
add_component!(sys, gen3)
# Create plant with generators on different shafts
plant = ThermalPowerPlant(name = "Test Plant")
add_supplemental_attribute!(sys, gen1, plant; shaft_number = 1)
add_supplemental_attribute!(sys, gen2, plant; shaft_number = 1)
add_supplemental_attribute!(sys, gen3, plant; shaft_number = 2)
# Test getting components in shaft 1
shaft1_components = get_components_in_shaft(sys, plant, 1)
@test length(shaft1_components) == 2
shaft1_names = Set([get_name(c) for c in shaft1_components])
@test "gen1" in shaft1_names
@test "gen2" in shaft1_names
# Test getting components in shaft 2
shaft2_components = get_components_in_shaft(sys, plant, 2)
@test length(shaft2_components) == 1
@test get_name(shaft2_components[1]) == "gen3"
# Test error for non-existent shaft
@test_throws IS.ArgumentError get_components_in_shaft(sys, plant, 99)
end
@testset "Get components in penstock" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
# Create hydro generators
turb1 = HydroTurbine(nothing)
turb1.bus = bus
turb1.name = "turb1"
add_component!(sys, turb1)
turb2 = HydroTurbine(nothing)
turb2.bus = bus
turb2.name = "turb2"
add_component!(sys, turb2)
pump = HydroPumpTurbine(nothing)
pump.bus = bus
pump.name = "pump1"
add_component!(sys, pump)
# Create plant with generators on different penstocks
plant = HydroPowerPlant(name = "Hydro Plant")
add_supplemental_attribute!(sys, turb1, plant, 1)
add_supplemental_attribute!(sys, turb2, plant, 1)
add_supplemental_attribute!(sys, pump, plant, 2)
# Test getting components in penstock 1
penstock1_components = get_components_in_penstock(sys, plant, 1)
@test length(penstock1_components) == 2
penstock1_names = Set([get_name(c) for c in penstock1_components])
@test "turb1" in penstock1_names
@test "turb2" in penstock1_names
# Test getting components in penstock 2
penstock2_components = get_components_in_penstock(sys, plant, 2)
@test length(penstock2_components) == 1
@test get_name(penstock2_components[1]) == "pump1"
# Test error for non-existent penstock
@test_throws IS.ArgumentError get_components_in_penstock(sys, plant, 99)
end
@testset "Get components in PCC" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
# Create renewable generators and storage
wind1 = RenewableDispatch(nothing)
wind1.bus = bus
wind1.name = "wind1"
add_component!(sys, wind1)
solar = RenewableNonDispatch(nothing)
solar.bus = bus
solar.name = "solar1"
add_component!(sys, solar)
battery = EnergyReservoirStorage(nothing)
battery.bus = bus
battery.name = "battery1"
add_component!(sys, battery)
# Create plant with components on different PCCs
plant = RenewablePowerPlant(name = "Renewable Plant")
add_supplemental_attribute!(sys, wind1, plant, 1)
add_supplemental_attribute!(sys, battery, plant, 1)
add_supplemental_attribute!(sys, solar, plant, 2)
# Test getting components in PCC 1
pcc1_components = get_components_in_pcc(sys, plant, 1)
@test length(pcc1_components) == 2
pcc1_names = Set([get_name(c) for c in pcc1_components])
@test "wind1" in pcc1_names
@test "battery1" in pcc1_names
# Test getting components in PCC 2
pcc2_components = get_components_in_pcc(sys, plant, 2)
@test length(pcc2_components) == 1
@test get_name(pcc2_components[1]) == "solar1"
# Test error for non-existent PCC
@test_throws IS.ArgumentError get_components_in_pcc(sys, plant, 99)
end
@testset "Add and remove HydroGen to/from HydroPowerPlant" begin
sys = System(100.0)
# Create buses
bus1 = ACBus(nothing)
bus1.name = "bus1"
bus1.number = 1
bus1.bustype = ACBusTypes.REF
add_component!(sys, bus1)
bus2 = ACBus(nothing)
bus2.name = "bus2"
bus2.number = 2
add_component!(sys, bus2)
# Create hydro generators
gen1 = HydroTurbine(nothing)
gen1.bus = bus1
gen1.name = "hydro_gen1"
add_component!(sys, gen1)
gen2 = HydroPumpTurbine(nothing)
gen2.bus = bus2
gen2.name = "hydro_gen2"
add_component!(sys, gen2)
# Create hydro power plant
plant = HydroPowerPlant(name = "Hydro Dam")
# Add generators to plant with penstock numbers
add_supplemental_attribute!(sys, gen1, plant, 1)
add_supplemental_attribute!(sys, gen2, plant, 2)
# Verify penstock mappings
penstock_map = get_penstock_map(plant)
@test length(penstock_map) == 2
@test penstock_map[1][1] == IS.get_uuid(gen1)
@test penstock_map[2][1] == IS.get_uuid(gen2)
# Verify reverse mappings
reverse_map = get_reverse_penstock_map(plant)
@test reverse_map[IS.get_uuid(gen1)] == 1
@test reverse_map[IS.get_uuid(gen2)] == 2
# Remove generator from plant
remove_supplemental_attribute!(sys, gen1, plant)
@test !haskey(reverse_map, IS.get_uuid(gen1))
@test !haskey(penstock_map, 1)
# Test error for HydroDispatch
hydro_dispatch = HydroDispatch(nothing)
hydro_dispatch.bus = bus1
hydro_dispatch.name = "hydro_dispatch"
add_component!(sys, hydro_dispatch)
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys,
hydro_dispatch,
plant,
1,
)
end
@testset "Add and remove RenewableGen to/from RenewablePowerPlant" begin
sys = System(100.0)
# Create buses
bus1 = ACBus(nothing)
bus1.name = "bus1"
bus1.number = 1
bus1.bustype = ACBusTypes.REF
add_component!(sys, bus1)
bus2 = ACBus(nothing)
bus2.name = "bus2"
bus2.number = 2
add_component!(sys, bus2)
# Create renewable generators
gen1 = RenewableDispatch(nothing)
gen1.bus = bus1
gen1.name = "wind_gen1"
add_component!(sys, gen1)
gen2 = RenewableNonDispatch(nothing)
gen2.bus = bus2
gen2.name = "solar_gen2"
add_component!(sys, gen2)
# Create storage
storage = EnergyReservoirStorage(nothing)
storage.bus = bus1
storage.name = "battery1"
add_component!(sys, storage)
# Create renewable power plant
plant = RenewablePowerPlant(name = "Renewable Farm")
# Add generators to plant with PCC numbers
add_supplemental_attribute!(sys, gen1, plant, 1)
add_supplemental_attribute!(sys, gen2, plant, 2)
add_supplemental_attribute!(sys, storage, plant, 1)
# Verify PCC mappings
pcc_map = get_pcc_map(plant)
@test length(pcc_map) == 2
@test length(pcc_map[1]) == 2 # gen1 and storage on same PCC
@test length(pcc_map[2]) == 1
@test IS.get_uuid(gen1) in pcc_map[1]
@test IS.get_uuid(storage) in pcc_map[1]
@test pcc_map[2][1] == IS.get_uuid(gen2)
# Verify reverse mappings
reverse_map = get_reverse_pcc_map(plant)
@test reverse_map[IS.get_uuid(gen1)] == 1
@test reverse_map[IS.get_uuid(gen2)] == 2
@test reverse_map[IS.get_uuid(storage)] == 1
# Remove generator from plant
remove_supplemental_attribute!(sys, gen1, plant)
@test !haskey(reverse_map, IS.get_uuid(gen1))
@test length(pcc_map[1]) == 1
@test pcc_map[1][1] == IS.get_uuid(storage)
# Remove storage
remove_supplemental_attribute!(sys, storage, plant)
@test !haskey(pcc_map, 1)
@test !haskey(reverse_map, IS.get_uuid(storage))
end
@testset "Serialization and deserialization of ThermalPowerPlant" begin
sys = System(100.0)
# Create bus and generator
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen1 = ThermalStandard(nothing)
gen1.bus = bus
gen1.name = "thermal_gen1"
add_component!(sys, gen1)
gen2 = ThermalStandard(nothing)
gen2.bus = bus
gen2.name = "thermal_gen2"
add_component!(sys, gen2)
# Create and add plant
plant = ThermalPowerPlant(name = "Coal Plant")
add_supplemental_attribute!(sys, gen1, plant; shaft_number = 1)
add_supplemental_attribute!(sys, gen2, plant; shaft_number = 2)
# Serialize and deserialize
sys2, result = validate_serialization(sys)
@test result
# Verify plant is preserved
gen1_restored = get_component(ThermalStandard, sys2, "thermal_gen1")
gen2_restored = get_component(ThermalStandard, sys2, "thermal_gen2")
@test has_supplemental_attributes(gen1_restored)
@test has_supplemental_attributes(gen2_restored)
attrs = get_supplemental_attributes(ThermalPowerPlant, gen1_restored)
plant_restored = collect(attrs)[1]
@test get_name(plant_restored) == "Coal Plant"
# Verify mappings are preserved
shaft_map = get_shaft_map(plant_restored)
reverse_map = get_reverse_shaft_map(plant_restored)
@test length(shaft_map) == 2
@test length(reverse_map) == 2
@test reverse_map[IS.get_uuid(gen1_restored)] == 1
@test reverse_map[IS.get_uuid(gen2_restored)] == 2
end
@testset "Serialization and deserialization of HydroPowerPlant" begin
sys = System(100.0)
# Create bus and generator
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen1 = HydroTurbine(nothing)
gen1.bus = bus
gen1.name = "hydro_gen1"
add_component!(sys, gen1)
gen2 = HydroTurbine(nothing)
gen2.bus = bus
gen2.name = "hydro_gen2"
add_component!(sys, gen2)
# Create and add plant
plant = HydroPowerPlant(name = "Hydro Dam")
add_supplemental_attribute!(sys, gen1, plant, 1)
add_supplemental_attribute!(sys, gen2, plant, 2)
# Serialize and deserialize
sys2, result = validate_serialization(sys)
@test result
# Verify plant is preserved
gen1_restored = get_component(HydroTurbine, sys2, "hydro_gen1")
attrs = get_supplemental_attributes(HydroPowerPlant, gen1_restored)
plant_restored = collect(attrs)[1]
@test get_name(plant_restored) == "Hydro Dam"
# Verify mappings are preserved
penstock_map = get_penstock_map(plant_restored)
reverse_map = get_reverse_penstock_map(plant_restored)
@test length(penstock_map) == 2
@test length(reverse_map) == 2
end
@testset "Serialization and deserialization of RenewablePowerPlant" begin
sys = System(100.0)
# Create bus and generator
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen1 = RenewableDispatch(nothing)
gen1.bus = bus
gen1.name = "wind_gen1"
add_component!(sys, gen1)
storage = EnergyReservoirStorage(nothing)
storage.bus = bus
storage.name = "battery1"
add_component!(sys, storage)
# Create and add plant
plant = RenewablePowerPlant(name = "Wind Farm")
add_supplemental_attribute!(sys, gen1, plant, 1)
add_supplemental_attribute!(sys, storage, plant, 1)
# Serialize and deserialize
sys2, result = validate_serialization(sys)
@test result
# Verify plant is preserved
gen1_restored = get_component(RenewableDispatch, sys2, "wind_gen1")
attrs = get_supplemental_attributes(RenewablePowerPlant, gen1_restored)
plant_restored = collect(attrs)[1]
@test get_name(plant_restored) == "Wind Farm"
# Verify mappings are preserved
pcc_map = get_pcc_map(plant_restored)
reverse_map = get_reverse_pcc_map(plant_restored)
@test length(pcc_map) == 1
@test length(pcc_map[1]) == 2 # Both generator and storage on same PCC
@test length(reverse_map) == 2
end
@testset "Add and remove ThermalGen to/from CombinedCycleBlock" begin
sys = System(100.0)
bus1 = ACBus(nothing)
bus1.name = "bus1"
bus1.number = 1
bus1.bustype = ACBusTypes.REF
add_component!(sys, bus1)
bus2 = ACBus(nothing)
bus2.name = "bus2"
bus2.number = 2
add_component!(sys, bus2)
# Create thermal generators with appropriate prime mover types
ct_gen = ThermalStandard(nothing)
ct_gen.bus = bus1
ct_gen.name = "ct_gen1"
ct_gen.prime_mover_type = PrimeMovers.CT
add_component!(sys, ct_gen)
ca_gen = ThermalStandard(nothing)
ca_gen.bus = bus2
ca_gen.name = "ca_gen1"
ca_gen.prime_mover_type = PrimeMovers.CA
add_component!(sys, ca_gen)
# Create combined cycle block
cc_block = CombinedCycleBlock(
name = "CC Block 1",
configuration = CombinedCycleConfiguration.SeparateShaftCombustionSteam,
heat_recovery_to_steam_factor = 0.75,
)
# Add generators with HRSG numbers (prime mover type is read from component)
add_supplemental_attribute!(
sys, ct_gen, cc_block; hrsg_number = 1,
)
add_supplemental_attribute!(
sys, ca_gen, cc_block; hrsg_number = 1,
)
# Verify HRSG CT mappings
hrsg_ct_map = get_hrsg_ct_map(cc_block)
@test length(hrsg_ct_map) == 1
@test length(hrsg_ct_map[1]) == 1
@test hrsg_ct_map[1][1] == IS.get_uuid(ct_gen)
# Verify HRSG CA mappings
hrsg_ca_map = get_hrsg_ca_map(cc_block)
@test length(hrsg_ca_map) == 1
@test length(hrsg_ca_map[1]) == 1
@test hrsg_ca_map[1][1] == IS.get_uuid(ca_gen)
# Verify reverse CT mapping
ct_hrsg_map = get_ct_hrsg_map(cc_block)
@test ct_hrsg_map[IS.get_uuid(ct_gen)] == [1]
# Verify reverse CA mapping
ca_hrsg_map = get_ca_hrsg_map(cc_block)
@test ca_hrsg_map[IS.get_uuid(ca_gen)] == [1]
# Verify supplemental attributes are attached
@test has_supplemental_attributes(ct_gen)
@test has_supplemental_attributes(ca_gen)
# Test multiple CTs on same HRSG
ct_gen2 = ThermalStandard(nothing)
ct_gen2.bus = bus1
ct_gen2.name = "ct_gen2"
ct_gen2.prime_mover_type = PrimeMovers.CT
add_component!(sys, ct_gen2)
add_supplemental_attribute!(
sys, ct_gen2, cc_block; hrsg_number = 1,
)
@test length(hrsg_ct_map[1]) == 2
@test hrsg_ct_map[1][2] == IS.get_uuid(ct_gen2)
# Remove generator from block
remove_supplemental_attribute!(sys, ct_gen, cc_block)
@test !haskey(ct_hrsg_map, IS.get_uuid(ct_gen))
@test length(hrsg_ct_map[1]) == 1
@test hrsg_ct_map[1][1] == IS.get_uuid(ct_gen2)
# Remove last CT generator from HRSG 1
remove_supplemental_attribute!(sys, ct_gen2, cc_block)
@test !haskey(hrsg_ct_map, 1)
@test !haskey(ct_hrsg_map, IS.get_uuid(ct_gen2))
# Test error when removing non-existent generator
@test_throws IS.ArgumentError remove_supplemental_attribute!(
sys, ct_gen, cc_block,
)
end
@testset "CombinedCycleBlock rejects invalid PrimeMover types" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
cc_block = CombinedCycleBlock(
name = "CC Block Invalid",
configuration = CombinedCycleConfiguration.SingleShaftCombustionSteam,
)
# Invalid prime mover types should throw (only CT and CA are valid)
for (i, pm) in enumerate([
PrimeMovers.GT,
PrimeMovers.ST,
PrimeMovers.WT,
PrimeMovers.CC,
PrimeMovers.CS,
])
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen_invalid_$i"
gen.prime_mover_type = pm
add_component!(sys, gen)
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys, gen, cc_block; hrsg_number = 1,
)
end
# Valid prime mover types should not throw (CT and CA only)
ct_gen = ThermalStandard(nothing)
ct_gen.bus = bus
ct_gen.name = "gen_ct"
ct_gen.prime_mover_type = PrimeMovers.CT
add_component!(sys, ct_gen)
add_supplemental_attribute!(
sys, ct_gen, cc_block; hrsg_number = 1,
)
ca_gen = ThermalStandard(nothing)
ca_gen.bus = bus
ca_gen.name = "gen_ca"
ca_gen.prime_mover_type = PrimeMovers.CA
add_component!(sys, ca_gen)
add_supplemental_attribute!(
sys, ca_gen, cc_block; hrsg_number = 1,
)
@test length(get_hrsg_ct_map(cc_block)) == 1
@test length(get_hrsg_ca_map(cc_block)) == 1
end
@testset "Serialization and deserialization of CombinedCycleBlock" begin
sys = System(100.0)
# Create bus and generators with appropriate prime mover types
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
ct_gen = ThermalStandard(nothing)
ct_gen.bus = bus
ct_gen.name = "cc_ct_gen1"
ct_gen.prime_mover_type = PrimeMovers.CT
add_component!(sys, ct_gen)
ca_gen = ThermalStandard(nothing)
ca_gen.bus = bus
ca_gen.name = "cc_ca_gen1"
ca_gen.prime_mover_type = PrimeMovers.CA
add_component!(sys, ca_gen)
# Create and add combined cycle block with HRSG mappings
cc_block = CombinedCycleBlock(
name = "CC Block 1",
configuration = CombinedCycleConfiguration.SeparateShaftCombustionSteam,
heat_recovery_to_steam_factor = 0.75,
)
add_supplemental_attribute!(
sys, ct_gen, cc_block; hrsg_number = 1,
)
add_supplemental_attribute!(
sys, ca_gen, cc_block; hrsg_number = 1,
)
# Serialize and deserialize
sys2, result = validate_serialization(sys)
@test result
# Verify block is preserved
ct_gen_restored = get_component(ThermalStandard, sys2, "cc_ct_gen1")
@test has_supplemental_attributes(ct_gen_restored)
attrs = get_supplemental_attributes(CombinedCycleBlock, ct_gen_restored)
cc_block_restored = collect(attrs)[1]
@test get_name(cc_block_restored) == "CC Block 1"
@test get_configuration(cc_block_restored) ==
CombinedCycleConfiguration.SeparateShaftCombustionSteam
@test get_heat_recovery_to_steam_factor(cc_block_restored) == 0.75
# Verify HRSG mappings are preserved
hrsg_ct_map = get_hrsg_ct_map(cc_block_restored)
hrsg_ca_map = get_hrsg_ca_map(cc_block_restored)
ct_hrsg_map = get_ct_hrsg_map(cc_block_restored)
ca_hrsg_map = get_ca_hrsg_map(cc_block_restored)
@test length(hrsg_ct_map) == 1
@test length(hrsg_ca_map) == 1
@test length(ct_hrsg_map) == 1
@test length(ca_hrsg_map) == 1
ct_gen_restored_uuid = IS.get_uuid(ct_gen_restored)
ca_gen_restored = get_component(ThermalStandard, sys2, "cc_ca_gen1")
ca_gen_restored_uuid = IS.get_uuid(ca_gen_restored)
@test ct_hrsg_map[ct_gen_restored_uuid] == [1]
@test ca_hrsg_map[ca_gen_restored_uuid] == [1]
@test ct_gen_restored_uuid in hrsg_ct_map[1]
@test ca_gen_restored_uuid in hrsg_ca_map[1]
end
@testset "Duplicate generator rejection for ThermalPowerPlant" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen1"
add_component!(sys, gen)
plant = ThermalPowerPlant(name = "Plant")
add_supplemental_attribute!(sys, gen, plant; shaft_number = 1)
# Adding the same generator again should throw
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys, gen, plant; shaft_number = 1,
)
# Also rejects with a different shaft number
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys, gen, plant; shaft_number = 2,
)
# Maps should be unchanged after rejected adds
@test length(get_shaft_map(plant)) == 1
@test length(get_shaft_map(plant)[1]) == 1
@test get_reverse_shaft_map(plant)[IS.get_uuid(gen)] == 1
end
@testset "Duplicate generator rejection for HydroPowerPlant" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
turb = HydroTurbine(nothing)
turb.bus = bus
turb.name = "turb1"
add_component!(sys, turb)
plant = HydroPowerPlant(name = "Hydro Plant")
add_supplemental_attribute!(sys, turb, plant, 1)
# Adding the same turbine again should throw
@test_throws IS.ArgumentError add_supplemental_attribute!(sys, turb, plant, 1)
@test_throws IS.ArgumentError add_supplemental_attribute!(sys, turb, plant, 2)
# Maps should be unchanged
@test length(get_penstock_map(plant)) == 1
@test length(get_penstock_map(plant)[1]) == 1
@test get_reverse_penstock_map(plant)[IS.get_uuid(turb)] == 1
end
@testset "Duplicate generator rejection for RenewablePowerPlant" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
wind = RenewableDispatch(nothing)
wind.bus = bus
wind.name = "wind1"
add_component!(sys, wind)
plant = RenewablePowerPlant(name = "Renewable Plant")
add_supplemental_attribute!(sys, wind, plant, 1)
# Adding the same generator again should throw
@test_throws IS.ArgumentError add_supplemental_attribute!(sys, wind, plant, 1)
@test_throws IS.ArgumentError add_supplemental_attribute!(sys, wind, plant, 2)
# Maps should be unchanged
@test length(get_pcc_map(plant)) == 1
@test length(get_pcc_map(plant)[1]) == 1
@test get_reverse_pcc_map(plant)[IS.get_uuid(wind)] == 1
end
@testset "Duplicate generator rejection for CombinedCycleBlock" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
ct_gen = ThermalStandard(nothing)
ct_gen.bus = bus
ct_gen.name = "ct_gen1"
ct_gen.prime_mover_type = PrimeMovers.CT
add_component!(sys, ct_gen)
ca_gen = ThermalStandard(nothing)
ca_gen.bus = bus
ca_gen.name = "ca_gen1"
ca_gen.prime_mover_type = PrimeMovers.CA
add_component!(sys, ca_gen)
cc_block = CombinedCycleBlock(
name = "CC Block",
configuration = CombinedCycleConfiguration.SeparateShaftCombustionSteam,
)
add_supplemental_attribute!(sys, ct_gen, cc_block; hrsg_number = 1)
add_supplemental_attribute!(sys, ca_gen, cc_block; hrsg_number = 1)
# Adding the same CT again should throw
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys, ct_gen, cc_block; hrsg_number = 1,
)
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys, ct_gen, cc_block; hrsg_number = 2,
)
# Adding the same CA again should throw
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys, ca_gen, cc_block; hrsg_number = 1,
)
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys, ca_gen, cc_block; hrsg_number = 2,
)
# Maps should be unchanged after rejected adds
hrsg_ct_map = get_hrsg_ct_map(cc_block)
hrsg_ca_map = get_hrsg_ca_map(cc_block)
ct_hrsg_map = get_ct_hrsg_map(cc_block)
ca_hrsg_map = get_ca_hrsg_map(cc_block)
@test length(hrsg_ct_map) == 1
@test length(hrsg_ct_map[1]) == 1
@test length(hrsg_ca_map) == 1
@test length(hrsg_ca_map[1]) == 1
@test ct_hrsg_map[IS.get_uuid(ct_gen)] == [1]
@test ca_hrsg_map[IS.get_uuid(ca_gen)] == [1]
end
@testset "Multiple plants per generator" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "thermal_gen1"
add_component!(sys, gen)
# Add multiple plant attributes to same generator
plant1 = ThermalPowerPlant(name = "Plant A")
plant2 = ThermalPowerPlant(name = "Plant B")
add_supplemental_attribute!(sys, gen, plant1; shaft_number = 1)
add_supplemental_attribute!(sys, gen, plant2; shaft_number = 1)
# Verify both plants are attached
attrs = get_supplemental_attributes(ThermalPowerPlant, gen)
plants = collect(attrs)
@test length(plants) == 2
plant_names = Set([get_name(p) for p in plants])
@test "Plant A" in plant_names
@test "Plant B" in plant_names
# Remove one plant
remove_supplemental_attribute!(sys, gen, plant1)
attrs = get_supplemental_attributes(ThermalPowerPlant, gen)
@test length(collect(attrs)) == 1
@test get_name(collect(attrs)[1]) == "Plant B"
end
@testset "Empty plant serialization" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "thermal_gen1"
add_component!(sys, gen)
# Create empty plant (no generators added yet)
plant = ThermalPowerPlant(name = "Empty Plant")
IS.add_supplemental_attribute!(sys.data, gen, plant)
# Serialize and deserialize
sys2, result = validate_serialization(sys)
@test result
# Verify empty plant is preserved
gen_restored = get_component(ThermalStandard, sys2, "thermal_gen1")
attrs = get_supplemental_attributes(ThermalPowerPlant, gen_restored)
plant_restored = collect(attrs)[1]
@test get_name(plant_restored) == "Empty Plant"
@test isempty(get_shaft_map(plant_restored))
@test isempty(get_reverse_shaft_map(plant_restored))
end
@testset "Plant attributes with case builder system and full serialization cycle" begin
# Load a system from case builder
sys = PSB.build_system(PSB.PSITestSystems, "c_sys5")
# Get thermal generators
thermal_gens = collect(get_components(ThermalStandard, sys))
@test length(thermal_gens) >= 2
# Create thermal power plant and add generators
thermal_plant = ThermalPowerPlant(name = "Test Coal Plant")
add_supplemental_attribute!(sys, thermal_gens[1], thermal_plant; shaft_number = 1)
add_supplemental_attribute!(sys, thermal_gens[2], thermal_plant; shaft_number = 2)
# Verify plant is attached
@test has_supplemental_attributes(thermal_gens[1])
attrs = get_supplemental_attributes(ThermalPowerPlant, thermal_gens[1])
@test length(collect(attrs)) == 1
@test get_name(collect(attrs)[1]) == "Test Coal Plant"
# Get renewable generators if available
renewable_gens = collect(get_components(RenewableGen, sys))
if length(renewable_gens) >= 1
# Create renewable power plant
renewable_plant = RenewablePowerPlant(name = "Test Wind Farm")
add_supplemental_attribute!(sys, renewable_gens[1], renewable_plant, 1)
# Verify plant is attached
@test has_supplemental_attributes(renewable_gens[1])
end
# Test to_json serialization
test_dir = mktempdir()
json_path = joinpath(test_dir, "system_with_plants.json")
try
# Serialize using to_json
to_json(sys, json_path; force = true)
@test isfile(json_path)
# Verify JSON file contains plant data
json_data = open(json_path, "r") do io
JSON3.read(io)
end
@test haskey(json_data, "data_format_version")
@test json_data["data_format_version"] == PSY.DATA_FORMAT_VERSION
# Test System(file) constructor
sys_loaded = System(json_path)
# Verify system loaded correctly
@test get_base_power(sys_loaded) == get_base_power(sys)
@test length(get_components(ThermalStandard, sys_loaded)) ==
length(thermal_gens)
# Verify thermal power plant is preserved
gen1_loaded = get_component(
ThermalStandard,
sys_loaded,
get_name(thermal_gens[1]),
)
@test gen1_loaded !== nothing
@test has_supplemental_attributes(gen1_loaded)
attrs_loaded = get_supplemental_attributes(ThermalPowerPlant, gen1_loaded)
plant_loaded = collect(attrs_loaded)[1]
@test get_name(plant_loaded) == "Test Coal Plant"
# Verify shaft mappings are preserved
shaft_map = get_shaft_map(plant_loaded)
reverse_map = get_reverse_shaft_map(plant_loaded)
@test length(shaft_map) == 2
@test length(reverse_map) == 2
gen1_uuid = IS.get_uuid(gen1_loaded)
gen2_loaded = get_component(
ThermalStandard,
sys_loaded,
get_name(thermal_gens[2]),
)
gen2_uuid = IS.get_uuid(gen2_loaded)
@test reverse_map[gen1_uuid] == 1
@test reverse_map[gen2_uuid] == 2
@test gen1_uuid in shaft_map[1]
@test gen2_uuid in shaft_map[2]
# Verify renewable plant if it was added
if length(renewable_gens) >= 1
ren1_loaded = get_component(
RenewableGen,
sys_loaded,
get_name(renewable_gens[1]),
)
@test has_supplemental_attributes(ren1_loaded)
ren_attrs = get_supplemental_attributes(RenewablePowerPlant, ren1_loaded)
ren_plant_loaded = collect(ren_attrs)[1]
@test get_name(ren_plant_loaded) == "Test Wind Farm"
pcc_map = get_pcc_map(ren_plant_loaded)
@test length(pcc_map) == 1
@test IS.get_uuid(ren1_loaded) in pcc_map[1]
end
# Test that we can serialize the loaded system again (round-trip)
json_path2 = joinpath(test_dir, "system_roundtrip.json")
to_json(sys_loaded, json_path2; force = true)
@test isfile(json_path2)
# Load the round-trip system
sys_roundtrip = System(json_path2)
@test get_base_power(sys_roundtrip) == get_base_power(sys)
# Verify plant still exists after round-trip
gen1_rt = get_component(
ThermalStandard,
sys_roundtrip,
get_name(thermal_gens[1]),
)
@test has_supplemental_attributes(gen1_rt)
attrs_rt = get_supplemental_attributes(ThermalPowerPlant, gen1_rt)
@test get_name(collect(attrs_rt)[1]) == "Test Coal Plant"
finally
# Clean up temporary files
rm(test_dir; recursive = true, force = true)
end
end
@testset "CombinedCycleFractional construction and basic accessors" begin
cc_frac = CombinedCycleFractional(
name = "CC Frac 1",
configuration = CombinedCycleConfiguration.SingleShaftCombustionSteam,
)
@test get_name(cc_frac) == "CC Frac 1"
@test get_configuration(cc_frac) ==
CombinedCycleConfiguration.SingleShaftCombustionSteam
@test isempty(get_operation_exclusion_map(cc_frac))
@test isempty(get_inverse_operation_exclusion_map(cc_frac))
end
@testset "Add and remove ThermalGen to/from CombinedCycleFractional" begin
sys = System(100.0)
bus1 = ACBus(nothing)
bus1.name = "bus1"
bus1.number = 1
bus1.bustype = ACBusTypes.REF
add_component!(sys, bus1)
bus2 = ACBus(nothing)
bus2.name = "bus2"
bus2.number = 2
add_component!(sys, bus2)
# Create thermal generators with CC prime mover type
cc_gen1 = ThermalStandard(nothing)
cc_gen1.bus = bus1
cc_gen1.name = "cc_gen1"
cc_gen1.prime_mover_type = PrimeMovers.CC
add_component!(sys, cc_gen1)
cc_gen2 = ThermalStandard(nothing)
cc_gen2.bus = bus2
cc_gen2.name = "cc_gen2"
cc_gen2.prime_mover_type = PrimeMovers.CC
add_component!(sys, cc_gen2)
# Create combined cycle fractional plant
cc_frac = CombinedCycleFractional(
name = "CC Frac 1",
configuration = CombinedCycleConfiguration.SeparateShaftCombustionSteam,
)
# Add generators with exclusion group numbers
add_supplemental_attribute!(
sys, cc_gen1, cc_frac; exclusion_group = 1,
)
add_supplemental_attribute!(
sys, cc_gen2, cc_frac; exclusion_group = 1,
)
# Verify exclusion mappings
excl_map = get_operation_exclusion_map(cc_frac)
@test length(excl_map) == 1
@test length(excl_map[1]) == 2
@test IS.get_uuid(cc_gen1) in excl_map[1]
@test IS.get_uuid(cc_gen2) in excl_map[1]
# Verify inverse mappings
inv_map = get_inverse_operation_exclusion_map(cc_frac)
@test length(inv_map) == 2
@test inv_map[IS.get_uuid(cc_gen1)] == 1
@test inv_map[IS.get_uuid(cc_gen2)] == 1
# Verify supplemental attributes are attached
@test has_supplemental_attributes(cc_gen1)
@test has_supplemental_attributes(cc_gen2)
# Test multiple exclusion groups
cc_gen3 = ThermalStandard(nothing)
cc_gen3.bus = bus1
cc_gen3.name = "cc_gen3"
cc_gen3.prime_mover_type = PrimeMovers.CC
add_component!(sys, cc_gen3)
add_supplemental_attribute!(
sys, cc_gen3, cc_frac; exclusion_group = 2,
)
@test length(excl_map) == 2
@test length(excl_map[2]) == 1
@test excl_map[2][1] == IS.get_uuid(cc_gen3)
# Remove generator from plant
remove_supplemental_attribute!(sys, cc_gen1, cc_frac)
@test length(excl_map[1]) == 1
@test excl_map[1][1] == IS.get_uuid(cc_gen2)
# Remove last generator from group 1
remove_supplemental_attribute!(sys, cc_gen2, cc_frac)
@test !haskey(excl_map, 1)
# Test error when removing non-existent generator
@test_throws IS.ArgumentError remove_supplemental_attribute!(
sys, cc_gen1, cc_frac,
)
end
@testset "CombinedCycleFractional rejects invalid PrimeMover types" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
cc_frac = CombinedCycleFractional(
name = "CC Frac Invalid",
configuration = CombinedCycleConfiguration.SingleShaftCombustionSteam,
)
# Invalid prime mover types should throw (only CC is valid)
for (i, pm) in enumerate([
PrimeMovers.GT,
PrimeMovers.ST,
PrimeMovers.WT,
PrimeMovers.CT,
PrimeMovers.CA,
])
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen_invalid_$i"
gen.prime_mover_type = pm
add_component!(sys, gen)
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys, gen, cc_frac; exclusion_group = 1,
)
end
# Valid prime mover type (CC only)
cc_gen = ThermalStandard(nothing)
cc_gen.bus = bus
cc_gen.name = "gen_cc"
cc_gen.prime_mover_type = PrimeMovers.CC
add_component!(sys, cc_gen)
add_supplemental_attribute!(
sys, cc_gen, cc_frac; exclusion_group = 1,
)
@test length(get_operation_exclusion_map(cc_frac)) == 1
end
@testset "Get components in exclusion group" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
# Create CC generators
gen1 = ThermalStandard(nothing)
gen1.bus = bus
gen1.name = "cc_gen1"
gen1.prime_mover_type = PrimeMovers.CC
add_component!(sys, gen1)
gen2 = ThermalStandard(nothing)
gen2.bus = bus
gen2.name = "cc_gen2"
gen2.prime_mover_type = PrimeMovers.CC
add_component!(sys, gen2)
gen3 = ThermalStandard(nothing)
gen3.bus = bus
gen3.name = "cc_gen3"
gen3.prime_mover_type = PrimeMovers.CC
add_component!(sys, gen3)
# Create plant with generators in different exclusion groups
cc_frac = CombinedCycleFractional(
name = "CC Frac Test",
configuration = CombinedCycleConfiguration.SeparateShaftCombustionSteam,
)
add_supplemental_attribute!(sys, gen1, cc_frac; exclusion_group = 1)
add_supplemental_attribute!(sys, gen2, cc_frac; exclusion_group = 1)
add_supplemental_attribute!(sys, gen3, cc_frac; exclusion_group = 2)
# Test getting components in exclusion group 1
group1_components = get_components_in_exclusion_group(sys, cc_frac, 1)
@test length(group1_components) == 2
group1_names = Set([get_name(c) for c in group1_components])
@test "cc_gen1" in group1_names
@test "cc_gen2" in group1_names
# Test getting components in exclusion group 2
group2_components = get_components_in_exclusion_group(sys, cc_frac, 2)
@test length(group2_components) == 1
@test get_name(group2_components[1]) == "cc_gen3"
# Test error for non-existent exclusion group
@test_throws IS.ArgumentError get_components_in_exclusion_group(sys, cc_frac, 99)
end
@testset "Duplicate generator rejection for CombinedCycleFractional" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
cc_gen = ThermalStandard(nothing)
cc_gen.bus = bus
cc_gen.name = "cc_gen1"
cc_gen.prime_mover_type = PrimeMovers.CC
add_component!(sys, cc_gen)
cc_frac = CombinedCycleFractional(
name = "CC Frac",
configuration = CombinedCycleConfiguration.SeparateShaftCombustionSteam,
)
add_supplemental_attribute!(sys, cc_gen, cc_frac; exclusion_group = 1)
# Adding the same generator again should throw
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys, cc_gen, cc_frac; exclusion_group = 1,
)
# Also rejects with a different exclusion group
@test_throws IS.ArgumentError add_supplemental_attribute!(
sys, cc_gen, cc_frac; exclusion_group = 2,
)
# Maps should be unchanged after rejected adds
excl_map = get_operation_exclusion_map(cc_frac)
@test length(excl_map) == 1
@test length(excl_map[1]) == 1
end
@testset "Serialization and deserialization of CombinedCycleFractional" begin
sys = System(100.0)
# Create bus and generators with CC prime mover type
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
cc_gen1 = ThermalStandard(nothing)
cc_gen1.bus = bus
cc_gen1.name = "cc_frac_gen1"
cc_gen1.prime_mover_type = PrimeMovers.CC
add_component!(sys, cc_gen1)
cc_gen2 = ThermalStandard(nothing)
cc_gen2.bus = bus
cc_gen2.name = "cc_frac_gen2"
cc_gen2.prime_mover_type = PrimeMovers.CC
add_component!(sys, cc_gen2)
# Create and add combined cycle fractional plant
cc_frac = CombinedCycleFractional(
name = "CC Frac 1",
configuration = CombinedCycleConfiguration.SeparateShaftCombustionSteam,
)
add_supplemental_attribute!(sys, cc_gen1, cc_frac; exclusion_group = 1)
add_supplemental_attribute!(sys, cc_gen2, cc_frac; exclusion_group = 2)
# Serialize and deserialize
sys2, result = validate_serialization(sys)
@test result
# Verify plant is preserved
gen1_restored = get_component(ThermalStandard, sys2, "cc_frac_gen1")
@test has_supplemental_attributes(gen1_restored)
attrs = get_supplemental_attributes(CombinedCycleFractional, gen1_restored)
cc_frac_restored = collect(attrs)[1]
@test get_name(cc_frac_restored) == "CC Frac 1"
@test get_configuration(cc_frac_restored) ==
CombinedCycleConfiguration.SeparateShaftCombustionSteam
# Verify exclusion mappings are preserved
excl_map = get_operation_exclusion_map(cc_frac_restored)
inv_map = get_inverse_operation_exclusion_map(cc_frac_restored)
@test length(excl_map) == 2
@test length(inv_map) == 2
gen1_restored_uuid = IS.get_uuid(gen1_restored)
gen2_restored = get_component(ThermalStandard, sys2, "cc_frac_gen2")
gen2_restored_uuid = IS.get_uuid(gen2_restored)
@test gen1_restored_uuid in excl_map[1]
@test gen2_restored_uuid in excl_map[2]
end
end
================================================
FILE: test/test_power_system_table_data.jl
================================================
import PowerSystems: LazyDictFromIterator
@testset "PowerSystemTableData parsing" begin
resolutions = (
(resolution = Dates.Minute(5), len = 288),
(resolution = Dates.Minute(60), len = 24),
)
for (resolution, len) in resolutions
sys = create_rts_system(resolution)
for time_series in get_time_series_multiple(sys)
@test length(time_series) == len
end
end
end
@testset "PowerSystemTableData parsing invalid directory" begin
@test_throws ErrorException PowerSystemTableData(DATA_DIR, 100.0, DESCRIPTORS)
end
@testset "Consistency between PowerSystemTableData and standardfiles" begin
# This signature is used to capture expected error logs from parsing matpower
consistency_test =
() -> begin
mpsys = System(joinpath(BAD_DATA, "RTS_GMLC_original.m"))
cdmsys = PSB.build_system(
PSB.PSITestSystems,
"test_RTS_GMLC_sys";
force_build = true,
)
mp_iter = get_components(HydroGen, mpsys)
mp_generators = LazyDictFromIterator(String, HydroGen, mp_iter, get_name)
for cdmgen in get_components(HydroGen, cdmsys)
mpgen = get(mp_generators, uppercase(get_name(cdmgen)))
if isnothing(mpgen)
error("did not find $cdmgen")
end
@test cdmgen.available == mpgen.available
@test lowercase(cdmgen.bus.name) == lowercase(mpgen.bus.name)
gen_dat = (
structname = nothing,
fields = (
:active_power,
:reactive_power,
:rating,
:active_power_limits,
:reactive_power_limits,
:ramp_limits,
),
)
function check_fields(chk_dat)
for field in chk_dat.fields
n = get(chk_dat, :structname, nothing)
(cdmd, mpd) =
if isnothing(n)
(cdmgen, mpgen)
else
(getfield(cdmgen, n), getfield(mpgen, n))
end
cdmgen_val = getfield(cdmd, field)
mpgen_val = getfield(mpd, field)
if isnothing(cdmgen_val) || isnothing(mpgen_val)
@warn "Skip value with nothing" repr(cdmgen_val) repr(mpgen_val)
continue
end
@test cdmgen_val == mpgen_val
end
end
check_fields(gen_dat)
end
mp_iter = get_components(ThermalGen, mpsys)
mp_generators = LazyDictFromIterator(String, ThermalGen, mp_iter, get_name)
for cdmgen in get_components(ThermalGen, cdmsys)
if isnothing(cdmgen)
# Skips generators parsed from Matpower as SynchCondensers in PSY5
# The fields are different so those aren't valiated in this loop
continue
end
mpgen = get(mp_generators, uppercase(get_name(cdmgen)))
@test cdmgen.available == mpgen.available
@test lowercase(cdmgen.bus.name) == lowercase(mpgen.bus.name)
for field in (:active_power_limits, :reactive_power_limits, :ramp_limits)
cdmgen_val = getfield(cdmgen, field)
mpgen_val = getfield(mpgen, field)
if isnothing(cdmgen_val) || isnothing(mpgen_val)
@warn "Skip value with nothing" repr(cdmgen_val) repr(mpgen_val)
continue
end
@test cdmgen_val == mpgen_val
end
mpgen_cost = get_operation_cost(mpgen)
# Currently true; this is likely to change in the future and then we'd have to change the test
@assert get_variable(mpgen_cost) isa
CostCurve{InputOutputCurve{PiecewiseLinearData}}
mp_points = get_points(
get_function_data(get_value_curve(
get_variable(mpgen_cost))),
)
if length(mp_points) == 4
cdm_op_cost = get_operation_cost(cdmgen)
@test get_fixed(cdm_op_cost) == 0.0
fuel_curve = get_variable(cdm_op_cost)
fuel_cost = get_fuel_cost(fuel_curve)
mp_fixed = get_fixed(mpgen_cost)
io_curve = InputOutputCurve(get_value_curve(fuel_curve))
cdm_points = get_points(io_curve)
@test all(
isapprox.(
[p.y * fuel_cost for p in cdm_points],
[p.y + mp_fixed for p in mp_points],
atol = 0.1),
)
@test all(
isapprox.(
[p.x for p in cdm_points],
[p.x * get_base_power(mpgen) for p in mp_points],
atol = 0.1),
)
end
end
mp_iter = get_components(RenewableGen, mpsys)
mp_generators =
LazyDictFromIterator(String, RenewableGen, mp_iter, get_name)
for cdmgen in get_components(RenewableGen, cdmsys)
mpgen = get(mp_generators, uppercase(get_name(cdmgen)))
# Disabled since data is inconsisten between sources
#@test cdmgen.available == mpgen.available
@test lowercase(cdmgen.bus.name) == lowercase(mpgen.bus.name)
for field in (:rating, :power_factor)
cdmgen_val = getfield(cdmgen, field)
mpgen_val = getfield(mpgen, field)
if isnothing(cdmgen_val) || isnothing(mpgen_val)
@warn "Skip value with nothing" repr(cdmgen_val) repr(mpgen_val)
continue
end
@test cdmgen_val == mpgen_val
end
#@test compare_values_without_uuids(cdmgen.operation_cost, mpgen.operation_cost)
end
cdm_ac_branches = collect(get_components(ACBranch, cdmsys))
@test get_rating(cdm_ac_branches[2]) ==
get_rating(get_branch(mpsys, cdm_ac_branches[2]))
@test get_rating(cdm_ac_branches[6]) ==
get_rating(get_branch(mpsys, cdm_ac_branches[6]))
@test get_rating(cdm_ac_branches[120]) ==
get_rating(get_branch(mpsys, cdm_ac_branches[120]))
cdm_dc_branches =
collect(get_components(TwoTerminalGenericHVDCLine, cdmsys))
@test get_active_power_limits_from(cdm_dc_branches[1]) ==
get_active_power_limits_from(get_branch(mpsys, cdm_dc_branches[1]))
end
@test_logs (:error,) match_mode = :any min_level = Logging.Error consistency_test()
end
@testset "Test reserve direction" begin
@test PSY.get_reserve_direction("Up") == ReserveUp
@test PSY.get_reserve_direction("Down") == ReserveDown
@test PSY.get_reserve_direction("up") == ReserveUp
@test PSY.get_reserve_direction("down") == ReserveDown
for invalid in ("right", "left")
@test_throws PSY.DataFormatError PSY.get_reserve_direction(invalid)
end
end
@testset "Test consistency between variable cost and heat rate parsing" begin
fivebus_dir = joinpath(DATA_DIR, "5-Bus")
rawsys_hr = PowerSystemTableData(
fivebus_dir,
100.0,
joinpath(fivebus_dir, "user_descriptors_var_cost.yaml");
generator_mapping_file = joinpath(fivebus_dir, "generator_mapping.yaml"),
)
rawsys = PowerSystemTableData(
fivebus_dir,
100.0,
joinpath(fivebus_dir, "user_descriptors_var_cost.yaml");
generator_mapping_file = joinpath(fivebus_dir, "generator_mapping.yaml"),
)
sys_hr = System(rawsys_hr)
sys = System(rawsys)
g_hr = get_components(ThermalStandard, sys_hr)
g = get_components(ThermalStandard, sys)
@test get_variable.(get_operation_cost.(g)) == get_variable.(get_operation_cost.(g))
end
@testset "Test create_poly_cost function" begin
cost_colnames = ["heat_rate_a0", "heat_rate_a1", "heat_rate_a2"]
# Coefficients for a CC using natural gas
a2 = -0.000531607
a1 = 0.060554675
a0 = 8.951100118
# First test that return quadratic if all coefficients are provided.
# We convert the coefficients to string to mimic parsing from csv
example_generator = (
name = "test-gen",
heat_rate_a0 = string(a0),
heat_rate_a1 = string(a1),
heat_rate_a2 = string(a2),
)
cost_curve, fixed_cost = create_poly_cost(example_generator, cost_colnames)
@assert cost_curve isa QuadraticCurve
@assert isapprox(get_quadratic_term(cost_curve), a2, atol = 0.01)
@assert isapprox(get_proportional_term(cost_curve), a1, atol = 0.01)
@assert isapprox(get_constant_term(cost_curve), a0, atol = 0.01)
# Test return linear with both proportional and constant term
example_generator = (
name = "test-gen",
heat_rate_a0 = string(a0),
heat_rate_a1 = string(a1),
heat_rate_a2 = nothing,
)
cost_curve, fixed_cost = create_poly_cost(example_generator, cost_colnames)
@assert cost_curve isa LinearCurve
@assert isapprox(get_proportional_term(cost_curve), a1, atol = 0.01)
@assert isapprox(get_constant_term(cost_curve), a0, atol = 0.01)
# Test return linear with just proportional term
example_generator = (
name = "test-gen",
heat_rate_a0 = nothing,
heat_rate_a1 = string(a1),
heat_rate_a2 = nothing,
)
cost_curve, fixed_cost = create_poly_cost(example_generator, cost_colnames)
@assert cost_curve isa LinearCurve
@assert isapprox(get_proportional_term(cost_curve), a1, atol = 0.01)
# Test raises error if a2 is passed but other coefficients are nothing
example_generator = (
name = "test-gen",
heat_rate_a0 = nothing,
heat_rate_a1 = nothing,
heat_rate_a2 = string(a2),
)
@test_throws IS.DataFormatError create_poly_cost(example_generator, cost_colnames)
example_generator = (
name = "test-gen",
heat_rate_a0 = nothing,
heat_rate_a1 = string(a1),
heat_rate_a2 = string(a2),
)
@test_throws IS.DataFormatError create_poly_cost(example_generator, cost_colnames)
example_generator = (
name = "test-gen",
heat_rate_a0 = string(a0),
heat_rate_a1 = nothing,
heat_rate_a2 = string(a2),
)
@test_throws IS.DataFormatError create_poly_cost(example_generator, cost_colnames)
# Test that it works with zero proportional and constant term
example_generator = (
name = "test-gen",
heat_rate_a0 = string(0.0),
heat_rate_a1 = string(0.0),
heat_rate_a2 = string(a2),
)
cost_curve, fixed_cost = create_poly_cost(example_generator, cost_colnames)
@assert cost_curve isa QuadraticCurve
@assert isapprox(get_quadratic_term(cost_curve), a2, atol = 0.01)
@assert isapprox(get_proportional_term(cost_curve), 0.0, atol = 0.01)
@assert isapprox(get_constant_term(cost_curve), 0.0, atol = 0.01)
# Test that create_poly_cost works with numeric values (not just strings)
# Some CSV parsers return numeric types directly instead of strings
example_generator = (
name = "test-gen",
heat_rate_a0 = a0, # Float64
heat_rate_a1 = a1, # Float64
heat_rate_a2 = a2, # Float64
)
cost_curve, fixed_cost = create_poly_cost(example_generator, cost_colnames)
@assert cost_curve isa QuadraticCurve
@assert isapprox(get_quadratic_term(cost_curve), a2, atol = 0.01)
@assert isapprox(get_proportional_term(cost_curve), a1, atol = 0.01)
@assert isapprox(get_constant_term(cost_curve), a0, atol = 0.01)
# Test with Int64 values (another common numeric type from CSV parsers)
example_generator = (
name = "test-gen",
heat_rate_a0 = Int64(9),
heat_rate_a1 = Int64(0),
heat_rate_a2 = Int64(0),
)
cost_curve, fixed_cost = create_poly_cost(example_generator, cost_colnames)
@assert cost_curve isa QuadraticCurve
@assert isapprox(get_quadratic_term(cost_curve), 0.0, atol = 0.01)
@assert isapprox(get_proportional_term(cost_curve), 0.0, atol = 0.01)
@assert isapprox(get_constant_term(cost_curve), 9.0, atol = 0.01)
end
@testset "Test parsing with ThermalMultiStart generators" begin
# Test that ThermalMultiStart generators parse correctly with multi-start costs
# This exercises the multi-start cost fallback logic in make_thermal_generator_multistart
rawsys = PowerSystemTableData(
RTS_GMLC_DIR,
100.0,
DESCRIPTORS;
generator_mapping_file = joinpath(
RTS_GMLC_DIR,
"generator_mapping_multi_start.yaml",
),
)
sys = System(rawsys; time_series_resolution = Dates.Hour(1))
# Verify ThermalMultiStart generators were created
ms_gens = collect(get_components(ThermalMultiStart, sys))
@test length(ms_gens) > 0
# Check that startup costs were parsed correctly
for gen in ms_gens
op_cost = get_operation_cost(gen)
startup_costs = get_start_up(op_cost)
# Startup costs should be non-negative
@test startup_costs.hot >= 0.0
@test startup_costs.warm >= 0.0
@test startup_costs.cold >= 0.0
end
end
@testset "Test Reservoirs and Turbines" begin
cdmsys = PSB.build_system(
PSB.PSITestSystems,
"test_RTS_GMLC_sys";
force_build = true,
)
@test !isempty(get_components(HydroTurbine, cdmsys))
for turbine in get_components(HydroTurbine, cdmsys)
reservoir = get_connected_head_reservoirs(cdmsys, turbine)
@test !isempty(reservoir)
reservoir = get_connected_tail_reservoirs(cdmsys, turbine)
@test isempty(reservoir)
end
@test !isempty(get_components(HydroReservoir, cdmsys))
for reservoir in get_components(HydroReservoir, cdmsys)
turbines = get_downstream_turbines(reservoir)
@test !isempty(turbines)
@test isempty(get_upstream_turbines(reservoir))
end
end
================================================
FILE: test/test_powersystemconstructors.jl
================================================
checksys = false
@testset "Test System constructors from .jl files" begin
tPowerSystem = System(nothing)
nodes_5_nodes = nodes5()
nodes_14_nodes = nodes14()
for node in nodes_5_nodes
node.angle = deg2rad(node.angle)
end
# Components with time_series cannot be added to multiple systems, so clear them on each
# test.
sys5 = System(
100.0,
nodes_5_nodes,
thermal_generators5(nodes_5_nodes),
loads5(nodes_5_nodes);
runchecks = checksys,
)
clear_components!(sys5)
sys5b = System(
100.0,
nodes_5_nodes,
thermal_generators5(nodes_5_nodes),
loads5(nodes_5_nodes),
battery5(nodes_5_nodes);
runchecks = checksys,
)
clear_components!(sys5b)
sys5f = System(
100.0,
nodes_5_nodes,
thermal_generators5(nodes_5_nodes),
loads5(nodes_5_nodes),
shiftable5(nodes_5_nodes);
runchecks = checksys,
)
clear_components!(sys5f)
# GitHub issue #234 - fix time_series5 in data file, use new format
#_sys5b = PowerSystems._System(nodes_5, thermal_generators5(nodes_5), loads5(nodes_5), nothing, battery5(nodes_5),
# 100.0, time_series5, nothing, nothing)
#sys5b = System(_sys5b)
sys5bh = System(
100.0,
nodes_5_nodes,
thermal_generators5(nodes_5_nodes),
hydro_generators5(nodes_5_nodes),
loads5(nodes_5_nodes),
branches5(nodes_5_nodes),
battery5(nodes_5_nodes);
runchecks = checksys,
)
clear_components!(sys5bh)
# Test Data for 14 Bus
# GitHub issue #234 - fix time_series5 in data file, use new format
#_sys14 = PowerSystems._System(nodes_14, thermal_generators14, loads14, nothing, nothing,
# 100.0, Dict{Symbol,Vector{<:TimeSeriesData}}(),nothing,nothing)
#sys14 = System(_sys14)
for node in nodes_14_nodes
node.angle = deg2rad(node.angle)
end
sys14b = PowerSystems.System(
100.0,
nodes_14_nodes,
thermal_generators14(nodes_14_nodes),
loads14(nodes_14_nodes),
battery14(nodes_14_nodes);
runchecks = checksys,
)
clear_components!(sys14b)
sys14b = PowerSystems.System(
100.0,
nodes_14_nodes,
thermal_generators14(nodes_14_nodes),
loads14(nodes_14_nodes),
branches14(nodes_14_nodes),
battery14(nodes_14_nodes);
runchecks = checksys,
)
clear_components!(sys14b)
end
@testset "Test System constructor from Matpower" begin
# Include a System kwarg to make sure it doesn't get forwarded to PM functions.
kwarg_test =
() -> begin
sys = System(
joinpath(BAD_DATA,
"case5_re.m");
runchecks = true,
)
end
@test_logs (:error,) min_level = Logging.Error match_mode = :any kwarg_test()
end
@testset "Test accessor functions of PowerSystems auto-generated types" begin
# If this test fails because a type doesn't have a constructor that takes nothing,
# it's because not all fields in that type are defined in power_system_structs.json
# with nullable values. Consider adding them so that this "demo-constructor" works.
# If that isn't appropriate for this type, add it to types_to_skip below.
# You can also call test_accessors wherever an instance has been created.
types_to_skip = (TestDevice, TestRenDevice, TestInjector, NonexistentComponent)
types = vcat(
IS.get_all_concrete_subtypes(Component),
IS.get_all_concrete_subtypes(DynamicComponent),
IS.get_all_concrete_subtypes(PowerSystems.ActivePowerControl),
IS.get_all_concrete_subtypes(PowerSystems.ReactivePowerControl),
)
sort!(types; by = x -> string(x))
for ps_type in types
ps_type in types_to_skip && continue
component = ps_type(nothing)
test_accessors(component)
end
end
@testset "Test required accessor functions of subtypes of Component " begin
types = IS.get_all_concrete_subtypes(Component)
types_to_skip = (TestDevice, TestRenDevice, NonexistentComponent, TestInjector)
sort!(types; by = x -> string(x))
for ps_type in types
ps_type in types_to_skip && continue
component = ps_type(nothing)
@test get_name(component) isa String
@test IS.get_internal(component) isa IS.InfrastructureSystemsInternal
end
end
@testset "Test component conversion" begin
test_line_conversion =
() -> begin
sys = System(joinpath(BAD_DATA, "case5_re.m"))
l = get_component(Line, sys, "bus2-bus3-i_4")
initial_time = Dates.DateTime("2020-01-01T00:00:00")
dates = collect(
initial_time:Dates.Hour(1):Dates.DateTime("2020-01-01T23:00:00"),
)
data = collect(1:24)
ta = TimeSeries.TimeArray(dates, data, [get_name(l)])
name = "active_power_flow"
time_series = SingleTimeSeries(; name = name, data = ta)
add_time_series!(sys, l, time_series)
@test get_time_series(SingleTimeSeries, l, name) isa SingleTimeSeries
PSY.convert_component!(sys, l, MonitoredLine)
@test isnothing(get_component(Line, sys, "bus2-bus3-i_4"))
mline = get_component(MonitoredLine, sys, "bus2-bus3-i_4")
@test !isnothing(mline)
@test get_name(mline) == "bus2-bus3-i_4"
@test get_time_series(SingleTimeSeries, mline, name) isa SingleTimeSeries
@test_throws ErrorException convert_component!(
sys,
get_component(MonitoredLine, sys, "bus2-bus3-i_4"),
Line,
)
convert_component!(
sys,
get_component(MonitoredLine, sys, "bus2-bus3-i_4"),
Line;
force = true,
)
line = get_component(Line, sys, "bus2-bus3-i_4")
@test !isnothing(mline)
@test get_time_series(SingleTimeSeries, line, name) isa SingleTimeSeries
end
test_load_conversion =
() -> begin
sys = PSB.build_system(PSB.PSITestSystems, "c_sys5")
component_name = "Bus2"
# We use this name to avoid conflicts with the existing time series in the system
ts_name = "max_active_power_test"
old_component = get_component(PowerLoad, sys, component_name)
dates = collect(
Dates.DateTime("2020-01-01T00:00:00"):Dates.Hour(1):Dates.DateTime(
"2020-01-01T23:00:00",
),
)
data = collect(1:24)
ta = TimeSeries.TimeArray(dates, data, [component_name])
time_series = SingleTimeSeries(; name = ts_name, data = ta)
add_time_series!(sys, old_component, time_series)
@test get_time_series(SingleTimeSeries, old_component, ts_name) isa
SingleTimeSeries
convert_component!(sys, old_component, StandardLoad)
@test isnothing(get_component(typeof(old_component), sys, component_name))
new_component = get_component(StandardLoad, sys, component_name)
@test !isnothing(new_component)
@test get_name(new_component) == component_name
@test get_time_series(SingleTimeSeries, new_component, ts_name) isa
SingleTimeSeries
# Conversion back is not implemented
end
@test_logs (:error,) min_level = Logging.Error match_mode = :any test_line_conversion()
test_load_conversion()
end
================================================
FILE: test/test_printing.jl
================================================
function are_type_and_fields_in_output(obj::T) where {T <: Component}
match = true
normal = repr(obj)
io = IOBuffer()
show(io, "text/plain", obj)
custom = String(take!(io))
fields = fieldnames(T)
# Type must always be present. name should be also, if the type defines it.
#for text in (normal, custom)
for text in (custom,)
if !occursin(string(T), text)
@error "type name is not in output" string(T) text
match = false
end
if :name in fields
if !occursin(obj.name, text)
@error "name is not in output" name text
match = false
end
end
end
for (name, type) in zip(fields, fieldtypes(T))
val = getfield(obj, name)
if val === nothing || type <: IS.InfrastructureSystemsInternal
continue
end
# Account for the fact that type may be abstract.
actual_type = typeof(val)
if actual_type <: IS.InfrastructureSystemsType
expected = string(actual_type)
elseif actual_type <: Vector{<:Service}
expected = string(actual_type)
elseif actual_type <: Vector{<:IS.InfrastructureSystemsType}
expected = string(actual_type)
else
expected = string(val)
end
if !occursin(expected, custom)
@error "field's value is not in custom output" name custom
match = false
end
end
return match
end
@testset "Test printing of system and components" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
@test are_type_and_fields_in_output(iterate(get_components(ACBus, sys))[1])
@test are_type_and_fields_in_output(iterate(get_components(Generator, sys))[1])
@test are_type_and_fields_in_output(iterate(get_components(ThermalGen, sys))[1])
@test are_type_and_fields_in_output(iterate(get_components(Branch, sys))[1])
@test are_type_and_fields_in_output(iterate(get_components(ElectricLoad, sys))[1])
io = IOBuffer()
component = first(get_components(ThermalGen, sys))
show(io, "text/plain", component)
text = String(take!(io))
expected_sa = string(has_supplemental_attributes(component))
expected_ts = string(has_time_series(component))
@test occursin("has_supplemental_attributes: $expected_sa", text)
@test occursin("has_time_series: $expected_ts", text)
# Just make sure nothing blows up.
for component in iterate_components(sys)
print(devnull, component)
print(devnull, MIME"text/plain")
@test !isempty(summary(component))
end
for time_series in get_time_series_multiple(sys)
show(devnull, time_series)
show(devnull, MIME"text/plain")
@test !isempty(summary(time_series))
end
@test !isempty(summary(sys))
@test isnothing(
show(
IOBuffer(),
"text/plain",
PowerSystemTableData(RTS_GMLC_DIR, 100.0, DESCRIPTORS),
),
)
@test isnothing(show(IOBuffer(), "text/plain", sys))
@test isnothing(show(IOBuffer(), "text/html", sys))
@test isnothing(show_components(IOBuffer(), sys, RenewableNonDispatch))
@test isnothing(show_components(IOBuffer(), sys, RenewableNonDispatch, [:rating]))
@test isnothing(
show_components(
IOBuffer(),
sys,
RenewableNonDispatch,
Dict("ts" => x -> has_time_series(x)),
),
)
end
@testset "Test printing of non-PowerSystems struct" begin
struct MyComponent <: Component
name::String
internal::IS.InfrastructureSystemsInternal
end
PSY.get_internal(x::MyComponent) = x.internal
PSY.get_name(x::MyComponent) = string(x.name)
component = MyComponent("component1", IS.InfrastructureSystemsInternal())
@test isnothing(show(IOBuffer(), component))
@test isnothing(show(IOBuffer(), "text/plain", component))
end
================================================
FILE: test/test_read_time_series.jl
================================================
import DataFrames
import Dates
import TimeSeries
function verify_time_series(sys::System, num_initial_times, num_time_series, len)
total_time_series = 0
all_time_series = get_time_series_multiple(sys)
for time_series in all_time_series
if length(time_series) != len
@error "length doesn't match" length(time_series) len
return false
end
total_time_series += 1
end
if num_time_series != total_time_series
@error "num_time_series doesn't match" num_time_series total_time_series
return false
end
return true
end
@testset "Test read_time_series_file_metadata" begin
for file in ["timeseries_pointers.json", "timeseries_pointers.csv"]
filename = joinpath(RTS_GMLC_DIR, file)
all_time_series = IS.read_time_series_file_metadata(filename)
@test length(all_time_series) == 260
for time_series in all_time_series
@test isfile(time_series.data_file)
end
end
end
@testset "Test time_series normalization" begin
component_name = "122_HYDRO_1"
timeseries_file = joinpath(
RTS_GMLC_DIR,
"RTS_GMLC_forecasts",
"gen",
"Hydro",
"DAY_AHEAD_hydro.csv",
)
gen = ThermalStandard(nothing)
gen.name = component_name
resolution = Dates.Hour(1)
# Parse the file directly in order to compare values.
ts_base = SingleTimeSeries(component_name, timeseries_file, gen, resolution)
timeseries = get_data(ts_base)
max_value = maximum(TimeSeries.values(timeseries))
file_metadata = IS.TimeSeriesFileMetadata(;
simulation = "DAY_AHEAD",
category = "Generator",
component_name = "122_HYDRO_1",
name = "active_power",
normalization_factor = 1.0,
data_file = timeseries_file,
percentiles = [],
resolution = resolution,
time_series_type_module = "InfrastructureSystems",
time_series_type = "SingleTimeSeries",
)
# Test code path where no normalization occurs.
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_RTS_GMLC_sys")
add_time_series!(sys, [file_metadata])
verify_time_series(sys, 1, 1, 24)
time_series = collect(get_time_series_multiple(sys))[1]
@test TimeSeries.values(time_series.data) == TimeSeries.values(timeseries)
# Test code path where timeseries is normalized by dividing by the max value.
file_metadata.normalization_factor = "Max"
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_RTS_GMLC_sys")
add_time_series!(sys, [file_metadata])
verify_time_series(sys, 1, 1, 24)
time_series = collect(get_time_series_multiple(sys))[1]
@test TimeSeries.values(time_series.data) == TimeSeries.values(timeseries ./ max_value)
# Test code path where timeseries is normalized by dividing by a custom value.
nf = 95.0
file_metadata.normalization_factor = nf
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_RTS_GMLC_sys")
add_time_series!(sys, [file_metadata])
verify_time_series(sys, 1, 1, 24)
time_series = collect(get_time_series_multiple(sys))[1]
@test TimeSeries.values(time_series.data) == TimeSeries.values(timeseries ./ nf)
end
@testset "Test single time_series addition" begin
component_name = "122_HYDRO_1"
name = "active_power"
timeseries_file = joinpath(
RTS_GMLC_DIR,
"RTS_GMLC_forecasts",
"gen",
"Hydro",
"DAY_AHEAD_hydro.csv",
)
resolution = Dates.Hour(1)
# Test with a filename.
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_RTS_GMLC_sys")
component = get_component(HydroDispatch, sys, component_name)
ts = SingleTimeSeries(
name,
timeseries_file,
component,
resolution;
normalization_factor = 1.0,
)
ta = get_data(ts)
add_time_series!(sys, component, ts)
verify_time_series(sys, 1, 1, 24)
time_series = collect(get_time_series_multiple(sys))[1]
@test TimeSeries.timestamp(get_data(time_series)) == TimeSeries.timestamp(ta)
@test TimeSeries.values(get_data(time_series)) == TimeSeries.values(ta)
# Test with TimeSeries.TimeArray.
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_RTS_GMLC_sys")
component = get_component(HydroDispatch, sys, component_name)
ts = SingleTimeSeries(name, ta; normalization_factor = 1.0)
add_time_series!(sys, component, ts)
verify_time_series(sys, 1, 1, 24)
time_series = collect(get_time_series_multiple(sys))[1]
@test TimeSeries.values(get_data(time_series)) == TimeSeries.values(ta)
# Test with DataFrames.DataFrame.
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_RTS_GMLC_sys")
component = get_component(HydroDispatch, sys, component_name)
df = DataFrames.DataFrame(ta)
ts = SingleTimeSeries(name, df; normalization_factor = 1.0)
add_time_series!(sys, component, ts)
verify_time_series(sys, 1, 1, 24)
time_series = collect(get_time_series_multiple(sys))[1]
end
@testset "TimeSeriesData data matpower" begin
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_case5_re_sys")
file_metadata = joinpath(DATA_DIR, "5-Bus", "5bus_ts", "timeseries_pointers_da.json")
add_time_series!(sys, file_metadata)
@test verify_time_series(sys, 1, 5, 24)
# Add the same files.
# This will fail because the component-name pairs will be duplicated.
@test_throws ArgumentError add_time_series!(sys, file_metadata)
file_metadata = joinpath(DATA_DIR, "5-Bus", "5bus_ts", "timeseries_pointers_rt.json")
# sys = System(PowerSystems.PowerModelsData(joinpath(MATPOWER_DIR, "case5_re.m")))
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_case5_re_sys")
add_time_series!(sys, file_metadata)
@test verify_time_series(sys, 1, 5, 288)
end
================================================
FILE: test/test_serialization.jl
================================================
@testset "Test JSON serialization of RTS data with immutable time series" begin
sys =
PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys"; time_series_read_only = true)
sys2, result = validate_serialization(sys; time_series_read_only = true)
@test result
@test_throws ArgumentError clear_time_series!(sys2)
# Full error checking is done in IS.
end
@testset "Test JSON serialization of matpower data" begin
sys = PSB.build_system(PSB.MatpowerTestSystems, "matpower_case5_re_sys")
# Add a Probabilistic time_series to get coverage serializing it.
bus = ACBus(nothing)
bus.name = "Bus1234"
add_component!(sys, bus)
tg = RenewableNonDispatch(nothing)
tg.bus = bus
add_component!(sys, tg)
# TODO 1.0
#ts = PSY.Probabilistic("scalingfactor", Hour(1), DateTime("01-01-01"), [0.5, 0.5], 24)
#add_time_series!(sys, tg, ts)
_, result = validate_serialization(sys)
@test result
end
@testset "Test JSON serialization of dynamic inverter" begin
sys = PSB.build_system(PSB.PSYTestSystems, "dynamic_inverter_sys")
# Add a dynamic branch to test that code.
branch = collect(get_components(Branch, sys))[1]
dynamic_branch = DynamicBranch(branch)
add_component!(sys, dynamic_branch)
_, result = validate_serialization(sys)
@test result
test_accessors(dynamic_branch)
end
@testset "Test JSON serialization of StaticGroupReserve" begin
sys = System(100.0)
devices = []
for i in 1:2
bus = ACBus(nothing)
bus.name = "bus" * string(i)
bus.number = i
# This prevents an error log message.
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen" * string(i)
add_component!(sys, gen)
push!(devices, gen)
end
service = ConstantReserve{ReserveDown}(nothing)
add_service!(sys, service, devices)
groupservice = ConstantReserveGroup{ReserveDown}(nothing)
add_service!(sys, groupservice)
members = Vector{Service}()
push!(members, service)
set_contributing_services!(sys, groupservice, members)
_, result = validate_serialization(sys)
@test result
end
@testset "Test deepcopy of a system" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
sys2 = deepcopy(sys)
clear_time_series!(sys2)
@test !isempty(collect(get_time_series_multiple(sys)))
end
@testset "Test JSON serialization of MarketBidCost" begin
sys = System(100.0)
generators = [ThermalStandard(nothing), ThermalMultiStart(nothing)]
for i in 1:2
bus = ACBus(nothing)
bus.name = "bus" * string(i)
bus.number = i
# This prevents an error log message.
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen = generators[i]
gen.bus = bus
gen.name = "gen" * string(i)
initial_time = Dates.DateTime("2020-01-01T00:00:00")
end_time = Dates.DateTime("2020-01-01T23:00:00")
dates = collect(initial_time:Dates.Hour(1):end_time)
data =
PiecewiseStepData.(
[[i, i + 1, i + 2] for i in 1.0:24.0],
[[i, i + 1] for i in 1.0:24.0],
)
market_bid = MarketBidCost(nothing)
set_operation_cost!(gen, market_bid)
add_component!(sys, gen)
ta = TimeSeries.TimeArray(dates, data)
time_series = IS.SingleTimeSeries(; name = "variable_cost", data = ta)
power_units = UnitSystem.NATURAL_UNITS
set_variable_cost!(sys, gen, time_series, power_units)
service = ConstantReserve{ReserveDown}(;
name = "init_$i",
available = false,
time_frame = 0.0,
requirement = 0.0,
sustained_time = 0.0,
max_output_fraction = 1.0,
max_participation_factor = 1.0,
deployed_fraction = 0.0,
ext = Dict{String, Any}(),
)
add_component!(sys, service)
add_service!(gen, service, sys)
set_service_bid!(
sys,
gen,
service,
IS.SingleTimeSeries(; name = "init_$i", data = ta),
power_units,
)
end
_, result = validate_serialization(sys)
@test result
end
@testset "Test JSON serialization of ReserveDemandCurve" begin
sys = System(100.0)
devices = []
for i in 1:2
bus = ACBus(nothing)
bus.name = "bus" * string(i)
bus.number = i
# This prevents an error log message.
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen" * string(i)
add_component!(sys, gen)
push!(devices, gen)
end
initial_time = Dates.DateTime("2020-01-01T00:00:00")
end_time = Dates.DateTime("2020-01-01T23:00:00")
dates = collect(initial_time:Dates.Hour(1):end_time)
data = collect(1:24)
service = ReserveDemandCurve{ReserveDown}(nothing)
add_service!(sys, service, devices)
ta = TimeSeries.TimeArray(dates, data)
time_series = IS.SingleTimeSeries(; name = "variable_cost", data = ta)
set_variable_cost!(sys, service, time_series)
_, result = validate_serialization(sys)
@test result
end
@testset "Test JSON serialization of HybridSystem" begin
sys = PSB.build_system(
PSB.PSITestSystems,
"test_RTS_GMLC_sys_with_hybrid";
add_forecasts = true,
)
h_sys = first(get_components(HybridSystem, sys))
subcomponents = collect(get_subcomponents(h_sys))
@test length(subcomponents) == 4
sys2, result = validate_serialization(sys)
@test result
subcomponent = subcomponents[1]
@test IS.get_masked_component(
typeof(subcomponent),
sys2.data,
get_name(subcomponent),
) !== nothing
end
@testset "Test deserialization with new UUIDs" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
sys2, result = validate_serialization(sys; assign_new_uuids = true)
@test result
@test IS.get_uuid(sys) != IS.get_uuid(sys2)
for component1 in get_components(Component, sys)
component2 = get_component(typeof(component1), sys2, get_name(component1))
@test IS.get_uuid(component1) != IS.get_uuid(component2)
end
end
@testset "Test serialization of supplemental attributes" begin
sys = create_system_with_outages()
sys2, result = validate_serialization(sys; assign_new_uuids = true)
@test result
end
@testset "Test verification of invalid ext fields" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys"; add_forecasts = false)
gen = first(get_components(ThermalStandard, sys))
ext = get_ext(gen)
struct MyType
func::Function
end
val = MyType(println)
ext["val"] = val
tmpdir = mktempdir()
filename = joinpath(tmpdir, "invalid_sys.json")
@test_logs(
(:error, r"only basic types are allowed"),
match_mode = :any,
@test_throws(
ErrorException,
to_json(sys, filename, force = true),
),
)
end
@testset "Test serialization of System fields" begin
frequency = 50.0
name = "my_system"
description = "test"
sys = System(100; frequency = frequency, name = name, description = description)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
# This prevents an error log message.
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen1"
add_component!(sys, gen)
sys2, result = validate_serialization(sys)
@test result
@test sys2.frequency == frequency
@test sys2.metadata.name == name
@test sys2.metadata.description == description
end
@testset "Test serialization of subsystems" begin
sys = create_system_with_subsystems()
sys2, result = validate_serialization(sys)
@test result
@test sort!(collect(get_subsystems(sys))) == ["subsystem_1"]
end
@testset "Test serialization to JSON string" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
set_name!(sys, "test_RTS_GMLC_sys")
set_description!(sys, "test description")
@test !isempty(collect(IS.iterate_components_with_time_series(sys.data)))
text = to_json(sys)
sys2 = from_json(text, System)
exclude = Set([:time_series_manager])
@test PSY.compare_values(sys2, sys, exclude = exclude)
@test isempty(collect(IS.iterate_components_with_time_series(sys2.data)))
end
@testset "Test serialization of component with shared time series" begin
for use_scaling_factor in (true, false)
for in_memory in (true, false)
sys = System(100.0)
bus = ACBus(nothing)
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.name = "gen1"
gen.bus = bus
gen.base_power = 1.0
gen.active_power = 1.2
gen.reactive_power = 2.3
gen.active_power_limits = (0.0, 5.0)
add_component!(sys, gen)
initial_time = Dates.DateTime("2020-01-01T00:00:00")
end_time = Dates.DateTime("2020-01-01T23:00:00")
dates = collect(initial_time:Dates.Hour(1):end_time)
data = rand(length(dates))
ta = TimeSeries.TimeArray(dates, data, ["1"])
sfm1 = use_scaling_factor ? get_max_active_power : nothing
sfm2 = use_scaling_factor ? get_max_reactive_power : nothing
ts1a = SingleTimeSeries(;
name = "max_active_power",
data = ta,
scaling_factor_multiplier = sfm1,
)
add_time_series!(sys, gen, ts1a)
ts2a = SingleTimeSeries(
ts1a,
"max_reactive_power";
scaling_factor_multiplier = sfm2,
)
add_time_series!(sys, gen, ts2a)
sys2, result = validate_serialization(sys)
@test result
@test IS.get_num_time_series(sys2.data) == 1
gen2 = get_component(ThermalStandard, sys2, "gen1")
ts1b = get_time_series(SingleTimeSeries, gen2, "max_active_power")
ts2b = get_time_series(SingleTimeSeries, gen2, "max_reactive_power")
@test ts1b.data == ts2b.data
ta_vals = TimeSeries.values(ta)
expected1 = use_scaling_factor ? ta_vals * get_max_active_power(gen) : ta_vals
expected2 = use_scaling_factor ? ta_vals * get_max_reactive_power(gen) : ta_vals
@test get_time_series_values(
gen2,
ts1b,
start_time = initial_time;
) == expected1
@test get_time_series_values(
gen2,
ts2b,
start_time = initial_time,
) == expected2
end
end
end
@testset "Test serialization of GenericArcImpedance" begin
sys = PSB.build_system(PSB.PSITestSystems, "c_sys5")
arc = first(get_components(Arc, sys))
generic_arc_impedance = GenericArcImpedance(;
name = "test_impedance",
available = true,
active_power_flow = 0.0,
reactive_power_flow = 0.0,
max_flow = 0.0,
arc = arc,
r = 0.01,
x = 0.1,
)
add_component!(sys, generic_arc_impedance)
_, result = validate_serialization(sys)
@test result
end
================================================
FILE: test/test_services.jl
================================================
@testset "Test add/remove services" begin
@testset "Case: $direction" for direction in [ReserveDown; ReserveUp; ReserveSymmetric]
sys = System(100.0)
devices = []
for i in 1:2
bus = ACBus(nothing)
bus.name = "bus" * string(i)
bus.number = i
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen" * string(i)
add_component!(sys, gen)
push!(devices, gen)
end
service = ConstantReserve{direction}(nothing)
add_service!(sys, service, devices)
for device in devices
services = get_services(device)
@test length(services) == 1
@test services[1] isa Service
@test services[1] == service
end
services = collect(get_components(Service, sys))
@test length(services) == 1
@test services[1] == service
remove_component!(sys, service)
for device in devices
@test length(get_services(device)) == 0
end
sys = System(100.0)
devices = []
for i in 1:2
bus = ACBus(nothing)
bus.name = "bus" * string(i)
bus.number = i
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen" * string(i)
add_component!(sys, gen)
push!(devices, gen)
end
service = ConstantReserve{direction}(nothing)
add_component!(sys, service)
test_device = get_component(ThermalStandard, sys, "gen1")
add_service!(test_device, service, sys)
@test PowerSystems.has_service(test_device, service)
end
end
@testset "Test add_component Service" begin
sys = System(100.0)
static_reserve = ConstantReserve{ReserveDown}(nothing)
add_component!(sys, static_reserve)
services = get_components(ConstantReserve{ReserveDown}, sys)
@test length(services) == 1
@test iterate(services)[1] == static_reserve
end
@testset "Test add_service errors" begin
sys = System(100.0)
bus = ACBus(nothing)
service = ConstantReserve{ReserveDown}(nothing)
# Bus is not a Device.
@test_throws ArgumentError add_service!(sys, service, [bus])
gen = ThermalStandard(nothing)
# gen is not in sys.
@test_throws ArgumentError add_service!(sys, service, [bus])
end
@testset "Test remove service from device" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen"
add_component!(sys, gen)
service = ConstantReserve{ReserveDown}(nothing)
add_service!(sys, service, [gen])
@test length(get_services(gen)) == 1
remove_service!(gen, service)
@test length(get_services(gen)) == 0
end
@testset "Test has service" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen"
add_component!(sys, gen)
service = ConstantReserve{ReserveDown}(nothing)
add_service!(sys, service, [gen])
@test has_service(gen, service)
@test has_service(gen, typeof(service))
remove_service!(gen, service)
@test !has_service(gen, service)
@test !has_service(gen, typeof(service))
end
@testset "Test remove device with service" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen"
add_component!(sys, gen)
service = ConstantReserve{ReserveDown}(nothing)
add_service!(sys, service, [gen])
@test length(get_services(gen)) == 1
remove_component!(sys, gen)
@test length(get_services(gen)) == 0
end
@testset "Test clear_services" begin
gen = ThermalStandard(nothing)
service = ConstantReserve{ReserveDown}(nothing)
PSY.add_service_internal!(gen, service)
@test length(get_services(gen)) == 1
remove_service!(gen, service)
@test length(get_services(gen)) == 0
end
@testset "Test add device with service" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.name = "bus1"
bus.number = 1
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen"
service = ConstantReserve{ReserveDown}(nothing)
PSY.add_service_internal!(gen, service)
@test length(get_services(gen)) == 1
@test_throws ArgumentError add_component!(sys, gen)
end
@testset "Test get_contributing_devices" begin
sys = System(100.0)
devices = []
services = []
for i in 1:5
bus = ACBus(nothing)
bus.name = "bus" * string(i)
bus.number = i
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen" * string(i)
add_component!(sys, gen)
push!(devices, gen)
service = ConstantReserve{ReserveUp}(nothing)
service.name = "ConstantReserve" * string(i)
push!(services, service)
add_component!(sys, service)
end
PSY.add_service_internal!(devices[1], services[1])
PSY.add_service_internal!(devices[2], services[1])
PSY.add_service_internal!(devices[3], services[2])
PSY.add_service_internal!(devices[4], services[2])
PSY.add_service_internal!(devices[5], services[2])
expected_contributing_devices1 = [devices[1], devices[2]]
expected_contributing_devices2 = [devices[3], devices[4], devices[5]]
contributing_devices1 = get_contributing_devices(sys, services[1])
contributing_devices2 = get_contributing_devices(sys, services[2])
# Order of contributing_devices isn't guaranteed, sort them to test.
sort!(contributing_devices1; by = x -> get_name(x))
sort!(contributing_devices2; by = x -> get_name(x))
@test contributing_devices1 == expected_contributing_devices1
@test contributing_devices2 == expected_contributing_devices2
mapping = get_contributing_device_mapping(sys)
@test length(mapping) == length(services)
key1 =
ServiceContributingDevicesKey((ConstantReserve{ReserveUp}, get_name(services[1])))
key2 =
ServiceContributingDevicesKey((ConstantReserve{ReserveUp}, get_name(services[2])))
key3 =
ServiceContributingDevicesKey((ConstantReserve{ReserveUp}, get_name(services[3])))
@test haskey(mapping, key1)
@test haskey(mapping, key2)
@test haskey(mapping, key3)
@test length(mapping[key1].contributing_devices) == 2
@test length(mapping[key2].contributing_devices) == 3
@test length(mapping[key3].contributing_devices) == 0
sort!(mapping[key1].contributing_devices; by = x -> get_name(x))
sort!(mapping[key2].contributing_devices; by = x -> get_name(x))
@test mapping[key1].contributing_devices == expected_contributing_devices1
@test mapping[key2].contributing_devices == expected_contributing_devices2
end
@testset "Test get_component combinations" begin
sys = System(100.0)
reserves = (
ConstantReserve{ReserveUp}(nothing),
ConstantReserve{ReserveDown}(nothing),
VariableReserve{ReserveUp}(nothing),
VariableReserve{ReserveDown}(nothing),
ReserveDemandCurve{ReserveUp}(nothing),
ReserveDemandCurve{ReserveDown}(nothing),
)
for reserve in reserves
add_component!(sys, reserve)
end
@test length(get_components(Service, sys)) == length(reserves)
@test length(get_components(Reserve, sys)) == length(reserves)
@test length(get_components(ConstantReserve, sys)) == 2
@test length(get_components(VariableReserve, sys)) == 2
@test length(get_components(ConstantReserve{ReserveUp}, sys)) == 1
@test length(get_components(ConstantReserve{ReserveDown}, sys)) == 1
@test length(get_components(VariableReserve{ReserveUp}, sys)) == 1
@test length(get_components(VariableReserve{ReserveDown}, sys)) == 1
@test length(get_components(ReserveDemandCurve{ReserveUp}, sys)) == 1
@test length(get_components(ReserveDemandCurve{ReserveDown}, sys)) == 1
end
@testset "Test struct type collections" begin
concrete_types = IS.get_all_concrete_subtypes(Service)
reserve_types = InteractiveUtils.subtypes(Reserve)
reserve_parametric_types = InteractiveUtils.subtypes(ReserveDirection)
actual_count = length(concrete_types)
for reserve in reserve_types
for parametric in reserve_parametric_types
actual_count += 1
end
end
# Changed 14 to 13 as we eliminated the Transfer Service
@test 13 == actual_count
end
@testset "Test ConstantReserveGroup" begin
# create system
sys = System(100.0)
# add buses and generators
devices = []
for i in 1:2
bus = ACBus(nothing)
bus.name = "bus" * string(i)
bus.number = i
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen" * string(i)
add_component!(sys, gen)
push!(devices, gen)
end
# add ConstantReserve
service = ConstantReserve{ReserveDown}(nothing)
add_service!(sys, service, devices)
# add ConstantReserve
groupservice = ConstantReserveGroup{ReserveDown}(nothing)
add_service!(sys, groupservice)
# add ConstantReserveGroup
groupservices = collect(get_components(ConstantReserveGroup, sys))
# test if ConstantReserveGroup was added
@test length(groupservices) == 1
@test groupservices[1] == groupservice
# add contributing services
expected_contributing_services = Vector{Service}()
push!(expected_contributing_services, service)
set_contributing_services!(sys, groupservice, expected_contributing_services)
# get contributing services
contributing_services = get_contributing_services(groupservice)
# check if expected contributing services is iqual to contributing services
sort!(contributing_services; by = x -> get_name(x))
@test contributing_services == expected_contributing_services
end
@testset "Test ConstantReserveGroup errors" begin
sys = System(100.0)
bus = ACBus(nothing)
groupservice = ConstantReserveGroup{ReserveDown}(nothing)
# Bus is not a Service.
@test_throws MethodError set_contributing_services!(sys, groupservice, [bus])
# Service not in System
service = ConstantReserve{ReserveDown}(nothing)
contributing_services = Vector{Service}()
push!(contributing_services, service)
@test_throws ArgumentError add_service!(sys, groupservice, contributing_services)
# Service in a ConstantReserveGroup
devices = []
for i in 1:2
bus = ACBus(nothing)
bus.name = "bus" * string(i)
bus.number = i
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen" * string(i)
add_component!(sys, gen)
push!(devices, gen)
end
add_service!(sys, service, devices)
add_service!(sys, groupservice, contributing_services)
@test_throws ArgumentError remove_component!(sys, service)
end
@testset "Test ReserveNonSpinning" begin
# create system
sys = System(100.0)
# add buses and generators
devices = []
for i in 1:2
bus = ACBus(nothing)
bus.name = "bus" * string(i)
bus.number = i
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.bus = bus
gen.name = "gen" * string(i)
add_component!(sys, gen)
push!(devices, gen)
end
# add ConstantReserve
service = ConstantReserveNonSpinning(nothing)
add_service!(sys, service, devices)
for device in devices
services = get_services(device)
@test length(services) == 1
@test services[1] isa Service
@test services[1] == service
end
services = collect(get_components(Service, sys))
@test length(services) == 1
@test services[1] == service
remove_component!(sys, service)
for device in devices
@test length(get_services(device)) == 0
end
end
@testset "Test Service Removal" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
res_up = PSY.get_component(PSY.VariableReserve{PSY.ReserveUp}, sys, "Flex_Up")
res_dn = PSY.get_component(PSY.VariableReserve{PSY.ReserveDown}, sys, "Flex_Down")
PSY.remove_component!(sys, res_dn)
PSY.remove_component!(sys, res_up)
@test isnothing(PSY.get_component(PSY.VariableReserve{PSY.ReserveUp}, sys, "Flex_Up"))
@test isnothing(
PSY.get_component(PSY.VariableReserve{PSY.ReserveDown}, sys, "Flex_Down"),
)
end
@testset "Test TransmissionInterface" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
lines = get_components(Line, sys)
xfr = get_components(TapTransformer, sys)
hvdc = collect(get_components(TwoTerminalGenericHVDCLine, sys))
some_lines = collect(lines)[1:2]
other_lines_and_hvdc = vcat(collect(lines)[10:14], hvdc)
lines_and_transformers = [some_lines; collect(xfr)[1:2]]
interface1 = TransmissionInterface("foo1", true, (min = -10.0, max = 10.0))
interface2 = TransmissionInterface("foo2", true, (min = -10.0, max = 10.0))
interface3 = TransmissionInterface("foo3", true, (min = -10.0, max = 10.0))
add_service!(sys, interface1, some_lines)
add_service!(sys, interface2, other_lines_and_hvdc)
add_service!(sys, interface3, lines_and_transformers)
for br in get_contributing_devices(sys, interface1)
@test br ∈ some_lines
end
for br in get_contributing_devices(sys, interface2)
@test br ∈ other_lines_and_hvdc
end
for br in get_contributing_devices(sys, interface3)
@test br ∈ lines_and_transformers
end
tmp_path = joinpath(mktempdir(), "sys_with_interfaces.json")
to_json(sys, tmp_path)
sys = System(tmp_path)
@test length(get_components(TransmissionInterface, sys)) == 3
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
area1 = get_component(Area, sys, "1")
area2 = get_component(Area, sys, "2")
area3 = get_component(Area, sys, "3")
area_interchange12 = AreaInterchange(;
name = "interchange_a1_a2",
available = true,
active_power_flow = 0.0,
from_area = area1,
to_area = area2,
flow_limits = (from_to = 100.0, to_from = 100.0),
)
area_interchange13 = AreaInterchange(;
name = "interchange_a1_a3",
available = true,
active_power_flow = 0.0,
from_area = area1,
to_area = area3,
flow_limits = (from_to = 100.0, to_from = 100.0),
)
line = first(get_components(Line, sys))
add_component!(sys, area_interchange12)
add_component!(sys, area_interchange13)
area_level_interface = TransmissionInterface("foo3", true, (min = -10.0, max = 10.0))
area_level_mixed = TransmissionInterface("foo4", true, (min = -10.0, max = 10.0))
add_service!(sys, area_level_interface, [area_interchange12, area_interchange13])
@test_throws ArgumentError add_service!(
sys,
area_level_mixed,
[area_interchange12, area_interchange13, line],
)
end
@testset "Test AGC" begin
sys = PSB.build_system(PSITestSystems, "c_sys5_uc"; add_reserves = true)
thermals = get_components(ThermalStandard, sys)
reserves = get_components(VariableReserve{ReserveUp}, sys)
agc = AGC(;
name = "agc",
available = true,
bias = 0.0,
K_p = 1.0,
K_i = 1.0,
K_d = 1.0,
delta_t = 1.0,
)
@test_throws ArgumentError add_service!(sys, agc, thermals)
add_service!(sys, agc, reserves)
mapping = get_contributing_reserve_mapping(sys)
@test length(mapping) == 1
@test_throws ArgumentError add_service!(sys, agc, reserves)
#Test serialization of system with AGC + contributing reserves
sys = PSB.build_system(PSITestSystems, "c_sys5_uc"; add_reserves = true)
reserves = get_components(VariableReserve{ReserveUp}, sys)
agc = AGC(;
name = "agc",
available = true,
bias = 0.0,
K_p = 1.0,
K_i = 1.0,
K_d = 1.0,
delta_t = 1.0,
)
add_service!(sys, agc, reserves)
_, result = validate_serialization(sys)
@test result
end
================================================
FILE: test/test_subsystems.jl
================================================
function create_system_with_test_subsystems()
sys = PSB.build_system(
PSITestSystems,
"c_sys5_uc";
add_forecasts = false,
time_series_read_only = false,
)
components = collect(get_components(ThermalStandard, sys))
@test length(components) >= 5
subsystems = String[]
for i in 1:3
name = "subsystem_$i"
add_subsystem!(sys, name)
push!(subsystems, name)
end
add_component_to_subsystem!(sys, subsystems[1], components[1])
add_component_to_subsystem!(sys, subsystems[1], components[2])
add_component_to_subsystem!(sys, subsystems[2], components[2])
add_component_to_subsystem!(sys, subsystems[2], components[3])
add_component_to_subsystem!(sys, subsystems[3], components[3])
add_component_to_subsystem!(sys, subsystems[3], components[4])
return (sys, components)
end
function create_system_with_2_test_subsystems()
c_sys5 = PSB.build_system(PSISystems, "2Area 5 Bus System")
components = collect(get_components(Component, c_sys5))
#@test length(components) == 52
subsystems = String[]
for i in 1:2
name = "subsystem_$i"
add_subsystem!(c_sys5, name)
push!(subsystems, name)
end
#name of components solely belonging to subsystem 2 ends with 2
suffix = "2"
for component in get_components(Component, c_sys5)
if (endswith(get_name(component), suffix))
add_component_to_subsystem!(c_sys5, subsystems[2], component)
else
add_component_to_subsystem!(c_sys5, subsystems[1], component)
end
end
#components connecting the subsystems are shared
add_component_to_subsystem!(
c_sys5,
subsystems[1],
get_component(TwoTerminalGenericHVDCLine, c_sys5, "nodeC-nodeC2"),
)
add_component_to_subsystem!(
c_sys5,
subsystems[1],
get_component(Arc, c_sys5, "nodeC -> nodeC2"),
)
add_component_to_subsystem!(
c_sys5,
subsystems[1],
get_component(ACBus, c_sys5, "nodeC2"),
)
add_component_to_subsystem!(
c_sys5,
subsystems[2],
get_component(ACBus, c_sys5, "nodeC"),
)
PSY.check(c_sys5)
PSY.check_components(c_sys5)
return (c_sys5, components)
end
@testset "Test get subsystems and components" begin
sys, components = create_system_with_test_subsystems()
@test sort!(collect(get_subsystems(sys))) ==
["subsystem_1", "subsystem_2", "subsystem_3"]
@test has_component(sys, "subsystem_1", components[1])
@test has_component(sys, "subsystem_1", components[2])
@test has_component(sys, "subsystem_2", components[2])
@test has_component(sys, "subsystem_2", components[3])
@test has_component(sys, "subsystem_3", components[3])
@test has_component(sys, "subsystem_3", components[4])
@test !has_component(sys, "subsystem_3", components[5])
@test sort!(get_name.(get_subsystem_components(sys, "subsystem_2"))) ==
sort!([get_name(components[2]), get_name(components[3])])
@test get_assigned_subsystems(sys, components[1]) == ["subsystem_1"]
@test is_assigned_to_subsystem(sys, components[1])
@test !is_assigned_to_subsystem(sys, components[5])
@test is_assigned_to_subsystem(sys, components[1], "subsystem_1")
@test !is_assigned_to_subsystem(sys, components[5], "subsystem_1")
@test_throws ArgumentError add_subsystem!(sys, "subsystem_1")
end
@testset "Test get_components" begin
sys, components = create_system_with_test_subsystems()
@test length(
get_components(ThermalStandard, sys; subsystem_name = "subsystem_1"),
) == 2
name = get_name(components[1])
@test collect(
get_components(
x -> x.name == name,
ThermalStandard,
sys;
subsystem_name = "subsystem_1",
),
)[1].name == name
end
@testset "Test subsystem after remove_component" begin
sys, components = create_system_with_test_subsystems()
remove_component!(sys, components[3])
@test !has_component(sys, "subsystem_2", components[3])
@test !has_component(sys, "subsystem_3", components[3])
@test has_component(sys, "subsystem_2", components[2])
@test has_component(sys, "subsystem_3", components[4])
end
@testset "Test removal of subsystem" begin
sys, components = create_system_with_test_subsystems()
remove_subsystem!(sys, "subsystem_2")
@test sort!(collect(get_subsystems(sys))) == ["subsystem_1", "subsystem_3"]
@test get_assigned_subsystems(sys, components[2]) == ["subsystem_1"]
@test_throws ArgumentError remove_subsystem!(sys, "subsystem_2")
end
@testset "Test removal of subsystem component" begin
sys, components = create_system_with_test_subsystems()
remove_component_from_subsystem!(sys, "subsystem_2", components[2])
@test get_name.(get_subsystem_components(sys, "subsystem_2")) ==
[get_name(components[3])]
@test_throws ArgumentError remove_component_from_subsystem!(
sys,
"subsystem_2",
components[2],
)
end
@testset "Test addition of component to invalid subsystem" begin
sys, components = create_system_with_test_subsystems()
@test_throws ArgumentError add_component_to_subsystem!(sys, "invalid", components[1])
end
@testset "Test addition of duplicate component to subsystem" begin
sys, components = create_system_with_test_subsystems()
@test_throws ArgumentError add_component_to_subsystem!(
sys,
"subsystem_1",
components[1],
)
end
@testset "Test addition of non-system component" begin
sys, components = create_system_with_test_subsystems()
remove_component!(sys, components[1])
@test_throws ArgumentError add_component_to_subsystem!(
sys,
"subsystem_1",
components[1],
)
end
@testset "Test invalid subsystem count" begin
sys = PSB.build_system(
PSITestSystems,
"c_sys5_uc";
add_forecasts = false,
time_series_read_only = true,
)
num_buses = length(get_components(Bus, sys))
for i in 1:num_buses
add_subsystem!(sys, "subsystem_$i")
end
@test_throws "cannot exceed the number of buses" add_subsystem!(sys, "subsystem")
end
@testset "Test valid subsystem" begin
sys = create_system_with_subsystems()
check_components(sys)
end
@testset "Test inconsistent component-subsystem membership" begin
sys, components = create_system_with_test_subsystems()
@test_throws IS.InvalidValue check_components(sys)
end
@testset "Test mismatch component-topological membership" begin
sys = create_system_with_subsystems()
add_subsystem!(sys, "incomplete_subsystem")
gen = first(get_components(ThermalStandard, sys))
bus = get_bus(gen)
remove_component_from_subsystem!(sys, "subsystem_1", bus)
add_component_to_subsystem!(sys, "incomplete_subsystem", bus)
@test_throws IS.InvalidValue PSY._check_topological_consistency(sys, gen)
end
@testset "Test mismatch branch-arc membership" begin
sys = create_system_with_subsystems()
add_subsystem!(sys, "incomplete_subsystem")
branch = first(get_components(Branch, sys))
arc = get_arc(branch)
remove_component_from_subsystem!(sys, "subsystem_1", arc)
add_component_to_subsystem!(sys, "incomplete_subsystem", arc)
@test_throws IS.InvalidValue PSY._check_branch_consistency(sys, branch)
end
@testset "Test service-contributing-device consistency" begin
sys = create_system_with_subsystems()
add_subsystem!(sys, "incomplete_subsystem")
device = nothing
service = nothing
for dev in get_components(Device, sys)
if !PSY.supports_services(dev)
continue
end
services = get_services(dev)
if !isempty(services)
device = dev
service = first(services)
break
end
end
@test !isnothing(device) && !isnothing(service)
remove_component_from_subsystem!(sys, "subsystem_1", device)
add_subsystem!(sys, "subsystem_2")
add_component_to_subsystem!(sys, "subsystem_2", device)
@test_throws IS.InvalidValue PSY._check_device_service_consistency(sys, device)
end
@testset "Test subsystems with HybridSystem" begin
sys = PSB.build_system(PSB.PSITestSystems, "test_RTS_GMLC_sys_with_hybrid")
h_sys = first(get_components(HybridSystem, sys))
subcomponents = collect(get_subcomponents(h_sys))
subsystem_name = "subsystem_1"
add_subsystem!(sys, subsystem_name)
add_component_to_subsystem!(sys, subsystem_name, h_sys)
# Ensure that subcomponents get added automatically.
for subcomponent in subcomponents
@test is_assigned_to_subsystem(sys, subcomponent, subsystem_name)
end
remove_component_from_subsystem!(sys, subsystem_name, subcomponents[1])
@test_throws IS.InvalidValue PSY._check_subcomponent_consistency(sys, h_sys)
add_component_to_subsystem!(sys, subsystem_name, subcomponents[1])
remove_component_from_subsystem!(sys, subsystem_name, h_sys)
# Ensure that subcomponents get removed automatically.
for subcomponent in subcomponents
@test !is_assigned_to_subsystem(sys, subcomponent, subsystem_name)
end
end
@testset "Test get subsystems and components for c_sys5" begin
bus_c = ACBus(
3,
"nodeC",
true,
"PV",
0,
1.0,
(min = 0.9, max = 1.05),
230,
nothing,
nothing,
)
bus_d = ACBus(
4,
"nodeD",
true,
"REF",
0,
1.0,
(min = 0.9, max = 1.05),
230,
nothing,
nothing,
)
bus_d2 =
ACBus(
9,
"nodeD2",
true,
"REF",
0,
1.0,
(min = 0.9, max = 1.05),
230,
nothing,
nothing,
)
d_d2 = Line(
"nodeD-nodeD2",
true,
0.0,
0.0,
Arc(; from = bus_d, to = bus_d2),
0.00108,
0.0108,
(from = 0.00926, to = 0.00926),
11.1480,
(min = -0.7, max = 0.7),
)
c_d2 = Line(
"nodeC-nodeD2",
true,
0.0,
0.0,
Arc(; from = bus_c, to = bus_d2),
0.00297,
0.0297,
(from = 0.00337, to = 0.00337),
40.530,
(min = -0.7, max = 0.7),
)
c_sys5, components = create_system_with_2_test_subsystems()
@test sort!(collect(get_subsystems(c_sys5))) ==
["subsystem_1", "subsystem_2"]
@test has_component(c_sys5, "subsystem_1", get_component(Arc, c_sys5, "nodeA -> nodeB"))
@test has_component(c_sys5, "subsystem_1", get_component(Arc, c_sys5, "nodeA -> nodeD"))
@test has_component(c_sys5, "subsystem_1", get_component(Arc, c_sys5, "nodeA -> nodeE"))
@test has_component(c_sys5, "subsystem_1", get_component(Arc, c_sys5, "nodeB -> nodeC"))
@test has_component(c_sys5, "subsystem_1", get_component(Arc, c_sys5, "nodeC -> nodeD"))
@test has_component(c_sys5, "subsystem_1", get_component(Arc, c_sys5, "nodeD -> nodeE"))
@test has_component(
c_sys5,
"subsystem_1",
get_component(Arc, c_sys5, "nodeC -> nodeC2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(Arc, c_sys5, "nodeA2 -> nodeB2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(Arc, c_sys5, "nodeA2 -> nodeD2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(Arc, c_sys5, "nodeA2 -> nodeE2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(Arc, c_sys5, "nodeB2 -> nodeC2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(Arc, c_sys5, "nodeC2 -> nodeD2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(Arc, c_sys5, "nodeD2 -> nodeE2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(Arc, c_sys5, "nodeC -> nodeC2"),
)
@test has_component(
c_sys5,
"subsystem_1",
get_component(ThermalStandard, c_sys5, "Solitude"),
)
@test has_component(
c_sys5,
"subsystem_1",
get_component(ThermalStandard, c_sys5, "Park City"),
)
@test has_component(
c_sys5,
"subsystem_1",
get_component(ThermalStandard, c_sys5, "Alta"),
)
@test has_component(
c_sys5,
"subsystem_1",
get_component(ThermalStandard, c_sys5, "Brighton"),
)
@test has_component(
c_sys5,
"subsystem_1",
get_component(ThermalStandard, c_sys5, "Sundance"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(ThermalStandard, c_sys5, "Park City-2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(ThermalStandard, c_sys5, "Solitude-2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(ThermalStandard, c_sys5, "Alta-2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(ThermalStandard, c_sys5, "Sundance-2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(ThermalStandard, c_sys5, "Brighton-2"),
)
@test has_component(
c_sys5,
"subsystem_1",
get_component(PowerLoad, c_sys5, "Load-nodeB"),
)
@test has_component(
c_sys5,
"subsystem_1",
get_component(PowerLoad, c_sys5, "Load-nodeC"),
)
@test has_component(
c_sys5,
"subsystem_1",
get_component(PowerLoad, c_sys5, "Load-nodeD"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(PowerLoad, c_sys5, "Load-nodeB2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(PowerLoad, c_sys5, "Load-nodeC2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(PowerLoad, c_sys5, "Load-nodeD2"),
)
@test has_component(c_sys5, "subsystem_1", get_component(Line, c_sys5, "nodeA-nodeB"))
@test has_component(c_sys5, "subsystem_1", get_component(Line, c_sys5, "nodeA-nodeD"))
@test has_component(c_sys5, "subsystem_1", get_component(Line, c_sys5, "nodeA-nodeE"))
@test has_component(c_sys5, "subsystem_1", get_component(Line, c_sys5, "nodeB-nodeC"))
@test has_component(c_sys5, "subsystem_1", get_component(Line, c_sys5, "nodeC-nodeD"))
@test has_component(c_sys5, "subsystem_1", get_component(Line, c_sys5, "nodeD-nodeE"))
@test has_component(c_sys5, "subsystem_2", get_component(Line, c_sys5, "nodeA2-nodeB2"))
@test has_component(c_sys5, "subsystem_2", get_component(Line, c_sys5, "nodeA2-nodeD2"))
@test has_component(c_sys5, "subsystem_2", get_component(Line, c_sys5, "nodeA2-nodeE2"))
@test has_component(c_sys5, "subsystem_2", get_component(Line, c_sys5, "nodeB2-nodeC2"))
@test has_component(c_sys5, "subsystem_2", get_component(Line, c_sys5, "nodeC2-nodeD2"))
@test has_component(c_sys5, "subsystem_2", get_component(Line, c_sys5, "nodeD2-nodeE2"))
@test has_component(c_sys5, "subsystem_1", get_component(ACBus, c_sys5, "nodeA"))
@test has_component(c_sys5, "subsystem_1", get_component(ACBus, c_sys5, "nodeB"))
@test has_component(c_sys5, "subsystem_1", get_component(ACBus, c_sys5, "nodeC"))
@test has_component(c_sys5, "subsystem_1", get_component(ACBus, c_sys5, "nodeD"))
@test has_component(c_sys5, "subsystem_1", get_component(ACBus, c_sys5, "nodeE"))
@test has_component(c_sys5, "subsystem_1", get_component(ACBus, c_sys5, "nodeC2"))
@test has_component(c_sys5, "subsystem_2", get_component(ACBus, c_sys5, "nodeA2"))
@test has_component(c_sys5, "subsystem_2", get_component(ACBus, c_sys5, "nodeB2"))
@test has_component(c_sys5, "subsystem_2", get_component(ACBus, c_sys5, "nodeC2"))
@test has_component(c_sys5, "subsystem_2", get_component(ACBus, c_sys5, "nodeD2"))
@test has_component(c_sys5, "subsystem_2", get_component(ACBus, c_sys5, "nodeE2"))
@test has_component(c_sys5, "subsystem_2", get_component(ACBus, c_sys5, "nodeC"))
@test has_component(
c_sys5,
"subsystem_1",
get_component(TwoTerminalGenericHVDCLine, c_sys5, "nodeC-nodeC2"),
)
@test has_component(
c_sys5,
"subsystem_2",
get_component(TwoTerminalGenericHVDCLine, c_sys5, "nodeC-nodeC2"),
)
@test sort!(get_name.(get_subsystem_components(c_sys5, "subsystem_1"))) ==
sort!([
get_name(get_component(Arc, c_sys5, "nodeA -> nodeB")),
get_name(get_component(Arc, c_sys5, "nodeA -> nodeD")),
get_name(get_component(Arc, c_sys5, "nodeA -> nodeE")),
get_name(get_component(Arc, c_sys5, "nodeB -> nodeC")),
get_name(get_component(Arc, c_sys5, "nodeC -> nodeD")),
get_name(get_component(Arc, c_sys5, "nodeD -> nodeE")),
get_name(get_component(Arc, c_sys5, "nodeC -> nodeC2")),
get_name(get_component(ThermalStandard, c_sys5, "Solitude")),
get_name(get_component(ThermalStandard, c_sys5, "Park City")),
get_name(get_component(ThermalStandard, c_sys5, "Alta")),
get_name(get_component(ThermalStandard, c_sys5, "Brighton")),
get_name(get_component(ThermalStandard, c_sys5, "Sundance")),
get_name(get_component(PowerLoad, c_sys5, "Load-nodeB")),
get_name(get_component(PowerLoad, c_sys5, "Load-nodeC")),
get_name(get_component(PowerLoad, c_sys5, "Load-nodeD")),
get_name(get_component(Line, c_sys5, "nodeA-nodeB")),
get_name(get_component(Line, c_sys5, "nodeA-nodeD")),
get_name(get_component(Line, c_sys5, "nodeA-nodeE")),
get_name(get_component(Line, c_sys5, "nodeB-nodeC")),
get_name(get_component(Line, c_sys5, "nodeC-nodeD")),
get_name(get_component(Line, c_sys5, "nodeD-nodeE")),
get_name(get_component(ACBus, c_sys5, "nodeA")),
get_name(get_component(ACBus, c_sys5, "nodeB")),
get_name(get_component(ACBus, c_sys5, "nodeC")),
get_name(get_component(ACBus, c_sys5, "nodeD")),
get_name(get_component(ACBus, c_sys5, "nodeE")),
get_name(get_component(ACBus, c_sys5, "nodeC2")),
get_name(get_component(TwoTerminalGenericHVDCLine, c_sys5, "nodeC-nodeC2")),
])
@test get_assigned_subsystems(c_sys5, get_component(ACBus, c_sys5, "nodeD")) ==
["subsystem_1"]
@test get_assigned_subsystems(c_sys5, get_component(ACBus, c_sys5, "nodeD2")) ==
["subsystem_2"]
@test sort!(get_assigned_subsystems(c_sys5, get_component(ACBus, c_sys5, "nodeC2"))) ==
["subsystem_1", "subsystem_2"]
@test sort!(get_assigned_subsystems(c_sys5, get_component(ACBus, c_sys5, "nodeC"))) ==
["subsystem_1", "subsystem_2"]
@test is_assigned_to_subsystem(c_sys5, get_component(ACBus, c_sys5, "nodeC"))
@test !is_assigned_to_subsystem(c_sys5, d_d2)
@test !is_assigned_to_subsystem(c_sys5, c_d2)
@test is_assigned_to_subsystem(
c_sys5,
get_component(ACBus, c_sys5, "nodeC"),
"subsystem_1",
)
@test is_assigned_to_subsystem(
c_sys5,
get_component(ACBus, c_sys5, "nodeC"),
"subsystem_2",
)
@test is_assigned_to_subsystem(
c_sys5,
get_component(ACBus, c_sys5, "nodeD"),
"subsystem_1",
)
@test is_assigned_to_subsystem(
c_sys5,
get_component(ACBus, c_sys5, "nodeD2"),
"subsystem_2",
)
@test !is_assigned_to_subsystem(
c_sys5,
get_component(ACBus, c_sys5, "nodeD2"),
"subsystem_1",
)
@test_throws ArgumentError add_subsystem!(c_sys5, "subsystem_1")
end
@testset "Test get_components for c_sys5" begin
c_sys5, components = create_system_with_2_test_subsystems()
@test length(
get_components(ThermalStandard, c_sys5; subsystem_name = "subsystem_1"),
) == 5
name = get_name(get_component(PowerLoad, c_sys5, "Load-nodeB2"))
@test collect(
get_components(
x -> x.name == name,
PowerLoad,
c_sys5;
subsystem_name = "subsystem_2",
),
)[1].name == name
end
@testset "Test c_sys5 subsystem after remove_component" begin
c_sys5, components = create_system_with_2_test_subsystems()
comp = get_component(Arc, c_sys5, "nodeB -> nodeC")
remove_component!(c_sys5, comp)
@test !has_component(c_sys5, "subsystem_1", comp)
@test !has_component(c_sys5, "subsystem_2", comp)
@test has_component(c_sys5, "subsystem_1", get_component(Arc, c_sys5, "nodeA -> nodeB"))
@test has_component(
c_sys5,
"subsystem_2",
get_component(Arc, c_sys5, "nodeA2 -> nodeB2"),
)
end
@testset "Test removal of subsystem from c_sys5" begin
c_sys5, components = create_system_with_2_test_subsystems()
remove_subsystem!(c_sys5, "subsystem_2")
@test sort!(collect(get_subsystems(c_sys5))) == ["subsystem_1"]
@test get_assigned_subsystems(c_sys5, get_component(Arc, c_sys5, "nodeA -> nodeB")) ==
["subsystem_1"]
@test_throws ArgumentError remove_subsystem!(c_sys5, "subsystem_2")
end
@testset "Test removal of subsystem component" begin
c_sys5, components = create_system_with_2_test_subsystems()
comp = get_component(Arc, c_sys5, "nodeA -> nodeB")
remove_component_from_subsystem!(c_sys5, "subsystem_1", comp)
@test sort!(get_name.(get_subsystem_components(c_sys5, "subsystem_1"))) ==
sort!([
get_name(get_component(Arc, c_sys5, "nodeA -> nodeD")),
get_name(get_component(Arc, c_sys5, "nodeA -> nodeE")),
get_name(get_component(Arc, c_sys5, "nodeB -> nodeC")),
get_name(get_component(Arc, c_sys5, "nodeC -> nodeD")),
get_name(get_component(Arc, c_sys5, "nodeD -> nodeE")),
get_name(get_component(Arc, c_sys5, "nodeC -> nodeC2")),
get_name(get_component(ThermalStandard, c_sys5, "Solitude")),
get_name(get_component(ThermalStandard, c_sys5, "Park City")),
get_name(get_component(ThermalStandard, c_sys5, "Alta")),
get_name(get_component(ThermalStandard, c_sys5, "Brighton")),
get_name(get_component(ThermalStandard, c_sys5, "Sundance")),
get_name(get_component(PowerLoad, c_sys5, "Load-nodeB")),
get_name(get_component(PowerLoad, c_sys5, "Load-nodeC")),
get_name(get_component(PowerLoad, c_sys5, "Load-nodeD")),
get_name(get_component(Line, c_sys5, "nodeA-nodeB")),
get_name(get_component(Line, c_sys5, "nodeA-nodeD")),
get_name(get_component(Line, c_sys5, "nodeA-nodeE")),
get_name(get_component(Line, c_sys5, "nodeB-nodeC")),
get_name(get_component(Line, c_sys5, "nodeC-nodeD")),
get_name(get_component(Line, c_sys5, "nodeD-nodeE")),
get_name(get_component(ACBus, c_sys5, "nodeA")),
get_name(get_component(ACBus, c_sys5, "nodeB")),
get_name(get_component(ACBus, c_sys5, "nodeC")),
get_name(get_component(ACBus, c_sys5, "nodeD")),
get_name(get_component(ACBus, c_sys5, "nodeE")),
get_name(get_component(ACBus, c_sys5, "nodeC2")),
get_name(get_component(TwoTerminalGenericHVDCLine, c_sys5, "nodeC-nodeC2")),
])
@test_throws ArgumentError remove_component_from_subsystem!(
c_sys5,
"subsystem_1",
comp,
)
end
@testset "Test addition of component to invalid subsystem for c_sys5" begin
c_sys5, components = create_system_with_2_test_subsystems()
@test_throws ArgumentError add_component_to_subsystem!(c_sys5, "invalid", components[1])
end
@testset "Test addition of duplicate component to subsystem for c_sys5" begin
c_sys5, components = create_system_with_2_test_subsystems()
@test_throws ArgumentError add_component_to_subsystem!(
c_sys5,
"subsystem_1",
get_component(ACBus, c_sys5, "nodeD"),
)
end
@testset "Test addition of non-system component to c_sys5" begin
c_sys5, components = create_system_with_2_test_subsystems()
comp = get_component(ACBus, c_sys5, "nodeD")
remove_component!(c_sys5, comp)
@test_throws ArgumentError add_component_to_subsystem!(
c_sys5,
"subsystem_1",
comp,
)
end
@testset "Test invalid subsystem count" begin
c_sys5, components = create_system_with_2_test_subsystems()
num_buses = length(get_components(Bus, c_sys5))
for i in 3:num_buses
add_subsystem!(c_sys5, "subsystem_$i")
end
@test_throws "cannot exceed the number of buses" add_subsystem!(
c_sys5,
"subsystem134523",
)
end
@testset "Test service-contributing-device consistency for c_sys5" begin
c_sys5, components = create_system_with_2_test_subsystems()
device = nothing
service = nothing
for dev in get_components(Device, c_sys5; subsystem_name = "subsystem_1")
res = VariableReserve{ReserveUp}("REG1", true, 5.0, 0.1)
add_service!(c_sys5, res, dev)
services = get_services(dev)
if !isempty(services)
device = dev
service = first(services)
break
end
end
@test !isnothing(device) && !isnothing(service)
remove_component_from_subsystem!(c_sys5, "subsystem_1", device)
add_subsystem!(c_sys5, "incomplete_subsystem")
add_component_to_subsystem!(c_sys5, "incomplete_subsystem", device)
@test_throws IS.InvalidValue PSY._check_device_service_consistency(c_sys5, device)
end
@testset "Test construct system from subsystem" begin
base_sys = create_system_with_2_test_subsystems()[1]
ts_counts = get_time_series_counts(base_sys)
@test ts_counts.components_with_time_series == 6
@test ts_counts.forecast_count == 6
subsystem1_uuids = get_component_uuids(base_sys, "subsystem_1")
subsystem2_uuids = get_component_uuids(base_sys, "subsystem_2")
sys1 = from_subsystem(base_sys, "subsystem_1")
sys2 = from_subsystem(base_sys, "subsystem_2")
base_sys_components = get_components(Component, base_sys)
sys1_components = get_components(Component, sys1)
sys2_components = get_components(Component, sys2)
@test length(sys1_components) < length(base_sys_components)
@test length(sys2_components) < length(base_sys_components)
for (components, uuids) in
((sys1_components, subsystem1_uuids), (sys2_components, subsystem2_uuids))
for component in components
base_component = get_component(typeof(component), base_sys, get_name(component))
@test IS.get_uuid(base_component) in uuids
end
end
for sys in (sys1, sys2)
ts_counts = get_time_series_counts(sys)
@test ts_counts.components_with_time_series == 3
@test ts_counts.forecast_count == 3
end
end
================================================
FILE: test/test_supplemental_accessors.jl
================================================
@testset "Test supplemental voltage accessors" begin
@testset "get_base_voltage for Line - matching voltages" begin
sys = PSB.build_system(PSB.PSITestSystems, "c_sys5")
lines = collect(get_components(Line, sys))
@test !isempty(lines)
for line in lines
from_bus = get_from(get_arc(line))
expected = get_base_voltage(from_bus)
@test get_base_voltage(line) == expected
@test get_base_voltage(line) isa Float64
end
end
@testset "get_base_voltage for Line - within tolerance picks rounder value" begin
bus_from = ACBus(nothing)
bus_from.name = "bus_from"
bus_from.number = 1
bus_from.bustype = ACBusTypes.PV
bus_from.base_voltage = 230.0
bus_to = ACBus(nothing)
bus_to.name = "bus_to"
bus_to.number = 2
bus_to.bustype = ACBusTypes.PQ
bus_to.base_voltage = 229.5 # within 1% of 230.0
arc = Arc(; from = bus_from, to = bus_to)
line = Line(
"test_line",
true,
0.0,
0.0,
arc,
0.01,
0.05,
(from = 0.0, to = 0.0),
100.0,
(min = -0.7, max = 0.7),
)
# 230.0 has fewer significant figures than 229.5
@test get_base_voltage(line) == 230.0
# Reverse: from has more digits, to has fewer
bus_from2 = ACBus(nothing)
bus_from2.name = "bus_from2"
bus_from2.number = 3
bus_from2.bustype = ACBusTypes.PV
bus_from2.base_voltage = 229.5
bus_to2 = ACBus(nothing)
bus_to2.name = "bus_to2"
bus_to2.number = 4
bus_to2.bustype = ACBusTypes.PQ
bus_to2.base_voltage = 230.0
arc2 = Arc(; from = bus_from2, to = bus_to2)
line2 = Line(
"test_line2",
true,
0.0,
0.0,
arc2,
0.01,
0.05,
(from = 0.0, to = 0.0),
100.0,
(min = -0.7, max = 0.7),
)
@test get_base_voltage(line2) == 230.0
end
@testset "get_base_voltage for Line - exceeds tolerance throws error" begin
bus_from = ACBus(nothing)
bus_from.name = "bus_hi"
bus_from.number = 5
bus_from.bustype = ACBusTypes.PV
bus_from.base_voltage = 230.0
bus_to = ACBus(nothing)
bus_to.name = "bus_lo"
bus_to.number = 6
bus_to.bustype = ACBusTypes.PQ
bus_to.base_voltage = 115.0 # 50% difference
arc = Arc(; from = bus_from, to = bus_to)
line = Line(
"bad_line",
true,
0.0,
0.0,
arc,
0.01,
0.05,
(from = 0.0, to = 0.0),
100.0,
(min = -0.7, max = 0.7),
)
@test_throws ErrorException get_base_voltage(line)
end
@testset "get_high_voltage and get_low_voltage for TapTransformer" begin
sys = PSB.build_system(PSB.PSITestSystems, "c_sys14")
taps = collect(get_components(TapTransformer, sys))
@test !isempty(taps)
for t in taps
v_primary = get_base_voltage_primary(t)
v_secondary = get_base_voltage_secondary(t)
@test get_high_voltage(t) == max(v_primary, v_secondary)
@test get_low_voltage(t) == min(v_primary, v_secondary)
@test get_high_voltage(t) >= get_low_voltage(t)
@test get_high_voltage(t) isa Float64
@test get_low_voltage(t) isa Float64
end
end
@testset "get_high_voltage and get_low_voltage for Transformer2W" begin
sys = PSB.build_system(PSB.PSITestSystems, "c_sys14")
t2ws = collect(get_components(Transformer2W, sys))
@test !isempty(t2ws)
for t in t2ws
v_primary = get_base_voltage_primary(t)
v_secondary = get_base_voltage_secondary(t)
@test get_high_voltage(t) == max(v_primary, v_secondary)
@test get_low_voltage(t) == min(v_primary, v_secondary)
@test get_high_voltage(t) >= get_low_voltage(t)
end
end
end
================================================
FILE: test/test_system.jl
================================================
@testset "Test functionality of System" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys"; add_forecasts = false)
summary(devnull, sys)
@test get_frequency(sys) == PSY.DEFAULT_SYSTEM_FREQUENCY
generators = collect(get_components(ThermalStandard, sys))
generator = get_component(ThermalStandard, sys, get_name(generators[1]))
@test IS.get_uuid(generator) == IS.get_uuid(generators[1])
@test_throws(IS.ArgumentError, add_component!(sys, generator))
@test get_available_component(ThermalStandard, sys, get_name(generators[1])) ===
generator
set_available!(generator, false)
@test isnothing(get_available_component(ThermalStandard, sys, get_name(generators[1])))
set_available!(generator, true)
generators2 = get_components_by_name(ThermalGen, sys, get_name(generators[1]))
@test length(generators2) == 1
@test IS.get_uuid(generators2[1]) == IS.get_uuid(generators[1])
@test !has_time_series(generators2[1])
@test isnothing(get_component(ThermalStandard, sys, "not-a-name"))
@test isempty(get_components_by_name(ThermalGen, sys, "not-a-name"))
@test_throws(
IS.ArgumentError,
get_components_by_name(ThermalStandard, sys, "not-a-name")
)
@test isempty(get_components(x -> (!get_available(x)), ThermalStandard, sys))
@test !isempty(get_available_components(ThermalStandard, sys))
@test !isempty(get_available_components(x -> true, ThermalStandard, sys))
# Test get_bus* functionality.
bus_numbers = Vector{Int}()
for bus in get_components(ACBus, sys)
push!(bus_numbers, bus.number)
if length(bus_numbers) >= 2
break
end
end
bus = PowerSystems.get_bus(sys, bus_numbers[1])
@test bus.number == bus_numbers[1]
buses = PowerSystems.get_buses(sys, Set(bus_numbers))
sort!(bus_numbers)
sort!(buses; by = x -> x.number)
@test length(bus_numbers) == length(buses)
for (bus_number, bus) in zip(bus_numbers, buses)
@test bus_number == bus.number
end
@test get_forecast_initial_times(sys) == []
@test get_time_series_resolutions(sys)[1] == Dates.Hour(1)
# Get time_series with a name and without.
components = collect(get_components(HydroTurbine, sys))
@test !isempty(components)
component = components[1]
ts = get_time_series(SingleTimeSeries, component, "max_active_power")
@test ts isa SingleTimeSeries
components = collect(get_components(HydroReservoir, sys))
@test !isempty(components)
returned_it, returned_len = check_time_series_consistency(sys, SingleTimeSeries)
@test returned_it == first(TimeSeries.timestamp(get_data(ts)))
@test returned_len == length(get_data(ts))
# Test all versions of get_time_series_[array|timestamps|values]
values1 = get_time_series_array(component, ts)
values2 = get_time_series_array(SingleTimeSeries, component, "max_active_power")
@test values1 == values2
values3 = get_time_series_array(SingleTimeSeries, component, "max_active_power")
@test values1 == values3
val = get_time_series_array(SingleTimeSeries, component, "max_active_power")
@test val isa TimeSeries.TimeArray
val = get_time_series_timestamps(SingleTimeSeries, component, "max_active_power")
@test val isa Array
@test val[1] isa Dates.DateTime
val = get_time_series_values(SingleTimeSeries, component, "max_active_power")
@test val isa Array
@test val[1] isa AbstractFloat
val = get_time_series_array(component, ts)
@test val isa TimeSeries.TimeArray
val = get_time_series_timestamps(component, ts)
@test val isa Array
@test val[1] isa Dates.DateTime
val = get_time_series_values(component, ts)
@test val isa Array
@test val[1] isa AbstractFloat
clear_time_series!(sys)
@test length(collect(get_time_series_multiple(sys))) == 0
@test IS.get_internal(sys) isa IS.InfrastructureSystemsInternal
end
@testset "Test get_componets filter_func" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys"; add_forecasts = false)
gen = first(get_components(ThermalStandard, sys))
name = get_name(gen)
generators = get_components(ThermalStandard, sys) do gen
get_name(gen) == name && get_available(gen)
end
@test length(generators) == 1 && get_name(first(generators)) == name
end
@testset "Test handling of bus_numbers" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
@test length(sys.bus_numbers) > 0
buses = get_components(ACBus, sys)
bus_numbers = sort!([get_number(bus) for bus in buses])
@test bus_numbers == get_bus_numbers(sys)
# Remove some components
remove_components!(x -> get_number(x) ∈ [101, 201], sys, ACBus)
@test length(sys.bus_numbers) == length(bus_numbers) - 2
# Remove entire type
remove_components!(sys, ACBus)
@test length(sys.bus_numbers) == 0
# Remove individually.
for bus in buses
add_component!(sys, bus)
end
@test length(sys.bus_numbers) > 0
for bus in buses
remove_component!(sys, bus)
end
@test length(sys.bus_numbers) == 0
# Remove by name.
for bus in buses
add_component!(sys, bus)
end
@test length(sys.bus_numbers) > 0
for bus in buses
remove_component!(ACBus, sys, get_name(bus))
end
@test length(sys.bus_numbers) == 0
end
@testset "Test System iterators" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
i = 0
for component in iterate_components(sys)
i += 1
end
components = get_components(Component, sys)
@test i == length(components)
# Test debugging functions.
component = first(components)
uuid = IS.get_uuid(component)
@test get_name(get_component(sys, uuid)) == get_name(component)
@test get_name(get_component(sys, string(uuid))) == get_name(component)
end
@testset "Test remove_component" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
generators = get_components(ThermalStandard, sys)
initial_length = length(generators)
@assert initial_length > 0
gen = collect(generators)[1]
remove_component!(sys, gen)
@test isnothing(get_component(typeof(gen), sys, get_name(gen)))
generators = get_components(typeof(gen), sys)
@test length(generators) == initial_length - 1
@test_throws(IS.ArgumentError, remove_component!(sys, gen))
add_component!(sys, gen)
remove_component!(typeof(gen), sys, get_name(gen))
@test isnothing(get_component(typeof(gen), sys, get_name(gen)))
@assert length(get_components(typeof(gen), sys)) > 0
remove_components!(sys, typeof(gen))
@test_throws(IS.ArgumentError, remove_components!(sys, typeof(gen)))
remove_components!(sys, Area)
@test isempty(get_components(Area, sys))
@test isnothing(get_area(collect(get_components(ACBus, sys))[1]))
end
@testset "Test missing Arc bus" begin
sys = System(100.0)
line = Line(nothing)
@test_throws(IS.ArgumentError, add_component!(sys, line))
end
@testset "Test frequency set" begin
sys = System(100; frequency = 50.0)
@test get_frequency(sys) == 50.0
end
@testset "Test exported names" begin
@test IS.validate_exported_names(PowerSystems)
end
@testset "Test system ext" begin
sys = System(100.0)
ext = get_ext(sys)
ext["data"] = 2
@test get_ext(sys)["data"] == 2
clear_ext!(sys)
@test isempty(get_ext(sys))
end
@testset "Test system checks" begin
sys = System(100.0)
@test_logs (:warn, r"There are no .* Components in the System") match_mode = :any check(
sys,
)
end
@testset "Test system units" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys"; add_forecasts = false)
set_units_base_system!(sys, "DEVICE_BASE")
@test get_units_base(sys) == "DEVICE_BASE"
set_units_base_system!(sys, "SYSTEM_BASE")
@test get_units_base(sys) == "SYSTEM_BASE"
gen = get_component(ThermalStandard, sys, "322_CT_6")
active_power_mw = with_units_base(sys, UnitSystem.NATURAL_UNITS) do
get_active_power(gen)
end
@test get_units_base(sys) == "SYSTEM_BASE"
set_units_base_system!(sys, UnitSystem.NATURAL_UNITS)
@test active_power_mw == get_active_power(gen)
end
@testset "Test with_units_base on component" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys"; add_forecasts = false)
set_units_base_system!(sys, "SYSTEM_BASE")
gen = get_component(ThermalStandard, sys, "322_CT_6")
base_power = get_base_power(sys)
# Component shares system's units_settings initially
@test sys.units_settings === PSY.get_internal(gen).units_info
# with_units_base on component should work and preserve reference after
P_pu = get_active_power(gen)
P_natural = with_units_base(gen, "NATURAL_UNITS") do
get_active_power(gen)
end
@test P_natural ≈ P_pu * base_power
# Reference should be preserved after with_units_base(component, ...)
@test sys.units_settings === PSY.get_internal(gen).units_info
# System-level with_units_base should still work after component-level call
P_natural_via_sys = with_units_base(sys, UnitSystem.NATURAL_UNITS) do
get_active_power(gen)
end
@test P_natural ≈ P_natural_via_sys
end
@testset "Test with_units_base on component removed during block" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys"; add_forecasts = false)
set_units_base_system!(sys, "SYSTEM_BASE")
line = first(get_components(Line, sys))
# Component shares system's units_settings initially
@test sys.units_settings === PSY.get_internal(line).units_info
# Remove component during with_units_base block
@test_throws ErrorException begin
with_units_base(line, "NATURAL_UNITS") do
remove_component!(sys, line)
end
end
# After removal, units_info should be nothing (not restored to system's)
@test isnothing(PSY.get_internal(line).units_info)
end
@testset "Test add_time_series multiple components" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
components = []
len = 2
for i in 1:len
gen = ThermalStandard(nothing)
gen.name = string(i)
gen.bus = bus
add_component!(sys, gen)
push!(components, gen)
end
initial_time = Dates.DateTime("2020-01-01T00:00:00")
end_time = Dates.DateTime("2020-01-01T23:00:00")
dates = collect(initial_time:Dates.Hour(1):end_time)
data = collect(1:24)
ta = TimeSeries.TimeArray(dates, data, ["1"])
name = "max_active_power"
ts = SingleTimeSeries(; name = name, data = ta)
res = add_time_series!(sys, components, ts)
for i in 1:len
component = get_component(ThermalStandard, sys, string(i))
ts = get_time_series(SingleTimeSeries, component, name)
@test ts isa SingleTimeSeries
end
end
@testset "Test bulk add of time series" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
components = []
len = 2
component = ThermalStandard(nothing)
component.name = "gen"
component.bus = bus
add_component!(sys, component)
initial_time = Dates.DateTime("2020-09-01")
resolution = Dates.Hour(1)
len = 24
timestamps = range(initial_time; length = len, step = resolution)
arrays = [TimeSeries.TimeArray(timestamps, rand(len)) for _ in 1:5]
ts_name = "test"
open_time_series_store!(sys, "r+") do
for (i, ta) in enumerate(arrays)
ts = SingleTimeSeries(; data = ta, name = "$(ts_name)_$(i)")
add_time_series!(sys, component, ts)
end
end
open_time_series_store!(sys, "r") do
for (i, expected_array) in enumerate(arrays)
ts = IS.get_time_series(IS.SingleTimeSeries, component, "$(ts_name)_$(i)")
@test ts.data == expected_array
end
end
end
@testset "Test begin_time_series_update" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
components = []
len = 2
component = ThermalStandard(nothing)
component.name = "gen"
component.bus = bus
add_component!(sys, component)
initial_time = Dates.DateTime("2020-09-01")
resolution = Dates.Hour(1)
len = 24
timestamps = range(initial_time; length = len, step = resolution)
arrays = [TimeSeries.TimeArray(timestamps, rand(len)) for _ in 1:5]
ts_name = "test"
begin_time_series_update(sys) do
for (i, ta) in enumerate(arrays)
ts = SingleTimeSeries(; data = ta, name = "$(ts_name)_$(i)")
add_time_series!(sys, component, ts)
end
end
open_time_series_store!(sys, "r") do
for (i, expected_array) in enumerate(arrays)
ts = IS.get_time_series(IS.SingleTimeSeries, component, "$(ts_name)_$(i)")
@test ts.data == expected_array
end
end
end
@testset "Test set_name! of system component" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
set_name!(sys, bus, "new_name")
@test get_component(ACBus, sys, "new_name") === bus
@test_throws ErrorException set_name!(bus, "new_name2")
remove_component!(sys, bus)
set_name!(bus, "new_name2")
@test get_name(bus) == "new_name2"
end
@testset "Test forecast parameters" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.name = "gen"
gen.bus = bus
add_component!(sys, gen)
resolution = Dates.Hour(1)
initial_time = Dates.DateTime("2020-09-01")
second_time = initial_time + resolution
name = "test"
horizon = Hour(24)
horizon_count = 24
data =
SortedDict(initial_time => ones(horizon_count), second_time => ones(horizon_count))
forecast = Deterministic(; data = data, name = name, resolution = resolution)
add_time_series!(sys, gen, forecast)
@test get_time_series_resolutions(sys)[1] == resolution
@test get_forecast_horizon(sys) == horizon
@test get_forecast_initial_timestamp(sys) == initial_time
@test get_forecast_interval(sys) == Dates.Millisecond(second_time - initial_time)
@test get_forecast_window_count(sys) == 2
@test get_forecast_initial_times(sys) == [initial_time, second_time]
remove_time_series!(sys, typeof(forecast), gen, get_name(forecast))
@test_throws ArgumentError get_time_series(typeof(forecast), gen, get_name(forecast))
end
@testset "Test multi-interval DeterministicSingleTimeSeries" begin
sys = System(100.0)
bus = ACBus(nothing)
bus.bustype = ACBusTypes.REF
add_component!(sys, bus)
gen = ThermalStandard(nothing)
gen.name = "gen"
gen.bus = bus
add_component!(sys, gen)
initial_time = Dates.DateTime("2020-09-01")
resolution = Dates.Minute(5)
sts_length = 288 # 24 hours at 5-min resolution
data = TimeSeries.TimeArray(
range(initial_time; length = sts_length, step = resolution),
rand(sts_length),
)
sts_name = "max_active_power"
sts = SingleTimeSeries(; data = data, name = sts_name)
add_time_series!(sys, gen, sts)
horizon = Dates.Hour(1)
interval1 = Dates.Minute(30)
interval2 = Dates.Hour(1)
transform_single_time_series!(
sys,
horizon,
interval1;
delete_existing = false,
)
transform_single_time_series!(
sys,
horizon,
interval2;
delete_existing = false,
)
@test has_time_series(
gen,
DeterministicSingleTimeSeries,
sts_name;
interval = interval1,
)
@test has_time_series(
gen,
DeterministicSingleTimeSeries,
sts_name;
interval = interval2,
)
ts1 = get_time_series(
DeterministicSingleTimeSeries,
gen,
sts_name;
interval = interval1,
)
@test ts1 isa DeterministicSingleTimeSeries
@test IS.get_interval(ts1) == interval1
ts2 = get_time_series(
DeterministicSingleTimeSeries,
gen,
sts_name;
interval = interval2,
)
@test ts2 isa DeterministicSingleTimeSeries
@test IS.get_interval(ts2) == interval2
@test_throws ArgumentError get_time_series(
DeterministicSingleTimeSeries,
gen,
sts_name,
)
@test get_forecast_interval(sys; interval = interval1) == interval1
@test get_forecast_interval(sys; interval = interval2) == interval2
@test get_forecast_horizon(sys; interval = interval1) == horizon
@test get_forecast_window_count(sys; interval = interval1) > 0
@test get_forecast_window_count(sys; interval = interval2) > 0
ts_interval1 = collect(
get_time_series_multiple(
sys;
type = DeterministicSingleTimeSeries,
interval = interval1,
),
)
@test length(ts_interval1) > 0
for ts in ts_interval1
@test IS.get_interval(ts) == interval1
end
remove_time_series!(
sys,
DeterministicSingleTimeSeries,
gen,
sts_name;
interval = interval1,
)
@test !has_time_series(
gen,
DeterministicSingleTimeSeries,
sts_name;
interval = interval1,
)
@test has_time_series(
gen,
DeterministicSingleTimeSeries,
sts_name;
interval = interval2,
)
@test has_time_series(gen, SingleTimeSeries, sts_name)
end
@testset "Invalid constructor" begin
@test_throws IS.DataFormatError System("data.invalid")
end
@testset "Test deepcopy with runchecks" begin
sys = System(100.0)
@test get_runchecks(sys)
@test get_runchecks(deepcopy(sys))
end
@testset "Test deepcopy with runchecks disabled" begin
sys = System(100.0; runchecks = false)
@test !get_runchecks(sys)
sys2 = deepcopy(sys)
@test sys2 isa System
@test !get_runchecks(sys)
end
@testset "Test deepcopy with custom time_series_directory" begin
ts_dir = mktempdir()
sys = System(100.0; time_series_directory = ts_dir)
sys2 = deepcopy(sys)
@test dirname(sys2.data.time_series_manager.data_store.file_path) == ts_dir
end
@testset "Test time series counts" begin
# The system has both single and deterministic forecasts time series
c_sys5 = PSB.build_system(
PSITestSystems,
"c_sys5_uc";
add_forecasts = true,
skip_serialization = true,
)
counts = get_time_series_counts(c_sys5)
@test counts.static_time_series_count == 0
@test counts.forecast_count == 3
# The system has both single and deterministic forecasts time series
c_sys5 = PSB.build_system(
PSITestSystems,
"c_sys5_uc";
add_single_time_series = true,
skip_serialization = true,
)
counts = get_time_series_counts(c_sys5)
@test counts.static_time_series_count == 3
@test counts.forecast_count == 0
end
@testset "Test deepcopy with time series options" begin
sys = PSB.build_system(
PSITestSystems,
"test_RTS_GMLC_sys";
time_series_in_memory = true,
force_build = true,
)
@test sys.data.time_series_manager.data_store isa IS.InMemoryTimeSeriesStorage
sys2 = deepcopy(sys)
@test sys2.data.time_series_manager.data_store isa IS.InMemoryTimeSeriesStorage
@test IS.compare_values(sys, sys2)
# Ensure that the storage references got updated correctly.
for component in get_components(x -> has_time_series(x), Component, sys2)
@test component.internal.shared_system_references.time_series_manager ===
sys2.data.time_series_manager
end
sys = PSB.build_system(
PSITestSystems,
"test_RTS_GMLC_sys";
time_series_in_memory = false,
force_build = true,
)
@test sys.data.time_series_manager.data_store isa IS.Hdf5TimeSeriesStorage
sys2 = deepcopy(sys)
@test sys2.data.time_series_manager.data_store isa IS.Hdf5TimeSeriesStorage
@test sys.data.time_series_manager.data_store.file_path !=
sys2.data.time_series_manager.data_store.file_path
@test IS.compare_values(sys, sys2)
for component in get_components(x -> has_time_series(x), Component, sys2)
@test component.internal.shared_system_references.time_series_manager ===
sys2.data.time_series_manager
end
end
@testset "Test fast deepcopy of system" begin
systems = Dict(
in_memory => PSB.build_system(
PSITestSystems,
"test_RTS_GMLC_sys";
time_series_in_memory = in_memory,
force_build = true,
) for in_memory in (true, false)
)
@testset for (in_memory, skip_ts, skip_sa) in # Iterate over all permutations
Iterators.product(repeat([(true, false)], 3)...)
sys = systems[in_memory]
sys2 = IS.fast_deepcopy_system(sys;
skip_time_series = skip_ts, skip_supplemental_attributes = skip_sa)
@test IS.compare_values(
sys,
sys2;
exclude = Set(
[:time_series_manager, :supplemental_attribute_manager][[skip_ts, skip_sa]],
),
)
# We copy the SystemData separately from the other System fields, so the egal-ity of these references could get broken
generator = get_component(ThermalStandard, sys2, "322_CT_6")
@test sys2.units_settings === generator.internal.units_info
end
end
@testset "Test with compression enabled" begin
@test get_compression_settings(System(100.0)) == CompressionSettings(; enabled = false)
settings = CompressionSettings(; enabled = true, type = CompressionTypes.BLOSC)
@test get_compression_settings(System(100.0; compression = settings)) == settings
@test get_compression_settings(System(100.0; enable_compression = true)) ==
CompressionSettings(; enabled = true)
end
@testset "Test compare_values" begin
sys1 = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
sys2 = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
gen1 = first(get_components(ThermalStandard, sys1))
gen2 = first(get_components(ThermalStandard, sys2))
@test IS.compare_values(gen1, gen2)
@test IS.compare_values(sys1, sys2)
set_active_power!(gen1, get_active_power(gen1) + 0.1)
@test(
@test_logs(
(:error, r"not match"),
match_mode = :any,
!IS.compare_values(gen1, gen2),
)
)
@test(
@test_logs(
(:error, r"not match"),
match_mode = :any,
!IS.compare_values(sys1, sys2)
)
)
my_match_fn(a::Float64, b::Float64) =
isapprox(a, b; atol = 0.2) || IS.isequivalent(a, b)
my_match_fn(a, b) = IS.isequivalent(a, b)
@test IS.compare_values(my_match_fn, gen1, gen2)
@test IS.compare_values(my_match_fn, sys1, sys2)
end
@testset "Test check_components" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys"; add_forecasts = false)
check_components(sys)
check_components(sys, Component)
check_components(sys, Generator)
check_components(sys, ThermalStandard)
check_components(sys, get_components(ThermalStandard, sys))
components = get_components(ThermalStandard, sys)
gen = first(components)
check_components(sys, components)
check_component(sys, gen)
# Invalid Bus base_voltage values throw errors.
# Invalid ThermalStandard active_power logs warning messages.
bus = first(get_components(ACBus, sys))
check_component(sys, bus)
orig = get_base_voltage(bus)
set_base_voltage!(bus, -1.0)
try
@test_logs(
(:error, "Invalid range"),
match_mode = :any,
@test_throws IS.InvalidValue check_component(sys, bus)
)
finally
set_base_voltage!(bus, orig)
end
gen.active_power = 100.0
@test_logs :warn, "Invalid range" match_mode = :any check_component(sys, gen)
@test_logs :warn, "Invalid range" match_mode = :any check_components(
sys,
ThermalStandard,
)
# @test !(@test_logs :warn, r"is larger than the max expected in the" match_mode = :any check_ac_transmission_rate_values(
# sys,
# ))
@test check_ac_transmission_rate_values(sys)
end
@testset "Test system name and description" begin
name = "test_system"
description = "a system description"
sys = System(100.0)
@test get_name(sys) === nothing
@test get_description(sys) === nothing
set_name!(sys, name)
set_description!(sys, description)
sys = System(100.0; name = name, description = description)
@test get_name(sys) == name
@test get_description(sys) == description
end
@testset "Test system metadata" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
name = "test_system"
description = "a system description"
set_name!(sys, name)
set_description!(sys, description)
tempdir = mktempdir()
sys_file = joinpath(tempdir, "sys.json")
to_json(sys, sys_file; user_data = Dict("author" => "test"))
sys2 = System(sys_file)
@test get_name(sys2) == name
@test get_description(sys2) == description
metadata_file = joinpath(tempdir, "sys_metadata.json")
metadata = open(metadata_file) do io
JSON3.read(io, Dict)
end
@test metadata["name"] == name
@test metadata["description"] == description
found_component_thermal = false
found_component_condenser = false
for item in metadata["component_counts"]
if item["type"] == "ThermalStandard"
@test item["count"] == 73
found_component_thermal = true
end
if item["type"] == "SynchronousCondenser"
@test item["count"] == 3
found_component_condenser = true
end
end
@test found_component_thermal
@test found_component_condenser
@test metadata["time_series_counts"][1]["type"] == "DeterministicSingleTimeSeries"
@test metadata["time_series_counts"][1]["count"] == 182
@test metadata["time_series_counts"][2]["type"] == "SingleTimeSeries"
@test metadata["time_series_counts"][2]["count"] == 182
@test metadata["user_data"]["author"] == "test"
end
@testset "Test addition of service to the wrong system" begin
sys1 = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
sys2 = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
service1 = first(get_components(VariableReserve{ReserveDown}, sys1))
device2 = first(get_components(ThermalStandard, sys2))
@test_throws ArgumentError add_service!(device2, service1, sys2)
end
@testset "Test has_components" begin
sys1 = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
@test has_components(sys1, ThermalStandard)
@test !has_components(sys1, TransmissionInterface)
end
@testset "Test set_bus_number!" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys")
buses = collect(get_components(ACBus, sys))
bus1 = buses[1]
bus2 = buses[2]
orig = get_number(bus1)
new_number = 9999999
@test orig != new_number
set_bus_number!(sys, bus1, new_number)
@test get_number(bus1) == new_number
bus_numbers = get_bus_numbers(sys)
@test new_number in bus_numbers
@test !(orig in bus_numbers)
# Ensure that the no-op case works.
set_bus_number!(sys, bus1, new_number)
@test get_number(bus1) == new_number
@test new_number in get_bus_numbers(sys)
# Ensure that duplicate numbers are blocked.
@test_throws ArgumentError set_bus_number!(sys, bus1, get_number(bus2))
# Ensure that you can't change an unattached bus.
remove_component!(sys, bus1)
@test_throws ArgumentError set_bus_number!(sys, bus1, new_number + 1)
# Ensure that this is exported. This can be deleted in PSY5.
set_number!(bus1, new_number + 2)
@test get_number(bus1) == new_number + 2
end
================================================
FILE: test/test_topology.jl
================================================
function get_expected_buses(::Type{T}, sys::System) where {T <: AggregationTopology}
expected_buses = Dict{String, Vector{String}}()
for bus in get_components(ACBus, sys)
agg = get_aggregation_topology_accessor(T)(bus)
name = get_name(agg)
if !haskey(expected_buses, name)
expected_buses[name] = Vector{String}()
end
push!(expected_buses[name], get_name(bus))
end
return expected_buses
end
function test_aggregation_topologies(sys::System, expected_areas, expected_zones)
expected_buses_by_area = get_expected_buses(Area, sys)
expected_buses_by_zone = get_expected_buses(LoadZone, sys)
areas = collect(get_components(Area, sys))
@test length(areas) == expected_areas
area_mapping = get_aggregation_topology_mapping(Area, sys)
for area in areas
area_name = get_name(area)
buses = sort!([get_name(x) for x in get_buses(sys, area)])
@test buses == sort(expected_buses_by_area[area_name])
@test buses == sort!([get_name(x) for x in area_mapping[area_name]])
end
zones = collect(get_components(LoadZone, sys))
zone_mapping = get_aggregation_topology_mapping(LoadZone, sys)
@test length(zones) == expected_zones
for zone in zones
zone_name = get_name(zone)
buses = sort!([get_name(x) for x in get_buses(sys, zone)])
@test buses == sort(expected_buses_by_zone[zone_name])
@test buses == sort!([get_name(x) for x in zone_mapping[zone_name]])
end
end
@testset "Test topology mappings" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys"; add_forecasts = false)
test_aggregation_topologies(sys, 3, 3)
end
@testset "Test PM areas and load zones" begin
sys = PSB.build_system(MatpowerTestSystems, "matpower_RTS_GMLC_sys")
test_aggregation_topologies(sys, 3, 21)
end
@testset "Test get_components_in_aggregation_topology and is_component_in_aggregation_topology" begin
sys = PSB.build_system(PSITestSystems, "test_RTS_GMLC_sys"; add_forecasts = false)
areas = collect(get_components(Area, sys))
@test !isempty(areas)
zones = collect(get_components(LoadZone, sys))
@test !isempty(zones)
for (agg, accessor) in [(first(areas), get_area), (first(zones), get_load_zone)]
all_generators = get_components(ThermalStandard, sys)
in_generators = get_components_in_aggregation_topology(ThermalStandard, sys, agg)
covered_in = covered_out = false # Invalid test if agg is empty or includes everything
for gen in all_generators
bus = get_bus(gen)
if gen in in_generators
@test IS.get_uuid(accessor(bus)) == IS.get_uuid(agg)
@test is_component_in_aggregation_topology(gen, agg)
covered_in = true
else
@test IS.get_uuid(accessor(bus)) != IS.get_uuid(agg)
@test !is_component_in_aggregation_topology(gen, agg)
covered_out = true
end
end
@test covered_in && covered_out
end
end
================================================
FILE: test/test_validation.jl
================================================
import YAML
const WRONG_FORMAT_CONFIG_FILE =
joinpath(dirname(pathof(PowerSystems)), "descriptors", "config.yml")
@testset "Test reading in config data" begin
data = IS.read_validation_descriptor(PSY.POWER_SYSTEM_STRUCT_DESCRIPTOR_FILE)
@test data isa Vector
@test !isempty(data)
function find_struct()
for item in data
if item["struct_name"] == "ThermalStandard"
return true
end
end
return false
end
@test find_struct()
@test_throws(ErrorException, IS.read_validation_descriptor("badfile.toml"))
end
@testset "Test adding custom validation YAML file to System" begin
nodes = nodes5()
sys_no_config =
System(100.0, nodes, thermal_generators5(nodes), loads5(nodes); runchecks = true)
@test !isempty(sys_no_config.data.validation_descriptors)
nodes = nodes5()
sys_no_runchecks =
System(100.0, nodes, thermal_generators5(nodes), loads5(nodes); runchecks = false)
@test !isempty(sys_no_runchecks.data.validation_descriptors)
end
@testset "Test extracting struct info from validation_descriptor vector" begin
data = [
Dict(
"fields" => Dict{Any, Any}[
Dict(
"name" => "curtailpenalty",
"valid_range" => Dict{Any, Any}("max" => nothing, "min" => 0.0),
),
Dict(
"name" => "variablecost",
"valid_range" => Dict{Any, Any}("max" => nothing, "min" => 0.0),
),
Dict("name" => "internal"),
],
"struct_name" => "EconHydro",
),
Dict(
"fields" => Dict{Any, Any}[
Dict(
"name" => "curtailpenalty",
"valid_range" => Dict{Any, Any}("max" => nothing, "min" => 0.0),
),
Dict(
"name" => "variablecost",
"valid_range" => Dict{Any, Any}("max" => nothing, "min" => 0.0),
),
Dict("name" => "internal"),
],
"struct_name" => "EconLoad",
),
]
struct_name = "EconHydro"
descriptor = IS.get_config_descriptor(data, struct_name)
@test descriptor isa Dict{String, Any}
@test haskey(descriptor, "struct_name")
@test haskey(descriptor, "fields")
@test descriptor["struct_name"] == struct_name
end
@testset "Test extracting field info from struct descriptor dictionary" begin
config = Dict{Any, Any}(
"fields" => Dict{Any, Any}[
Dict("name" => "name", "data_type" => "String"),
Dict("name" => "available", "data_type" => "Bool"),
Dict("name" => "bus", "data_type" => "ACBus"),
Dict("name" => "tech", "data_type" => "Union{Nothing, TechThermal}"),
Dict("name" => "econ", "data_type" => "Union{Nothing, EconThermal}"),
Dict("name" => "internal", "data_type" => "IS.InfrastructureSystemsInternal"),
],
"struct_name" => "ThermalStandard",
)
field_name = "econ"
field_descriptor = IS.get_field_descriptor(config, field_name)
@test field_descriptor isa Dict{Any, Any}
@test haskey(field_descriptor, "name")
@test field_descriptor["name"] == field_name
end
@testset "Test retrieving validation action" begin
warn_descriptor = Dict{Any, Any}(
"name" => "ramp_limits",
"valid_range" => Dict{Any, Any}("max" => 5, "min" => 0),
"validation_action" => "warn",
)
error_descriptor = Dict{Any, Any}(
"name" => "ramp_limits",
"valid_range" => Dict{Any, Any}("max" => 5, "min" => 0),
"validation_action" => "error",
)
typo_descriptor = Dict{Any, Any}(
"name" => "ramp_limits",
"valid_range" => Dict{Any, Any}("max" => 5, "min" => 0),
"validation_action" => "asdfasdfsd",
)
@test IS.get_validation_action(warn_descriptor) == IS.validation_warning
@test IS.get_validation_action(error_descriptor) == IS.validation_error
@test_throws(ErrorException, IS.get_validation_action(typo_descriptor))
end
@testset "Test field validation" begin
#test recursive call of validate_fields and a regular valid range
nodes = nodes5()
bad_therm_gen_rating = thermal_generators5(nodes)
bad_therm_gen_rating[1].rating = -10
@test_logs(
(:error, r"Invalid range"),
@test_throws(
PSY.InvalidValue,
System(100.0, nodes, bad_therm_gen_rating, loads5(nodes); runchecks = true)
)
)
#test custom range (active_power and active_power_limits)
nodes = nodes5()
bad_therm_gen_act_power = thermal_generators5(nodes)
bad_therm_gen_act_power[1].active_power = 10
# This is an explicit check for one error message.
@test_logs (:warn, r"Invalid range") System(
100.0,
nodes,
bad_therm_gen_act_power,
loads5(nodes);
runchecks = true,
)
#test validating named tuple
nodes = nodes5()
bad_therm_gen_ramp_lim = thermal_generators5(nodes)
bad_therm_gen_ramp_lim[1].ramp_limits = (up = -10, down = -3)
@test_logs(
(:error, r"Invalid range"),
match_mode = :any,
@test_throws(
PSY.InvalidValue,
System(100.0, nodes, bad_therm_gen_ramp_lim, loads5(nodes); runchecks = true)
)
)
end
@testset "Test field validation" begin
nodes = nodes5()
sys = System(100.0, nodes, thermal_generators5(nodes), loads5(nodes); runchecks = true)
add_component!(
sys,
ACBus(
11,
"11",
true,
ACBusTypes.PQ,
1,
1,
(min = 0.9, max = 1.1),
123,
nothing,
nothing,
),
)
B = collect(get_components(ACBus, sys))
sort!(B, by = get_number)
a = Arc(B[1], B[6])
badline = Line(
"badline",
true,
0.01,
0.01,
a,
0.002,
0.014,
(from = 0.015, to = 0.015),
5.0,
(min = -1, max = 1),
)
@test_logs(
(:error, r"cannot create Line"),
match_mode = :any,
@test_throws(PSY.InvalidValue, add_component!(sys, badline))
)
end
# disabled until serialization is updated
@testset "Test field validation after deserialization" begin
nodes = nodes5()
sys = System(100.0, nodes, thermal_generators5(nodes), loads5(nodes))
add_component!(
sys,
ACBus(
11,
"11",
true,
ACBusTypes.PQ,
1,
1,
(min = 0.9, max = 1.1),
123,
nothing,
nothing,
),
)
path = joinpath(mktempdir(), "test_validation.json")
try
PSY.to_json(sys, path)
catch
rm(path)
rethrow()
end
try
sys2 = PSY.System(path)
B = collect(get_components(ACBus, sys2))
sort!(B, by = get_number)
a = Arc(B[1], B[6])
badline = Line(
"badline",
true,
0.01,
0.01,
a,
0.002,
0.014,
(from = 0.015, to = 0.015),
5.0,
(min = -1, max = 1),
)
@test_logs(
(:error, r"cannot create Line"),
match_mode = :any,
@test_throws(PSY.InvalidValue, add_component!(sys2, badline))
)
finally
rm(path)
end
end
function _make_bus()
return ACBus(;
number = 1,
name = "bus1",
available = true,
bustype = ACBusTypes.REF,
angle = 0.0,
magnitude = 0.0,
voltage_limits = (min = 0.0, max = 0.0),
base_voltage = nothing,
area = nothing,
load_zone = nothing,
)
end
@testset "Test add_component with runchecks enabled" begin
sys = System(100.0; runchecks = true)
@test get_runchecks(sys)
bus = _make_bus()
add_component!(sys, bus)
remove_component!(sys, bus)
# Make the bus invalid.
set_base_voltage!(bus, -1000.0)
@test_logs(
(:error, r"Invalid range"),
match_mode = :any,
@test_throws IS.InvalidValue add_component!(sys, bus)
)
# Allowed with skip_validation.
add_component!(sys, bus; skip_validation = true)
@test !get_runchecks(sys)
end
@testset "Test add_component with runchecks disabled" begin
sys = System(100.0; runchecks = false)
bus = _make_bus()
# Make the bus invalid.
set_base_voltage!(bus, -1000.0)
add_component!(sys, bus)
end
@testset "Test serialization and range checks" begin
sys = System(100.0; runchecks = false)
bus = _make_bus()
# Make the bus invalid.
set_base_voltage!(bus, -1000.0)
add_component!(sys, bus)
@test_logs(
(:error, r"Invalid range"),
match_mode = :any,
@test_throws(IS.InvalidValue, validate_serialization(sys, runchecks = true)),
)
end
@testset "Test serialization and system checks" begin
# Serialize/deserialize an invalid system.
sys = System(100.0; runchecks = false)
@test !get_runchecks(sys)
bus = _make_bus()
set_bustype!(bus, ACBusTypes.PQ)
add_component!(sys, bus)
@test_logs(
(:error, r"Model doesn't contain a slack bus"),
match_mode = :any,
validate_serialization(sys, runchecks = true)
)
sys, result = validate_serialization(sys; runchecks = false)
@test result
@test !get_runchecks(sys)
end
@testset "Test runchecks" begin
sys = System(100.0)
@test get_runchecks(sys)
sys = System(100.0; runchecks = false)
@test !get_runchecks(sys)
set_runchecks!(sys, true)
@test get_runchecks(sys)
set_runchecks!(sys, false)
@test !get_runchecks(sys)
end
@testset "Test check_component" begin
sys = System(100.0; runchecks = false)
bus = _make_bus()
# Make the bus invalid.
set_base_voltage!(bus, -1000.0)
add_component!(sys, bus)
@test_logs(
(:error, r"Invalid range"),
match_mode = :any,
@test_throws(IS.InvalidValue, check_component(sys, bus)),
)
@test_logs(
(:error, r"Invalid range"),
match_mode = :any,
@test_throws(IS.InvalidValue, check_components(sys)),
)
end
@testset "Test check at serialization" begin
nodes = nodes5()
bad_therm_gen_rating = thermal_generators5(nodes)
bad_therm_gen_rating[1].rating = -10
sys = System(100.0, nodes, bad_therm_gen_rating, loads5(nodes); runchecks = false)
@test_logs(
(:error, r"Invalid range"),
(:warn, r"exceeds total capacity capability"),
match_mode = :any,
@test_throws(
IS.InvalidValue,
to_json(sys, "sys.json", force = true, runchecks = true)
),
)
end