From 3485f0fd068ecd46c67e86f012ace2925b82af84 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (h)" <j.wuttke@fz-juelich.de>
Date: Fri, 6 May 2016 16:59:44 +0200
Subject: [PATCH] + ff triangle, for test purposes; corr and improved runff.

---
 Core/FormFactors/FormFactorPolyhedron.cpp | 40 +++++++++++------
 Core/FormFactors/FormFactorPolyhedron.h   | 17 ++++++++
 Core/FormFactors/FormFactorTriangle.cpp   | 52 +++++++++++++++++++++++
 Core/FormFactors/FormFactorTriangle.h     | 39 +++++++++++++++++
 dev-tools/math/fftest/runff.cpp           |  7 ++-
 5 files changed, 140 insertions(+), 15 deletions(-)
 create mode 100644 Core/FormFactors/FormFactorTriangle.cpp
 create mode 100644 Core/FormFactors/FormFactorTriangle.h

diff --git a/Core/FormFactors/FormFactorPolyhedron.cpp b/Core/FormFactors/FormFactorPolyhedron.cpp
index 1ce17009b4c..acacdfaa243 100644
--- a/Core/FormFactors/FormFactorPolyhedron.cpp
+++ b/Core/FormFactors/FormFactorPolyhedron.cpp
@@ -228,21 +228,17 @@ complex_t PolyhedralFace::ff_n( int n, const cvector_t q ) const
     }
 }
 
-//! Returns the contribution of this face to the polyhedral form factor.
+//! Returns the contribution ff(q) of this face to the polyhedral form factor.
 
 complex_t PolyhedralFace::ff( const cvector_t q, const bool sym_Ci ) const
 {
-    //std::cout<<"Face "<<m_normal<<":\n";
-    complex_t qn = q.dot(m_normal); // conj(q)*normal (BasicVector3D::dot is antilinear in 'this' argument)
-    if ( std::abs(qn)<eps*q.mag() )
-        return 0;
     complex_t qperp;
     cvector_t qpa;
     decompose_q( q, qperp, qpa );
     double qpa_red = m_radius_2d * qpa.mag();
     complex_t qr_perp = qperp*m_rperp;
     if ( qpa_red==0 ) {
-        return qn * (sym_Ci ? 2.*I*sin(qr_perp) : exp(I*qr_perp)) * m_area;
+        return (sym_Ci ? 2.*I*sin(qr_perp) : exp(I*qr_perp)) * m_area;
     } else if ( qpa_red < qpa_limit_series && !sym_S2 ) {
         // summation of power series
 #ifdef POLYHEDRAL_DIAGNOSTIC
@@ -251,10 +247,10 @@ complex_t PolyhedralFace::ff( const cvector_t q, const bool sym_Ci ) const
         complex_t fac_even;
         complex_t fac_odd;
         if( sym_Ci ) {
-            fac_even = qn * 2. * I * sin(qr_perp);
-            fac_odd = qn * 2. * cos(qr_perp);
+            fac_even = 2. * I * sin(qr_perp);
+            fac_odd = 2. * cos(qr_perp);
         } else {
-            fac_even = qn * exp( I*qr_perp );
+            fac_even = exp( I*qr_perp );
             fac_odd = fac_even;
         }
         complex_t sum = fac_even * m_area;
@@ -277,8 +273,8 @@ complex_t PolyhedralFace::ff( const cvector_t q, const bool sym_Ci ) const
 #endif
     } else {
         // direct evaluation of analytic formula
-        cvector_t prevec = 2.*m_normal.cross( qpa ); // complex conjugation will take place in .dot
-        complex_t prefac = qn;
+        cvector_t prevec = m_normal.cross( qpa ); // complex conjugation will take place in .dot
+        complex_t prefac = 2.;
         if( sym_S2 )
             prefac *= sym_Ci ? -4.*sin(qr_perp) : 2.*I*exp(I*qr_perp);
         complex_t sum = 0;
@@ -288,6 +284,7 @@ complex_t PolyhedralFace::ff( const cvector_t q, const bool sym_Ci ) const
             complex_t Rfac = sym_S2 ? sin(e.qR(qpa)) : ( sym_Ci ? 2.*cos(qR) : exp(I*qR) );
             sum += prevec.dot(e.E()) * MathFunctions::sinc(qE) * Rfac;
         }
+        std::cerr<<std::setprecision(12)<<"DEBUG "<<qpa<<" "<<prevec.mag()<<"  "<<sum.real()<<" "<<sum.imag()<<"\n";
         //std::cout<<std::setprecision(16)<<"  ret="<<prefac * sum / ( I*qpa.mag2() )<<"\n";
         return prefac * sum / ( I*qpa.mag2() );
     }
