decline_curve_analysis/
lib.rs1use std::marker::PhantomData;
2use thiserror::Error;
3
4mod decline_rate;
5mod delay;
6mod exponential;
7mod flat;
8mod harmonic;
9mod hyperbolic;
10mod linear;
11
12pub use decline_rate::*;
13pub use delay::*;
14pub use exponential::*;
15pub use flat::*;
16pub use harmonic::*;
17pub use hyperbolic::*;
18pub use linear::*;
19
20#[derive(Clone, Debug, Error, Eq, PartialEq)]
22pub enum DeclineCurveAnalysisError {
23 #[error("decline rate too high")]
24 DeclineRateTooHigh,
25 #[error("decline rate has wrong sign")]
26 DeclineRateWrongSign,
27 #[error("cannot solve decline")]
28 CannotSolveDecline,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq)]
33pub struct ProductionRate<Time: DeclineTimeUnit> {
34 value: f64,
35 _time: PhantomData<Time>,
36}
37
38impl<Time: DeclineTimeUnit> ProductionRate<Time> {
39 pub const fn new(value: f64) -> Self {
40 Self {
41 value,
42 _time: PhantomData,
43 }
44 }
45
46 pub const fn value(&self) -> f64 {
47 self.value
48 }
49}
50
51impl Into<ProductionRate<AverageDaysTime>> for ProductionRate<AverageYearsTime> {
52 fn into(self) -> ProductionRate<AverageDaysTime> {
53 ProductionRate::new(self.value * AverageDaysTime::LENGTH / AverageYearsTime::LENGTH)
54 }
55}
56
57impl Into<ProductionRate<AverageYearsTime>> for ProductionRate<AverageDaysTime> {
58 fn into(self) -> ProductionRate<AverageYearsTime> {
59 ProductionRate::new(self.value * AverageYearsTime::LENGTH / AverageDaysTime::LENGTH)
60 }
61}
62
63#[derive(Clone, Copy, PartialEq, Eq)]
64enum DeclineRateSignValidation {
65 Continue,
66 ZeroDuration,
67}
68
69fn validate_decline_rate_sign(
70 decline_rate: f64,
71 initial_rate: f64,
72 final_rate: f64,
73) -> Result<DeclineRateSignValidation, DeclineCurveAnalysisError> {
74 if initial_rate < final_rate {
75 if decline_rate > 0. {
76 return Err(DeclineCurveAnalysisError::DeclineRateWrongSign);
77 }
78 } else if initial_rate > final_rate {
79 if decline_rate < 0. {
80 return Err(DeclineCurveAnalysisError::DeclineRateWrongSign);
81 }
82 } else {
83 return Ok(DeclineRateSignValidation::ZeroDuration);
85 }
86
87 Ok(DeclineRateSignValidation::Continue)
88}