Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions GridKit/Model/PhasorDynamics/Branch/Branch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ namespace GridKit
setDerivedParams();
}

/// True when the branch is in service (closed). The underlying
/// `status_` is a smooth multiplier (1.0 closed / 0.0 open) so that
/// `evaluateBusResidualNN` kernels see a constant expression structure
bool status() const
{
return status_ > RealT{0.5};
}

void apply(Action action) override final;

const Model::VariableMonitorBase* getMonitor() const override;

private:
Expand Down Expand Up @@ -166,6 +176,7 @@ namespace GridKit
RealT X_{0.0};
RealT G_{0.0};
RealT B_{0.0};
RealT status_{1.0}; ///< Multiplier on residual contributions: 1.0 = closed, 0.0 = open
IdxT bus1_id_{0};
IdxT bus2_id_{0};

Expand Down
9 changes: 5 additions & 4 deletions GridKit/Model/PhasorDynamics/Branch/BranchData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ namespace GridKit
/// Initial parameters for a branch
enum class BranchParameters
{
R, ///< Line series resistance
X, ///< Line series reactance
G, ///< Line shunt conductance
B, ///< Line shunt charging
R, ///< Line series resistance
X, ///< Line series reactance
G, ///< Line shunt conductance
B, ///< Line shunt charging
state0, ///< Initial branch status (true = closed/in-service, default true)
};

/// Ports for a branch
Expand Down
37 changes: 29 additions & 8 deletions GridKit/Model/PhasorDynamics/Branch/BranchImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ namespace GridKit
// std::cout << "Destroy Branch..." << std::endl;
}

template <class ScalarT, typename IdxT>
void Branch<ScalarT, IdxT>::apply(Action action)
{
switch (action)
{
case Action::On:
status_ = RealT{1.0};
break;
case Action::Off:
status_ = RealT{0.0};
break;
}
}

/**
* @brief Set the component ID
*/
Expand Down Expand Up @@ -155,8 +169,8 @@ namespace GridKit
ScalarT Vi1 = wb[1];
ScalarT Ir1 = -(g_ + 0.5 * G_) * Vr1 + (b_ + 0.5 * B_) * Vi1;
ScalarT Ii1 = -(b_ + 0.5 * B_) * Vr1 - (g_ + 0.5 * G_) * Vi1;
h[0] = Ir1;
h[1] = Ii1;
h[0] = status_ * Ir1;
h[1] = status_ * Ii1;

return 0;
}
Expand All @@ -176,8 +190,8 @@ namespace GridKit
ScalarT Vi2 = wb[1];
ScalarT Ir1 = g_ * Vr2 - b_ * Vi2;
ScalarT Ii1 = b_ * Vr2 + g_ * Vi2;
h[0] = Ir1;
h[1] = Ii1;
h[0] = status_ * Ir1;
h[1] = status_ * Ii1;

return 0;
}
Expand All @@ -197,8 +211,8 @@ namespace GridKit
ScalarT Vi1 = wb[1];
ScalarT Ir2 = g_ * Vr1 - b_ * Vi1;
ScalarT Ii2 = b_ * Vr1 + g_ * Vi1;
h[0] = Ir2;
h[1] = Ii2;
h[0] = status_ * Ir2;
h[1] = status_ * Ii2;

return 0;
}
Expand All @@ -218,8 +232,8 @@ namespace GridKit
ScalarT Vi2 = wb[1];
ScalarT Ir2 = -(g_ + 0.5 * G_) * Vr2 + (b_ + 0.5 * B_) * Vi2;
ScalarT Ii2 = -(b_ + 0.5 * B_) * Vr2 - (g_ + 0.5 * G_) * Vi2;
h[0] = Ir2;
h[1] = Ii2;
h[0] = status_ * Ir2;
h[1] = status_ * Ii2;

return 0;
}
Expand Down Expand Up @@ -275,6 +289,13 @@ namespace GridKit
B_ = std::get<RealT>(data.parameters.at(model_data_type::Parameters::B));
}

if (data.parameters.contains(model_data_type::Parameters::state0))
{
status_ = std::get<bool>(data.parameters.at(model_data_type::Parameters::state0))
? RealT{1.0}
: RealT{0.0};
}

