1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use core::marker::PhantomData;
use fehler::throws;
use mexprp::{Context, Expression};
use snafu::ensure;

use crate::{
    engine::{
        helper_equation_traits::{Bounds, EquationOfThreeVariable, EquationOfTwoVariable},
        quadrature::GetQuadratureRange,
        utils, CalculationResult, CalculationStep,
    },
    errors::{self, Error},
};

pub struct ThirdIntegrator<G: GetQuadratureRange, E: EquationOfThreeVariable> {
    a_equation: Expression<f64>,
    b_equation: Expression<f64>,
    h: f64,
    equation: E,
    _p: PhantomData<G>,
}

impl<G: GetQuadratureRange, E: EquationOfThreeVariable> ThirdIntegrator<G, E> {
    #[throws]
    pub fn new(a_equation: &str, b_equation: &str, h: f64, equation: E) -> Self {
        let a_equation = Expression::parse(a_equation)?;
        let b_equation = Expression::parse(b_equation)?;

        Self {
            a_equation,
            b_equation,
            h,
            equation,
            _p: PhantomData,
        }
    }
}

impl<G: GetQuadratureRange, E: EquationOfThreeVariable> EquationOfTwoVariable
    for ThirdIntegrator<G, E>
{
    #[throws]
    fn calculate(
        &self,
        x: CalculationStep,
        bounds_x: Bounds,
        y: CalculationStep,
        bounds_y: Bounds,
    ) -> CalculationResult {
        let mut context = Context::new();
        context.set_var("x", *x);
        context.set_var("y", *y);

        let a = utils::calculate_expression_one_value_result(&context, &self.a_equation)?;
        let b = utils::calculate_expression_one_value_result(&context, &self.b_equation)?;

        ensure!(a <= b, errors::BeginBoundGreaterThanEndBound { a, b });

        let mut result = CalculationResult::new();
        let mut range = if let Some(range) = G::get_range_generator(a, b, self.h)? {
            range
        } else {
            return result;
        };

        loop {
            let step = range.next()?;
            result += self
                .equation
                .calculate(x, bounds_x, y, bounds_y, step, (a, b))?;

            if step.is_last() {
                break;
            }
        }

        result
    }
}