BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
PolyhedralFace Class Reference

A polygon, for form factor computation. More...

Collaboration diagram for PolyhedralFace:
[legend]

Public Member Functions

 PolyhedralFace (const std::vector< kvector_t > &_V=std::vector< kvector_t >(), bool _sym_S2=false)
 Sets internal variables for given vertex chain. More...
 
double area () const
 
void assert_Ci (const PolyhedralFace &other) const
 Throws if deviation from inversion symmetry is detected. Does not check vertices. More...
 
complex_t ff (cvector_t q, bool sym_Ci) const
 Returns the contribution ff(q) of this face to the polyhedral form factor. More...
 
complex_t ff_2D (cvector_t qpa) const
 Returns the two-dimensional form factor of this face, for use in a prism. More...
 
complex_t ff_2D_direct (cvector_t qpa) const
 Two-dimensional form factor, for use in prism, from sum over edge form factors. More...
 
complex_t ff_2D_expanded (cvector_t qpa) const
 Two-dimensional form factor, for use in prism, from power series. More...
 
complex_t ff_n (int m, cvector_t q) const
 Returns contribution qn*f_n [of order q^(n+1)] from this face to the polyhedral form factor. More...
 
complex_t normalProjectionConj (cvector_t q) const
 Returns conj(q)*normal [BasicVector3D::dot is antilinear in 'this' argument]. More...
 
double pyramidalVolume () const
 
double radius3d () const
 

Static Public Member Functions

static double diameter (const std::vector< kvector_t > &V)
 Static method, returns diameter of circle that contains all vertices. More...
 

Private Member Functions

void decompose_q (cvector_t q, complex_t &qperp, cvector_t &qpa) const
 Sets qperp and qpa according to argument q and to this polygon's normal. More...
 
complex_t edge_sum_ff (cvector_t q, cvector_t qpa, bool sym_Ci) const
 Returns core contribution to analytic 2d form factor. More...
 
complex_t expansion (complex_t fac_even, complex_t fac_odd, cvector_t qpa, double abslevel) const
 Returns sum of n>=1 terms of qpa expansion of 2d form factor. More...
 
complex_t ff_n_core (int m, cvector_t qpa, complex_t qperp) const
 Returns core contribution to f_n. More...
 

Private Attributes

std::vector< PolyhedralEdgeedges
 
double m_area
 
kvector_t m_normal
 normal vector of this polygon's plane More...
 
double m_radius_2d
 radius of enclosing cylinder More...
 
double m_radius_3d
 radius of enclosing sphere More...
 
double m_rperp
 distance of this polygon's plane from the origin, along 'm_normal' More...
 
bool sym_S2
 if true, then edges obtainable by inversion are not provided More...
 

Static Private Attributes

static int n_limit_series = 20
 
static double qpa_limit_series = 1e-2
 determines when use power series More...
 

Detailed Description

A polygon, for form factor computation.

Definition at line 60 of file PolyhedralComponents.h.

Constructor & Destructor Documentation

◆ PolyhedralFace()

PolyhedralFace::PolyhedralFace ( const std::vector< kvector_t > &  V = std::vector<kvector_t>(),
bool  _sym_S2 = false 
)

Sets internal variables for given vertex chain.

Parameters
Voriented vertex list
_sym_S2true if face has a perpedicular two-fold symmetry axis

Definition at line 126 of file PolyhedralComponents.cpp.