@@ -447,8 +444,12 @@ complex_t FormFactorPolyhedron::evaluate_centered( const cvector_t q ) const
     } else {
         // direct evaluation of analytic formula (coefficients may involve series)
         complex_t sum = 0;
-        for( const PolyhedralFace& Gk: m_faces )
-            sum += Gk.ff(q, m_sym_Ci );
+        for( const PolyhedralFace& Gk: m_faces ) {
+            complex_t qn = Gk.normalProjectionConj( q ); // conj(q)*normal
+            if ( std::abs(qn)<eps*q.mag() )
+                continue;
+            sum += qn * Gk.ff(q, m_sym_Ci );
+        }
         return sum / (I * q.mag2());
     }
 }
@@ -495,3 +496,16 @@ complex_t FormFactorPolygonalPrism::evaluate_for_q( const cvector_t q ) const
     return m_height * exp(I*(m_height/2)*q.z()) * MathFunctions::sinc(m_height/2*q.z()) *
         m_base->ff_2D( qxy );
 }
+
+
+//***************************************************************************************************
+//  FormFactorPolygonalSurface implementation
+//***************************************************************************************************
+
+complex_t FormFactorPolygonalSurface::evaluate_for_q( const cvector_t q ) const
+{
+#ifdef POLYHEDRAL_DIAGNOSTIC
+    diagnosis = { 0, 0 };
+#endif
+    return m_base->ff( q, false );
+}
diff --git a/Core/FormFactors/FormFactorPolyhedron.h b/Core/FormFactors/FormFactorPolyhedron.h
index f0f41253343..9cae7cbf56c 100644
--- a/Core/FormFactors/FormFactorPolyhedron.h
+++ b/Core/FormFactors/FormFactorPolyhedron.h
@@ -60,6 +60,8 @@ public:
     kvector_t center() const { return m_center; }
     double pyramidalVolume() const { return m_rperp*m_area/3; }
     double radius3d() const { return m_radius_3d; }
+    //! Returns conj(q)*normal [BasicVector3D::dot is antilinear in 'this' argument]
+    complex_t normalProjectionConj( cvector_t q ) const { return q.dot(m_normal); } 
     complex_t ff_n( int m, const cvector_t q ) const;
     complex_t ff( const cvector_t q, const bool sym_Ci ) const;
     complex_t ff_2D( const cvector_t qpa ) const;
@@ -141,4 +143,19 @@ protected:
     double m_height;
 };
 
+
+//! A polygonal surface, for testing form factor computations.
+
+class FormFactorPolygonalSurface : public IFormFactorBorn {
+public:
+    FormFactorPolygonalSurface() {}
+
+    virtual complex_t evaluate_for_q(const cvector_t q ) const final;
+    double getVolume() const { return 0; }
+    virtual double getRadius() const final { return std::sqrt(m_base->area()); }
+
+protected:
+    std::unique_ptr<PolyhedralFace> m_base;
+};
+
 #endif // FORMFACTORPOLYHEDRON_H
