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, Default, Serialize, Deserialize)] pub struct Operators { pub xi: Option, pub eta: Option, } #[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), /* #[serde(rename = "initial_conditions")] InitialConditions, */ } #[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), /// The usize is the inner dimension (nx) Array2(ndarray::Array2), /* /// A still unknown array, will be filled out by later /// pass when initial_conditions file is known Unknown, */ } 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) } } impl From for ArrayForm { fn from(t: GridLike) -> Self { match t { GridLike::Linspace(lin) => Self::Array1(if lin.h2 { h2linspace(lin.start, lin.end, lin.steps) } else { ndarray::Array::linspace(lin.start, lin.end, lin.steps) }), GridLike::Array(arr) => arr, // GridLike::InitialConditions => Self::Unknown, } } } 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(Copy, Clone, Debug, Serialize, Deserialize)] pub enum InterpolationOperator { #[serde(rename = "4")] Four, #[serde(rename = "8")] Eight, #[serde(rename = "9")] Nine, #[serde(rename = "9h2")] NineH2, } impl Into> for InterpolationOperator { fn into(self) -> Box { use sbp::operators::{Interpolation4, Interpolation8, Interpolation9, Interpolation9h2}; match self { InterpolationOperator::Four => Box::new(Interpolation4), InterpolationOperator::Eight => Box::new(Interpolation8), InterpolationOperator::Nine => Box::new(Interpolation9), InterpolationOperator::NineH2 => Box::new(Interpolation9h2), } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Interpolate { pub operator: Option, #[serde(alias = "neighbor")] pub neighbour: String, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Multi { #[serde(alias = "neighbor")] pub neighbour: String, pub start: usize, pub end: usize, } #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum BoundaryType { This, Interpolate(Interpolate), #[serde(alias = "neighbor")] Neighbour(String), Vortex, Multi(Vec), } pub type BoundaryDescriptors = sbp::utils::Direction>; #[derive(Clone, Debug, Serialize, Deserialize, Default)] 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)] /// Will be evaluated by evalexpr pub struct ExpressionsConservation { pub globals: Option, pub rho: String, pub rhou: String, pub rhov: String, pub e: String, } #[derive(Clone, Debug, Serialize, Deserialize)] /// Will be evaluated by evalexpr pub struct ExpressionsPressure { pub globals: Option, pub rho: String, pub u: String, pub v: String, pub p: String, } #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] #[serde(untagged)] pub enum Expressions { Conservation(ExpressionsConservation), Pressure(ExpressionsPressure), } #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum InitialConditions { Vortex(euler::VortexParameters), // File(String), Expressions(Expressions), } #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum BoundaryConditions { /// Initial conditions also contain the bc #[serde(rename = "initial_conditions")] InputInitialConditions, Vortex(euler::VortexParameters), Expressions(Expressions), #[serde(rename = "not_needed")] NotNeeded, } impl Default for BoundaryConditions { fn default() -> Self { Self::NotNeeded } } fn default_gamma() -> Float { 1.4 } #[derive(Clone, Debug, Serialize, Deserialize)] /// Input configuration (json) pub struct Configuration { pub grids: Grids, pub integration_time: Float, pub initial_conditions: InitialConditions, #[serde(default)] pub boundary_conditions: BoundaryConditions, #[serde(default = "default_gamma")] pub gamma: Float, } #[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: Some(Operator::Upwind4), eta: Some(Operator::Upwind9), }), }, ); grids.insert( "operators2".to_string(), GridConfig { boundary_conditions: None, x: None, y: None, operators: Some(Operators { xi: Some(Operator::Upwind4h2), eta: Some(Operator::Upwind9h2), }), }, ); grids.insert( "operators3".to_string(), GridConfig { boundary_conditions: None, x: None, y: None, operators: Some(Operators { xi: Some(Operator::Sbp4), eta: Some(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, }, ); grids.insert( "boundary_conditions_multigrid".to_string(), GridConfig { boundary_conditions: Some(BoundaryDescriptors { north: Some(BoundaryType::Multi(vec![Multi { neighbour: "name_of_grid".to_string(), start: 4, end: 7, }])), south: Some(BoundaryType::Multi(vec![ Multi { neighbour: "name_of_grid".to_string(), start: 4, end: 7, }, Multi { neighbour: "name_of_grid".to_string(), start: 41, end: 912, }, ])), east: None, west: None, }), x: None, y: None, operators: None, }, ); let configuration = Configuration { grids, integration_time: 2.0, initial_conditions: InitialConditions::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 }, }), boundary_conditions: BoundaryConditions::default(), gamma: 1.4, }; println!("{}", json5::to_string(&configuration).unwrap()); }