use serde_json::Value;
use super::costly::{Costly, CostlyOptions};
use super::evaluate::FlowModel;
use super::linear::{ObjectiveKind, ObjectiveUnit};
use super::search::{SearchOptions, SecondPreventiveCondition};
pub fn from_json(text: &str) -> SearchOptions {
match serde_json::from_str::<Value>(text) {
Ok(doc) => from_document(&doc),
Err(_) => SearchOptions::default(),
}
}
pub fn flow_model(doc: &serde_json::Value) -> FlowModel {
let dc = doc
.pointer(
"/extensions/open-rao-search-tree-parameters/load-flow-and-sensitivity-computation\
/sensitivity-parameters/load-flow-parameters/dc",
)
.and_then(|v| v.as_bool());
match dc {
Some(false) => FlowModel::Ac,
_ => FlowModel::Dc,
}
}
pub fn from_document(doc: &serde_json::Value) -> SearchOptions {
let mut options = SearchOptions::default();
options.linear.flow_model = flow_model(doc);
options.linear.objective_unit = match options.linear.flow_model {
FlowModel::Ac => ObjectiveUnit::Ampere,
FlowModel::Dc => ObjectiveUnit::Megawatt,
};
if let Some(v) = doc
.pointer(
"/extensions/open-rao-search-tree-parameters/objective-function\
/curative-min-obj-improvement",
)
.and_then(Value::as_f64)
{
options.curative_min_obj_improvement = v;
}
if let Some(v) = doc
.pointer("/objective-function/enforce-curative-security")
.and_then(Value::as_bool)
{
options.enforce_curative_security = v;
}
if doc
.pointer("/objective-function/type")
.and_then(|v| v.as_str())
== Some("SECURE_FLOW")
{
options.stop_at_target = Some(0.0);
}
if doc
.pointer("/objective-function/type")
.and_then(|v| v.as_str())
== Some("MIN_COST")
{
let mut costly = CostlyOptions::default();
if let Some(c) =
doc.pointer("/extensions/open-rao-search-tree-parameters/costly-min-margin-parameters")
{
if let Some(v) = c.get("shifted-violation-penalty").and_then(Value::as_f64) {
costly.violation_penalty = v;
}
if let Some(v) = c.get("shifted-violation-threshold").and_then(Value::as_f64) {
costly.violation_threshold = v;
}
}
options.linear.objective_kind = ObjectiveKind::MinCost(Costly { options: costly });
}
if let Some(topology) =
doc.pointer("/extensions/open-rao-search-tree-parameters/topological-actions-optimization")
{
let skip = topology
.get("skip-actions-far-from-most-limiting-element")
.and_then(|v| v.as_bool())
.unwrap_or(false);
if skip {
options.skip_far_actions = Some(
topology
.get("max-number-of-boundaries-for-skipping-actions")
.and_then(|v| v.as_u64())
.unwrap_or(0) as usize,
);
}
}
if let Some(topology) = doc.get("topological-actions-optimization") {
if let Some(v) = topology
.get("absolute-minimum-impact-threshold")
.and_then(|v| v.as_f64())
{
options.absolute_min_impact = v;
}
if let Some(v) = topology
.get("relative-minimum-impact-threshold")
.and_then(|v| v.as_f64())
{
options.relative_min_impact = v;
}
}
if let Some(range) = doc.get("range-actions-optimization") {
if let Some(v) = range
.get("pst-ra-min-impact-threshold")
.and_then(|v| v.as_f64())
{
options.linear.pst_penalty = v;
}
if let Some(v) = range
.get("injection-ra-min-impact-threshold")
.and_then(|v| v.as_f64())
{
options.linear.injection_penalty = v;
}
}
let extension = doc
.get("extensions")
.and_then(|e| e.get("open-rao-search-tree-parameters"));
if let Some(range) = extension.and_then(|e| e.get("range-actions-optimization")) {
if let Some(v) = range.get("max-mip-iterations").and_then(|v| v.as_u64()) {
options.linear.max_iterations = v as usize;
}
if let Some(v) = range
.get("pst-sensitivity-threshold")
.and_then(|v| v.as_f64())
{
options.linear.sensitivity_threshold = v;
}
}
let base_mnec = doc.get("mnec-parameters");
let extension_mnec = extension.and_then(|e| e.get("mnec-parameters"));
options.linear.mnec.options.enabled = base_mnec.is_some() && extension_mnec.is_some();
if let Some(v) = base_mnec
.and_then(|m| m.get("acceptable-margin-decrease"))
.and_then(Value::as_f64)
{
options.linear.mnec.options.acceptable_margin_decrease = v;
}
if let Some(m) = extension_mnec {
if let Some(v) = m.get("violation-cost").and_then(Value::as_f64) {
options.linear.mnec.options.violation_cost = v;
}
if let Some(v) = m
.get("constraint-adjustment-coefficient")
.and_then(Value::as_f64)
{
options
.linear
.mnec
.options
.constraint_adjustment_coefficient = v;
}
}
if let Some(second) = extension.and_then(|e| e.get("second-preventive-rao")) {
options.second_preventive.condition =
match second.get("execution-condition").and_then(|v| v.as_str()) {
Some("POSSIBLE_CURATIVE_IMPROVEMENT") => {
SecondPreventiveCondition::PossibleCurativeImprovement
}
Some("COST_INCREASE") => SecondPreventiveCondition::CostIncrease,
_ => SecondPreventiveCondition::Disabled,
};
options.second_preventive.hint = second
.get("hint-from-first-preventive-rao")
.and_then(|v| v.as_bool())
.unwrap_or(false);
}
if let Some(topology) = extension.and_then(|e| e.get("topological-actions-optimization")) {
if let Some(v) = topology
.get("max-preventive-search-tree-depth")
.and_then(|v| v.as_u64())
{
options.max_depth = v as usize;
}
if let Some(v) = topology
.get("max-curative-search-tree-depth")
.and_then(|v| v.as_u64())
{
options.curative_max_depth = Some(v as usize);
}
if let Some(list) = topology
.get("predefined-combinations")
.and_then(|v| v.as_array())
{
options.predefined_combinations = list
.iter()
.filter_map(|c| c.as_array())
.map(|c| {
c.iter()
.filter_map(|v| v.as_str().map(str::to_string))
.collect()
})
.collect();
}
}
options
}