if (data.ports.contains(model_data_type::Ports::bus1))
{
bus1_id_ = data.ports.at(model_data_type::Ports::bus1);
Expand Down
7 changes: 2 additions & 5 deletions GridKit/Model/PhasorDynamics/BusFault/BusFault.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ namespace GridKit
{
}

void apply(Action action) override final;

public:
void setR(RealT R)
{
Expand All @@ -77,11 +79,6 @@ namespace GridKit
setDerivedParams();
}

void setStatus(bool status)
{
status_ = status;
}

const Model::VariableMonitorBase* getMonitor() const override;

private:
Expand Down
14 changes: 14 additions & 0 deletions GridKit/Model/PhasorDynamics/BusFault/BusFaultImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,20 @@ namespace GridKit
return monitor_.get();
}

template <class ScalarT, typename IdxT>
void BusFault<ScalarT, IdxT>::apply(Action action)
{
switch (action)
{
case Action::On:
status_ = true;
break;
case Action::Off:
status_ = false;
break;
}
}

/**
* @brief Derived parameters
*
Expand Down
20 changes: 20 additions & 0 deletions GridKit/Model/PhasorDynamics/Component.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <stdexcept>
#include <string>
#include <vector>

#include <GridKit/AutomaticDifferentiation/DependencyTracking/Variable.hpp>
Expand All @@ -13,6 +15,15 @@ namespace GridKit
{
using Log = ::GridKit::Utilities::Logger;

/// Project-wide control actions shared by cue-targetable components such
/// as BusFault and Branch. If future runtime controls stop fitting these
/// verbs naturally, switch to per-component action enums + typed dispatch.
enum class Action
{
On,
Off,
};

/**
* @brief Component model implementation base class.
*/
Expand Down Expand Up @@ -43,6 +54,15 @@ namespace GridKit

virtual int verify() const = 0;

/// Cue dispatch. Called by PDSim only at IDA re-init points; never
/// during integration. Default throws — Components without a runtime
/// control surface inherit the default and ignore cues.
/// SystemModel's routing layer wraps the throw with the target id.
virtual void apply(Action)
{
throw std::runtime_error("Component does not accept cues");
}

virtual IdxT size() override
{
return size_;
Expand Down
2 changes: 1 addition & 1 deletion GridKit/Model/PhasorDynamics/INPUT_FORMAT.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ are specified:

Device class | Description | Ports | Initialization parameters | Variables available to monitor
--------------|------------------------------------------------------|----------------------------------|---------------------------- | -------------------------
`Branch` | a basic algebraic pi model for a line or transformer | `bus1`, `bus2` | `R`, `X`, `G`, `B` | `ir1`, `ii1`, `im1`, `p1`, `q1`, `ir2`, `ii2`, `im2`, `p2`, `q2`
`Branch` | a basic algebraic pi model for a line or transformer | `bus1`, `bus2` | `R`, `X`, `G`, `B`, `state0` | `ir1`, `ii1`, `im1`, `p1`, `q1`, `ir2`, `ii2`, `im2`, `p2`, `q2`
`Load` | a basic static impedence load model | `bus` | `R`, `X` | `p`, `q`
`Genrou` | 6th order machine model | `bus`, `pmech`\*, `speed`\*, `efd`\* | `p0`, `q0`, `H`, `D`, `Ra`, `Tdop`, `Tdopp`, `Tqopp`, `Tqop`, `Xd`, `Xdp`, `Xdpp`, `Xq`, `Xqp`, `Xqpp`, `Xl`, `S10`, `S12`, `mva_base` | `ir`, `ii`, `p`, `q`, `delta`, `omega`, `speed`
`GenClassical`| the classical machine model | `bus`, `pmech`\*, `speed`\*, `efd`\* | `p0`, `q0`, `H`, `D`, `Ra`, `Xdp`, `mva_base` | `ir`, `ii`, `p`, `q`, `delta`, `omega`
Expand Down
51 changes: 22 additions & 29 deletions GridKit/Model/PhasorDynamics/SystemModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

#include <cassert>
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>

#include <GridKit/Definitions.hpp>
Expand Down Expand Up @@ -121,7 +125,7 @@ namespace GridKit
}

auto* branch = new Branch<ScalarT, IdxT>(getBus(bus1_index), getBus(bus2_index), branchdata);
addComponent(branch);
addComponent(branch, branchdata.disambiguation_string);
}

// Add loads
Expand Down Expand Up @@ -308,7 +312,7 @@ namespace GridKit
bus_index = faultdata.ports.at(BusFaultData<ScalarT, IdxT>::Ports::bus);
}
auto* fault = new BusFault<ScalarT, IdxT>(getBus(bus_index), faultdata);
addFault(fault);
addComponent(fault, faultdata.disambiguation_string);
}