126  : sym_S2(_sym_S2)
127 {
128  size_t NV = V.size();
129  if (!NV)
130  throw std::logic_error("Face with no edges");
131  if (NV < 3)
132  throw std::logic_error("Face with less than three edges");
133 
134  // compute radius in 2d and 3d
135  m_radius_2d = diameter(V) / 2;
136  m_radius_3d = 0;
137  for (const kvector_t& v : V)
138  m_radius_3d = std::max(m_radius_3d, v.mag());
139 
140  // Initialize list of 'edges'.
141  // Do not create an edge if two vertices are too close to each other.
142  // TODO This is implemented in a somewhat sloppy way: we just skip an edge if it would
143  // be too short. This leaves tiny open edges. In a clean implementation, we
144  // rather should merge adjacent vertices before generating edges.
145  for (size_t j = 0; j < NV; ++j) {
146  size_t jj = (j + 1) % NV;
147  if ((V[j] - V[jj]).mag() < 1e-14 * m_radius_2d)
148  continue; // distance too short -> skip this edge
149  edges.push_back(PolyhedralEdge(V[j], V[jj]));
150  }
151  size_t NE = edges.size();
152  if (NE < 3)
153  throw std::invalid_argument("Face has less than three non-vanishing edges");
154 
155  // compute n_k, rperp
156  m_normal = kvector_t();
157  for (size_t j = 0; j < NE; ++j) {
158  size_t jj = (j + 1) % NE;
159  kvector_t ee = edges[j].E().cross(edges[jj].E());
160  if (ee.mag2() == 0) {
161  throw std::logic_error("Two adjacent edges are parallel");
162  }
163  m_normal += ee.unit();
164  }
165  m_normal /= NE;
166  m_rperp = 0;
167  for (size_t j = 0; j < NV; ++j)
168  m_rperp += V[j].dot(m_normal);
169  m_rperp /= NV;
170  // assert that the vertices lay in a plane
171  for (size_t j = 1; j < NV; ++j)
172  if (std::abs(V[j].dot(m_normal) - m_rperp) > 1e-14 * m_radius_3d)
173  throw std::logic_error("Face is not planar");
174  // compute m_area
175  m_area = 0;
176  for (size_t j = 0; j < NV; ++j) {
177  size_t jj = (j + 1) % NV;
178  m_area += m_normal.dot(V[j].cross(V[jj])) / 2;
179  }
180  // only now deal with inversion symmetry
181  if (sym_S2) {
182  if (NE & 1)
183  throw std::logic_error("Odd #edges violates symmetry S2");
184  NE /= 2;
185  for (size_t j = 0; j < NE; ++j) {
186  if (((edges[j].R() - m_rperp * m_normal) + (edges[j + NE].R() - m_rperp * m_normal))
187  .mag()
188  > 1e-12 * m_radius_2d)
189  throw std::logic_error("Edge centers violate symmetry S2");
190  if ((edges[j].E() + edges[j + NE].E()).mag() > 1e-12 * m_radius_2d)
191  throw std::logic_error("Edge vectors violate symmetry S2");
192  }
193  // keep only half of the egdes
194  edges.erase(edges.begin() + NE, edges.end());
195  }
196 }
BasicVector3D< double > kvector_t
Definition: Vectors3D.h:21
double mag2() const
Returns magnitude squared of the vector.
auto dot(const BasicVector3D< U > &v) const
Returns dot product of vectors (antilinear in the first [=self] argument).
BasicVector3D< T > unit() const
Returns unit vector in direction of this. Throws for null vector.
One edge of a polygon, for form factor computation.
bool sym_S2
if true, then edges obtainable by inversion are not provided
double m_radius_2d
radius of enclosing cylinder
double m_rperp
distance of this polygon's plane from the origin, along 'm_normal'
static double diameter(const std::vector< kvector_t > &V)
Static method, returns diameter of circle that contains all vertices.
std::vector< PolyhedralEdge > edges
kvector_t m_normal
normal vector of this polygon's plane
double m_radius_3d
radius of enclosing sphere
float dot(const Vector3D &v1, const Vector3D &v2)
Definition: def.cpp:59
Vector3D cross(const Vector3D &v1, const Vector3D &v2)
Definition: def.cpp:54

References RealSpace::cross(), diameter(), BasicVector3D< T >::dot(), RealSpace::dot(), edges, m_area, m_normal, m_radius_2d, m_radius_3d, m_rperp, BasicVector3D< T >::mag2(), sym_S2, and BasicVector3D< T >::unit().

Here is the call graph for this function:

Member Function Documentation

◆ area()

double PolyhedralFace::area ( ) const
inline

Definition at line 67 of file PolyhedralComponents.h.

67 { return m_area; }

References m_area.

◆ assert_Ci()

void PolyhedralFace::assert_Ci ( const PolyhedralFace other) const

Throws if deviation from inversion symmetry is detected. Does not check vertices.

Definition at line 376 of file PolyhedralComponents.cpp.

