From d0e6727ac31a0102bbe17d19e068d441dc7b5d1c Mon Sep 17 00:00:00 2001 From: Magnus Ulimoen Date: Thu, 3 Sep 2020 21:30:28 +0200 Subject: [PATCH] Use serde for json configuration file --- euler/Cargo.toml | 2 + euler/src/lib.rs | 5 + multigrid/Cargo.toml | 9 +- multigrid/src/parsing.rs | 291 ++++++++++++++++++++++++++++++++++++++- sbp/Cargo.toml | 1 + sbp/src/utils.rs | 4 + 6 files changed, 304 insertions(+), 8 deletions(-) diff --git a/euler/Cargo.toml b/euler/Cargo.toml index 2bbda8e..c7a031a 100644 --- a/euler/Cargo.toml +++ b/euler/Cargo.toml @@ -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" diff --git a/euler/src/lib.rs b/euler/src/lib.rs index 264bada..4802ae8 100644 --- a/euler/src/lib.rs +++ b/euler/src/lib.rs @@ -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, diff --git a/multigrid/Cargo.toml b/multigrid/Cargo.toml index d34a026..440250c 100644 --- a/multigrid/Cargo.toml +++ b/multigrid/Cargo.toml @@ -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"] } diff --git a/multigrid/src/parsing.rs b/multigrid/src/parsing.rs index 2eb8e2a..5dd965e 100644 --- a/multigrid/src/parsing.rs +++ b/multigrid/src/parsing.rs @@ -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 for GridLike { + fn from(t: Linspace) -> Self { + Self::Linspace(t) + } +} + +impl From for GridLike { + fn from(t: ArrayForm) -> Self { + Self::Array(t) + } +} + +impl From> for GridLike { + fn from(t: ndarray::Array1) -> Self { + Self::Array(t.into()) + } +} + +impl From> for GridLike { + fn from(t: ndarray::Array2) -> 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, + 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>; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct GridConfig { + pub operators: Option, + pub x: Option, + pub y: Option, + pub boundary_conditions: Option, +} + +type Grids = indexmap::IndexMap; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Configuration { + pub grids: Grids, + pub integration_time: Float, + pub vortex: euler::VortexParameters, +} + +pub struct RuntimeConfiguration { + names: Vec, + grids: Vec, + bc: Vec, + op: Vec, +} + +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), @@ -200,6 +318,18 @@ enum ArrayForm { Array2(ndarray::Array2), } +impl From> for ArrayForm { + fn from(t: ndarray::Array1) -> Self { + Self::Array1(t) + } +} + +impl From> for ArrayForm { + fn from(t: ndarray::Array2) -> 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 { +fn json2grid(x: JsonValue, y: JsonValue) -> Result { 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 { }; 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()); +} diff --git a/sbp/Cargo.toml b/sbp/Cargo.toml index 1ef3c42..7895675 100644 --- a/sbp/Cargo.toml +++ b/sbp/Cargo.toml @@ -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 diff --git a/sbp/src/utils.rs b/sbp/src/utils.rs index 6dcabf3..2e0d5b2 100644 --- a/sbp/src/utils.rs +++ b/sbp/src/utils.rs @@ -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 { pub north: T, pub south: T,