Skip to content

Commit 790fdfa

Browse files
pitkajuhdpiparo
authored andcommitted
[TMath] Add Gradient and Laplacian methods for arrays
1 parent 0515776 commit 790fdfa

2 files changed

Lines changed: 115 additions & 0 deletions

File tree

math/mathcore/inc/TMath.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,10 @@ struct Limits {
442442
template <typename T> Long64_t LocMax(Long64_t n, const T *a);
443443
template <typename Iterator> Iterator LocMax(Iterator first, Iterator last);
444444

445+
// Derivatives of an array
446+
template <typename T> T *Gradient(Long64_t n, T *f, double h = 1);
447+
template <typename T> T *Laplacian(Long64_t n, T *f, double h = 1);
448+
445449
// Hashing
446450
ULong_t Hash(const void *txt, Int_t ntxt);
447451
ULong_t Hash(const char *str);
@@ -1002,6 +1006,82 @@ Iterator TMath::LocMin(Iterator first, Iterator last) {
10021006
return std::min_element(first, last);
10031007
}
10041008

1009+
////////////////////////////////////////////////////////////////////////////////
1010+
/// \brief Calculate the one-dimensional gradient of an array with length n.
1011+
/// The first value in the returned array is a forward difference,
1012+
/// the next n-2 values are central differences, and the last is a backward difference.
1013+
///
1014+
/// \note Function leads to undefined behavior if n does not match the length of f
1015+
/// \param n the number of points in the array
1016+
/// \param f the array of points.
1017+
/// \param h the step size. The default step size is 1.
1018+
/// \return an array of size n with the gradient. Returns nullptr if n < 2 or f empty. Ownership is transferred to the
1019+
/// caller.
1020+
1021+
template <typename T>
1022+
T *TMath::Gradient(const Long64_t n, T *f, const double h)
1023+
{
1024+
if (!f) {
1025+
::Error("TMath::Gradient", "Input parameter f is empty.");
1026+
return nullptr;
1027+
} else if (n < 2) {
1028+
::Error("TMath::Gradient", "Input parameter n=%lld is smaller than 2.", n);
1029+
return nullptr;
1030+
}
1031+
Long64_t i = 1;
1032+
T *result = new T[n];
1033+
1034+
// Forward difference
1035+
result[0] = (f[1] - f[0]) / h;
1036+
1037+
// Central difference
1038+
while (i < n - 1) {
1039+
result[i] = (f[i + 1] - f[i - 1]) / (2 * h);
1040+
i++;
1041+
}
1042+
// Backward difference
1043+
result[i] = (f[i] - f[i - 1]) / h;
1044+
return result;
1045+
}
1046+
1047+
////////////////////////////////////////////////////////////////////////////////
1048+
/// \brief Calculate the Laplacian of an array with length n.
1049+
/// The first value in the returned array is a forward difference,
1050+
/// the next n-2 values are central differences, and the last is a backward difference.
1051+
///
1052+
/// \note Function leads to undefined behavior if n does not match the length of f
1053+
/// \param n the number of points in the array
1054+
/// \param f the array of points.
1055+
/// \param h the step size. The default step size is 1.
1056+
/// \return an array of size n with the laplacian. Returns nullptr if n < 4 or f empty. Ownership is transferred to the
1057+
/// caller.
1058+
1059+
template <typename T>
1060+
T *TMath::Laplacian(const Long64_t n, T *f, const double h)
1061+
{
1062+
if (!f) {
1063+
::Error("TMath::Laplacian", "Input parameter f is empty.");
1064+
return nullptr;
1065+
} else if (n < 4) {
1066+
::Error("TMath::Laplacian", "Input parameter n=%lld is smaller than 4.", n);
1067+
return nullptr;
1068+
}
1069+
Long64_t i = 1;
1070+
T *result = new T[n];
1071+
1072+
// Forward difference
1073+
result[0] = (4 * f[2] + 2 * f[0] - 5 * f[1] - f[3]) / (4 * h * h);
1074+
1075+
// Central difference
1076+
while (i < n - 1) {
1077+
result[i] = (f[i + 1] + f[i - 1] - 2 * f[i]) / (4 * h * h);
1078+
i++;
1079+
}
1080+
// Backward difference
1081+
result[i] = (2 * f[i] - 5 * f[i - 1] + 4 * f[i - 2] - f[i - 3]) / (4 * h * h);
1082+
return result;
1083+
}
1084+
10051085
////////////////////////////////////////////////////////////////////////////////
10061086
/// Returns index of array with the maximum element.
10071087
/// If more than one element is maximum returns first found.

math/mathcore/test/testTMath.cxx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,32 @@ void testNormCross()
3636
<< endl;
3737
}
3838

39+
template <typename T>
40+
void testArrayDerivatives()
41+
{
42+
const Long64_t n = 10;
43+
const double h = 0.1;
44+
T sa[n] = {18, 47, 183, 98, 56, 74, 28, 75, 10, 89};
45+
T *gradient = TMath::Gradient(n, sa, h);
46+
T *laplacian = TMath::Laplacian(n, sa, h);
47+
48+
const T gradienta[n] = {290, 825, 255, -635, -120, -140, 5, -90, 70, 790};
49+
const T laplaciana[n] = {10875, 2675, -5525, 1075, 1500, -1600, 2325, -2800, 3600, 10000};
50+
51+
// test results
52+
53+
for (Long64_t i = 0; i < n; i++) {
54+
if (gradient[i] != gradienta[i])
55+
Error("testArrayDerivatives", "For Gradient, different values found at i = %lld", i);
56+
57+
if (laplacian[i] != laplaciana[i])
58+
Error("testArrayDerivatives", "For Laplacian, different values found at i = %lld", i);
59+
}
60+
61+
delete [] gradient;
62+
delete [] laplacian;
63+
64+
}
3965

4066
template <typename T, typename U>
4167
void testArrayFunctions()
@@ -174,6 +200,15 @@ void testTMath()
174200
testArrayFunctions<Long_t,Long64_t>();
175201
testArrayFunctions<Long64_t,Long64_t>();
176202

203+
cout << "\nArray derivative tests: " << endl;
204+
205+
testArrayDerivatives<Short_t>();
206+
testArrayDerivatives<Int_t>();
207+
testArrayDerivatives<Float_t>();
208+
testArrayDerivatives<Double_t>();
209+
testArrayDerivatives<Long_t>();
210+
testArrayDerivatives<Long64_t>();
211+
177212
cout << "\nIterator functions tests: " << endl;
178213

179214
testIteratorFunctions<Short_t>();

0 commit comments

Comments
 (0)