377 {
378  if (std::abs(m_rperp - other.m_rperp) > 1e-15 * (m_rperp + other.m_rperp))
379  throw std::logic_error("Faces with different distance from origin violate symmetry Ci");
380  if (std::abs(m_area - other.m_area) > 1e-15 * (m_area + other.m_area))
381  throw std::logic_error("Faces with different areas violate symmetry Ci");
382  if ((m_normal + other.m_normal).mag() > 1e-14)
383  throw std::logic_error("Faces do not have opposite orientation, violating symmetry Ci");
384 }

References m_area, m_normal, and m_rperp.

◆ decompose_q()

void PolyhedralFace::decompose_q ( cvector_t  q,
complex_t qperp,
cvector_t qpa 
) const
private

Sets qperp and qpa according to argument q and to this polygon's normal.

Definition at line 200 of file PolyhedralComponents.cpp.

201 {
202  qperp = m_normal.dot(q);
203  qpa = q - qperp * m_normal;
204  // improve numeric accuracy:
205  qpa -= m_normal.dot(qpa) * m_normal;
206  if (qpa.mag() < eps * std::abs(qperp))
207  qpa = cvector_t(0., 0., 0.);
208 }
BasicVector3D< complex_t > cvector_t
Definition: Vectors3D.h:22
double mag() const
Returns magnitude of the vector.

References BasicVector3D< T >::dot(), m_normal, and BasicVector3D< T >::mag().

Referenced by ff(), and ff_n().

Here is the call graph for this function:

◆ diameter()

double PolyhedralFace::diameter ( const std::vector< kvector_t > &  V)
static

Static method, returns diameter of circle that contains all vertices.

Definition at line 112 of file PolyhedralComponents.cpp.

113 {
114  double diameterFace = 0;
115  for (size_t j = 0; j < V.size(); ++j)
116  for (size_t jj = j + 1; jj < V.size(); ++jj)
117  diameterFace = std::max(diameterFace, (V[j] - V[jj]).mag());
118  return diameterFace;
119 }

Referenced by PolyhedralFace(), and Polyhedron::Polyhedron().

◆ edge_sum_ff()

complex_t PolyhedralFace::edge_sum_ff ( cvector_t  q,
cvector_t  qpa,
bool  sym_Ci 
) const
private

Returns core contribution to analytic 2d form factor.

Definition at line 282 of file PolyhedralComponents.cpp.

283 {
284  cvector_t prevec = m_normal.cross(qpa); // complex conjugation will take place in .dot
285  complex_t sum = 0;
286  complex_t vfacsum = 0;
287  for (size_t i = 0; i < edges.size(); ++i) {
288  const PolyhedralEdge& e = edges[i];
289  complex_t qE = e.qE(qpa);
290  complex_t qR = e.qR(qpa);
291  complex_t Rfac = sym_S2 ? sin(qR) : (sym_Ci ? cos(e.qR(q)) : exp_I(qR));
292  complex_t vfac;
293  if (sym_S2 || i < edges.size() - 1) {
294  vfac = prevec.dot(e.E());
295  vfacsum += vfac;
296  } else {
297  vfac = -vfacsum; // to improve numeric accuracy: qcE_J = - sum_{j=0}^{J-1} qcE_j
298  }
299  complex_t term = vfac * Math::sinc(qE) * Rfac;
300  sum += term;
301  // std::cout << std::scientific << std::showpos << std::setprecision(16)
302  // << " sum=" << sum << " term=" << term << " vf=" << vfac << " qE=" << qE
303  // << " qR=" << qR << " sinc=" << Math::sinc(qE) << " Rfac=" << Rfac << "\n";
304  }
305  return sum;
306 }
std::complex< double > complex_t
Definition: Complex.h:20
complex_t exp_I(complex_t z)
Returns exp(I*z), where I is the imaginary unit.
Definition: Complex.h:30
auto cross(const BasicVector3D< U > &v) const
Returns cross product of vectors (linear in both arguments).
kvector_t E() const
complex_t qE(cvector_t q) const
complex_t qR(cvector_t q) const
double sinc(double x)
sinc function:
Definition: Functions.cpp:53

References BasicVector3D< T >::cross(), BasicVector3D< T >::dot(), PolyhedralEdge::E(), edges, exp_I(), m_normal, PolyhedralEdge::qE(), PolyhedralEdge::qR(), Math::sinc(), and sym_S2.

Referenced by ff(), and ff_2D_direct().

