Move evalexpr down one level

This commit is contained in:
Magnus Ulimoen 2021-07-01 18:37:22 +02:00
parent c7eab96845
commit 891cee3160
3 changed files with 394 additions and 362 deletions

View File

@ -1,24 +1,14 @@
use euler::GAMMA; use ndarray::{ArrayView, ArrayViewMut, Dimension};
use evalexpr::*;
use ndarray::{azip, ArrayView, ArrayViewMut, Dimension};
use sbp::Float; use sbp::Float;
pub mod evalexpr;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Evaluator { pub enum Evaluator {
Pressure(EvaluatorPressure), EvalExpr(evalexpr::Evaluator),
Conservation(EvaluatorConservation),
} }
#[derive(Debug, Clone)] impl<D: Dimension> euler::eval::Evaluator<D> for Evaluator {
pub struct EvaluatorConservation {
pub(crate) ctx: HashMapContext,
pub(crate) rho: Node,
pub(crate) rhou: Node,
pub(crate) rhov: Node,
pub(crate) e: Node,
}
impl<D: ndarray::Dimension> euler::eval::Evaluator<D> for Evaluator {
fn evaluate( fn evaluate(
&self, &self,
t: Float, t: Float,
@ -30,338 +20,7 @@ impl<D: ndarray::Dimension> euler::eval::Evaluator<D> for Evaluator {
e: ArrayViewMut<Float, D>, e: ArrayViewMut<Float, D>,
) { ) {
match self { match self {
Self::Conservation(c) => c.evaluate(t, x, y, rho, rhou, rhov, e), Self::EvalExpr(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<Value>,
y: Option<Value>,
t: Value,
rho: Option<Value>,
u: Option<Value>,
v: Option<Value>,
rhou: Option<Value>,
rhov: Option<Value>,
id: std::collections::HashMap<String, Value>,
}
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<Value> {
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<D: Dimension> euler::eval::Evaluator<D> for EvaluatorConservation {
fn evaluate(
&self,
t: Float,
x: ArrayView<Float, D>,
y: ArrayView<Float, D>,
mut rho: ArrayViewMut<Float, D>,
mut rhou: ArrayViewMut<Float, D>,
mut rhov: ArrayViewMut<Float, D>,
mut e: ArrayViewMut<Float, D>,
) {
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<D: Dimension> euler::eval::EvaluatorPressure<D> for EvaluatorPressure {
fn rho(
&self,
t: Float,
x: ArrayView<Float, D>,
y: ArrayView<Float, D>,
mut rho: ArrayViewMut<Float, D>,
) {
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<Float, D>,
y: ArrayView<Float, D>,
rho: ArrayView<Float, D>,
mut u: ArrayViewMut<Float, D>,
) {
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<Float, D>,
y: ArrayView<Float, D>,
rho: ArrayView<Float, D>,
mut v: ArrayViewMut<Float, D>,
) {
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<Float, D>,
y: ArrayView<Float, D>,
rho: ArrayView<Float, D>,
u: ArrayView<Float, D>,
v: ArrayView<Float, D>,
mut p: ArrayViewMut<Float, D>,
) {
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
}

View File

@ -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<D: Dimension> euler::eval::Evaluator<D> for Evaluator {
fn evaluate(
&self,
t: Float,
x: ArrayView<Float, D>,
y: ArrayView<Float, D>,
rho: ArrayViewMut<Float, D>,
rhou: ArrayViewMut<Float, D>,
rhov: ArrayViewMut<Float, D>,
e: ArrayViewMut<Float, D>,
) {
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<Value>,
y: Option<Value>,
t: Value,
rho: Option<Value>,
u: Option<Value>,
v: Option<Value>,
rhou: Option<Value>,
rhov: Option<Value>,
id: std::collections::HashMap<String, Value>,
}
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<Value> {
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<D: Dimension> euler::eval::Evaluator<D> for EvaluatorConservation {
fn evaluate(
&self,
t: Float,
x: ArrayView<Float, D>,
y: ArrayView<Float, D>,
mut rho: ArrayViewMut<Float, D>,
mut rhou: ArrayViewMut<Float, D>,
mut rhov: ArrayViewMut<Float, D>,
mut e: ArrayViewMut<Float, D>,
) {
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<D: Dimension> euler::eval::EvaluatorPressure<D> for EvaluatorPressure {
fn rho(
&self,
t: Float,
x: ArrayView<Float, D>,
y: ArrayView<Float, D>,
mut rho: ArrayViewMut<Float, D>,
) {
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<Float, D>,
y: ArrayView<Float, D>,
rho: ArrayView<Float, D>,
mut u: ArrayViewMut<Float, D>,
) {
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<Float, D>,
y: ArrayView<Float, D>,
rho: ArrayView<Float, D>,
mut v: ArrayViewMut<Float, D>,
) {
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<Float, D>,
y: ArrayView<Float, D>,
rho: ArrayView<Float, D>,
u: ArrayView<Float, D>,
v: ArrayView<Float, D>,
mut p: ArrayViewMut<Float, D>,
) {
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
}

View File

@ -9,7 +9,7 @@ use crate::input;
impl TryFrom<input::Expressions> for eval::Evaluator { impl TryFrom<input::Expressions> for eval::Evaluator {
type Error = (); type Error = ();
fn try_from(expr: input::Expressions) -> Result<Self, Self::Error> { fn try_from(expr: input::Expressions) -> Result<Self, Self::Error> {
let mut context = eval::default_context(); let mut context = eval::evalexpr::default_context();
match expr { match expr {
input::Expressions::Pressure(input::ExpressionsPressure { input::Expressions::Pressure(input::ExpressionsPressure {
globals, globals,
@ -27,13 +27,15 @@ impl TryFrom<input::Expressions> for eval::Evaluator {
evalexpr::build_operator_tree(&v).unwrap(), evalexpr::build_operator_tree(&v).unwrap(),
evalexpr::build_operator_tree(&p).unwrap(), evalexpr::build_operator_tree(&p).unwrap(),
]; ];
Ok(eval::Evaluator::Pressure(eval::EvaluatorPressure { Ok(eval::Evaluator::EvalExpr(
eval::evalexpr::Evaluator::Pressure(eval::evalexpr::EvaluatorPressure {
ctx: context, ctx: context,
rho, rho,
u, u,
v, v,
p, p,
})) }),
))
} }
input::Expressions::Conservation(input::ExpressionsConservation { input::Expressions::Conservation(input::ExpressionsConservation {
globals, globals,
@ -51,13 +53,17 @@ impl TryFrom<input::Expressions> for eval::Evaluator {
evalexpr::build_operator_tree(&rhov).unwrap(), evalexpr::build_operator_tree(&rhov).unwrap(),
evalexpr::build_operator_tree(&e).unwrap(), evalexpr::build_operator_tree(&e).unwrap(),
]; ];
Ok(eval::Evaluator::Conservation(eval::EvaluatorConservation { Ok(eval::Evaluator::EvalExpr(
eval::evalexpr::Evaluator::Conservation(
eval::evalexpr::EvaluatorConservation {
ctx: context, ctx: context,
rho, rho,
rhou, rhou,
rhov, rhov,
e, e,
})) },
),
))
} }
} }
} }