diff --git a/multigrid/src/eval.rs b/multigrid/src/eval.rs index 7fe4c38..c530224 100644 --- a/multigrid/src/eval.rs +++ b/multigrid/src/eval.rs @@ -1,24 +1,14 @@ -use euler::GAMMA; -use evalexpr::*; -use ndarray::{azip, ArrayView, ArrayViewMut, Dimension}; +use ndarray::{ArrayView, ArrayViewMut, Dimension}; use sbp::Float; +pub mod evalexpr; + #[derive(Clone, Debug)] pub enum Evaluator { - Pressure(EvaluatorPressure), - Conservation(EvaluatorConservation), + EvalExpr(evalexpr::Evaluator), } -#[derive(Debug, Clone)] -pub struct EvaluatorConservation { - pub(crate) ctx: HashMapContext, - pub(crate) rho: Node, - pub(crate) rhou: Node, - pub(crate) rhov: Node, - pub(crate) e: Node, -} - -impl euler::eval::Evaluator for Evaluator { +impl euler::eval::Evaluator for Evaluator { fn evaluate( &self, t: Float, @@ -30,338 +20,7 @@ impl euler::eval::Evaluator for Evaluator { e: ArrayViewMut, ) { match self { - Self::Conservation(c) => c.evaluate(t, x, y, rho, rhou, rhov, e), - Self::Pressure(p) => { - euler::eval::EvaluatorPressureWrapper::new(p).evaluate(t, x, y, rho, rhou, rhov, e) - } + Self::EvalExpr(c) => c.evaluate(t, x, y, rho, rhou, rhov, e), } } } - -#[derive(Debug, Clone)] -pub struct EvaluatorPressure { - pub(crate) ctx: HashMapContext, - pub(crate) rho: Node, - pub(crate) u: Node, - pub(crate) v: Node, - pub(crate) p: Node, -} - -struct ContextWrapper<'a> { - ctx: &'a HashMapContext, - x: Option, - y: Option, - t: Value, - rho: Option, - u: Option, - v: Option, - rhou: Option, - rhov: Option, - id: std::collections::HashMap, -} - -impl<'a> ContextWrapper<'a> { - fn wrap(ctx: &'a HashMapContext, t: Value) -> Self { - Self { - ctx, - t, - x: None, - y: None, - rho: None, - rhou: None, - rhov: None, - u: None, - v: None, - id: std::collections::HashMap::new(), - } - } -} - -impl Context for ContextWrapper<'_> { - fn get_value(&self, identifier: &str) -> Option<&Value> { - match identifier { - "t" => Some(&self.t), - "x" => self.x.as_ref(), - "y" => self.y.as_ref(), - "rho" => self.rho.as_ref(), - "rhou" => self.rhou.as_ref(), - "rhov" => self.rhov.as_ref(), - "u" => self.u.as_ref(), - "v" => self.v.as_ref(), - id => self.id.get(id).or_else(|| self.ctx.get_value(id)), - } - } - - fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult { - self.ctx.call_function(identifier, argument) - } -} - -impl ContextWithMutableVariables for ContextWrapper<'_> { - fn set_value(&mut self, identifier: String, value: Value) -> EvalexprResult<()> { - self.id.insert(identifier, value); - Ok(()) - } -} - -impl euler::eval::Evaluator for EvaluatorConservation { - fn evaluate( - &self, - t: Float, - x: ArrayView, - y: ArrayView, - mut rho: ArrayViewMut, - mut rhou: ArrayViewMut, - mut rhov: ArrayViewMut, - mut e: ArrayViewMut, - ) { - let mut ctx = ContextWrapper::wrap(&self.ctx, t.into()); - - azip!((&x in &x.view(), &y in &y, rho in &mut rho) { - ctx.x = Some(x.into()); - ctx.y = Some(y.into()); - - *rho = self.rho.eval_number_with_context_mut(&mut ctx).unwrap(); - }); - - azip!((&x in &x, &y in &y, &rho in &rho, rhou in &mut rhou) { - ctx.x = Some(x.into()); - ctx.y = Some(y.into()); - ctx.rho = Some(rho.into()); - - *rhou = self.rhou.eval_number_with_context_mut(&mut ctx).unwrap(); - }); - - azip!((&x in &x, &y in &y, &rho in &rho, rhov in &mut rhov) { - ctx.x = Some(x.into()); - ctx.y = Some(y.into()); - ctx.rho = Some(rho.into()); - - *rhov = self.rhov.eval_number_with_context_mut(&mut ctx).unwrap(); - }); - - azip!((&x in &x, &y in &y, &rho in &rho, &rhou in &rhou, &rhov in &rhov, e in &mut e) { - ctx.x = Some(x.into()); - ctx.y = Some(y.into()); - ctx.rho = Some(rho.into()); - ctx.rhou = Some(rhou.into()); - ctx.rhov = Some(rhov.into()); - - *e = self.e.eval_number_with_context_mut(&mut ctx).unwrap(); - }); - } -} - -impl euler::eval::EvaluatorPressure for EvaluatorPressure { - fn rho( - &self, - t: Float, - x: ArrayView, - y: ArrayView, - mut rho: ArrayViewMut, - ) { - let mut ctx = ContextWrapper::wrap(&self.ctx, t.into()); - - azip!((&x in &x, &y in &y, rho in &mut rho) { - ctx.x = Some(x.into()); - ctx.y = Some(y.into()); - - *rho = self.rho.eval_number_with_context_mut(&mut ctx).unwrap(); - }) - } - - fn u( - &self, - t: Float, - x: ArrayView, - y: ArrayView, - rho: ArrayView, - mut u: ArrayViewMut, - ) { - let mut ctx = ContextWrapper::wrap(&self.ctx, t.into()); - - azip!((&x in &x, &y in &y, &rho in &rho, u in &mut u) { - ctx.x = Some(x.into()); - ctx.y = Some(y.into()); - ctx.rho = Some(rho.into()); - - *u = self.u.eval_number_with_context_mut(&mut ctx).unwrap(); - }) - } - fn v( - &self, - t: Float, - x: ArrayView, - y: ArrayView, - rho: ArrayView, - mut v: ArrayViewMut, - ) { - let mut ctx = ContextWrapper::wrap(&self.ctx, t.into()); - - azip!((&x in &x, &y in &y, &rho in &rho, v in &mut v) { - ctx.x = Some(x.into()); - ctx.y = Some(y.into()); - ctx.rho = Some(rho.into()); - - *v = self.v.eval_number_with_context_mut(&mut ctx).unwrap(); - }) - } - - fn p( - &self, - t: Float, - x: ArrayView, - y: ArrayView, - rho: ArrayView, - u: ArrayView, - v: ArrayView, - mut p: ArrayViewMut, - ) { - let mut ctx = ContextWrapper::wrap(&self.ctx, t.into()); - - azip!((&x in &x, &y in &y, &rho in &rho, &u in &u, &v in &v, p in &mut p) { - ctx.x = Some(x.into()); - ctx.y = Some(y.into()); - ctx.rho = Some(rho.into()); - ctx.u = Some(u.into()); - ctx.v = Some(v.into()); - - *p = self.p.eval_number_with_context_mut(&mut ctx).unwrap(); - }) - } -} - -#[test] -fn append_default_context() { - let basic_ctx = context_map! { - "a" => 2, - } - .unwrap(); - - let mut ctx = ContextWrapper::wrap(&basic_ctx, Value::from(4)); - ctx.x = Some(3.into()); - - let expr = "a + x + t"; - - let node = build_operator_tree(expr).unwrap(); - - assert_eq!(node.eval_with_context(&ctx).unwrap().as_int().unwrap(), 9); -} - -pub fn default_context() -> HashMapContext { - let mut context = math_consts_context! {}.unwrap(); - let gamma = *GAMMA.get().expect("GAMMA is not defined"); - context.set_value("GAMMA".into(), gamma.into()).unwrap(); - - context - .set_function( - "if".into(), - Function::new(|arg| { - let arg = arg.as_tuple()?; - if arg.len() != 3 { - return Err(error::EvalexprError::WrongFunctionArgumentAmount { - expected: 3, - actual: arg.len(), - }); - } - let b = arg[0].as_boolean()?; - if b { - Ok(arg[1].clone()) - } else { - Ok(arg[2].clone()) - } - }), - ) - .unwrap(); - - context - .set_function( - "case".into(), - Function::new(|arg| { - let mut arg = arg.as_tuple()?; - if arg.len() % 2 == 0 { - return Err(error::EvalexprError::WrongFunctionArgumentAmount { - expected: arg.len() + 1, - actual: arg.len(), - }); - } - //let mut arg = arg.as_slice(); - while arg.len() > 2 { - let boolean = arg.remove(0); - let value = arg.remove(0); - - if boolean.as_boolean()? { - return Ok(value); - } - } - Ok(arg.pop().unwrap()) - }), - ) - .unwrap(); - - context - .set_function( - "math::atan2".into(), - Function::new(|arg| { - let arg = arg.as_tuple()?; - if arg.len() != 2 { - return Err(error::EvalexprError::WrongFunctionArgumentAmount { - expected: 2, - actual: arg.len(), - }); - } - let s = arg[0].as_number()?; - let o = arg[1].as_number()?; - Ok(s.atan2(o).into()) - }), - ) - .unwrap(); - - context - .set_function( - "math::hypot".into(), - Function::new(|arg| { - let arg = arg.as_tuple()?; - if arg.len() != 2 { - return Err(error::EvalexprError::WrongFunctionArgumentAmount { - expected: 2, - actual: arg.len(), - }); - } - let s = arg[0].as_number()?; - let o = arg[1].as_number()?; - Ok(s.hypot(o).into()) - }), - ) - .unwrap(); - - context - .set_function( - "math::exp".into(), - Function::new(|arg| { - let arg = arg.as_number()?; - Ok(arg.exp().into()) - }), - ) - .unwrap(); - - context - .set_function( - "math::pow".into(), - Function::new(|arg| { - let arg = arg.as_tuple()?; - if arg.len() != 2 { - return Err(error::EvalexprError::WrongFunctionArgumentAmount { - expected: 2, - actual: arg.len(), - }); - } - let s = arg[0].as_number()?; - let o = arg[1].as_number()?; - Ok(s.powf(o).into()) - }), - ) - .unwrap(); - - context -} diff --git a/multigrid/src/eval/evalexpr.rs b/multigrid/src/eval/evalexpr.rs new file mode 100644 index 0000000..939f7e7 --- /dev/null +++ b/multigrid/src/eval/evalexpr.rs @@ -0,0 +1,367 @@ +use euler::GAMMA; +use evalexpr::*; +use ndarray::{azip, ArrayView, ArrayViewMut, Dimension}; +use sbp::Float; + +#[derive(Clone, Debug)] +pub enum Evaluator { + Pressure(EvaluatorPressure), + Conservation(EvaluatorConservation), +} + +#[derive(Debug, Clone)] +pub struct EvaluatorConservation { + pub(crate) ctx: HashMapContext, + pub(crate) rho: Node, + pub(crate) rhou: Node, + pub(crate) rhov: Node, + pub(crate) e: Node, +} + +impl euler::eval::Evaluator for Evaluator { + fn evaluate( + &self, + t: Float, + x: ArrayView, + y: ArrayView, + rho: ArrayViewMut, + rhou: ArrayViewMut, + rhov: ArrayViewMut, + e: ArrayViewMut, + ) { + match self { + Self::Conservation(c) => c.evaluate(t, x, y, rho, rhou, rhov, e), + Self::Pressure(p) => { + euler::eval::EvaluatorPressureWrapper::new(p).evaluate(t, x, y, rho, rhou, rhov, e) + } + } + } +} + +#[derive(Debug, Clone)] +pub struct EvaluatorPressure { + pub(crate) ctx: HashMapContext, + pub(crate) rho: Node, + pub(crate) u: Node, + pub(crate) v: Node, + pub(crate) p: Node, +} + +struct ContextWrapper<'a> { + ctx: &'a HashMapContext, + x: Option, + y: Option, + t: Value, + rho: Option, + u: Option, + v: Option, + rhou: Option, + rhov: Option, + id: std::collections::HashMap, +} + +impl<'a> ContextWrapper<'a> { + fn wrap(ctx: &'a HashMapContext, t: Value) -> Self { + Self { + ctx, + t, + x: None, + y: None, + rho: None, + rhou: None, + rhov: None, + u: None, + v: None, + id: std::collections::HashMap::new(), + } + } +} + +impl Context for ContextWrapper<'_> { + fn get_value(&self, identifier: &str) -> Option<&Value> { + match identifier { + "t" => Some(&self.t), + "x" => self.x.as_ref(), + "y" => self.y.as_ref(), + "rho" => self.rho.as_ref(), + "rhou" => self.rhou.as_ref(), + "rhov" => self.rhov.as_ref(), + "u" => self.u.as_ref(), + "v" => self.v.as_ref(), + id => self.id.get(id).or_else(|| self.ctx.get_value(id)), + } + } + + fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult { + self.ctx.call_function(identifier, argument) + } +} + +impl ContextWithMutableVariables for ContextWrapper<'_> { + fn set_value(&mut self, identifier: String, value: Value) -> EvalexprResult<()> { + self.id.insert(identifier, value); + Ok(()) + } +} + +impl euler::eval::Evaluator for EvaluatorConservation { + fn evaluate( + &self, + t: Float, + x: ArrayView, + y: ArrayView, + mut rho: ArrayViewMut, + mut rhou: ArrayViewMut, + mut rhov: ArrayViewMut, + mut e: ArrayViewMut, + ) { + let mut ctx = ContextWrapper::wrap(&self.ctx, t.into()); + + azip!((&x in &x.view(), &y in &y, rho in &mut rho) { + ctx.x = Some(x.into()); + ctx.y = Some(y.into()); + + *rho = self.rho.eval_number_with_context_mut(&mut ctx).unwrap(); + }); + + azip!((&x in &x, &y in &y, &rho in &rho, rhou in &mut rhou) { + ctx.x = Some(x.into()); + ctx.y = Some(y.into()); + ctx.rho = Some(rho.into()); + + *rhou = self.rhou.eval_number_with_context_mut(&mut ctx).unwrap(); + }); + + azip!((&x in &x, &y in &y, &rho in &rho, rhov in &mut rhov) { + ctx.x = Some(x.into()); + ctx.y = Some(y.into()); + ctx.rho = Some(rho.into()); + + *rhov = self.rhov.eval_number_with_context_mut(&mut ctx).unwrap(); + }); + + azip!((&x in &x, &y in &y, &rho in &rho, &rhou in &rhou, &rhov in &rhov, e in &mut e) { + ctx.x = Some(x.into()); + ctx.y = Some(y.into()); + ctx.rho = Some(rho.into()); + ctx.rhou = Some(rhou.into()); + ctx.rhov = Some(rhov.into()); + + *e = self.e.eval_number_with_context_mut(&mut ctx).unwrap(); + }); + } +} + +impl euler::eval::EvaluatorPressure for EvaluatorPressure { + fn rho( + &self, + t: Float, + x: ArrayView, + y: ArrayView, + mut rho: ArrayViewMut, + ) { + let mut ctx = ContextWrapper::wrap(&self.ctx, t.into()); + + azip!((&x in &x, &y in &y, rho in &mut rho) { + ctx.x = Some(x.into()); + ctx.y = Some(y.into()); + + *rho = self.rho.eval_number_with_context_mut(&mut ctx).unwrap(); + }) + } + + fn u( + &self, + t: Float, + x: ArrayView, + y: ArrayView, + rho: ArrayView, + mut u: ArrayViewMut, + ) { + let mut ctx = ContextWrapper::wrap(&self.ctx, t.into()); + + azip!((&x in &x, &y in &y, &rho in &rho, u in &mut u) { + ctx.x = Some(x.into()); + ctx.y = Some(y.into()); + ctx.rho = Some(rho.into()); + + *u = self.u.eval_number_with_context_mut(&mut ctx).unwrap(); + }) + } + fn v( + &self, + t: Float, + x: ArrayView, + y: ArrayView, + rho: ArrayView, + mut v: ArrayViewMut, + ) { + let mut ctx = ContextWrapper::wrap(&self.ctx, t.into()); + + azip!((&x in &x, &y in &y, &rho in &rho, v in &mut v) { + ctx.x = Some(x.into()); + ctx.y = Some(y.into()); + ctx.rho = Some(rho.into()); + + *v = self.v.eval_number_with_context_mut(&mut ctx).unwrap(); + }) + } + + fn p( + &self, + t: Float, + x: ArrayView, + y: ArrayView, + rho: ArrayView, + u: ArrayView, + v: ArrayView, + mut p: ArrayViewMut, + ) { + let mut ctx = ContextWrapper::wrap(&self.ctx, t.into()); + + azip!((&x in &x, &y in &y, &rho in &rho, &u in &u, &v in &v, p in &mut p) { + ctx.x = Some(x.into()); + ctx.y = Some(y.into()); + ctx.rho = Some(rho.into()); + ctx.u = Some(u.into()); + ctx.v = Some(v.into()); + + *p = self.p.eval_number_with_context_mut(&mut ctx).unwrap(); + }) + } +} + +#[test] +fn append_default_context() { + let basic_ctx = context_map! { + "a" => 2, + } + .unwrap(); + + let mut ctx = ContextWrapper::wrap(&basic_ctx, Value::from(4)); + ctx.x = Some(3.into()); + + let expr = "a + x + t"; + + let node = build_operator_tree(expr).unwrap(); + + assert_eq!(node.eval_with_context(&ctx).unwrap().as_int().unwrap(), 9); +} + +pub fn default_context() -> HashMapContext { + let mut context = math_consts_context! {}.unwrap(); + let gamma = *GAMMA.get().expect("GAMMA is not defined"); + context.set_value("GAMMA".into(), gamma.into()).unwrap(); + + context + .set_function( + "if".into(), + Function::new(|arg| { + let arg = arg.as_tuple()?; + if arg.len() != 3 { + return Err(error::EvalexprError::WrongFunctionArgumentAmount { + expected: 3, + actual: arg.len(), + }); + } + let b = arg[0].as_boolean()?; + if b { + Ok(arg[1].clone()) + } else { + Ok(arg[2].clone()) + } + }), + ) + .unwrap(); + + context + .set_function( + "case".into(), + Function::new(|arg| { + let mut arg = arg.as_tuple()?; + if arg.len() % 2 == 0 { + return Err(error::EvalexprError::WrongFunctionArgumentAmount { + expected: arg.len() + 1, + actual: arg.len(), + }); + } + //let mut arg = arg.as_slice(); + while arg.len() > 2 { + let boolean = arg.remove(0); + let value = arg.remove(0); + + if boolean.as_boolean()? { + return Ok(value); + } + } + Ok(arg.pop().unwrap()) + }), + ) + .unwrap(); + + context + .set_function( + "math::atan2".into(), + Function::new(|arg| { + let arg = arg.as_tuple()?; + if arg.len() != 2 { + return Err(error::EvalexprError::WrongFunctionArgumentAmount { + expected: 2, + actual: arg.len(), + }); + } + let s = arg[0].as_number()?; + let o = arg[1].as_number()?; + Ok(s.atan2(o).into()) + }), + ) + .unwrap(); + + context + .set_function( + "math::hypot".into(), + Function::new(|arg| { + let arg = arg.as_tuple()?; + if arg.len() != 2 { + return Err(error::EvalexprError::WrongFunctionArgumentAmount { + expected: 2, + actual: arg.len(), + }); + } + let s = arg[0].as_number()?; + let o = arg[1].as_number()?; + Ok(s.hypot(o).into()) + }), + ) + .unwrap(); + + context + .set_function( + "math::exp".into(), + Function::new(|arg| { + let arg = arg.as_number()?; + Ok(arg.exp().into()) + }), + ) + .unwrap(); + + context + .set_function( + "math::pow".into(), + Function::new(|arg| { + let arg = arg.as_tuple()?; + if arg.len() != 2 { + return Err(error::EvalexprError::WrongFunctionArgumentAmount { + expected: 2, + actual: arg.len(), + }); + } + let s = arg[0].as_number()?; + let o = arg[1].as_number()?; + Ok(s.powf(o).into()) + }), + ) + .unwrap(); + + context +} diff --git a/multigrid/src/parsing.rs b/multigrid/src/parsing.rs index c5f43e1..e064dd8 100644 --- a/multigrid/src/parsing.rs +++ b/multigrid/src/parsing.rs @@ -9,7 +9,7 @@ use crate::input; impl TryFrom for eval::Evaluator { type Error = (); fn try_from(expr: input::Expressions) -> Result { - let mut context = eval::default_context(); + let mut context = eval::evalexpr::default_context(); match expr { input::Expressions::Pressure(input::ExpressionsPressure { globals, @@ -27,13 +27,15 @@ impl TryFrom for eval::Evaluator { evalexpr::build_operator_tree(&v).unwrap(), evalexpr::build_operator_tree(&p).unwrap(), ]; - Ok(eval::Evaluator::Pressure(eval::EvaluatorPressure { - ctx: context, - rho, - u, - v, - p, - })) + Ok(eval::Evaluator::EvalExpr( + eval::evalexpr::Evaluator::Pressure(eval::evalexpr::EvaluatorPressure { + ctx: context, + rho, + u, + v, + p, + }), + )) } input::Expressions::Conservation(input::ExpressionsConservation { globals, @@ -51,13 +53,17 @@ impl TryFrom for eval::Evaluator { evalexpr::build_operator_tree(&rhov).unwrap(), evalexpr::build_operator_tree(&e).unwrap(), ]; - Ok(eval::Evaluator::Conservation(eval::EvaluatorConservation { - ctx: context, - rho, - rhou, - rhov, - e, - })) + Ok(eval::Evaluator::EvalExpr( + eval::evalexpr::Evaluator::Conservation( + eval::evalexpr::EvaluatorConservation { + ctx: context, + rho, + rhou, + rhov, + e, + }, + ), + )) } } }