BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
SampleToPython.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Core/Export/SampleToPython.cpp
6 //! @brief Implements class SampleToPython.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 #include "Base/Utils/Assert.h"
21 #include "Core/Export/PyFmt.h"
22 #include "Core/Export/PyFmt2.h"
36 #include <iomanip>
37 #include <map>
38 #include <set>
39 
40 using pyfmt::indent;
41 
42 namespace {
43 
44 void setRotationInformation(const IParticle* particle, std::string name, std::ostringstream& result)
45 {
46  if (particle->rotation()) {
47  switch (particle->rotation()->getTransform3D().getRotationType()) {
48  case Transform3D::EULER: {
49  double alpha, beta, gamma;
50  particle->rotation()->getTransform3D().calculateEulerAngles(&alpha, &beta, &gamma);
51  result << indent() << name << "_rotation = ba.RotationEuler("
52  << pyfmt::printDegrees(alpha) << ", " << pyfmt::printDegrees(beta) << ", "
53  << pyfmt::printDegrees(gamma) << ")\n";
54  break;
55  }
56  case Transform3D::XAXIS: {
57  double alpha = particle->rotation()->getTransform3D().calculateRotateXAngle();
58  result << indent() << name << "_rotation = ba.RotationX(" << pyfmt::printDegrees(alpha)
59  << ")\n";
60  break;
61  }
62  case Transform3D::YAXIS: {
63  double alpha = particle->rotation()->getTransform3D().calculateRotateYAngle();
64  result << indent() << name << "_rotation = ba.RotationY(" << pyfmt::printDegrees(alpha)
65  << ")\n";
66  break;
67  }
68  case Transform3D::ZAXIS: {
69  double alpha = particle->rotation()->getTransform3D().calculateRotateZAngle();
70  result << indent() << name << "_rotation = ba.RotationZ(" << pyfmt::printDegrees(alpha)
71  << ")\n";
72  break;
73  }
74  }
75  result << indent() << name << ".setRotation(" << name << "_rotation)\n";
76  }
77 }
78 
79 void setPositionInformation(const IParticle* particle, std::string name, std::ostringstream& result)
80 {
81  kvector_t pos = particle->position();
82  if (pos == kvector_t())
83  return;
84 
85  result << indent() << name << "_position = kvector_t(" << pyfmt::printNm(pos.x()) << ", "
86  << pyfmt::printNm(pos.y()) << ", " << pyfmt::printNm(pos.z()) << ")\n";
87  result << indent() << name << ".setPosition(" << name << "_position)\n";
88 }
89 
90 } // namespace
91 
92 // ************************************************************************************************
93 // class SampleToPython
94 // ************************************************************************************************
95 
96 std::string SampleToPython::sampleCode(const MultiLayer& multilayer)
97 {
98  initLabels(multilayer);
99  return defineGetSample();
100 }
101 
102 void SampleToPython::initLabels(const MultiLayer& multilayer)
103 {
104  m_objs.reset(new ComponentKeyHandler());
105  m_materials.reset(new MaterialKeyHandler());
106 
107  for (auto x : multilayer.containedMaterials())
108  m_materials->insertMaterial(x);
109 
110  m_objs->insertModel("sample", &multilayer);
111  for (const auto* x : node_progeny::AllDescendantsOfType<Layer>(multilayer))
112  m_objs->insertModel("layer", x);
113  for (const auto* x : node_progeny::AllDescendantsOfType<LayerRoughness>(multilayer))
114  m_objs->insertModel("roughness", x);
115  for (const auto* x : node_progeny::AllDescendantsOfType<ParticleLayout>(multilayer))
116  m_objs->insertModel("layout", x);
117  for (const auto* x : node_progeny::AllDescendantsOfType<IFormFactor>(multilayer))
118  m_objs->insertModel("ff", x);
119  for (const auto* x : node_progeny::AllDescendantsOfType<IInterferenceFunction>(multilayer))
120  m_objs->insertModel("iff", x);
121  for (const auto* x : node_progeny::AllDescendantsOfType<Particle>(multilayer))
122  m_objs->insertModel("particle", x);
123  for (const auto* x : node_progeny::AllDescendantsOfType<ParticleComposition>(multilayer))
124  m_objs->insertModel("particle", x);
125  for (const auto* x : node_progeny::AllDescendantsOfType<ParticleCoreShell>(multilayer))
126  m_objs->insertModel("particle", x);
127  for (const auto* x : node_progeny::AllDescendantsOfType<MesoCrystal>(multilayer))
128  m_objs->insertModel("particle", x);
129  for (const auto* x : node_progeny::AllDescendantsOfType<ParticleDistribution>(multilayer))
130  m_objs->insertModel("particle_distrib", x);
131  for (const auto* x : node_progeny::AllDescendantsOfType<Lattice2D>(multilayer))
132  m_objs->insertModel("lattice", x);
133  for (const auto* x : node_progeny::AllDescendantsOfType<Lattice3D>(multilayer))
134  m_objs->insertModel("lattice", x);
135  for (const auto* x : node_progeny::AllDescendantsOfType<Crystal>(multilayer))
136  m_objs->insertModel("crystal", x);
137 }
138 
140 
142 
144 {
145  return "def get_sample():\n" + defineMaterials() + defineFormFactors() + defineParticles()
149  + defineRoughnesses() + defineLayers() + defineMultiLayers() + "\n\n";
150 }
151 
152 const std::map<MATERIAL_TYPES, std::string> factory_names{
153  {MATERIAL_TYPES::RefractiveMaterial, "HomogeneousMaterial"},
154  {MATERIAL_TYPES::MaterialBySLD, "MaterialBySLD"}};
155 
157 {
158  const auto themap = m_materials->materialMap();
159  if (themap.empty())
160  return "";
161  std::ostringstream result;
162  result << std::setprecision(12);
163  result << indent() << "# Define materials\n";
164  std::set<std::string> visitedMaterials;
165  for (auto it : themap) {
166  const std::string& key = it.first;
167  if (visitedMaterials.find(key) != visitedMaterials.end())
168  continue;
169  visitedMaterials.insert(key);
170  const Material* p_material = it.second;
171  const auto factory_name = factory_names.find(p_material->typeID());
172  if (factory_name == factory_names.cend())
173  throw std::runtime_error(
174  "Error in ExportToPython::defineMaterials(): unknown material type");
175  const complex_t& material_data = p_material->materialData();
176  if (p_material->isScalarMaterial()) {
177  result << indent() << m_materials->mat2key(p_material) << " = ba."
178  << factory_name->second << "(\"" << p_material->getName() << "\", "
179  << pyfmt::printDouble(material_data.real()) << ", "
180  << pyfmt::printDouble(material_data.imag()) << ")\n";
181  } else {
182  kvector_t magnetic_field = p_material->magnetization();
183  result << indent() << "magnetic_field = kvector_t(" << magnetic_field.x() << ", "
184  << magnetic_field.y() << ", " << magnetic_field.z() << ")\n";
185  result << indent() << m_materials->mat2key(p_material) << " = ba."
186  << factory_name->second << "(\"" << p_material->getName();
187  result << "\", " << pyfmt::printDouble(material_data.real()) << ", "
188  << pyfmt::printDouble(material_data.imag()) << ", "
189  << "magnetic_field)\n";
190  }
191  }
192  return result.str();
193 }
194 
195 std::string SampleToPython::defineLayers() const
196 {
197  std::vector<const Layer*> v = m_objs->objectsOfType<Layer>();
198  if (v.empty())
199  return "";
200  std::ostringstream result;
201  result << "\n" << indent() << "# Define layers\n";
202  result << std::setprecision(12);
203  for (const auto* s : v) {
204  const std::string& key = m_objs->obj2key(s);
205  result << indent() << key << " = ba.Layer(" << m_materials->mat2key(s->material());
206  if (s->thickness() != 0)
207  result << ", " << pyfmt::printNm(s->thickness());
208  result << ")\n";
209  if (s->numberOfSlices() != 1)
210  result << indent() << key << ".setNumberOfSlices(" << s->numberOfSlices() << ")\n";
211  for (const auto* layout : s->layouts())
212  result << indent() << key << ".addLayout(" << m_objs->obj2key(layout) << ")\n";
213  }
214  return result.str();
215 }
216 
218 {
219  std::vector<const LayerRoughness*> v = m_objs->objectsOfType<LayerRoughness>();
220  if (v.empty())
221  return "";
222  std::ostringstream result;
223  result << std::setprecision(12);
224  result << "\n" << indent() << "# Define roughness\n";
225  for (const auto* s : v) {
226  const std::string& key = m_objs->obj2key(s);
227  result << indent() << key << " = ba.LayerRoughness(" << pyfmt2::argumentList(s) << ")\n";
228  }
229  return result.str();
230 }
231 
233 {
234  std::vector<const IFormFactor*> v = m_objs->objectsOfType<IFormFactor>();
235  if (v.empty())
236  return "";
237  std::ostringstream result;
238  result << "\n" << indent() << "# Define form factors\n";
239  result << std::setprecision(12);
240  for (const auto* s : v) {
241  const std::string& key = m_objs->obj2key(s);
242  result << indent() << key << " = ba.FormFactor" << s->getName() << "("
243  << pyfmt2::argumentList(s) << ")\n";
244  }
245  return result.str();
246 }
247 
249 {
250  std::vector<const IInterferenceFunction*> v = m_objs->objectsOfType<IInterferenceFunction>();
251  if (v.empty())
252  return "";
253  std::ostringstream result;
254  result << std::setprecision(12);
255  result << "\n" << indent() << "# Define interference functions\n";
256  for (const auto* s : v) {
257  const std::string& key = m_objs->obj2key(s);
258 
259  if (dynamic_cast<const InterferenceFunctionNone*>(s))
260  result << indent() << key << " = ba.InterferenceFunctionNone()\n";
261 
262  else if (const auto* iff = dynamic_cast<const InterferenceFunction1DLattice*>(s)) {
263  result << indent() << key << " = ba.InterferenceFunction1DLattice("
264  << pyfmt::printNm(iff->getLength()) << ", " << pyfmt::printDegrees(iff->getXi())
265  << ")\n";
266 
267  const auto* pdf = node_progeny::OnlyChildOfType<IFTDecayFunction1D>(*iff);
268 
269  if (pdf->decayLength() != 0.0)
270  result << indent() << key << "_pdf = ba." << pdf->getName() << "("
271  << pyfmt2::argumentList(pdf) << ")\n"
272  << indent() << key << ".setDecayFunction(" << key << "_pdf)\n";
273 
274  } else if (const auto* iff =
275  dynamic_cast<const InterferenceFunctionRadialParaCrystal*>(s)) {
276  result << indent() << key << " = ba.InterferenceFunctionRadialParaCrystal("
277  << pyfmt::printNm(iff->peakDistance()) << ", "
278  << pyfmt::printNm(iff->dampingLength()) << ")\n";
279 
280  if (iff->kappa() != 0.0)
281  result << indent() << key << ".setKappa(" << pyfmt::printDouble(iff->kappa())
282  << ")\n";
283 
284  if (iff->domainSize() != 0.0)
285  result << indent() << key << ".setDomainSize("
286  << pyfmt::printDouble(iff->domainSize()) << ")\n";
287 
288  const auto* pdf = node_progeny::OnlyChildOfType<IFTDistribution1D>(*iff);
289 
290  if (pdf->omega() != 0.0)
291  result << indent() << key << "_pdf = ba." << pdf->getName() << "("
292  << pyfmt2::argumentList(pdf) << ")\n"
293  << indent() << key << ".setProbabilityDistribution(" << key << "_pdf)\n";
294 
295  } else if (const auto* iff = dynamic_cast<const InterferenceFunction2DLattice*>(s)) {
296  const auto* lattice = node_progeny::OnlyChildOfType<Lattice2D>(*iff);
297 
298  result << indent() << key << " = ba.InterferenceFunction2DLattice("
299  << m_objs->obj2key(lattice) << ")\n";
300 
301  const auto* pdf = node_progeny::OnlyChildOfType<IFTDecayFunction2D>(*iff);
302 
303  result << indent() << key << "_pdf = ba." << pdf->getName() << "("
304  << pyfmt2::argumentList(pdf) << ")\n"
305  << indent() << key << ".setDecayFunction(" << key << "_pdf)\n";
306 
307  if (iff->integrationOverXi() == true)
308  result << indent() << key << ".setIntegrationOverXi(True)\n";
309 
310  } else if (const auto* iff = dynamic_cast<const InterferenceFunctionFinite2DLattice*>(s)) {
311  const auto* lattice = node_progeny::OnlyChildOfType<Lattice2D>(*iff);
312 
313  result << indent() << key << " = ba.InterferenceFunctionFinite2DLattice("
314  << m_objs->obj2key(lattice) << ", " << iff->numberUnitCells1() << ", "
315  << iff->numberUnitCells2() << ")\n";
316 
317  if (iff->integrationOverXi() == true)
318  result << indent() << key << ".setIntegrationOverXi(True)\n";
319 
320  } else if (const auto* iff = dynamic_cast<const InterferenceFunction2DParaCrystal*>(s)) {
321  const auto* lattice = node_progeny::OnlyChildOfType<Lattice2D>(*iff);
322  std::vector<double> domainSize = iff->domainSizes();
323 
324  result << indent() << key << " = ba.InterferenceFunction2DParaCrystal("
325  << m_objs->obj2key(lattice) << ", " << pyfmt::printNm(iff->dampingLength())
326  << ", " << pyfmt::printNm(domainSize[0]) << ", " << pyfmt::printNm(domainSize[1])
327  << ")\n";
328 
329  if (iff->integrationOverXi() == true)
330  result << indent() << key << ".setIntegrationOverXi(True)\n";
331 
332  const auto pdf_vector = node_progeny::ChildNodesOfType<IFTDistribution2D>(*iff);
333  if (pdf_vector.size() != 2)
334  continue;
335  const IFTDistribution2D* pdf = pdf_vector[0];
336 
337  result << indent() << key << "_pdf_1 = ba." << pdf->getName() << "("
338  << pyfmt2::argumentList(pdf) << ")\n";
339 
340  pdf = pdf_vector[1];
341 
342  result << indent() << key << "_pdf_2 = ba." << pdf->getName() << "("
343  << pyfmt2::argumentList(pdf) << ")\n";
344  result << indent() << key << ".setProbabilityDistributions(" << key << "_pdf_1, " << key
345  << "_pdf_2)\n";
346 
347  } else if (const auto* lattice_hd = dynamic_cast<const InterferenceFunctionHardDisk*>(s)) {
348  result << indent() << key << " = ba.InterferenceFunctionHardDisk("
349  << pyfmt::printNm(lattice_hd->radius()) << ", "
350  << pyfmt::printDouble(lattice_hd->density()) << ")\n";
351 
352  } else
353  throw std::runtime_error(
354  "Bug: ExportToPython::defineInterferenceFunctions() called with unexpected "
355  "IInterferenceFunction "
356  + s->getName());
357 
358  if (s->positionVariance() > 0.0) {
359  result << indent() << key << ".setPositionVariance("
360  << pyfmt::printNm2(s->positionVariance()) << ")\n";
361  }
362  }
363  return result.str();
364 }
365 
367 {
368  std::vector<const ParticleLayout*> v = m_objs->objectsOfType<ParticleLayout>();
369  if (v.empty())
370  return "";
371  std::ostringstream result;
372  result << std::setprecision(12);
373  result << "\n" << indent() << "# Define particle layouts\n";
374  for (const auto* s : v) {
375  const std::string& key = m_objs->obj2key(s);
376  result << indent() << key << " = ba.ParticleLayout()\n";
377  const auto particles = node_progeny::ChildNodesOfType<IAbstractParticle>(*s);
378  for (const auto* particle : particles) {
379  double abundance = particle->abundance();
380  result << indent() << key << ".addParticle(" << m_objs->obj2key(particle) << ", "
381  << pyfmt::printDouble(abundance) << ")\n";
382  }
383  if (const auto* iff = node_progeny::OnlyChildOfType<IInterferenceFunction>(*s))
384  result << indent() << key << ".setInterferenceFunction(" << m_objs->obj2key(iff)
385  << ")\n";
386  result << indent() << key << ".setWeight(" << s->weight() << ")\n";
387  result << indent() << key << ".setTotalParticleSurfaceDensity("
388  << s->totalParticleSurfaceDensity() << ")\n";
389  }
390  return result.str();
391 }
392 
394 {
395  std::vector<const Particle*> v = m_objs->objectsOfType<Particle>();
396  if (v.empty())
397  return "";
398  std::ostringstream result;
399  result << std::setprecision(12);
400  result << "\n" << indent() << "# Define particles\n";
401  for (const auto* s : v) {
402  const std::string& key = m_objs->obj2key(s);
403  const auto* ff = node_progeny::OnlyChildOfType<IFormFactor>(*s);
404  ASSERT(ff);
405  result << indent() << key << " = ba.Particle(" << m_materials->mat2key(s->material())
406  << ", " << m_objs->obj2key(ff) << ")\n";
407  setRotationInformation(s, key, result);
408  setPositionInformation(s, key, result);
409  }
410  return result.str();
411 }
412 
414 {
415  std::vector<const ParticleCoreShell*> v = m_objs->objectsOfType<ParticleCoreShell>();
416  if (v.empty())
417  return "";
418  std::ostringstream result;
419  result << std::setprecision(12);
420  result << "\n" << indent() << "# Define core shell particles\n";
421  for (const auto* s : v) {
422  const std::string& key = m_objs->obj2key(s);
423  result << indent() << key << " = ba.ParticleCoreShell("
424  << m_objs->obj2key(s->shellParticle()) << ", " << m_objs->obj2key(s->coreParticle())
425  << ")\n";
426  setRotationInformation(s, key, result);
427  setPositionInformation(s, key, result);
428  }
429  return result.str();
430 }
431 
433 {
434  std::vector<const ParticleDistribution*> v = m_objs->objectsOfType<ParticleDistribution>();
435  if (v.empty())
436  return "";
437  std::ostringstream result;
438  result << std::setprecision(12);
439  result << "\n" << indent() << "# Define particles with parameter following a distribution\n";
440  int index = 1;
441  for (const auto* s : v) {
442  const std::string& key = m_objs->obj2key(s);
443  const std::string units = s->mainUnits();
444  ParameterDistribution par_distr = s->parameterDistribution();
445  // building distribution functions
446  std::string s_distr = "distr_" + std::to_string(index);
447  result << indent() << s_distr << " = "
448  << pyfmt2::printDistribution(*par_distr.getDistribution(), units) << "\n";
449 
450  // building parameter distribution
451  std::string s_par_distr = "par_distr_" + std::to_string(index);
452 
453  result << indent() << s_par_distr << " = "
454  << pyfmt2::printParameterDistribution(par_distr, s_distr, units) << "\n";
455 
456  // linked parameters
457  std::vector<std::string> linked_pars = par_distr.getLinkedParameterNames();
458  if (!linked_pars.empty()) {
459  result << indent() << s_par_distr;
460  for (size_t i = 0; i < linked_pars.size(); ++i)
461  result << ".linkParameter(\"" << linked_pars[i] << "\")";
462  result << "\n";
463  }
464 
465  auto particle = node_progeny::OnlyChildOfType<IParticle>(*s);
466  if (!particle)
467  continue;
468  result << indent() << key << " = ba.ParticleDistribution(" << m_objs->obj2key(particle)
469  << ", " << s_par_distr << ")\n";
470  index++;
471  }
472  return result.str();
473 }
474 
476 {
477  std::vector<const ParticleComposition*> v = m_objs->objectsOfType<ParticleComposition>();
478  if (v.empty())
479  return "";
480  std::ostringstream result;
481  result << std::setprecision(12);
482  result << "\n" << indent() << "# Define composition of particles at specific positions\n";
483  for (const auto* s : v) {
484  const std::string& key = m_objs->obj2key(s);
485  result << indent() << key << " = ba.ParticleComposition()\n";
486  const auto particle_list = node_progeny::ChildNodesOfType<IParticle>(*s);
487  for (const auto* particle : particle_list) {
488  result << indent() << key << ".addParticle(" << m_objs->obj2key(particle) << ")\n";
489  }
490  setRotationInformation(s, key, result);
491  setPositionInformation(s, key, result);
492  }
493  return result.str();
494 }
495 
497 {
498  std::vector<const MesoCrystal*> v = m_objs->objectsOfType<MesoCrystal>();
499  if (v.empty())
500  return "";
501  std::ostringstream result;
502  result << std::setprecision(12);
503  result << "\n" << indent() << "# Define mesocrystals\n";
504  for (const auto* s : v) {
505  const std::string& key = m_objs->obj2key(s);
506  auto crystal = node_progeny::OnlyChildOfType<Crystal>(*s);
507  auto outer_shape = node_progeny::OnlyChildOfType<IFormFactor>(*s);
508  if (!crystal || !outer_shape)
509  continue;
510  result << indent() << key << " = ba.MesoCrystal(";
511  result << m_objs->obj2key(crystal) << ", ";
512  result << m_objs->obj2key(outer_shape) << ")\n";
513  setRotationInformation(s, key, result);
514  setPositionInformation(s, key, result);
515  }
516  return result.str();
517 }
518 
520 {
521  std::vector<const Lattice2D*> v = m_objs->objectsOfType<Lattice2D>();
522  if (v.empty())
523  return "";
524  std::ostringstream result;
525  result << std::setprecision(12);
526  result << "\n" << indent() << "# Define 2D lattices\n";
527  for (const auto* s : v) {
528  const std::string& key = m_objs->obj2key(s);
529  result << indent() << key << " = ba.BasicLattice2D(\n";
530  result << indent() << indent() << pyfmt::printNm(s->length1()) << ", "
531  << pyfmt::printNm(s->length2()) << ", " << pyfmt::printDegrees(s->latticeAngle())
532  << ", " << pyfmt::printDegrees(s->rotationAngle()) << ")\n";
533  }
534  return result.str();
535 }
536 
538 {
539  std::vector<const Lattice3D*> v = m_objs->objectsOfType<Lattice3D>();
540  if (v.empty())
541  return "";
542  std::ostringstream result;
543  result << std::setprecision(12);
544  result << "\n" << indent() << "# Define 3D lattices\n";
545  for (const auto* s : v) {
546  const std::string& key = m_objs->obj2key(s);
547  kvector_t bas_a = s->getBasisVectorA();
548  kvector_t bas_b = s->getBasisVectorB();
549  kvector_t bas_c = s->getBasisVectorC();
550  result << indent() << key << " = ba.Lattice3D(\n";
551  result << indent() << indent() << "ba.kvector_t(" << pyfmt::printNm(bas_a.x()) << ", "
552  << pyfmt::printNm(bas_a.y()) << ", " << pyfmt::printNm(bas_a.z()) << "),\n";
553  result << indent() << indent() << "ba.kvector_t(" << pyfmt::printNm(bas_b.x()) << ", "
554  << pyfmt::printNm(bas_b.y()) << ", " << pyfmt::printNm(bas_b.z()) << "),\n";
555  result << indent() << indent() << "ba.kvector_t(" << pyfmt::printNm(bas_c.x()) << ", "
556  << pyfmt::printNm(bas_c.y()) << ", " << pyfmt::printNm(bas_c.z()) << "))\n";
557  }
558  return result.str();
559 }
560 
562 {
563  std::vector<const Crystal*> v = m_objs->objectsOfType<Crystal>();
564  if (v.empty())
565  return "";
566  std::ostringstream result;
567  result << std::setprecision(12);
568  result << "\n" << indent() << "# Define crystals\n";
569  for (const auto* s : v) {
570  const std::string& key = m_objs->obj2key(s);
571  const auto* lattice = node_progeny::OnlyChildOfType<Lattice3D>(*s);
572  const auto* basis = node_progeny::OnlyChildOfType<IParticle>(*s);
573  if (!lattice || !basis)
574  continue;
575  result << indent() << key << " = ba.Crystal(";
576  result << m_objs->obj2key(basis) << ", ";
577  result << m_objs->obj2key(lattice) << ")\n";
578  }
579  return result.str();
580 }
581 
583 {
584  std::vector<const MultiLayer*> v = m_objs->objectsOfType<MultiLayer>();
585  if (v.empty())
586  return "";
587  std::ostringstream result;
588  result << std::setprecision(12);
589  ASSERT(v.size() == 1); // as long as there is exactly one sample, we shall use the singular
590  result << "\n" << indent() << "# Define sample\n";
591  for (const auto* s : v) {
592  const std::string& key = m_objs->obj2key(s);
593  result << indent() << key << " = ba.MultiLayer()\n";
594  double ccl = s->crossCorrLength();
595  if (ccl > 0.0)
596  result << indent() << key << ".setCrossCorrLength(" << ccl << ")\n";
597  auto external_field = s->externalField();
598  if (external_field.mag() > 0.0) {
599  std::string field_name = key + "_external_field";
600  result << indent() << field_name << " = kvector_t("
601  << pyfmt::printScientificDouble(external_field.x()) << ", "
602  << pyfmt::printScientificDouble(external_field.y()) << ", "
603  << pyfmt::printScientificDouble(external_field.z()) << ")\n";
604  result << indent() << key << ".setExternalField(" << field_name << ")\n";
605  }
606  size_t numberOfLayers = s->numberOfLayers();
607  if (numberOfLayers) {
608  result << indent() << key << ".addLayer(" << m_objs->obj2key(s->layer(0)) << ")\n";
609 
610  size_t layerIndex = 1;
611  while (layerIndex != numberOfLayers) {
612  const LayerInterface* layerInterface = s->layerInterface(layerIndex - 1);
613  if (const LayerRoughness* rough = layerInterface->getRoughness())
614  result << indent() << key << ".addLayerWithTopRoughness("
615  << m_objs->obj2key(s->layer(layerIndex)) << ", "
616  << m_objs->obj2key(rough) << ")\n";
617  else
618  result << indent() << key << ".addLayer("
619  << m_objs->obj2key(s->layer(layerIndex)) << ")\n";
620  layerIndex++;
621  }
622  }
623  result << "\n" << indent() << "return " << key << "\n";
624  }
625  return result.str();
626 }
Defines the macro ASSERT.
#define ASSERT(condition)
Definition: Assert.h:31
std::complex< double > complex_t
Definition: Complex.h:20
Defines class ComponentKeyHandler.
Defines class Crystal.
Defines and implements interface IFormFactor.
Includes all interference function definitions.
Defines class LayerInterface.
Defines class LayerRoughness.
Defines class Layer.
Defines class MaterialKeyHandler.
Defines class MesoCrystal.
Defines class MultiLayer.
Defines namespace node_progeny.
Defines class ParticleComposition.
Defines ParticleCoreShell.
Defines class ParticleDistribution.
Defines class ParticleLayout.
Defines class Particle.
Defines namespace pyfmt2.
Defines functions in namespace pyfmt.
const std::map< MATERIAL_TYPES, std::string > factory_names
Defines class SampleToPython.
Declares class Transform3D.
BasicVector3D< double > kvector_t
Definition: Vectors3D.h:21
T z() const
Returns z-component in cartesian coordinate system.
Definition: BasicVector3D.h:67
T y() const
Returns y-component in cartesian coordinate system.
Definition: BasicVector3D.h:65
T x() const
Returns x-component in cartesian coordinate system.
Definition: BasicVector3D.h:63
Stores IComponent instances, associates them with given tag, and provides unique keys.
A crystal structure, defined by a Bravais lattice, a basis, and a position variance.
Definition: Crystal.h:35
double abundance() const
Interface for two-dimensional distributions in Fourier space.
Abstract base class for all form factors.
Definition: IFormFactor.h:36
Abstract base class of interference functions.
const std::string & getName() const
Abstract base class for Particle, ParticleComposition, ParticleCoreShell, MesoCrystal.
Definition: IParticle.h:33
kvector_t position() const
Returns particle position.
Definition: IParticle.h:45
const IRotation * rotation() const
Returns rotation object.
Definition: IParticle.cpp:39
virtual Transform3D getTransform3D() const =0
Returns transformation.
std::vector< const Material * > containedMaterials() const
Returns set of unique materials contained in this ISampleNode.
Definition: ISampleNode.cpp:26
Interference function of a 1D lattice.
Interference function of a 2D lattice.
Interference function of a 2D paracrystal.
Interference function of a finite 2D lattice.
Percus-Yevick hard disk interference function.
Default interference function (i.e.
Interference function of radial paracrystal.
A two-dimensional Bravais lattice.
Definition: Lattice2D.h:23
A Bravais lattice, characterized by three basis vectors, and optionally an ISelectionRule.
Definition: Lattice3D.h:29
Interface between two layers, possibly with roughness.
const LayerRoughness * getRoughness() const
Returns roughness of the interface.
A roughness of interface between two layers.
A layer in a MultiLayer sample.
Definition: Layer.h:27
Stores Material instances, associates them with given tag, and provides unique keys.
A wrapper for underlying material implementation.
Definition: Material.h:29
kvector_t magnetization() const
Get the magnetization (in A/m)
Definition: Material.cpp:76
bool isScalarMaterial() const
Indicates whether the interaction with the material is scalar.
Definition: Material.cpp:56
std::string getName() const
Returns the name of material.
Definition: Material.cpp:66
MATERIAL_TYPES typeID() const
Returns the type of underlying material implementation.
Definition: Material.cpp:71
complex_t materialData() const
Returns underlying material data.
Definition: Material.cpp:81
A particle with an internal structure of smaller particles.
Definition: MesoCrystal.h:25
Our sample model: a stack of layers one below the other.
Definition: MultiLayer.h:41
A parametric distribution function, for use with any model parameter.
const IDistribution1D * getDistribution() const
std::vector< std::string > getLinkedParameterNames() const
get list of linked parameter names
A composition of particles at fixed positions.
A particle with a core/shell geometry.
A particle type that is a parametric distribution of IParticle's.
Decorator class that adds particles to ISampleNode objects.
A particle with a form factor and refractive index.
Definition: Particle.h:24
std::string defineLayers() const
std::string defineGetSample() const
std::string defineFormFactors() const
std::string defineMaterials() const
std::string defineLattices3D() const
std::string defineMesoCrystals() const
void initLabels(const MultiLayer &multilayer)
std::string defineCrystals() const
std::string defineParticles() const
std::string defineParticleCompositions() const
std::string defineParticleDistributions() const
std::unique_ptr< ComponentKeyHandler > m_objs
std::string defineLattices2D() const
std::string defineParticleLayouts() const
std::string defineCoreShellParticles() const
std::string defineInterferenceFunctions() const
std::string defineMultiLayers() const
std::string defineRoughnesses() const
std::string sampleCode(const MultiLayer &multilayer)
std::unique_ptr< MaterialKeyHandler > m_materials
double calculateRotateYAngle() const
Calculates the rotation angle for a rotation around the y-axis alone Only meaningfull if the actual r...
Definition: Transform3D.cpp:94
void calculateEulerAngles(double *p_alpha, double *p_beta, double *p_gamma) const
Calculates the Euler angles corresponding to the rotation.
Definition: Transform3D.cpp:76
ERotationType getRotationType() const
Retrieve the rotation type (general, around x, y or z-axis)
double calculateRotateXAngle() const
Calculates the rotation angle for a rotation around the x-axis alone Only meaningfull if the actual r...
Definition: Transform3D.cpp:89
double calculateRotateZAngle() const
Calculates the rotation angle for a rotation around the z-axis alone Only meaningfull if the actual r...
Definition: Transform3D.cpp:99
QString const & name(EShape k)
Definition: particles.cpp:21
std::string printParameterDistribution(const ParameterDistribution &par_distr, const std::string &distVarName, const std::string &units)
Definition: PyFmt2.cpp:147
std::string printDistribution(const IDistribution1D &par_distr, const std::string &units)
Prints distribution with constructor parameters in given units.
Definition: PyFmt2.cpp:137
std::string argumentList(const IParametricComponent *ip)
Returns comma-separated list of parameter values, including unit multiplicator (like "* nm").
Definition: PyFmt2.cpp:106
std::string printNm(double input)
Definition: PyFmt.cpp:74
std::string printNm2(double input)
Definition: PyFmt.cpp:82
std::string printDegrees(double input)
Definition: PyFmt.cpp:111
std::string printDouble(double input)
Definition: PyFmt.cpp:41
std::string printScientificDouble(double input)
Definition: PyFmt.cpp:91
std::string indent(size_t width)
Returns a string of blanks with given width.
Definition: PyFmt.cpp:155