From d4631a06bdd2b813e69abfec931f0bbbfa2f0944 Mon Sep 17 00:00:00 2001 From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de> Date: Tue, 12 Apr 2016 16:13:41 +0200 Subject: [PATCH] Tetrahedron now using the generic Polyhedron --- Core/FormFactors/FormFactorCone6.h | 25 +---- Core/FormFactors/FormFactorTetrahedron.cpp | 104 ++++++------------ Core/FormFactors/FormFactorTetrahedron.h | 42 ++----- Doc/UserManual/Assemblies.tex | 28 ++--- Doc/UserManual/FormFactors.tex | 51 +++------ Doc/UserManual/Setup.tex | 3 + .../ref_FormFactors_Tetrahedron.int.gz | Bin 5447 -> 5448 bytes 7 files changed, 79 insertions(+), 174 deletions(-) diff --git a/Core/FormFactors/FormFactorCone6.h b/Core/FormFactors/FormFactorCone6.h index 1addfc03c85..1c64f3487e2 100644 --- a/Core/FormFactors/FormFactorCone6.h +++ b/Core/FormFactors/FormFactorCone6.h @@ -18,11 +18,6 @@ #include "FormFactorPolyhedron.h" -#include <memory> - -// Forward declaration to prevent IntegratorComplex.h to be parsed for Python API: -template <class T> class IntegratorComplex; - //! @class FormFactorCone6 //! @ingroup formfactors //! @brief The formfactor of a cone6. @@ -34,12 +29,11 @@ public: //! @param height of Cone6 //! @param angle in radians between base and facet FormFactorCone6(double radius, double height, double alpha); + virtual ~FormFactorCone6(); static std::vector<PolyhedralFace> polyhedral_faces( double radius, double height, double alpha); - virtual ~FormFactorCone6(); - virtual FormFactorCone6* clone() const; virtual void accept(ISampleVisitor *visitor) const; @@ -59,19 +53,8 @@ private: mutable cvector_t m_q; }; -inline double FormFactorCone6::getHeight() const -{ - return m_height; -} - -inline double FormFactorCone6::getRadius() const -{ - return m_radius; -} - -inline double FormFactorCone6::getAlpha() const -{ - return m_alpha; -} +inline double FormFactorCone6::getHeight() const { return m_height; } +inline double FormFactorCone6::getRadius() const { return m_radius; } +inline double FormFactorCone6::getAlpha() const { return m_alpha; } #endif // FORMFACTORCONE6_H diff --git a/Core/FormFactors/FormFactorTetrahedron.cpp b/Core/FormFactors/FormFactorTetrahedron.cpp index f27a6587d53..86b134159e2 100644 --- a/Core/FormFactors/FormFactorTetrahedron.cpp +++ b/Core/FormFactors/FormFactorTetrahedron.cpp @@ -20,8 +20,8 @@ using namespace BornAgain; -FormFactorTetrahedron::FormFactorTetrahedron( - double length, double height, double alpha) +FormFactorTetrahedron::FormFactorTetrahedron(double length, double height, double alpha) + : FormFactorPolyhedron( polyhedral_faces( length, height, alpha ), 0. ) { setName(FFTetrahedronType); m_height = height; @@ -29,12 +29,39 @@ FormFactorTetrahedron::FormFactorTetrahedron( m_alpha = alpha; check_initialization(); init_parameters(); - - mP_integrator = make_integrator_complex(this, &FormFactorTetrahedron::Integrand); } -FormFactorTetrahedron::~FormFactorTetrahedron() +FormFactorTetrahedron::~FormFactorTetrahedron() {} + +std::vector<PolyhedralFace> FormFactorTetrahedron::polyhedral_faces( + double length, double height, double alpha) { + double a = length; + double as = a/2; + double ac = a/sqrt(3)/2; + double ah = a/sqrt(3); + double b = a - 2*sqrt(3)*height/std::tan(alpha); + double bs = b/2; + double bc = b/sqrt(3)/2; + double bh = b/sqrt(3); + + kvector_t V[6] = { + // base: + { -as, -ac, 0. }, + { as, -ac, 0. }, + { 0., ah, 0. }, + // top: + { -bs, -bc, height }, + { bs, -bc, height }, + { 0., bh, height } }; + std::vector<PolyhedralFace> faces; + faces.push_back( PolyhedralFace( { V[2], V[1], V[0] } ) ); + faces.push_back( PolyhedralFace( { V[0], V[1], V[4], V[3] } ) ); + faces.push_back( PolyhedralFace( { V[1], V[2], V[5], V[4] } ) ); + faces.push_back( PolyhedralFace( { V[2], V[0], V[3], V[5] } ) ); + faces.push_back( PolyhedralFace( { V[3], V[4], V[5] } ) ); + + return faces; } bool FormFactorTetrahedron::check_initialization() const @@ -74,70 +101,3 @@ double FormFactorTetrahedron::getRadius() const { return m_length / 2; } - -complex_t FormFactorTetrahedron::Integrand(double Z) const -{ - static double root3 = std::sqrt(3.); - double Rz = m_length/2 -root3*Z/std::tan(m_alpha); - - complex_t xy_part = 0; - if (m_q.x()==complex_t(0,0) && m_q.y()==complex_t(0,0)) { - xy_part = root3*Rz*Rz; - } - else { - complex_t r3qyRz = root3*m_q.y()*Rz; - complex_t expminiqyRdivr3 = - std::exp(-complex_t(0.0, 1.0)*m_q.y()*Rz/root3); - if (std::abs(m_q.x()*m_q.x()-3.*m_q.y()*m_q.y()) == 0) { - xy_part = complex_t(0.0, 1.0)*root3*expminiqyRdivr3* - (std::sin(r3qyRz)-r3qyRz*std::exp(complex_t(0.0, 1.0)*r3qyRz))/ - m_q.x()/m_q.x(); - } else { - complex_t qxRz = m_q.x()*Rz; - xy_part = 2*root3*expminiqyRdivr3/ - (m_q.x()*m_q.x()-3.0*m_q.y()*m_q.y())*( - std::exp(complex_t(0.0, 1.0)*r3qyRz) - - std::cos(qxRz)-complex_t(0.0, 1.0)*r3qyRz* - MathFunctions::sinc(qxRz)); - } - } - return xy_part *std::exp(complex_t(0.0, 1.0)*m_q.z()*Z); -} - -complex_t FormFactorTetrahedron::evaluate_for_q(const cvector_t& q) const -{ - static double root3 = std::sqrt(3.); - const complex_t im(0.0,1.0); - double H = m_height; - double R = m_length/2; - double tga = std::tan(m_alpha); - double L = 2*tga*R/root3-H; - - if (std::abs(q.x()) <= Numeric::double_epsilon || - std::abs(q.y())<= Numeric::double_epsilon || - std::abs(q.z())<= Numeric::double_epsilon || - std::abs(q.x())*std::abs(q.x()) - - 3*std::abs(q.y())*std::abs(q.y()) <= Numeric::double_epsilon) - { - if ( std::abs(q.mag()) < Numeric::double_epsilon) { - double sqrt3HdivRtga = root3*H/R/tga; - return tga/3*R*R*R*(1 - (1-sqrt3HdivRtga) - *(1-sqrt3HdivRtga) - *(1-sqrt3HdivRtga)); - } else { - m_q = q; - complex_t integral = mP_integrator->integrate(0., m_height); - return integral; - } - } else { - //general case - const complex_t q1=(1./2.)*((root3*q.x() - q.y())/tga - q.z()); - const complex_t q2=(1./2.)*((root3*q.x() + q.y())/tga + q.z()); - const complex_t q3 = (q.y()/tga - q.z()/2.); - - return H*root3*std::exp(im*q.z()*R*tga/root3)/(q.x()*q.x()-3.*q.y()*q.y())* - (-(1.+root3*q.y()/q.x())*MathFunctions::sinc(q1*H)*std::exp(im*q1*L) - -(1.-root3*q.y()/q.x())*MathFunctions::sinc(q2*H)*std::exp(-im*q2*L) + - 2.*MathFunctions::sinc(q3*H)*std::exp(im*q3*L)); - } -} diff --git a/Core/FormFactors/FormFactorTetrahedron.h b/Core/FormFactors/FormFactorTetrahedron.h index a13f5f60d48..6c60dd34141 100644 --- a/Core/FormFactors/FormFactorTetrahedron.h +++ b/Core/FormFactors/FormFactorTetrahedron.h @@ -16,17 +16,12 @@ #ifndef FORMFACTORTETRAHEDRON_H #define FORMFACTORTETRAHEDRON_H -#include "IFormFactorBorn.h" - -#include <memory> - -// Forward declaration to prevent IntegratorComplex.h to be parsed for Python API: -template <class T> class IntegratorComplex; +#include "FormFactorPolyhedron.h" //! @class FormFactorTetrahedron //! @ingroup formfactors //! @brief The formfactor of tetrahedron. -class BA_CORE_API_ FormFactorTetrahedron : public IFormFactorBorn +class BA_CORE_API_ FormFactorTetrahedron : public FormFactorPolyhedron { public: //! @brief Tetrahedron constructor @@ -36,20 +31,18 @@ public: FormFactorTetrahedron(double length, double height, double alpha); virtual ~FormFactorTetrahedron(); + static std::vector<PolyhedralFace> polyhedral_faces( + double length, double height, double alpha); + virtual FormFactorTetrahedron *clone() const; virtual void accept(ISampleVisitor *visitor) const; virtual double getRadius() const; - double getHeight() const; - double getLength() const; - double getAlpha() const; - virtual complex_t evaluate_for_q(const cvector_t& q) const; - protected: virtual bool check_initialization() const; virtual void init_parameters(); @@ -58,29 +51,10 @@ private: double m_height; double m_length; double m_alpha; - - // addition integration - mutable cvector_t m_q; - complex_t Integrand(double Z) const; - -#ifndef GCCXML_SKIP_THIS - std::unique_ptr<IntegratorComplex<FormFactorTetrahedron>> mP_integrator; -#endif }; -inline double FormFactorTetrahedron::getHeight() const -{ - return m_height; -} - -inline double FormFactorTetrahedron::getLength() const -{ - return m_length; -} - -inline double FormFactorTetrahedron::getAlpha() const -{ - return m_alpha; -} +inline double FormFactorTetrahedron::getHeight() const { return m_height; } +inline double FormFactorTetrahedron::getLength() const { return m_length; } +inline double FormFactorTetrahedron::getAlpha() const { return m_alpha; } #endif // FORMFACTORTETRAHEDRON_H diff --git a/Doc/UserManual/Assemblies.tex b/Doc/UserManual/Assemblies.tex index 7254543554b..60821c6e94d 100644 --- a/Doc/UserManual/Assemblies.tex +++ b/Doc/UserManual/Assemblies.tex @@ -614,7 +614,7 @@ For very diluted distributions of particles, the particles are too far apart fro %=============================================================================== \subsection{The regular lattice and the ideal paracrystal} %=============================================================================== -The particles are positioned at regular intervals generating a layout characterized by its base vectors $\mathbf{a}$ and $\mathbf{b}$ (in direct space) and the angle between these two vectors. +The particles are positioned at regular intervals generating a layout characterized by its base vectors $\v{a}$ and $\v{b}$ (in direct space) and the angle between these two vectors. This lattice can be two or one-dimensional depending on the characteristics of the particles. For example when they are infinitely long, the implementation can be simplified and reduced to a "pseudo" 1D system. \index{Paracrystal} @@ -648,7 +648,7 @@ Figure~\ref{fig:1dparas_q} shows the evolution of $S(q)$ for different values of \label{fig:1dparas_q} \end{figure} -In two dimensions, the paracrystal is constructed on a pseudo-regular lattice with base vectors $\mathbf{a}$ and $\mathbf{b}$ using the following conditions for the densities of probabilities:\\ $\int p_{\mathbf{a}}(\r)d^2r=\int p_{\mathbf{b}}(\r)d^2r=1$, $\int \r p_{\mathbf{a}}(\r)d^2r=\mathbf{a}$, $\int \r p_{\mathbf{b}}(\r)d^2r=\mathbf{b}$.\\ +In two dimensions, the paracrystal is constructed on a pseudo-regular lattice with base vectors $\v{a}$ and $\v{b}$ using the following conditions for the densities of probabilities:\\ $\int p_{\v{a}}(\r)d^2r=\int p_{\v{b}}(\r)d^2r=1$, $\int \r p_{\v{a}}(\r)d^2r=\v{a}$, $\int \r p_{\v{b}}(\r)d^2r=\v{b}$.\\ In the ideal case the deformations along the two axes are decoupled and each unit cell should retain a parallelogram shape. The interference function is given by\\ $S(q_{\plll})=\prod_{k=a,b}\Re\left(\dfrac{1+P_k(q_{\plll})}{1-P_k(q_{\plll})} \right)$ with $P_k$ the Fourier transform of $p_k$, $k=a, b$. \paragraph{Probability distributions} \mbox{}\\ @@ -1092,7 +1092,7 @@ def get_sample(): %------------------------------------------------------------------------------- \subsection{\Code{InterferenceFunction1DLattice(lattice\_length, xi)}} %------------------------------------------------------------------------------- -where lattice\_length is the lattice constant and $\xi$ the angle in radian between the lattice unit vector and the $\mathbf{x}$-axis of the reference Cartesian frame as shown in fig.~\ref{fig:1dgrating}. +where lattice\_length is the lattice constant and $\xi$ the angle in radian between the lattice unit vector and the $\v{x}$-axis of the reference Cartesian frame as shown in fig.~\ref{fig:1dgrating}. \begin{figure}[tb] \begin{center} @@ -1193,8 +1193,8 @@ To illustrate the radial paracrystal interference function, we use the same samp where ($L_1$, $L_2$, $\alpha$, $\xi$) are shown in figure~\ref{fig:2dlattice} with \begin{itemize} \item[]$L_1$, $L_2$ the lengths of the lattice cell, -\item[]$\alpha$ the angle between the lattice basis vectors $\mathbf{a}, \mathbf{b}$ in direct space, -\item[] $\xi$ is the angle defining the lattice orientation (set to $0$ by default); it is taken as the angle between the $\mathbf{a}$ vector of the lattice basis and the $\mathbf{x}$ axis of the reference Cartesian frame (as shown in figure~\ref{fig:multil3d}). +\item[]$\alpha$ the angle between the lattice basis vectors $\v{a}, \v{b}$ in direct space, +\item[] $\xi$ is the angle defining the lattice orientation (set to $0$ by default); it is taken as the angle between the $\v{a}$ vector of the lattice basis and the $\v{x}$ axis of the reference Cartesian frame (as shown in figure~\ref{fig:multil3d}). \end{itemize} \begin{figure}[tb] @@ -1207,7 +1207,7 @@ where ($L_1$, $L_2$, $\alpha$, $\xi$) are shown in figure~\ref{fig:2dlattice} wi Like for the one-dimensional case, a probability distribution function \Code{pdf} has to be defined. One can choose between those listed in Sec.~\ref{baftd} and implements it using \Code{setProbabilityDistribution(pdf)}. -\paragraph{Example} The sample used to run the simulation is made of half-spheres deposited on a substrate. The interference function is "2Dlattice" and the particles are located at the nodes of a square lattice with $L_1=L_2=20$~nm, $\mathbf{a}\equiv \mathbf{b}$ and the probability distribution function is Gaussian. We also use the Decoupling Approximation. +\paragraph{Example} The sample used to run the simulation is made of half-spheres deposited on a substrate. The interference function is "2Dlattice" and the particles are located at the nodes of a square lattice with $L_1=L_2=20$~nm, $\v{a}\equiv \v{b}$ and the probability distribution function is Gaussian. We also use the Decoupling Approximation. \begin{lstlisting}[language=python, style=eclipseboxed,numbers=none,nolol,caption={\Code{Python} script to define a 2DLattice interference function between hemi-spherical particles as well as the Decoupling Approximation in \Code{getSimulation()}. The part specific to the interferences is marked in a red italic font.},label={lst:2dlatticeinterf}] #collection of particles @@ -1252,7 +1252,7 @@ Like for the one-dimensional case, a probability distribution function \Code{pdf %------------------------------------------------------------------------------- \begin{itemize} \item[where] $L_1$, $L_2$ are the lengths of the lattice cell, -\item[] lattice\_angle the angle between the lattice basis vectors $\mathbf{a}, \mathbf{b}$ in direct space, +\item[] lattice\_angle the angle between the lattice basis vectors $\v{a}, \v{b}$ in direct space, \item[] $\xi$ is the angle defining the lattice orientation (set to $0$ by default). \item[] \Code{damping\_length} is used to introduce finite size effects by applying a multiplicative coefficient equal to $\exp$(-\Code{peak\_distance/damping\_length}) to the Fourier transform of the probability densities. \Code{damping\_length} is equal to 0 by default and, in this case, no correction is applied. \end{itemize} @@ -1265,7 +1265,7 @@ it creates a squared lattice, where the angle between the base vectors of the lattice is set to $2\pi/3$ , \end{itemize} where -\Code{domain\_size1, 2} are the dimensions of coherent domains of the paracrystal along the main axes,\\ \Code{peak\_distance} is the same in both directions and $\mathbf{a}\equiv \mathbf{x}$.\\ +\Code{domain\_size1, 2} are the dimensions of coherent domains of the paracrystal along the main axes,\\ \Code{peak\_distance} is the same in both directions and $\v{a}\equiv \v{x}$.\\ Probability distribution functions have to be defined. As the two-dimensional paracrystal is defined from two independent one-dimensional paracrystals, we need two of these functions, using\\ \Code{setProbabilityDistributions(pdf\_1, pdf\_2)}, with \Code{pdf\_{1,2}} related to each main axis of the paracrystal (see figure~\ref{fig:2dparaschematic}). @@ -1312,23 +1312,23 @@ Function & Parameters & Comments\\ \Code{InterferenceFunctionNone} & None & disordered distribution \\ \hline \Code{InterferenceFunction1DLattice} & \Code{lattice\_length} & use only with infinitely long/wide particles \\ - & $\xi=\widehat{(\mathbf{x},\mathbf{a})}$ & pdf=(Cauchy, Gauss or Voigt) to be defined\\ + & $\xi=\widehat{(\v{x},\v{a})}$ & pdf=(Cauchy, Gauss or Voigt) to be defined\\ \hline \Code{InterferenceFunctionRadialParaCrystal} & peak\_distance of pdf & pdf=(Cauchy, Gauss or Voigt) to be defined \\ & damping\_length (optional) & \\ \hline \Code{InterferenceFunction2DLattice} & L\_1, L\_2: lattice lengths & pdf=(Cauchy, Gauss or Voigt) to be defined\\ - & lattice\_angle=$\widehat{(\mathbf{a},\mathbf{b})}$ & \\ - & $\xi =\widehat{(\mathbf{x},\mathbf{a})}$ & \\ + & lattice\_angle=$\widehat{(\v{a},\v{b})}$ & \\ + & $\xi =\widehat{(\v{x},\v{a})}$ & \\ \hline \Code{InterferenceFunction2DParaCrystal} & L\_1, L\_2: lattice lengths & 2D pdf=(Cauchy, Gauss or Voigt) to be defined \\ - & lattice\_angle=$\widehat{(\mathbf{a},\mathbf{b})}$ & (1 pdf per axis) \\ -& $\xi=\widehat{(\mathbf{x},\mathbf{a})}$ & \\ + & lattice\_angle=$\widehat{(\v{a},\v{b})}$ & (1 pdf per axis) \\ +& $\xi=\widehat{(\v{x},\v{a})}$ & \\ & damping\_length (optional) & same for both axes\\ \hline \hline \end{tabular} -\caption{List of interference functions implemented in \BornAgain. pdf : probability distribution function, $\mathbf{a}, \mathbf{b}$ are the lattice base vectors, and $\mathbf{x}$ is the axis vector perpendicular to the detector plane.} +\caption{List of interference functions implemented in \BornAgain. pdf : probability distribution function, $\v{a}, \v{b}$ are the lattice base vectors, and $\v{x}$ is the axis vector perpendicular to the detector plane.} \end{table} \index{Particle assemblies)}% diff --git a/Doc/UserManual/FormFactors.tex b/Doc/UserManual/FormFactors.tex index 163a8fda186..07532feb820 100644 --- a/Doc/UserManual/FormFactors.tex +++ b/Doc/UserManual/FormFactors.tex @@ -513,20 +513,12 @@ The parameters must fulfill \end{displaymath} \paragraph{Form factor, volume, horizontal section}\strut\\ -Notation: -\begin{equation*} - R_H \coloneqq R-\frac{H}{\tan\beta},\quad - \tilde{q}_x \coloneqq \frac{1}{2}q_y,\quad - \tilde{q}_y \coloneqq \frac{\sqrt{3}}{2}q_y,\quad - \tilde{q}_z \coloneqq (\tan\beta) q_z. -\end{equation*} -Results: \begin{equation*} F \text{~: computed algebraically, using the generic polyhedron form factor~\cite{ba:ffp},} \end{equation*} \begin{equation*} - V = \tan\beta \left( R^3- R_H^3 \right), + V = \tan\beta \left( R^3- \left(R-\frac{H}{\tan\beta}\right)^3 \right), \end{equation*} \begin{equation*} S =\dfrac{3\sqrt{3}R^2}{2}. @@ -544,13 +536,13 @@ for four different angles~$\omega$ of rotation around the $z$ axis.} \end{figure} \paragraph{References and History}\strut\\ -Originally computed through numeric integration, -as the (differently parametrized) form factor \E{Cone6} of \IsGISAXS\ +Our parametrization deviates from the form factor \E{Cone6} of \IsGISAXS \cite[Eq.~2.32]{Laz08} \cite[Eq.~222]{ReLL09}. -Algebraic implementation -based on the generic polyhedron form factor \cite{ba:ffp} -introduced in \BornAgain-1.6. +Up to \BornAgain-1.5 computed by numeric integration, as in \IsGISAXS. +Since \BornAgain-1.6 higher speed and accuracy are achieved +by using the generic polyhedron form factor \cite{ba:ffp}, +with series expansions near singularities. %=============================================================================== \ffsection{Cuboctahedron} \label{SCuboctahedron} @@ -1305,6 +1297,8 @@ Agrees with the \E{Ripple2} form factor of \FitGISAXS\ \cite{Bab13}. \noindent Incorrectly named so, since it actually has five, not four surfaces. +\Work{will soon be rotated by 30$^\circ$} + \begin{figure}[H] \hfill \subfigure[Perspective]{\includegraphics[width=.24\textwidth]{fig/blue/Tetrahedron3d.png}} @@ -1337,22 +1331,10 @@ but the angle~$\beta$ between the base and a side edge. They are related through $\tan \alpha = 2 \tan \beta$. \paragraph{Form factor, volume, horizontal section}\strut\\ -Notation: \begin{equation*} -q_1 \coloneqq \frac{1}{2}\left[\frac{q_x\sqrt{3} -q_y}{\tan \alpha}-q_z \right], -\quad q_2 \coloneqq \frac{1}{2}\left[\frac{q_x\sqrt{3} +q_y}{\tan \alpha}+q_z -\right], \quad -q_3 \coloneqq \frac{q_y}{\tan \alpha} -\frac{q_z}{2}, \quad -D \coloneqq \frac{L \tan \alpha}{\sqrt{3}} -H. + F\text{~: computed algebraically, + using the generic polyhedron form factor~\cite{ba:ffp},} \end{equation*} -Results: -\begin{align*} -&F=\frac{\sqrt{3}H}{q_x (q_x^2-3q_y^2)} -\exp\left(i\frac{q_z L\tan (\alpha)}{2\sqrt{3}}\right) \times \\ -&\Big\{2q_x \exp(iq_3 D)\sinc(q_3 H) - (q_x +\sqrt{3}q_y) -\exp(iq_1 D)\sinc(q_1 H)\\ -&-(q_x-\sqrt{3}q_y)\exp(-iq_2 D)\sinc(q_2 H) \Big\}, -\end{align*} \begin{equation*} V= \dfrac{\tan(\alpha) L^3}{24} \left[1- \left(1 - \dfrac{2\sqrt{3} H}{L \tan(\alpha)} \right)^3\right], @@ -1373,11 +1355,14 @@ for four different angles~$\omega$ of rotation around the $z$ axis. The low symmetry requires other angular ranges than used in most other figures.} \end{figure} -\paragraph{References}\strut\\ -Agrees with the \E{Tetrahedron} form factor of \IsGISAXS\ -\cite[Eq.~2.30]{Laz08} \cite[Eq.~220]{ReLL09}. -In \FitGISAXS\ correctly called \E{Truncated tetrahedron} \cite{Bab13}. - +\paragraph{References and History}\strut\\ +Previous implementations as \E{Tetrahedron} in \IsGISAXS\ +\cite[Eq.~2.30]{Laz08} \cite[Eq.~220]{ReLL09}, +and as \E{Truncated tetrahedron} in \FitGISAXS\ \cite{Bab13}. +Up to \BornAgain-1.5, we computed it by numeric integration, as in \IsGISAXS. +Since \BornAgain-1.6 higher speed and accuracy are achieved +by using the generic polyhedron form factor \cite{ba:ffp}, +with series expansions near singularities. %=============================================================================== \ffsection{TruncatedCube} \label{STruncatedCube} diff --git a/Doc/UserManual/Setup.tex b/Doc/UserManual/Setup.tex index cb8be89ff06..ced26f148d8 100644 --- a/Doc/UserManual/Setup.tex +++ b/Doc/UserManual/Setup.tex @@ -54,6 +54,9 @@ \usepackage{amssymb} \usepackage[bold-style=ISO]{unicode-math} % must come after ams and symbols +% from unicode-0.8, use \symbf instead of \mathbf +% see https://github.com/wspr/unicode-math/issues/340 +% http://apps.jcns.fz-juelich.de/redmine/issues/1293 \newif\ifolducm \makeatletter \@ifpackagelater{unicode-math}{2014/07/01}{\olducmfalse}{\olducmtrue} diff --git a/Tests/ReferenceData/BornAgain/ref_FormFactors_Tetrahedron.int.gz b/Tests/ReferenceData/BornAgain/ref_FormFactors_Tetrahedron.int.gz index cd612fb7e8d8b2e33bfe22f7ae765294f4226cea..375b0aa6b471a841b6af46b883974ff3b68ea534 100644 GIT binary patch delta 5187 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 Q$Mp=Kl;httn=vo|08PvNX#fBK delta 5186 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 L(NfK3GX@3#6z1x& -- GitLab