Skip to content
Open
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
9 changes: 7 additions & 2 deletions GridKit/Model/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,10 @@ add_subdirectory(PhasorDynamics)
add_subdirectory(PowerFlow)
add_subdirectory(PowerElectronics)

install(FILES Evaluator.hpp VariableMonitor.hpp VariableMonitorController.hpp
DESTINATION include/GridKit/Model)
install(
FILES ConfigurationChecks.hpp
Evaluator.hpp
ParameterReader.hpp
VariableMonitor.hpp
VariableMonitorController.hpp
DESTINATION include/GridKit/Model)
58 changes: 58 additions & 0 deletions GridKit/Model/ConfigurationChecks.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* @file ConfigurationChecks.hpp
* @author Luke Lowery (lukel@tamu.edu)
* @brief Collects the configuration problems found by a model.
*/

#pragma once

#include <string>
#include <utility>
#include <vector>

namespace GridKit
{
namespace Model
{
/**
* @brief Collects the configuration problems found by a model.
*
* A model's verify() fills one instance with a message for every
* condition that does not hold and returns it. The caller decides how
* the messages are reported; passed() is true when there are none.
*/
class ConfigurationChecks
{
public:
/// Record a problem.
void fail(std::string message)
{
errors_.push_back(std::move(message));
}

/// Record the message when the condition does not hold.
void check(bool condition, std::string message)
{
if (!condition)
{
fail(std::move(message));
}
}

/// True when no check has failed.
bool passed() const
{
return errors_.empty();
}

/// Every recorded message, in the order the checks ran.
const std::vector<std::string>& errors() const
{
return errors_;
}

Comment on lines +48 to +53

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the end goal should be to report errors using set error codes or structured errors instead of strings, but for now this is fine

private:
std::vector<std::string> errors_;
};
} // namespace Model
} // namespace GridKit
199 changes: 199 additions & 0 deletions GridKit/Model/ParameterReader.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/**
* @file ParameterReader.hpp
* @author Luke Lowery (lukel@tamu.edu)
* @brief Typed parameter loading from model data containers.
*/

#pragma once

#include <cmath>
#include <map>
#include <stdexcept>
#include <string>
#include <variant>

#include <magic_enum/magic_enum.hpp>

#include <GridKit/Model/PhasorDynamics/ModelData.hpp>