for (const auto& sink : data.monitor_sink)
Expand Down Expand Up @@ -905,11 +909,8 @@ namespace GridKit
/**
* @brief Add component
*
* Add component at the end of the components array and set GridKit's component ID
*
* @todo: No integer user-facing component_id for now, but we could map GridKit's
* component ID to the disambiguation_string
*
* Add component at the end of the components array and set GridKit's component ID.
* This overload does not register the component for cue routing.
*/
void addComponent(component_type* component)
{
Expand All @@ -919,18 +920,17 @@ namespace GridKit
}

/**
* @brief Add fault
*
* The fault is added to the components array, and we keep a map to its
* location, so it can easily be accessed.
* @brief Add component and register it as a cue target under `id`.
*
* The id originates from the case JSON (`"id"` field, parsed into
* `data.disambiguation_string`). It is stored only here, in the system's
* routing map — the component itself does not carry it.
*/
void addFault(component_type* component)
void addComponent(component_type* component, const std::string& id)
{
IdxT gridkit_component_id = static_cast<IdxT>(components_.size());
IdxT gridkit_fault_id = static_cast<IdxT>(gridkit_fault_indices_.size());
gridkit_fault_indices_[gridkit_fault_id] = gridkit_component_id;
addComponent(component);
if (!id.empty())
by_id_[id] = component;
}

/**
Expand Down Expand Up @@ -967,27 +967,20 @@ namespace GridKit
return components_[gridkit_component_id];
}

/**
* @brief Return pointer to a bus fault model
*
* This function is used to provide easier access to setting and
* clearing faults from the SystemModel interface.
*
*/
BusFault<ScalarT, IdxT>* getBusFault(IdxT fault_id)
/// Route a cue to the component registered under `target`.
void cue(const std::string& target, Action action)
{
IdxT component_id = gridkit_fault_indices_.at(fault_id);
return dynamic_cast<BusFault<ScalarT, IdxT>*>(components_[component_id]);
by_id_.at(target)->apply(action);
}

private:
std::vector<bus_type*> buses_;
std::vector<signal_type*> signals_;
std::vector<component_type*> components_;
std::vector<bus_type*> buses_;
std::vector<signal_type*> signals_;
std::vector<component_type*> components_;
std::unordered_map<std::string, component_type*> by_id_; ///< Routing map for cues

std::map<IdxT, IdxT> gridkit_bus_indices_; ///< Map between gridkit_bus_id and bus_id
std::map<IdxT, IdxT> gridkit_signal_indices_; ///< Map between gridkit_signal_id and signal_id
std::map<IdxT, IdxT> gridkit_fault_indices_; ///< Map between fault_id and component_id

bool owns_components_{false};

Expand Down
36 changes: 18 additions & 18 deletions application/PhasorDynamics/PDSim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ int main(int argc, const char* argv[])
Log::error() << "No input file provided" << std::endl;
std::cout << "\n"
"Usage:\n"
" pdsim <json-input-file>\n"
" pdsim <solver-file.solver.json>\n"
"\n"
"Please provide a json input file for the study to run.\n"
"Please provide a JSON solver file for the study to run.\n"
"\n";
exit(1);
}
Expand All @@ -48,30 +48,30 @@ int main(int argc, const char* argv[])
// Start timer
real_type start = static_cast<real_type>(clock());

using EventType = SystemEvent::Type;

// Initilize simultation for first run
ida.initializeSimulation(0.0, false);
real_type curr_time = 0.0;
for (const auto& event : study.events)

size_t i = 0;
while (i < study.schedule.size())
{
// Run to event time
int nout = static_cast<int>(std::round((event.time - curr_time) / dt));
ida.runSimulation(event.time, nout);
real_type t_cue = study.schedule[i].time;

// Set up run for event (to start at event time)
if (event.type == EventType::FAULT_ON)
{
sys.getBusFault(event.element_id)->setStatus(true);
}
else if (event.type == EventType::FAULT_OFF)
// Run to cue time
int nout = static_cast<int>(std::round((t_cue - curr_time) / dt));
ida.runSimulation(t_cue, nout);

// Batch simultaneous cues into one re-init so IDA never sees a
// zero-length segment between back-to-back applies at the same time.
while (i < study.schedule.size() && study.schedule[i].time == t_cue)
{
sys.getBusFault(event.element_id)->setStatus(false);
sys.cue(study.schedule[i].target, study.schedule[i].action);
++i;
}

// Re-initialize simulation at event time
ida.initializeSimulation(event.time, true);
curr_time = event.time;
// Re-initialize simulation at cue time
ida.initializeSimulation(t_cue, true);
curr_time = t_cue;
}

// Run to final time
Expand Down
Loading
Loading