caseformat 0.2.0

Power flow case data format
Documentation
use anyhow::Result;
use std::io::Write;

use crate::write::*;
use crate::{Branch, Bus, Case, DCLine, Gen, GenCost};

#[macro_export]
macro_rules! write_row {
    ($w:expr, $rec:expr) => {{
        write!(
            $w,
            "\t{};\n",
            $rec.iter().map(|r| r).collect::<Vec<&str>>().join("\t")
        )?;
    }};
}

pub fn write_mpc<W: Write>(
    mut w: W,
    case: &Case,
    bus: &[Bus],
    gen: &[Gen],
    branch: &[Branch],
    gencost: &[GenCost],
    dcline: &[DCLine],
) -> Result<W> {
    write!(w, "function mpc = {}\n", case.name)?;
    write!(w, "\nmpc.version = '{}';\n", case.version)?;

    if !bus.is_empty() {
        let is_opf = bus.iter().any(|b| b.is_opf());
        let header = if !is_opf {
            BUS_HEADER.to_vec()
        } else {
            BUS_HEADER_OPF.to_vec()
        };
        write!(w, "\n%\t{}\n", header.join("\t"))?;
        write!(w, "mpc.bus = [\n")?;
        for b in bus {
            write_row!(w, b.to_string_record(is_opf));
        }
        write!(w, "];\n")?;
    }

    if !gen.is_empty() {
        let is_version_1 = gen.iter().any(|g| g.is_version_1());
        let is_opf = gen.iter().any(|g| g.is_opf());
        let header = if !is_opf && is_version_1 {
            GEN_HEADER.to_vec()
        } else if !is_opf {
            GEN_HEADER_2.to_vec()
        } else {
            GEN_HEADER_OPF.to_vec()
        };
        write!(w, "\n%\t{}\n", header.join("\t"))?;
        write!(w, "mpc.gen = [\n")?;
        for g in gen {
            write_row!(w, g.to_string_record(is_version_1, is_opf));
        }
        write!(w, "];\n")?;
    }

    if !branch.is_empty() {
        let is_pf = branch.iter().any(|br| br.is_pf());
        let is_opf = branch.iter().any(|br| br.is_opf());
        let header = if !is_opf && !is_pf {
            BRANCH_HEADER.to_vec()
        } else if !is_opf {
            BRANCH_HEADER_PF.to_vec()
        } else {
            BRANCH_HEADER_OPF.to_vec()
        };
        write!(w, "\n%\t{}\n", header.join("\t"))?;
        write!(w, "mpc.branch = [\n")?;
        for br in branch {
            write_row!(w, br.to_string_record(is_pf, is_opf));
        }
        write!(w, "];\n")?;
    }

    if !gencost.is_empty() {
        write!(w, "\n%\t{}\n", GENCOST_HEADER.join("\t"))?;
        write!(w, "mpc.gencost = [\n")?;
        for c in gencost {
            write_row!(w, c.to_string_record());
        }
        write!(w, "];\n")?;
    }

    if !dcline.is_empty() {
        let is_opf = dcline.iter().any(|br| br.is_opf());
        let header = if !is_opf {
            DCLINE_HEADER.to_vec()
        } else {
            DCLINE_HEADER_OPF.to_vec()
        };
        write!(w, "\n%\t{}\n", header.join("\t"))?;
        write!(w, "mpc.dcline = [\n")?;
        for br in dcline {
            write_row!(w, br.to_string_record(is_opf));
        }
        write!(w, "];\n")?;
    }

    Ok(w)
}