Here is the call graph for this function:

◆ expansion()

complex_t PolyhedralFace::expansion ( complex_t  fac_even,
complex_t  fac_odd,
cvector_t  qpa,
double  abslevel 
) const
private

Returns sum of n>=1 terms of qpa expansion of 2d form factor.

Definition at line 253 of file PolyhedralComponents.cpp.

255 {
256 #ifdef ALGORITHM_DIAGNOSTIC
257  polyhedralDiagnosis.algo += 1;
258 #endif
259  complex_t sum = 0;
260  complex_t n_fac = I;
261  int count_return_condition = 0;
262  for (int n = 1; n < n_limit_series; ++n) {
263 #ifdef ALGORITHM_DIAGNOSTIC
264  polyhedralDiagnosis.order = std::max(polyhedralDiagnosis.order, n);
265 #endif
266  complex_t term = n_fac * (n & 1 ? fac_odd : fac_even) * ff_n_core(n, qpa, 0) / qpa.mag2();
267  // std::cout << std::setprecision(16) << " sum=" << sum << " +term=" << term << "\n";
268  sum += term;
269  if (std::abs(term) <= eps * std::abs(sum) || std::abs(sum) < eps * abslevel)
270  ++count_return_condition;
271  else
272  count_return_condition = 0;
273  if (count_return_condition > 2)
274  return sum; // regular exit
275  n_fac = mul_I(n_fac);
276  }
277  throw std::runtime_error("Series f(q_pa) not converged");
278 }
constexpr complex_t I
Definition: Complex.h:21
complex_t mul_I(complex_t z)
Returns product I*z, where I is the imaginary unit.
Definition: Complex.h:24
complex_t ff_n_core(int m, cvector_t qpa, complex_t qperp) const
Returns core contribution to f_n.
static int n_limit_series

References ff_n_core(), I, BasicVector3D< T >::mag2(), mul_I(), and n_limit_series.

Referenced by ff(), and ff_2D_expanded().

Here is the call graph for this function:

◆ ff()

complex_t PolyhedralFace::ff ( cvector_t  q,
bool  sym_Ci 
) const

Returns the contribution ff(q) of this face to the polyhedral form factor.

Definition at line 310 of file PolyhedralComponents.cpp.

311 {
312  complex_t qperp;
313  cvector_t qpa;
314  decompose_q(q, qperp, qpa);
315  double qpa_red = m_radius_2d * qpa.mag();
316  complex_t qr_perp = qperp * m_rperp;
317  complex_t ff0 = (sym_Ci ? 2. * I * sin(qr_perp) : exp_I(qr_perp)) * m_area;
318  if (qpa_red == 0) {
319  return ff0;
320  } else if (qpa_red < qpa_limit_series && !sym_S2) {
321  // summation of power series
322  complex_t fac_even;
323  complex_t fac_odd;
324  if (sym_Ci) {
325  fac_even = 2. * mul_I(sin(qr_perp));
326  fac_odd = 2. * cos(qr_perp);
327  } else {
328  fac_even = exp_I(qr_perp);
329  fac_odd = fac_even;
330  }
331  return ff0 + expansion(fac_even, fac_odd, qpa, std::abs(ff0));
332  } else {
333  // direct evaluation of analytic formula
334  complex_t prefac;
335  if (sym_S2)
336  prefac = sym_Ci ? -8. * sin(qr_perp) : 4. * mul_I(exp_I(qr_perp));
337  else
338  prefac = sym_Ci ? 4. : 2. * exp_I(qr_perp);
339  // std::cout << " qrperp=" << qr_perp << " => prefac=" << prefac << "\n";
340  return prefac * edge_sum_ff(q, qpa, sym_Ci) / mul_I(qpa.mag2());
341  }
342 }
static double qpa_limit_series
determines when use power series
complex_t expansion(complex_t fac_even, complex_t fac_odd, cvector_t qpa, double abslevel) const
Returns sum of n>=1 terms of qpa expansion of 2d form factor.
void decompose_q(cvector_t q, complex_t &qperp, cvector_t &qpa) const
Sets qperp and qpa according to argument q and to this polygon's normal.
complex_t edge_sum_ff(cvector_t q, cvector_t qpa, bool sym_Ci) const
Returns core contribution to analytic 2d form factor.

