Use serde for json configuration file
This commit is contained in:
		@@ -8,11 +8,13 @@ edition = "2018"
 | 
			
		||||
# Internal feature flag to gate the expensive tests
 | 
			
		||||
# which should be run only in release builds
 | 
			
		||||
expensive_tests = []
 | 
			
		||||
serde1 = ["serde", "arrayvec/serde"]
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
ndarray = "0.13.1"
 | 
			
		||||
sbp = { path = "../sbp" }
 | 
			
		||||
arrayvec = "0.5.1"
 | 
			
		||||
serde = { version = "1.0.115", default-features = false, optional = true, features = ["derive"] }
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
criterion = "0.3.2"
 | 
			
		||||
 
 | 
			
		||||
@@ -402,6 +402,7 @@ fn h2_diff() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, Debug)]
 | 
			
		||||
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 | 
			
		||||
pub struct Vortice {
 | 
			
		||||
    pub x0: Float,
 | 
			
		||||
    pub y0: Float,
 | 
			
		||||
@@ -409,7 +410,11 @@ pub struct Vortice {
 | 
			
		||||
    pub eps: Float,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "serde1")]
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 | 
			
		||||
pub struct VortexParameters {
 | 
			
		||||
    pub vortices: ArrayVec<[Vortice; 5]>,
 | 
			
		||||
    pub mach: Float,
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,15 @@ edition = "2018"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
sbp = { path = "../sbp", features = ["rayon"] }
 | 
			
		||||
euler = { path = "../euler" }
 | 
			
		||||
sbp = { path = "../sbp", features = ["rayon", "serde"] }
 | 
			
		||||
euler = { path = "../euler", features = ["serde1"] }
 | 
			
		||||
hdf5 = "0.7.0"
 | 
			
		||||
rayon = "1.3.0"
 | 
			
		||||
indicatif = "0.14.0"
 | 
			
		||||
structopt = "0.3.14"
 | 
			
		||||
ndarray = "0.13.1"
 | 
			
		||||
ndarray = { version = "0.13.1", features = ["serde"] }
 | 
			
		||||
json = "0.12.4"
 | 
			
		||||
either = "1.5.3"
 | 
			
		||||
serde = { version = "1.0.115", features = ["derive"] }
 | 
			
		||||
json5 = "0.2.8"
 | 
			
		||||
indexmap = { version = "1.5.2", features = ["serde-1"] }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,127 @@
 | 
			
		||||
use super::DiffOp;
 | 
			
		||||
use either::*;
 | 
			
		||||
use json::JsonValue;
 | 
			
		||||
use sbp::grid::Grid;
 | 
			
		||||
use sbp::utils::h2linspace;
 | 
			
		||||
use sbp::Float;
 | 
			
		||||
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
 | 
			
		||||
#[serde(rename_all = "lowercase")]
 | 
			
		||||
pub enum Operator {
 | 
			
		||||
    Upwind4,
 | 
			
		||||
    Upwind9,
 | 
			
		||||
    Upwind4h2,
 | 
			
		||||
    Upwind9h2,
 | 
			
		||||
    Sbp4,
 | 
			