namespace GridKit
{
namespace Model
{
/**
* @brief Reads typed parameters out of a model data container.
*
* A provided value with the wrong type or a non-finite value cannot
* produce a valid model, so every method throws std::invalid_argument
* at the first such value; the message names the model and the
* parameter. An omitted optional parameter leaves the target untouched.
* Real parameters accept integer values.
*
* @tparam ModelDataT A model data container satisfying
* PhasorDynamics::ModelData.
*/
template <PhasorDynamics::ModelData ModelDataT>
class ParameterReader
Comment thread
superwhiskers marked this conversation as resolved.
{
public:
using RealT = typename ModelDataT::RealT;
using IdxT = typename ModelDataT::IdxT;
using ParametersT = typename ModelDataT::Parameters;

/**
* @param[in] data Model data container to read from.
* @param[in] model Model name used in rejection messages.
*/
ParameterReader(const ModelDataT& data, const char* model)
: parameters_(data.parameters),
model_(model)
{
}

/**
* @brief Load an optional real parameter. Integer values are accepted.
*
* @param[in] key Parameter to look up.
* @param[out] target Stores the finite numeric value when provided.
* @return true when the parameter was provided.
*/
bool loadReal(ParametersT key, RealT& target) const

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be std::optional<RealT> instead

{
if (!parameters_.contains(key))
{
return false;
}

const auto& value = parameters_.at(key);
RealT parsed_value{};
if (const auto* real_value = std::get_if<RealT>(&value))
{
parsed_value = *real_value;
}
else if (const auto* index_value = std::get_if<IdxT>(&value))
{
parsed_value = static_cast<RealT>(*index_value);
}
else
{
reject(key, "must be numeric");
}

if (!std::isfinite(parsed_value))
{
reject(key, "must be finite");
}

target = parsed_value;
return true;
}

/**
* @brief Load a real parameter that must be provided.
*
* @param[in] key Parameter to look up.
* @param[out] target Stores the finite numeric value.
* @return true, since a missing parameter is rejected.
*/
bool requireReal(ParametersT key, RealT& target) const
{
if (!parameters_.contains(key))
{
reject(key, "is required");
}
return loadReal(key, target);
}

/**
* @brief Load an optional boolean switch parameter.
*
* @param[in] key Parameter to look up.
* @param[out] target Stores the boolean value when provided.
* @return true when the parameter was provided.
*/
bool loadSwitch(ParametersT key, bool& target) const

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

likewise, this return value could be std::optional<bool>

{
if (!parameters_.contains(key))
{
return false;
}

const auto& value = parameters_.at(key);
if (const auto* bool_value = std::get_if<bool>(&value))
{
target = *bool_value;
return true;
}

reject(key, "must be boolean");
}

/**
* @brief Load a switch parameter that must be provided. A boolean or an
* integer 0/1 value is accepted.
*
* @param[in] key Parameter to look up.
* @param[out] target Stores the switch value.
* @return true, since a missing parameter is rejected.
*/
bool requireSwitch(ParametersT key, bool& target) const
{
if (!parameters_.contains(key))
{
reject(key, "is required");
}

const auto& value = parameters_.at(key);
if (const auto* bool_value = std::get_if<bool>(&value))
{
target = *bool_value;
return true;
}
if (const auto* index_value = std::get_if<IdxT>(&value);
index_value && (*index_value == 0 || *index_value == 1))
{
target = (*index_value == 1);
return true;
}

reject(key, "must be bool or 0/1");
}

/**
* @brief Load an optional integer selector parameter.
*
* @param[in] key Parameter to look up.
* @param[out] target Stores the integer value when provided.
* @return true when the parameter was provided.
*/
bool loadSelector(ParametersT key, IdxT& target) const
{
if (!parameters_.contains(key))
{
return false;
}

const auto& value = parameters_.at(key);
if (const auto* index_value = std::get_if<IdxT>(&value))
{
target = *index_value;
return true;
}

reject(key, "must be an integer selector");
}

private:
/// Reject the model data with a message naming the model and parameter.
[[noreturn]] void reject(ParametersT key, const char* reason) const
{
throw std::invalid_argument(std::string(model_) + ": parameter '"
+ std::string(magic_enum::enum_name(key))
+ "' " + reason);
}

const std::map<ParametersT, std::variant<bool, RealT, IdxT>>& parameters_;
const char* model_;
};
} // namespace Model
} // namespace GridKit
21 changes: 8 additions & 13 deletions GridKit/Model/PhasorDynamics/Branch/Branch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ namespace GridKit
Branch(BusT* bus1, BusT* bus2, const ModelDataT& data);
virtual ~Branch();

virtual int setGridKitComponentID(IdxT) override final;
virtual int allocate() override final;
virtual int initialize() override final;
virtual int tagDifferentiable() override final;
virtual int setAbsoluteTolerance(RealT rel_tol) override final;
virtual int evaluateResidual() override final;
virtual int evaluateJacobian() override final;
virtual int verify() const override final;
virtual int setGridKitComponentID(IdxT) override final;
virtual int allocate() override final;
virtual int initialize() override final;
virtual int tagDifferentiable() override final;
virtual int setAbsoluteTolerance(RealT rel_tol) override final;
virtual int evaluateResidual() override final;
virtual int evaluateJacobian() override final;
virtual Model::ConfigurationChecks verify() const override final;

void setR(RealT R)
{
Expand Down Expand Up @@ -118,9 +118,6 @@ namespace GridKit
void setDerivedParams();
void terminalCurrent1(ScalarT& Ir, ScalarT& Ii);
void terminalCurrent2(ScalarT& Ir, ScalarT& Ii);
bool readRealParameter(const ModelDataT& data,
typename ModelDataT::Parameters parameter,
RealT& target);

static __attribute__((always_inline)) inline void addAdmittanceContribution(const RealT G,
const RealT B,
Expand Down Expand Up @@ -207,8 +204,6 @@ namespace GridKit
RealT g22_{0.0};
RealT b22_{0.0};

int parameter_error_count_{0};

/// Variable monitor
std::unique_ptr<MonitorT> monitor_;
};
Expand Down
Loading
Loading