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 [![Main - CI](https://github.com/Sienna-Platform/PowerSystems.jl/workflows/Main%20-%20CI/badge.svg)](https://github.com/Sienna-Platform/PowerSystems.jl/actions/workflows/main-tests.yml) [![codecov](https://codecov.io/gh/Sienna-Platform/PowerSystems.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/Sienna-Platform/PowerSystems.jl) [![Documentation](https://github.com/Sienna-Platform/PowerSystems.jl/actions/workflows/docs.yml/badge.svg)](https://github.com/Sienna-Platform/PowerSystems.jl/actions/workflows/docs.yml) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17703517.svg)](https://doi.org/10.5281/zenodo.17703517) [](https://join.slack.com/t/core-sienna/shared_invite/zt-glam9vdu-o8A9TwZTZqqNTKHa7q3BpQ) [![PowerSystems.jl Downloads](https://img.shields.io/badge/dynamic/json?url=http%3A%2F%2Fjuliapkgstats.com%2Fapi%2Fv1%2Ftotal_downloads%2FPowerSystems&query=total_requests&label=Downloads)](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 text](url) # !\[…\] — 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 configurations
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