References decompose_q(), edge_sum_ff(), exp_I(), expansion(), I, m_area, m_radius_2d, m_rperp, BasicVector3D< T >::mag(), BasicVector3D< T >::mag2(), mul_I(), qpa_limit_series, and sym_S2.

Here is the call graph for this function:

◆ ff_2D()

complex_t PolyhedralFace::ff_2D ( cvector_t  qpa) const

Returns the two-dimensional form factor of this face, for use in a prism.

Definition at line 360 of file PolyhedralComponents.cpp.

361 {
362  if (std::abs(qpa.dot(m_normal)) > eps * qpa.mag())
363  throw std::logic_error("ff_2D called with perpendicular q component");
364  double qpa_red = m_radius_2d * qpa.mag();
365  if (qpa_red == 0) {
366  return m_area;
367  } else if (qpa_red < qpa_limit_series && !sym_S2) {
368  return ff_2D_expanded(qpa);
369  } else {
370  return ff_2D_direct(qpa);
371  }
372 }
complex_t ff_2D_direct(cvector_t qpa) const
Two-dimensional form factor, for use in prism, from sum over edge form factors.
complex_t ff_2D_expanded(cvector_t qpa) const
Two-dimensional form factor, for use in prism, from power series.

References BasicVector3D< T >::dot(), ff_2D_direct(), ff_2D_expanded(), m_area, m_normal, m_radius_2d, BasicVector3D< T >::mag(), qpa_limit_series, and sym_S2.

Here is the call graph for this function:

◆ ff_2D_direct()

complex_t PolyhedralFace::ff_2D_direct ( cvector_t  qpa) const

Two-dimensional form factor, for use in prism, from sum over edge form factors.

Definition at line 353 of file PolyhedralComponents.cpp.

354 {
355  return (sym_S2 ? 4. : 2. / I) * edge_sum_ff(qpa, qpa, false) / qpa.mag2();
356 }

References edge_sum_ff(), I, BasicVector3D< T >::mag2(), and sym_S2.

Referenced by ff_2D().

Here is the call graph for this function:

◆ ff_2D_expanded()

complex_t PolyhedralFace::ff_2D_expanded ( cvector_t  qpa) const

Two-dimensional form factor, for use in prism, from power series.

Definition at line 346 of file PolyhedralComponents.cpp.

347 {
348  return m_area + expansion(1., 1., qpa, std::abs(m_area));
349 }

References expansion(), and m_area.

Referenced by ff_2D().

Here is the call graph for this function:

◆ ff_n()

complex_t PolyhedralFace::ff_n ( int  m,
cvector_t  q 
) const

Returns contribution qn*f_n [of order q^(n+1)] from this face to the polyhedral form factor.

Definition at line 231 of file PolyhedralComponents.cpp.

232 {
233  complex_t qn = q.dot(m_normal); // conj(q)*normal (dot is antilinear in 'this' argument)
234  if (std::abs(qn) < eps * q.mag())
235  return 0.;
236  complex_t qperp;
237  cvector_t qpa;
238  decompose_q(q, qperp, qpa);
239  double qpa_mag2 = qpa.mag2();
240  if (qpa_mag2 == 0.) {
241  return qn * pow(qperp * m_rperp, n) * m_area * ReciprocalFactorialArray[n];
242  } else if (sym_S2) {
243  return qn * (ff_n_core(n, qpa, qperp) + ff_n_core(n, -qpa, qperp)) / qpa_mag2;
244  } else {
245  complex_t tmp = ff_n_core(n, qpa, qperp);
246  // std::cout << "DBX ff_n " << n << " " << qn << " " << tmp << " " << qpa_mag2 << "\n";
247  return qn * tmp / qpa_mag2;
248  }
249 }

References decompose_q(), BasicVector3D< T >::dot(), ff_n_core(), m_area, m_normal, m_rperp, BasicVector3D< T >::mag(), BasicVector3D< T >::mag2(), and sym_S2.

Here is the call graph for this function:

◆ ff_n_core()

complex_t PolyhedralFace::ff_n_core ( int  m,
cvector_t  qpa,
complex_t  qperp 
) const
private

Returns core contribution to f_n.

Definition at line 212 of file PolyhedralComponents.cpp.