		||||
    Sbp8,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct Operators {
 | 
			
		||||
    pub xi: Operator,
 | 
			
		||||
    pub eta: Operator,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct Linspace {
 | 
			
		||||
    pub start: Float,
 | 
			
		||||
    pub end: Float,
 | 
			
		||||
    pub steps: usize,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub h2: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
			
		||||
#[serde(rename_all = "lowercase")]
 | 
			
		||||
pub enum GridLike {
 | 
			
		||||
    Linspace(Linspace),
 | 
			
		||||
    Array(ArrayForm),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Linspace> for GridLike {
 | 
			
		||||
    fn from(t: Linspace) -> Self {
 | 
			
		||||
        Self::Linspace(t)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ArrayForm> for GridLike {
 | 
			
		||||
    fn from(t: ArrayForm) -> Self {
 | 
			
		||||
        Self::Array(t)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ndarray::Array1<Float>> for GridLike {
 | 
			
		||||
    fn from(t: ndarray::Array1<Float>) -> Self {
 | 
			
		||||
        Self::Array(t.into())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ndarray::Array2<Float>> for GridLike {
 | 
			
		||||
    fn from(t: ndarray::Array2<Float>) -> Self {
 | 
			
		||||
        Self::Array(t.into())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
			
		||||
pub enum InterpolationOperator {
 | 
			
		||||
    #[serde(rename = "4")]
 | 
			
		||||
    Four,
 | 
			
		||||
    #[serde(rename = "8")]
 | 
			
		||||
    Eight,
 | 
			
		||||
    #[serde(rename = "9")]
 | 
			
		||||
    Nine,
 | 
			
		||||
    #[serde(rename = "9h2")]
 | 
			
		||||
    NineH2,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct Interpolate {
 | 
			
		||||
    operator: Option<InterpolationOperator>,
 | 
			
		||||
    neighbour: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
			
		||||
#[serde(rename_all = "lowercase")]
 | 
			
		||||
pub enum BoundaryType {
 | 
			
		||||
    This,
 | 
			
		||||
    Interpolate(Interpolate),
 | 
			
		||||
    Neighbour(String),
 | 
			
		||||
    Vortex,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub type BoundaryDescriptors = sbp::utils::Direction<Option<BoundaryType>>;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct GridConfig {
 | 
			
		||||
    pub operators: Option<Operators>,
 | 
			
		||||
    pub x: Option<GridLike>,
 | 
			
		||||
    pub y: Option<GridLike>,
 | 
			
		||||
    pub boundary_conditions: Option<BoundaryDescriptors>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Grids = indexmap::IndexMap<String, GridConfig>;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct Configuration {
 | 
			
		||||
    pub grids: Grids,
 | 
			
		||||
    pub integration_time: Float,
 | 
			
		||||
    pub vortex: euler::VortexParameters,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct RuntimeConfiguration {
 | 
			
		||||
    names: Vec<String>,
 | 
			
		||||
    grids: Vec<sbp::grid::Grid>,
 | 
			
		||||
    bc: Vec<euler::BoundaryCharacteristics>,
 | 
			
		||||
    op: Vec<DiffOp>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Configuration {
 | 
			
		||||
    fn to_runtime(self) -> RuntimeConfiguration {
 | 
			
		||||
        todo!()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn json_to_grids(
 | 
			
		||||
    mut jsongrids: JsonValue,
 | 
			
		||||
    vortexparams: euler::VortexParameters,
 | 
			
		||||
@@ -191,8 +308,9 @@ pub fn json_to_grids(
 | 
			
		||||
 | 
			
		||||
    (names, grids, bcs, operators)
 | 
			
		||||
}
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
enum ArrayForm {
 | 
			
		||||
#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
			
		||||
#[serde(untagged)]
 | 
			
		||||
pub enum ArrayForm {
 | 
			
		||||
    /// Only know the one dimension, will broadcast to
 | 
			
		||||
    /// two dimensions once we know about both dims
 | 
			
		||||
    Array1(ndarray::Array1<Float>),
 | 
			
		||||
@@ -200,6 +318,18 @@ enum ArrayForm {
 | 
			
		||||
    Array2(ndarray::Array2<Float>),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ndarray::Array1<Float>> for ArrayForm {
 | 
			
		||||
    fn from(t: ndarray::Array1<Float>) -> Self {
 | 
			
		||||
        Self::Array1(t)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ndarray::Array2<Float>> for ArrayForm {
 | 
			
		||||
    fn from(t: ndarray::Array2<Float>) -> Self {
 | 
			
		||||
        Self::Array2(t)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Parsing json strings to some gridlike form
 | 
			
		||||
///
 | 
			
		||||
/// Each grid should be an object with the descriptors on the form
 | 
			
		||||
@@ -217,7 +347,7 @@ enum ArrayForm {
 | 
			
		||||
/// Optional parameters:
 | 
			
		||||
/// * name (for relating boundaries)
 | 
			
		||||
/// * dir{e,w,n,s} (for boundary terms)
 | 
			
		||||
fn json2grid(x: JsonValue, y: JsonValue) -> Result<Grid, String> {
 | 
			
		||||
fn json2grid(x: JsonValue, y: JsonValue) -> Result<sbp::grid::Grid, String> {
 | 
			
		||||
    let to_array_form = |mut x: JsonValue| {
 | 
			
		||||
        if let Some(s) = x.take_string() {
 | 
			
		||||
            if let Some(s) = s.strip_prefix("linspace:") {
 | 
			
		||||
@@ -346,7 +476,7 @@ fn json2grid(x: JsonValue, y: JsonValue) -> Result<Grid, String> {
 | 
			
		||||
    };
 | 
			
		||||
    assert_eq!(x.shape(), y.shape());
 | 
			
		||||
 | 
			
		||||
    Ok(Grid::new(x, y).unwrap())
 | 
			
		||||
    Ok(sbp::grid::Grid::new(x, y).unwrap())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn json_to_vortex(mut json: JsonValue) -> euler::VortexParameters {
 | 
			
		||||
@@ -391,3 +521,154 @@ pub fn json_to_vortex(mut json: JsonValue) -> euler::VortexParameters {
 | 
			
		||||
 | 
			
		||||
    euler::VortexParameters { vortices, mach }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn output_configuration() {
 | 
			
		||||
    let mut grids = Grids::new();
 | 
			
		||||
    grids.insert(
 | 
			
		||||
        "default".to_string(),
 | 
			
		||||
        GridConfig {
 | 
			
		||||
            boundary_conditions: None,
 | 
			
		||||
            x: None,
 | 
			
		||||
            y: None,
 | 
			
		||||
            operators: None,
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    grids.insert(
 | 
			
		||||
        "operators1".to_string(),
 | 
			
		||||
        GridConfig {
 | 
			
		||||
            boundary_conditions: None,
 | 
			
		||||
            x: None,
 | 
			
		||||
            y: None,
 | 
			
		||||
            operators: Some(Operators {
 | 
			
		||||
                xi: Operator::Upwind4,
 | 
			
		||||
                eta: Operator::Upwind9,
 | 
			
		||||
            }),
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    grids.insert(
 | 
			
		||||
        "operators2".to_string(),
 | 
			
		||||
        GridConfig {
 | 
			
		||||
            boundary_conditions: None,
 | 
			
		||||
            x: None,
 | 
			
		||||
            y: None,
 | 
			
		||||
            operators: Some(Operators {
 | 
			
		||||
                xi: Operator::Upwind4h2,
 | 
			
		||||
                eta: Operator::Upwind9h2,
 | 
			
		||||
            }),
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    grids.insert(
 | 
			
		||||
        "operators3".to_string(),
 | 
			
		||||
        GridConfig {
 | 
			
		||||
            boundary_conditions: None,
 | 
			
		||||
            x: None,
 | 
			
		||||
            y: None,
 | 
			
		||||
            operators: Some(Operators {
 | 
			
		||||
                xi: Operator::Sbp4,
 | 
			
		||||
                eta: Operator::Sbp8,
 | 
			
		||||
            }),
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    grids.insert(
 | 
			
		||||
        "linspaced".to_string(),
 | 
			
		||||
        GridConfig {
 | 
			
		||||
            boundary_conditions: None,
 | 
			
		||||
            x: Some(
 | 
			
		||||
                Linspace {
 | 
			
		||||
                    start: 0.0,
 | 
			
		||||
                    end: 1.0,
 | 
			
		||||
                    steps: 32,
 | 
			
		||||
                    h2: false,
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
            ),
 | 
			
		||||
            y: Some(
 | 
			
		||||
                Linspace {
 | 
			
		||||
                    start: -1.0,
 | 
			
		||||
                    end: 1.0,
 | 
			
		||||
                    steps: 35,
 | 
			
		||||
                    h2: true,
 | 
			
		||||
                }
 | 
			
		||||
                .into(),
 | 
			
		||||
            ),
 | 
			
		||||
            operators: None,
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    grids.insert(
 | 
			
		||||
        "array1".to_string(),
 | 
			
		||||
        GridConfig {
 | 
			
		||||
            boundary_conditions: None,
 | 
			
		||||
            x: Some(ndarray::arr1(&[1.0, 2.0, 3.0, 4.0]).into()),
 | 
			
		||||
            y: Some(ndarray::arr1(&[-4.0, -3.0, -2.0, -1.0, 0.0]).into()),
 | 
			
		||||
            operators: None,
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    grids.insert(
 | 
			
		||||
        "array2".to_string(),
 | 
			
		||||
        GridConfig {
 | 
			
		||||
            boundary_conditions: None,
 | 
			
		||||
            x: Some(ndarray::arr2(&[[1.0, 2.0, 3.0, 4.0], [2.0, 3.0, 4.0, 5.0]]).into()),
 | 
			
		||||
            y: Some(ndarray::arr2(&[[0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]]).into()),
 | 
			
		||||
            operators: None,
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    grids.insert(
 | 
			
		||||
        "boundary_conditions".to_string(),
 | 
			
		||||
        GridConfig {
 | 
			
		||||
            boundary_conditions: Some(BoundaryDescriptors {
 | 
			
		||||
                north: None,
 | 
			
		||||
                south: Some(BoundaryType::This),
 | 
			
		||||
                east: Some(BoundaryType::Neighbour("name_of_grid".to_string())),
 | 
			
		||||
                west: Some(BoundaryType::Vortex),
 | 
			
		||||
            }),
 | 
			
		||||
            x: None,
 | 
			
		||||
            y: None,
 | 
			
		||||
            operators: None,
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    grids.insert(
 | 
			
		||||
        "boundary_conditions_interpolation".to_string(),
 | 
			
		||||
        GridConfig {
 | 
			
		||||
            boundary_conditions: Some(BoundaryDescriptors {
 | 
			
		||||
                north: Some(BoundaryType::Interpolate(Interpolate {
 | 
			
		||||
                    neighbour: "name_of_grid".to_string(),
 | 
			
		||||
                    operator: Some(InterpolationOperator::Four),
 | 
			
		||||
                })),
 | 
			
		||||
                south: Some(BoundaryType::Interpolate(Interpolate {
 | 
			
		||||
                    neighbour: "name_of_grid".to_string(),
 | 
			
		||||
                    operator: Some(InterpolationOperator::Nine),
 | 
			
		||||
                })),
 | 
			
		||||
                west: Some(BoundaryType::Interpolate(Interpolate {
 | 
			
		||||
                    neighbour: "name_of_grid".to_string(),
 | 
			
		||||
                    operator: Some(InterpolationOperator::Eight),
 | 
			
		||||
                })),
 | 
			
		||||
                east: Some(BoundaryType::Interpolate(Interpolate {
 | 
			
		||||
                    neighbour: "name_of_grid".to_string(),
 | 
			
		||||
                    operator: Some(InterpolationOperator::NineH2),
 | 
			
		||||
                })),
 | 
			
		||||
            }),
 | 
			
		||||
            x: None,
 | 
			
		||||
            y: None,
 | 
			
		||||
            operators: None,
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    let configuration = Configuration {
 | 
			
		||||
        grids,
 | 
			
		||||
        integration_time: 2.0,
 | 
			
		||||
        vortex: euler::VortexParameters {
 | 
			
		||||
            mach: 0.5,
 | 
			
		||||
            vortices: {
 | 
			
		||||
                let mut arr = euler::ArrayVec::new();
 | 
			
		||||
                arr.push(euler::Vortice {
 | 
			
		||||
                    eps: 1.0,
 | 
			
		||||
                    x0: -1.0,
 | 
			
		||||
                    y0: 0.0,
 | 
			
		||||
                    rstar: 0.5,
 | 
			
		||||
                });
 | 
			
		||||
                arr
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    };
 | 
			
		||||
    println!("{}", json5::to_string(&configuration).unwrap());
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ packed_simd = "0.3.3"
 | 
			
		||||
rayon = { version = "1.3.0", optional = true }
 | 
			
		||||
sprs = { version = "0.7.1", optional = true }
 | 
			
		||||
num-traits = "0.2.11"
 | 
			
		||||
serde = { version = "1.0.115", optional = true, default-features = false, features = ["derive"] }
 | 
			
		||||
 | 
			
		||||
[features]
 | 
			
		||||
# Use f32 as precision, default is f64
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,11 @@ pub use jacobi::*;
 | 
			
		||||
mod kronecker_product;
 | 
			
		||||
#[cfg(feature = "sparse")]
 | 
			
		||||
pub use kronecker_product::kronecker_product;
 | 
			
		||||
#[cfg(feature = "serde")]
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct Direction<T> {
 | 
			
		||||
    pub north: T,
 | 
			
		||||
    pub south: T,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user