diff --git a/Core/FormFactors/FormFactorTriangle.cpp b/Core/FormFactors/FormFactorTriangle.cpp
new file mode 100644
index 00000000000..79433812741
--- /dev/null
+++ b/Core/FormFactors/FormFactorTriangle.cpp
@@ -0,0 +1,52 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      FormFactors/FormFactorTriangle.cpp
+//! @brief     Implements class FormFactorTriangle.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2015-16
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
+//
+// ************************************************************************** //
+
+#include "FormFactorTriangle.h"
+#include "BornAgainNamespace.h"
+#include "MathFunctions.h"
+
+//! @brief Triangle constructor
+//! @param base_edge of hexagonal base
+//! @param height of Triangle
+FormFactorTriangle::FormFactorTriangle(const double base_edge)
+    : m_base_edge( base_edge )
+{
+    setName("Triangle");
+    registerParameter(BornAgain::BaseEdge, &m_base_edge, AttLimits::n_positive());
+    onChange();
+}
+
+void FormFactorTriangle::onChange()
+{
+    double a = m_base_edge;
+    double as = a/2;
+    double ac = a/sqrt(3)/2;
+    double ah = a/sqrt(3);
+    kvector_t V[3] = {
+        { -as, -ac, 0. },
+        {  as, -ac, 0. },
+        {  0.,  ah, 0. } };
+    m_base = std::unique_ptr<PolyhedralFace>( new PolyhedralFace( { V[0], V[1], V[2] }, false ) );
+}
+
+FormFactorTriangle* FormFactorTriangle::clone() const
+{
+    return new FormFactorTriangle(m_base_edge);
+}
+
+void FormFactorTriangle::accept(ISampleVisitor *visitor) const
+{
+    visitor->visit(this);
+}
diff --git a/Core/FormFactors/FormFactorTriangle.h b/Core/FormFactors/FormFactorTriangle.h
new file mode 100644
index 00000000000..308f6661eb4
--- /dev/null
+++ b/Core/FormFactors/FormFactorTriangle.h
@@ -0,0 +1,39 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      FormFactors/FormFactorTriangle.h
+//! @brief     Declares class FormFactorTriangle.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2015-16
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
+//
+// ************************************************************************** //
+
+#ifndef FORMFACTORTRIANGLE_H
+#define FORMFACTORTRIANGLE_H
+#include "FormFactorPolyhedron.h"
+
+//! @class FormFactorTriangle
+//! @ingroup formfactors
+//! @brief The formfactor of an equilateral triangle, for testing purposes.
+
+class BA_CORE_API_ FormFactorTriangle : public FormFactorPolygonalSurface
+{
+public:
+    FormFactorTriangle(const double base_edge);
+
+    virtual FormFactorTriangle *clone() const;
+    virtual void accept(ISampleVisitor *visitor) const;
+
+    double getBaseEdge() const { return m_base_edge; }
+
+private:
+    virtual void onChange() final;
+    double m_base_edge;
+};
+
+#endif // FORMFACTORTRIANGLE_H
diff --git a/dev-tools/math/fftest/runff.cpp b/dev-tools/math/fftest/runff.cpp
index e5df7d9371c..96a1418e04f 100644
--- a/dev-tools/math/fftest/runff.cpp
+++ b/dev-tools/math/fftest/runff.cpp
@@ -15,6 +15,7 @@
 #include <vector>
 
 #include "ParticleShapes.h"
+#include "FormFactorTriangle.h"
 
 using std::cout;
 using std::cerr;
@@ -61,6 +62,8 @@ IFormFactorBorn* make_particle( int ishape )
     } else if( ishape==11 ) {
         double alpha = 72 * Units::degree;
         return new FormFactorCuboctahedron(1., 1., .8, alpha);
+    } else if( ishape==90 ) {
+        return new FormFactorTriangle(1.);
     } else
         throw "Shape not implemented";
 }
@@ -315,10 +318,10 @@ int main (int argc, const char *argv[])
                     run( P, ishape, mag*uq, outfilter );
             } else if( inmode==1 ) {
                 NEXTARG;
-                mag = atof(argv[10]);
+                mag = atof( *arg );
                 run( P, ishape, mag*uq, outfilter );
             } else if( inmode==2 ) {
-                int n_mag = 2001;
+                int n_mag = 301;
                 double mag_i = 1e-9;
                 double mag_f = 1e2;
                 for( int i=1; i<n_mag; ++i ) {
-- 
GitLab