213 {
214  const cvector_t prevec = 2. * m_normal.cross(qpa); // complex conjugation not here but in .dot
215  complex_t ret = 0;
216  const complex_t qrperp = qperp * m_rperp;
217  for (size_t i = 0; i < edges.size(); ++i) {
218  const PolyhedralEdge& e = edges[i];
219  const complex_t vfac = prevec.dot(e.E());
220  const complex_t tmp = e.contrib(m + 1, qpa, qrperp);
221  ret += vfac * tmp;
222  // std::cout << std::scientific << std::showpos << std::setprecision(16)
223  // << "DBX ff_n_core " << m << " " << vfac << " " << tmp
224  // << " term=" << vfac * tmp << " sum=" << ret << "\n";
225  }
226  return ret;
227 }
complex_t contrib(int m, cvector_t qpa, complex_t qrperp) const
Returns sum_l=0^M/2 u^2l v^(M-2l) / (2l+1)!(M-2l)! - vperp^M/M!

References PolyhedralEdge::contrib(), BasicVector3D< T >::cross(), BasicVector3D< T >::dot(), PolyhedralEdge::E(), edges, m_normal, and m_rperp.

Referenced by expansion(), and ff_n().

Here is the call graph for this function:

◆ normalProjectionConj()

complex_t PolyhedralFace::normalProjectionConj ( cvector_t  q) const
inline

Returns conj(q)*normal [BasicVector3D::dot is antilinear in 'this' argument].

Definition at line 71 of file PolyhedralComponents.h.

71 { return q.dot(m_normal); }

References BasicVector3D< T >::dot(), and m_normal.

Here is the call graph for this function:

◆ pyramidalVolume()

double PolyhedralFace::pyramidalVolume ( ) const
inline

Definition at line 68 of file PolyhedralComponents.h.

68 { return m_rperp * m_area / 3; }

References m_area, and m_rperp.

◆ radius3d()

double PolyhedralFace::radius3d ( ) const
inline

Definition at line 69 of file PolyhedralComponents.h.

69 { return m_radius_3d; }

References m_radius_3d.

Member Data Documentation

◆ edges

std::vector<PolyhedralEdge> PolyhedralFace::edges
private

Definition at line 84 of file PolyhedralComponents.h.

Referenced by PolyhedralFace(), edge_sum_ff(), and ff_n_core().

◆ m_area

double PolyhedralFace::m_area
private

◆ m_normal

kvector_t PolyhedralFace::m_normal
private

normal vector of this polygon's plane

Definition at line 86 of file PolyhedralComponents.h.

Referenced by PolyhedralFace(), assert_Ci(), decompose_q(), edge_sum_ff(), ff_2D(), ff_n(), ff_n_core(), and normalProjectionConj().

◆ m_radius_2d

double PolyhedralFace::m_radius_2d
private

radius of enclosing cylinder

Definition at line 88 of file PolyhedralComponents.h.

Referenced by PolyhedralFace(), ff(), and ff_2D().

◆ m_radius_3d

double PolyhedralFace::m_radius_3d
private

radius of enclosing sphere

Definition at line 89 of file PolyhedralComponents.h.

Referenced by PolyhedralFace(), and radius3d().

◆ m_rperp

double PolyhedralFace::m_rperp
private

distance of this polygon's plane from the origin, along 'm_normal'

Definition at line 87 of file PolyhedralComponents.h.

Referenced by PolyhedralFace(), assert_Ci(), ff(), ff_n(), ff_n_core(), and pyramidalVolume().

◆ n_limit_series

int PolyhedralFace::n_limit_series = 20
staticprivate

Definition at line 81 of file PolyhedralComponents.h.

Referenced by expansion().

◆ qpa_limit_series

double PolyhedralFace::qpa_limit_series = 1e-2
staticprivate

determines when use power series

Definition at line 80 of file PolyhedralComponents.h.

Referenced by ff(), and ff_2D().

◆ sym_S2

bool PolyhedralFace::sym_S2
private

if true, then edges obtainable by inversion are not provided

Definition at line 83 of file PolyhedralComponents.h.

Referenced by PolyhedralFace(), edge_sum_ff(), ff(), ff_2D(), ff_2D_direct(), and ff_n().


The documentation for this class was generated from the following files: