From 7d035ec0589121d12a49d09e1e382137a0a9359d Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (h)" <j.wuttke@fz-juelich.de>
Date: Sun, 11 Dec 2022 19:26:37 +0100
Subject: [PATCH] further generalization of test function

pass functions q->ff instead of q's or ff's
---
 Tests/Unit/Numeric/FormFactorSymmetryTest.cpp | 29 +---------
 Tests/Unit/Numeric/MultiQTest.cpp             | 58 +++++++++++++++++++
 Tests/Unit/Numeric/MultiQTest.h               |  3 +
 3 files changed, 64 insertions(+), 26 deletions(-)

diff --git a/Tests/Unit/Numeric/FormFactorSymmetryTest.cpp b/Tests/Unit/Numeric/FormFactorSymmetryTest.cpp
index c5f5f861af1..5b2f86905f7 100644
--- a/Tests/Unit/Numeric/FormFactorSymmetryTest.cpp
+++ b/Tests/Unit/Numeric/FormFactorSymmetryTest.cpp
@@ -11,35 +11,12 @@ protected:
     void run_test(IFormFactor* ff, std::function<C3(const C3&)> trafo, double eps, double qmag1,
                   double qmag2)
     {
-        int failures = formfactorTest::run_test2_for_many_q(
-            [&](C3 q, bool report) -> double { return test_qq_eq(ff, q, trafo(q), eps, report); },
+        int failures = formfactorTest::run_test3_for_many_q(
+            [&](C3 q) -> complex_t { return ff->formfactor(q); },
+            [&](C3 q) -> complex_t { return ff->formfactor(trafo(q)); },
             qmag1, qmag2, eps);
         EXPECT_EQ(failures, 0);
     }
-
-private:
-    double test_qq_eq(IFormFactor* ff, C3 q, C3 p, double eps, bool report)
-    {
-        complex_t f0 = ff->formfactor(q);
-#ifdef ALGORITHM_DIAGNOSTIC
-        std::string msg0 = polyhedralDiagnosis.message();
-#endif
-        const complex_t f1 = ff->formfactor(p);
-        const double avge = (std::abs(f0) + std::abs(f1)) / 2;
-        const double abserr = std::max(fabs(real(f0) - real(f1)), fabs(imag(f0) - imag(f1)));
-        const double result = abserr / avge * std::min(1., eps * avge / 1e-16);
-        if (report) {
-            std::cout << "Deviation of q0 = " << q << "\n";
-            std::cout << "         and q1 = " << p << ":\n";
-            std::cout << "  Re(f0) = " << std::setprecision(16) << real(f0)
-                      << ", Im(f0) = " << imag(f0) << "\n";
-            std::cout << "  Re(f1) = " << real(f1) << ", Im(f1) = " << imag(f1) << "\n";
-            std::cout << "  abs dev = " << std::setprecision(8) << abserr
-                      << ", rel dev = " << abserr / avge << ", score = " << result
-                      << ", limit = " << eps << "\n";
-        }
-        return result;
-    }
 };
 
 //*********** polyhedra ***************
diff --git a/Tests/Unit/Numeric/MultiQTest.cpp b/Tests/Unit/Numeric/MultiQTest.cpp
index 61cc6aa0769..05c0a411a15 100644
--- a/Tests/Unit/Numeric/MultiQTest.cpp
+++ b/Tests/Unit/Numeric/MultiQTest.cpp
@@ -75,4 +75,62 @@ int run_test2_for_many_q(std::function<double(C3, bool)> run_one_test, double qm
     return failures;
 }
 
+int run_test3_for_many_q(std::function<complex_t(C3)> fff0, std::function<complex_t(C3)> fff1,
+                         double qmag_min, double qmag_max, double eps, bool real_only)
+{
+    auto evaluate = [&](C3 q) -> std::tuple<complex_t, complex_t, double, double, double> {
+        const complex_t f0 = fff0(q);
+        const complex_t f1 = fff1(q);
+        const double avge = (std::abs(f0) + std::abs(f1)) / 2;
+        const double abserr = real_only ?
+        std::abs(f0) - std::abs(f1)
+        : std::max(fabs(real(f0) - real(f1)), fabs(imag(f0) - imag(f1)));
+        const double deviation = abserr / avge * std::min(1., eps * avge / 1e-16);
+        return { f0, f1, avge, abserr, deviation };
+    };
+
+    ParamGenerator<std::tuple<C3, C3, double, double, double>> gen = qlist;
+    double max_deviation = 0;
+    C3 q_at_max;
+    int failures = 0;
+    for (auto it : gen) {
+        const C3 q_maindir = std::get<0>(it);
+        const C3 q_sidedir = std::get<1>(it);
+        const double qrealmag = std::get<2>(it);
+        const double qsidemag = std::get<3>(it);
+        const double qimagrel = std::get<4>(it);
+        if (real_only && qimagrel)
+            continue;
+        const complex_t qmag(qrealmag, qrealmag * qimagrel);
+        if (std::abs(qmag) <= qmag_min || std::abs(qmag) >= qmag_max)
+            continue;
+        if (q_maindir == q_sidedir)
+            continue;
+        const C3 q = qmag * (q_maindir + qsidemag * q_sidedir).unit();
+
+        const auto [f0, f1, avge, abserr, deviation] = evaluate(q);
+
+        if (deviation > eps) {
+            ++failures;
+            if (deviation > max_deviation) {
+                max_deviation = deviation;
+                q_at_max = q;
+            }
+        }
+    }
+
+    if (failures) {
+        const auto [f0, f1, avge, abserr, deviation] = evaluate(q_at_max);
+        std::cout << "Deviation at q = " << q_at_max << ":\n";
+        std::cout << "  Re(f0) = " << std::setprecision(16) << real(f0)
+                  << ", Im(f0) = " << imag(f0) << "\n";
+        std::cout << "  Re(f1) = " << real(f1) << ", Im(f1) = " << imag(f1) << "\n";
+        std::cout << "  abs dev = " << std::setprecision(8) << abserr
+                  << ", rel dev = " << abserr / avge << ", score = " << deviation
+                  << ", limit = " << eps << "\n";
+    }
+
+    return failures;
+}
+
 } // namespace formfactorTest
diff --git a/Tests/Unit/Numeric/MultiQTest.h b/Tests/Unit/Numeric/MultiQTest.h
index 152d2999a87..d22a3e24f72 100644
--- a/Tests/Unit/Numeric/MultiQTest.h
+++ b/Tests/Unit/Numeric/MultiQTest.h
@@ -18,6 +18,9 @@ void run_test_for_many_q(std::function<void(C3)> run_one_test, double qmag_min,
 int run_test2_for_many_q(std::function<double(C3, bool)> run_one_test, double qmag_min,
                          double qmag_max, double eps, bool real_only = false);
 
+int run_test3_for_many_q(std::function<complex_t(C3)> fff0, std::function<complex_t(C3)> fff1,
+                         double qmag_min, double qmag_max, double eps, bool real_only = false);
+
 } // namespace formfactorTest
 
 
-- 
GitLab