46 const std::vector<Real>& measures,
48 std::vector<Real> derivative(mesh_size, 0.0);
52 for (
int index = 2; index < mesh_size - 2; index++) {
53 Real index_derivative = (values[index - 2] - 8.0 * values[index - 1] +
54 8.0 * values[index + 1] - values[index + 2]) /
56 derivative[index] = index_derivative / measures[index];
59 auto forward = [&](
int index) {
60 return (-25.0 * values[index] + 48.0 * values[index + 1] - 36.0 * values[index + 2] +
61 16.0 * values[index + 3] - 3.0 * values[index + 4]) /
64 auto backward = [&](
int index) {
65 return (25.0 * values[index] - 48.0 * values[index - 1] + 36.0 * values[index - 2] -
66 16.0 * values[index - 3] + 3.0 * values[index - 4]) /
69 derivative[0] = forward(0) / measures[0];
70 derivative[1] = forward(1) / measures[1];
71 derivative[mesh_size - 1] = backward(mesh_size - 1) / measures[mesh_size - 1];
72 derivative[mesh_size - 2] = backward(mesh_size - 2) / measures[mesh_size - 2];
85 int maximum_angular_momentum = 0;
86 while ((maximum_angular_momentum + 1) * (maximum_angular_momentum + 1) < number_of_lm)
87 maximum_angular_momentum++;
89 constexpr Real step = 1e-5;
90 std::vector<std::vector<std::array<Real, 3>>> gradients(
91 angular_grid.size(), std::vector<std::array<Real, 3>>(number_of_lm, {0.0, 0.0, 0.0}));
93 for (
size_t point = 0; point < angular_grid.size(); point++) {
94 std::array<Real, 3> direction{
95 angular_grid[point].x, angular_grid[point].y, angular_grid[point].z};
96 for (
int axis = 0; axis < 3; axis++) {
97 std::array<Real, 3> plus = direction;
98 std::array<Real, 3> minus = direction;
101 Real plus_norm = std::sqrt(plus[0] * plus[0] + plus[1] * plus[1] + plus[2] * plus[2]);
103 std::sqrt(minus[0] * minus[0] + minus[1] * minus[1] + minus[2] * minus[2]);
104 Vector3D plus_direction{plus[0] / plus_norm, plus[1] / plus_norm, plus[2] / plus_norm};
106 minus[0] / minus_norm, minus[1] / minus_norm, minus[2] / minus_norm};
108 for (
int degree = 0; degree <= maximum_angular_momentum; degree++) {
111 if (lm >= number_of_lm)
117 gradients[point][lm][axis] = (value_plus - value_minus) / (2.0 * step);
141 const std::vector<Real>& channel_derivatives,
143 const std::vector<std::vector<Real>>& harmonics,
144 const std::vector<std::vector<std::array<Real, 3>>>& harmonic_gradients) {
145 int number_of_angles =
static_cast<int>(harmonics.size());
146 int number_of_lm =
static_cast<int>(channel_values.size());
150 result.
tangential.assign(number_of_angles, {0.0, 0.0, 0.0});
153 Real inverse_radius = 1.0 / radius;
154 for (
int angle = 0; angle < number_of_angles; angle++) {
156 std::array<Real, 3> tangential{0.0, 0.0, 0.0};
157 for (
int lm = 0; lm < number_of_lm; lm++) {
158 radial += channel_derivatives[lm] * harmonics[angle][lm];
159 for (
int axis = 0; axis < 3; axis++)
160 tangential[axis] += channel_values[lm] * harmonic_gradients[angle][lm][axis];
162 for (
int axis = 0; axis < 3; axis++)
163 tangential[axis] *= inverse_radius;
167 result.
gradient_squared[angle] = radial * radial + tangential[0] * tangential[0] +
168 tangential[1] * tangential[1] +
169 tangential[2] * tangential[2];
GradientAtRadius build_gradient_at_radius(const std::vector< Real > &channel_values, const std::vector< Real > &channel_derivatives, Real radius, const std::vector< std::vector< Real > > &harmonics, const std::vector< std::vector< std::array< Real, 3 > > > &harmonic_gradients)