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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//! Real-space functions.

use std::fmt;

use derive_builder::Builder;
use itertools::Itertools;
use nalgebra::Point3;
use ndarray_linalg::types::Lapack;
use num_complex::ComplexFloat;

#[cfg(test)]
mod real_space_function_tests;

pub mod real_space_function_analysis;
mod real_space_function_transformation;

// ==================
// Struct definitions
// ==================

/// Structure to manage real-space functions.
#[derive(Builder, Clone)]
#[builder(build_fn(validate = "Self::validate"))]
pub struct RealSpaceFunction<T, F>
where
    T: ComplexFloat + Lapack,
    F: Fn(&Point3<f64>) -> T,
{
    /// The grid points $`\mathbf{r}_j`$ at which the real-space function is to be evaluated.
    grid_points: Vec<Point3<f64>>,

    /// The function $`\mathbb{R}^3 \to T`$.
    function: F,

    /// A boolean indicating if action of [`Self::function`] needs to be complex-conjugated.
    #[builder(default = "false")]
    complex_conjugated: bool,
}

impl<T, F> RealSpaceFunctionBuilder<T, F>
where
    T: ComplexFloat + Lapack,
    F: Fn(&Point3<f64>) -> T,
{
    fn validate(&self) -> Result<(), String> {
        let _ = self
            .grid_points
            .as_ref()
            .ok_or("No grid points found.".to_string())?;
        let _ = self
            .function
            .as_ref()
            .ok_or("No real-space function found.".to_string())?;
        Ok(())
    }
}

impl<T, F> RealSpaceFunction<T, F>
where
    T: ComplexFloat + Clone + Lapack,
    F: Clone + Fn(&Point3<f64>) -> T,
{
    /// Returns a builder to construct a new [`RealSpaceFunction`].
    pub fn builder() -> RealSpaceFunctionBuilder<T, F> {
        RealSpaceFunctionBuilder::default()
    }

    /// Returns a vector of shared references to the grid points at which the real-space function is
    /// evaluated.
    pub fn grid_points(&self) -> Vec<&Point3<f64>> {
        self.grid_points.iter().collect_vec()
    }

    /// Returns a shared reference to the function defining the [`RealSpaceFunction`].
    pub fn function(&self) -> &F {
        &self.function
    }
}

// =====================
// Trait implementations
// =====================

// -------
// Display
// -------
impl<T, F> fmt::Display for RealSpaceFunction<T, F>
where
    T: ComplexFloat + Lapack,
    F: Fn(&Point3<f64>) -> T,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "RealSpaceFunction{}[grid of {} {}]",
            if self.complex_conjugated { "*" } else { "" },
            self.grid_points.len(),
            if self.grid_points.len() == 1 {
                "point"
            } else {
                "points"
            }
        )?;
        Ok(())
    }
}