BornAgain  1.18.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 scattering at grazing incidence
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/PyFmt.h"
17 #include "Core/Export/INodeUtils.h"
33 #include <iomanip>
34 #include <map>
35 #include <set>
36 
37 std::string SampleToPython::generateSampleCode(const MultiLayer& multilayer)
38 {
39  initLabels(multilayer);
40  return defineGetSample();
41 }
42 
43 void SampleToPython::initLabels(const MultiLayer& multilayer)
44 {
45  m_label.reset(new SampleLabelHandler());
46 
47  m_label->insertMultiLayer(&multilayer);
48 
49  for (auto x : multilayer.containedMaterials())
50  m_label->insertMaterial(x);
51  for (auto x : INodeUtils::AllDescendantsOfType<Layer>(multilayer))
52  m_label->insertLayer(x);
53  for (auto x : INodeUtils::AllDescendantsOfType<LayerRoughness>(multilayer))
54  m_label->insertRoughness(x);
55  for (auto x : INodeUtils::AllDescendantsOfType<IFormFactor>(multilayer))
56  m_label->insertFormFactor(x);
57  for (auto x : INodeUtils::AllDescendantsOfType<ILayout>(multilayer))
58  m_label->insertLayout(x);
59  for (auto x : INodeUtils::AllDescendantsOfType<IInterferenceFunction>(multilayer))
60  m_label->insertInterferenceFunction(x);
61  for (auto x : INodeUtils::AllDescendantsOfType<Particle>(multilayer))
62  m_label->insertParticle(x);
63  for (auto x : INodeUtils::AllDescendantsOfType<ParticleCoreShell>(multilayer))
64  m_label->insertParticleCoreShell(x);
65  for (auto x : INodeUtils::AllDescendantsOfType<ParticleComposition>(multilayer))
66  m_label->insertParticleComposition(x);
67  for (auto x : INodeUtils::AllDescendantsOfType<ParticleDistribution>(multilayer))
68  m_label->insertParticleDistribution(x);
69  for (auto x : INodeUtils::AllDescendantsOfType<Lattice>(multilayer))
70  m_label->insertLattice(x);
71  for (auto x : INodeUtils::AllDescendantsOfType<Crystal>(multilayer))
72  m_label->insertCrystal(x);
73  for (auto x : INodeUtils::AllDescendantsOfType<MesoCrystal>(multilayer))
74  m_label->insertMesoCrystal(x);
75  for (auto x : INodeUtils::AllDescendantsOfType<IRotation>(multilayer))
76  m_label->insertRotation(x);
77 }
78 
80 
82 
84 {
85  return "def " + pyfmt::getSampleFunctionName() + "():\n" + defineMaterials() + defineLayers()
90  + defineMultiLayers() + "\n\n";
91 }
92 
93 const std::map<MATERIAL_TYPES, std::string> factory_names{
94  {MATERIAL_TYPES::RefractiveMaterial, "HomogeneousMaterial"},
95  {MATERIAL_TYPES::MaterialBySLD, "MaterialBySLD"}};
96 
98 {
99  const LabelMap<const Material*>* themap = m_label->materialMap();
100  if (themap->empty())
101  return "# No Materials.\n\n";
102  std::ostringstream result;
103  result << std::setprecision(12);
104  result << indent() << "# Defining Materials\n";
105  std::set<std::string> visitedMaterials;
106  for (auto it = themap->begin(); it != themap->end(); ++it) {
107  if (visitedMaterials.find(it->second) != visitedMaterials.end())
108  continue;
109  visitedMaterials.insert(it->second);
110  const Material* p_material = it->first;
111  const auto factory_name = factory_names.find(p_material->typeID());
112  if (factory_name == factory_names.cend())
113  throw std::runtime_error(
114  "Error in ExportToPython::defineMaterials(): unknown material type");
115  const complex_t& material_data = p_material->materialData();
116  if (p_material->isScalarMaterial()) {
117  result << indent() << m_label->labelMaterial(p_material) << " = ba."
118  << factory_name->second << "(\"" << p_material->getName() << "\", "
119  << pyfmt::printDouble(material_data.real()) << ", "
120  << pyfmt::printDouble(material_data.imag()) << ")\n";
121  } else {
122  kvector_t magnetic_field = p_material->magnetization();
123  result << indent() << "magnetic_field = kvector_t(" << magnetic_field.x() << ", "
124  << magnetic_field.y() << ", " << magnetic_field.z() << ")\n";
125  result << indent() << m_label->labelMaterial(p_material) << " = ba."
126  << factory_name->second << "(\"" << p_material->getName();
127  result << "\", " << pyfmt::printDouble(material_data.real()) << ", "
128  << pyfmt::printDouble(material_data.imag()) << ", "
129  << "magnetic_field)\n";
130  }
131  }
132  return result.str();
133 }
134 
135 std::string SampleToPython::defineLayers() const
136 {
137  const auto themap = m_label->layerMap();
138  if (themap->empty())
139  return "# No Layers.\n\n";
140  std::ostringstream result;
141  result << std::setprecision(12);
142  result << "\n" << indent() << "# Defining Layers\n";
143  for (auto it = themap->begin(); it != themap->end(); ++it) {
144  const Layer* layer = it->first;
145  result << indent() << it->second << " = ba.Layer("
146  << m_label->labelMaterial(layer->material());
147  if (layer->thickness() != 0)
148  result << ", " << layer->thickness();
149  result << ")\n";
150  if (layer->numberOfSlices() != 1)
151  result << indent() << it->second << ".setNumberOfSlices(" << layer->numberOfSlices()
152  << ")\n";
153  }
154  return result.str();
155 }
156 
158 {
159  const auto themap = m_label->formFactorMap();
160  if (themap->empty())
161  return "";
162  std::ostringstream result;
163  result << std::setprecision(12);
164  result << "\n" << indent() << "# Defining Form Factors\n";
165  for (auto it = themap->begin(); it != themap->end(); ++it) {
166  const IFormFactor* p_ff = it->first;
167  result << indent() << it->second << " = ba.FormFactor" << p_ff->getName() << "("
168  << pyfmt2::argumentList(p_ff) << ")\n";
169  }
170  return result.str();
171 }
172 
174 {
175  const auto themap = m_label->particleMap();
176  if (themap->empty())
177  return "";
178  std::ostringstream result;
179  result << std::setprecision(12);
180  result << "\n" << indent() << "# Defining Particles\n";
181  for (auto it = themap->begin(); it != themap->end(); ++it) {
182  const Particle* p_particle = it->first;
183  std::string particle_name = it->second;
184  auto p_ff = INodeUtils::OnlyChildOfType<IFormFactor>(*p_particle);
185  if (!p_ff)
186  continue;
187  result << indent() << particle_name << " = ba.Particle("
188  << m_label->labelMaterial(p_particle->material()) << ", "
189  << m_label->labelFormFactor(p_ff) << ")\n";
190  setRotationInformation(p_particle, particle_name, result);
191  setPositionInformation(p_particle, particle_name, result);
192  }
193  return result.str();
194 }
195 
197 {
198  const auto themap = m_label->particleCoreShellMap();
199  if (themap->empty())
200  return "";
201  std::ostringstream result;
202  result << std::setprecision(12);
203  result << "\n" << indent() << "# Defining Core Shell Particles\n";
204  for (auto it = themap->begin(); it != themap->end(); ++it) {
205  const ParticleCoreShell* p_coreshell = it->first;
206  result << "\n"
207  << indent() << it->second << " = ba.ParticleCoreShell("
208  << m_label->labelParticle(p_coreshell->shellParticle()) << ", "
209  << m_label->labelParticle(p_coreshell->coreParticle()) << ")\n";
210  std::string core_shell_name = it->second;
211  setRotationInformation(p_coreshell, core_shell_name, result);
212  setPositionInformation(p_coreshell, core_shell_name, result);
213  }
214  return result.str();
215 }
216 
218 {
219  const auto themap = m_label->particleDistributionsMap();
220  if (themap->empty())
221  return "";
222 
223  std::ostringstream result;
224  result << std::setprecision(12);
225  result << "\n" << indent() << "# Defining particles with parameter following a distribution\n";
226 
227  int index(1);
228  for (auto it = themap->begin(); it != themap->end(); ++it) {
229  const ParticleDistribution* p_particle_distr = it->first;
230 
231  const std::string units = p_particle_distr->mainUnits();
232 
233  ParameterDistribution par_distr = p_particle_distr->parameterDistribution();
234 
235  // building distribution functions
236  std::string s_distr = "distr_" + std::to_string(index);
237  result << indent() << s_distr << " = "
238  << pyfmt2::printDistribution(*par_distr.getDistribution(), units) << "\n";
239 
240  // building parameter distribution
241  std::string s_par_distr = "par_distr_" + std::to_string(index);
242 
243  result << indent() << s_par_distr << " = "
244  << pyfmt2::printParameterDistribution(par_distr, s_distr, units) << "\n";
245 
246  // linked parameters
247  std::vector<std::string> linked_pars = par_distr.getLinkedParameterNames();
248  if (!linked_pars.empty()) {
249  result << indent() << s_par_distr;
250  for (size_t i = 0; i < linked_pars.size(); ++i)
251  result << ".linkParameter(\"" << linked_pars[i] << "\")";
252  result << "\n";
253  }
254 
255  auto p_particle = INodeUtils::OnlyChildOfType<IParticle>(*p_particle_distr);
256  if (!p_particle)
257  continue;
258  result << indent() << it->second << " = ba.ParticleDistribution("
259  << m_label->labelParticle(p_particle) << ", " << s_par_distr << ")\n";
260  index++;
261  }
262  return result.str();
263 }
264 
266 {
267  const auto themap = m_label->particleCompositionMap();
268  if (themap->empty())
269  return "";
270  std::ostringstream result;
271  result << std::setprecision(12);
272  result << "\n" << indent() << "# Defining composition of particles at specific positions\n";
273  for (auto it = themap->begin(); it != themap->end(); ++it) {
274  const ParticleComposition* p_particle_composition = it->first;
275  std::string particle_composition_name = it->second;
276  result << indent() << particle_composition_name << " = ba.ParticleComposition()\n";
277  auto particle_list = INodeUtils::ChildNodesOfType<IParticle>(*p_particle_composition);
278  for (auto p_particle : particle_list) {
279  result << indent() << particle_composition_name << ".addParticle("
280  << m_label->labelParticle(p_particle) << ")\n";
281  }
282  setRotationInformation(p_particle_composition, particle_composition_name, result);
283  setPositionInformation(p_particle_composition, particle_composition_name, result);
284  }
285  return result.str();
286 }
287 
289 {
290  const auto themap = m_label->latticeMap();
291  if (themap->empty())
292  return "";
293  std::ostringstream result;
294  result << std::setprecision(12);
295  result << "\n" << indent() << "# Defining 3D lattices\n";
296  for (auto it = themap->begin(); it != themap->end(); ++it) {
297  const Lattice* p_lattice = it->first;
298  std::string lattice_name = it->second;
299  kvector_t bas_a = p_lattice->getBasisVectorA();
300  kvector_t bas_b = p_lattice->getBasisVectorB();
301  kvector_t bas_c = p_lattice->getBasisVectorC();
302  result << indent() << lattice_name << " = ba.Lattice(\n";
303  result << indent() << indent() << "ba.kvector_t(" << pyfmt::printNm(bas_a.x()) << ", "
304  << pyfmt::printNm(bas_a.y()) << ", " << pyfmt::printNm(bas_a.z()) << "),\n";
305  result << indent() << indent() << "ba.kvector_t(" << pyfmt::printNm(bas_b.x()) << ", "
306  << pyfmt::printNm(bas_b.y()) << ", " << pyfmt::printNm(bas_b.z()) << "),\n";
307  result << indent() << indent() << "ba.kvector_t(" << pyfmt::printNm(bas_c.x()) << ", "
308  << pyfmt::printNm(bas_c.y()) << ", " << pyfmt::printNm(bas_c.z()) << "))\n";
309  }
310  return result.str();
311 }
312 
314 {
315  const auto themap = m_label->crystalMap();
316  if (themap->empty())
317  return "";
318  std::ostringstream result;
319  result << std::setprecision(12);
320  result << "\n" << indent() << "# Defining crystals: basis particle + lattice\n";
321  for (auto it = themap->begin(); it != themap->end(); ++it) {
322  const Crystal* p_crystal = it->first;
323  std::string crystal_name = it->second;
324  auto p_lattice = INodeUtils::OnlyChildOfType<Lattice>(*p_crystal);
325  auto p_basis = INodeUtils::OnlyChildOfType<IParticle>(*p_crystal);
326  if (!p_lattice || !p_basis)
327  continue;
328  result << indent() << crystal_name << " = ba.Crystal(";
329  result << m_label->labelParticle(p_basis) << ", ";
330  result << m_label->labelLattice(p_lattice) << ")\n";
331  }
332  return result.str();
333 }
334 
336 {
337  const auto themap = m_label->mesocrystalMap();
338  if (themap->empty())
339  return "";
340  std::ostringstream result;
341  result << std::setprecision(12);
342  result << "\n" << indent() << "# Defining mesocrystals\n";
343  for (auto it = themap->begin(); it != themap->end(); ++it) {
344  const MesoCrystal* p_mesocrystal = it->first;
345  std::string mesocrystal_name = it->second;
346  auto p_crystal = INodeUtils::OnlyChildOfType<Crystal>(*p_mesocrystal);
347  auto p_outer_shape = INodeUtils::OnlyChildOfType<IFormFactor>(*p_mesocrystal);
348  if (!p_crystal || !p_outer_shape)
349  continue;
350  result << indent() << mesocrystal_name << " = ba.MesoCrystal(";
351  result << m_label->labelCrystal(p_crystal) << ", ";
352  result << m_label->labelFormFactor(p_outer_shape) << ")\n";
353  setRotationInformation(p_mesocrystal, mesocrystal_name, result);
354  setPositionInformation(p_mesocrystal, mesocrystal_name, result);
355  }
356  return result.str();
357 }
358 
360 {
361  const auto themap = m_label->interferenceFunctionMap();
362  if (themap->empty())
363  return "";
364  std::ostringstream result;
365  result << std::setprecision(12);
366  result << "\n" << indent() << "# Defining Interference Functions\n";
367  for (auto it = themap->begin(); it != themap->end(); ++it) {
368  const IInterferenceFunction* interference = it->first;
369 
370  if (dynamic_cast<const InterferenceFunctionNone*>(interference))
371  result << indent() << it->second << " = ba.InterferenceFunctionNone()\n";
372  else if (auto p_lattice_1d =
373  dynamic_cast<const InterferenceFunction1DLattice*>(interference)) {
374  result << indent() << it->second << " = ba.InterferenceFunction1DLattice("
375  << pyfmt::printNm(p_lattice_1d->getLength()) << ", "
376  << pyfmt::printDegrees(p_lattice_1d->getXi()) << ")\n";
377 
378  auto pdf = INodeUtils::OnlyChildOfType<IFTDecayFunction1D>(*p_lattice_1d);
379 
380  if (pdf->decayLength() != 0.0)
381  result << indent() << it->second << "_pdf = ba." << pdf->getName() << "("
382  << pyfmt2::argumentList(pdf) << ")\n"
383  << indent() << it->second << ".setDecayFunction(" << it->second << "_pdf)\n";
384  } else if (auto p_para_radial =
385  dynamic_cast<const InterferenceFunctionRadialParaCrystal*>(interference)) {
386  result << indent() << it->second << " = ba.InterferenceFunctionRadialParaCrystal("
387  << pyfmt::printNm(p_para_radial->peakDistance()) << ", "
388  << pyfmt::printNm(p_para_radial->dampingLength()) << ")\n";
389 
390  if (p_para_radial->kappa() != 0.0)
391  result << indent() << it->second << ".setKappa("
392  << pyfmt::printDouble(p_para_radial->kappa()) << ")\n";
393 
394  if (p_para_radial->domainSize() != 0.0)
395  result << indent() << it->second << ".setDomainSize("
396  << pyfmt::printDouble(p_para_radial->domainSize()) << ")\n";
397 
398  auto pdf = INodeUtils::OnlyChildOfType<IFTDistribution1D>(*p_para_radial);
399 
400  if (pdf->omega() != 0.0)
401  result << indent() << it->second << "_pdf = ba." << pdf->getName() << "("
402  << pyfmt2::argumentList(pdf) << ")\n"
403  << indent() << it->second << ".setProbabilityDistribution(" << it->second
404  << "_pdf)\n";
405  } else if (auto p_lattice_2d =
406  dynamic_cast<const InterferenceFunction2DLattice*>(interference)) {
407  const Lattice2D& lattice = p_lattice_2d->lattice();
408  result << indent() << it->second << " = ba.InterferenceFunction2DLattice("
409  << pyfmt::printNm(lattice.length1()) << ", " << pyfmt::printNm(lattice.length2())
410  << ", " << pyfmt::printDegrees(lattice.latticeAngle()) << ", "
411  << pyfmt::printDegrees(lattice.rotationAngle()) << ")\n";
412 
413  auto pdf = INodeUtils::OnlyChildOfType<IFTDecayFunction2D>(*p_lattice_2d);
414 
415  result << indent() << it->second << "_pdf = ba." << pdf->getName() << "("
416  << pyfmt2::argumentList(pdf) << ")\n"
417  << indent() << it->second << ".setDecayFunction(" << it->second << "_pdf)\n";
418 
419  if (p_lattice_2d->integrationOverXi() == true)
420  result << indent() << it->second << ".setIntegrationOverXi(True)\n";
421  } else if (auto p_lattice_2d =
422  dynamic_cast<const InterferenceFunctionFinite2DLattice*>(interference)) {
423  const Lattice2D& lattice = p_lattice_2d->lattice();
424  result << indent() << it->second << " = ba.InterferenceFunctionFinite2DLattice("
425  << pyfmt::printNm(lattice.length1()) << ", " << pyfmt::printNm(lattice.length2())
426  << ", " << pyfmt::printDegrees(lattice.latticeAngle()) << ", "
427  << pyfmt::printDegrees(lattice.rotationAngle()) << ", "
428  << p_lattice_2d->numberUnitCells1() << ", " << p_lattice_2d->numberUnitCells2()
429  << ")\n";
430 
431  if (p_lattice_2d->integrationOverXi() == true)
432  result << indent() << it->second << ".setIntegrationOverXi(True)\n";
433  } else if (auto p_para_2d =
434  dynamic_cast<const InterferenceFunction2DParaCrystal*>(interference)) {
435  std::vector<double> domainSize = p_para_2d->domainSizes();
436  const Lattice2D& lattice = p_para_2d->lattice();
437  result << indent() << it->second << " = ba.InterferenceFunction2DParaCrystal("
438  << pyfmt::printNm(lattice.length1()) << ", " << pyfmt::printNm(lattice.length2())
439  << ", " << pyfmt::printDegrees(lattice.latticeAngle()) << ", "
440  << pyfmt::printDegrees(lattice.rotationAngle()) << ", "
441  << pyfmt::printNm(p_para_2d->dampingLength()) << ")\n";
442 
443  if (domainSize[0] != 0.0 || domainSize[1] != 0.0)
444  result << indent() << it->second << ".setDomainSizes("
445  << pyfmt::printNm(domainSize[0]) << ", " << pyfmt::printNm(domainSize[1])
446  << ")\n";
447  if (p_para_2d->integrationOverXi() == true)
448  result << indent() << it->second << ".setIntegrationOverXi(True)\n";
449 
450  auto pdf_vector = INodeUtils::ChildNodesOfType<IFTDistribution2D>(*p_para_2d);
451  if (pdf_vector.size() != 2)
452  continue;
453  const IFTDistribution2D* pdf = pdf_vector[0];
454 
455  result << indent() << it->second << "_pdf_1 = ba." << pdf->getName() << "("
456  << pyfmt2::argumentList(pdf) << ")\n";
457 
458  pdf = pdf_vector[1];
459 
460  result << indent() << it->second << "_pdf_2 = ba." << pdf->getName() << "("
461  << pyfmt2::argumentList(pdf) << ")\n";
462  result << indent() << it->second << ".setProbabilityDistributions(" << it->second
463  << "_pdf_1, " << it->second << "_pdf_2)\n";
464  } else if (auto p_lattice_hd =
465  dynamic_cast<const InterferenceFunctionHardDisk*>(interference)) {
466  result << indent() << it->second << " = ba.InterferenceFunctionHardDisk("
467  << pyfmt::printNm(p_lattice_hd->radius()) << ", "
468  << pyfmt::printDouble(p_lattice_hd->density()) << ")\n";
469  } else
471  "Bug: ExportToPython::defineInterferenceFunctions() called with unexpected "
472  "IInterferenceFunction "
473  + interference->getName());
474  if (interference->positionVariance() > 0.0) {
475  result << indent() << it->second << ".setPositionVariance("
476  << pyfmt::printNm2(interference->positionVariance()) << ")\n";
477  }
478  }
479  return result.str();
480 }
481 
483 {
484  const auto themap = m_label->particleLayoutMap();
485  if (themap->empty())
486  return "";
487  std::ostringstream result;
488  result << std::setprecision(12);
489  result << "\n" << indent() << "# Defining Particle Layouts and adding Particles\n";
490  for (auto it = themap->begin(); it != themap->end(); ++it) {
491  const ILayout* iLayout = it->first;
492  if (const ParticleLayout* particleLayout = dynamic_cast<const ParticleLayout*>(iLayout)) {
493  result << indent() << it->second << " = ba.ParticleLayout()\n";
494  auto particles = INodeUtils::ChildNodesOfType<IAbstractParticle>(*particleLayout);
495 
496  for (auto p_particle : particles) {
497  double abundance = p_particle->abundance();
498  result << indent() << it->second << ".addParticle("
499  << m_label->labelParticle(p_particle) << ", "
500  << pyfmt::printDouble(abundance) << ")\n";
501  }
502  if (auto p_iff = INodeUtils::OnlyChildOfType<IInterferenceFunction>(*particleLayout))
503  result << indent() << it->second << ".setInterferenceFunction("
504  << m_label->labelInterferenceFunction(p_iff) << ")\n";
505  result << indent() << it->second << ".setWeight(" << particleLayout->weight() << ")\n";
506  result << indent() << it->second << ".setTotalParticleSurfaceDensity("
507  << particleLayout->totalParticleSurfaceDensity() << ")\n";
508  }
509  }
510  return result.str();
511 }
512 
514 {
515  const auto themap = m_label->layerRoughnessMap();
516  if (themap->empty())
517  return "";
518  std::ostringstream result;
519  result << std::setprecision(12);
520  result << "\n" << indent() << "# Defining Roughness Parameters\n";
521  for (auto it = themap->begin(); it != themap->end(); ++it)
522  result << indent() << it->second << " = ba.LayerRoughness("
523  << pyfmt2::argumentList(it->first) << ")\n";
524  return result.str();
525 }
526 
528 {
529  if (m_label->particleLayoutMap()->empty())
530  return "";
531  std::ostringstream result;
532  result << std::setprecision(12);
533  result << "\n" << indent() << "# Adding layouts to layers";
534  const auto layermap = m_label->layerMap();
535  for (auto it = layermap->begin(); it != layermap->end(); ++it) {
536  const Layer* layer = it->first;
537  for (auto p_layout : layer->layouts())
538  result << "\n"
539  << indent() << it->second << ".addLayout(" << m_label->labelLayout(p_layout)
540  << ")\n";
541  }
542  return result.str();
543 }
544 
546 {
547  const auto themap = m_label->multiLayerMap();
548  if (themap->empty())
549  return "# No MultiLayers.\n\n";
550  std::ostringstream result;
551  result << std::setprecision(12);
552  result << "\n" << indent() << "# Defining Multilayers\n";
553  for (auto it = themap->begin(); it != themap->end(); ++it) {
554  result << indent() << it->second << " = ba.MultiLayer()\n";
555  double ccl = it->first->crossCorrLength();
556  if (ccl > 0.0)
557  result << indent() << it->second << ".setCrossCorrLength(" << ccl << ")\n";
558  auto external_field = it->first->externalField();
559  if (external_field.mag() > 0.0) {
560  std::string field_name = it->second + "_external_field";
561  result << indent() << field_name << " = kvector_t("
562  << pyfmt::printScientificDouble(external_field.x()) << ", "
563  << pyfmt::printScientificDouble(external_field.y()) << ", "
564  << pyfmt::printScientificDouble(external_field.z()) << ")\n";
565  result << indent() << it->second << ".setExternalField(" << field_name << ")\n";
566  }
567  size_t numberOfLayers = it->first->numberOfLayers();
568  if (numberOfLayers) {
569  result << indent() << it->second << ".addLayer("
570  << m_label->labelLayer(it->first->layer(0)) << ")\n";
571 
572  size_t layerIndex = 1;
573  while (layerIndex != numberOfLayers) {
574  const LayerInterface* layerInterface = it->first->layerInterface(layerIndex - 1);
575  if (m_label->layerRoughnessMap()->find(layerInterface->getRoughness())
576  == m_label->layerRoughnessMap()->end())
577  result << indent() << it->second << ".addLayer("
578  << m_label->labelLayer(it->first->layer(layerIndex)) << ")\n";
579  else
580  result << indent() << it->second << ".addLayerWithTopRoughness("
581  << m_label->labelLayer(it->first->layer(layerIndex)) << ", "
582  << m_label->labelRoughness(layerInterface->getRoughness()) << ")\n";
583  layerIndex++;
584  }
585  }
586  result << indent() << "return " << it->second << "\n";
587  }
588  return result.str();
589 }
590 
591 std::string SampleToPython::indent() const
592 {
593  return " ";
594 }
595 
596 void SampleToPython::setRotationInformation(const IParticle* p_particle, std::string name,
597  std::ostringstream& result) const
598 {
599  if (p_particle->rotation()) {
600  switch (p_particle->rotation()->getTransform3D().getRotationType()) {
601  case Transform3D::EULER: {
602  double alpha, beta, gamma;
603  p_particle->rotation()->getTransform3D().calculateEulerAngles(&alpha, &beta, &gamma);
604  result << indent() << name << "_rotation = ba.RotationEuler("
605  << pyfmt::printDegrees(alpha) << ", " << pyfmt::printDegrees(beta) << ", "
606  << pyfmt::printDegrees(gamma) << ")\n";
607  break;
608  }
609  case Transform3D::XAXIS: {
610  double alpha = p_particle->rotation()->getTransform3D().calculateRotateXAngle();
611  result << indent() << name << "_rotation = ba.RotationX(" << pyfmt::printDegrees(alpha)
612  << ")\n";
613  break;
614  }
615  case Transform3D::YAXIS: {
616  double alpha = p_particle->rotation()->getTransform3D().calculateRotateYAngle();
617  result << indent() << name << "_rotation = ba.RotationY(" << pyfmt::printDegrees(alpha)
618  << ")\n";
619  break;
620  }
621  case Transform3D::ZAXIS: {
622  double alpha = p_particle->rotation()->getTransform3D().calculateRotateZAngle();
623  result << indent() << name << "_rotation = ba.RotationZ(" << pyfmt::printDegrees(alpha)
624  << ")\n";
625  break;
626  }
627  }
628  result << indent() << name << ".setRotation(" << name << "_rotation)\n";
629  }
630 }
631 
632 void SampleToPython::setPositionInformation(const IParticle* p_particle, std::string name,
633  std::ostringstream& result) const
634 {
635  kvector_t pos = p_particle->position();
636  bool has_position_info = (pos != kvector_t());
637 
638  if (has_position_info) {
639  result << indent() << name << "_position = kvector_t(" << pyfmt::printNm(pos.x()) << ", "
640  << pyfmt::printNm(pos.y()) << ", " << pyfmt::printNm(pos.z()) << ")\n";
641 
642  result << indent() << name << ".setPosition(" << name << "_position)\n";
643  }
644 }
std::complex< double > complex_t
Definition: Complex.h:20
Defines class Crystal.
Defines namespace INodeUtils.
Includes all interference function definitions.
Defines class LayerInterface.
Defines class LayerRoughness.
Defines class Layer.
Defines class MesoCrystal.
Defines class MultiLayer.
Defines namespace ParameterUtils.
Defines class ParticleComposition.
Defines ParticleCoreShell.
Defines class ParticleDistribution.
Defines class ParticleLayout.
Defines class Particle.
Defines namespace pyfmt2.
Defines functions in namespace pyfmt.
Defines classes LabelMap and SampleLabelHandler.
const std::map< MATERIAL_TYPES, std::string > factory_names
Defines class SampleToPython.
BasicVector3D< double > kvector_t
Definition: Vectors3D.h:21
T z() const
Returns z-component in cartesian coordinate system.
Definition: BasicVector3D.h:68
T y() const
Returns y-component in cartesian coordinate system.
Definition: BasicVector3D.h:66
T x() const
Returns x-component in cartesian coordinate system.
Definition: BasicVector3D.h:64
A crystal structure with a ParticleComposition as a basis.
Definition: Crystal.h:26
Interface for two-dimensional distributions in Fourier space.
Pure virtual base class for all form factors.
Definition: IFormFactor.h:40
Pure virtual base class of interference functions.
double positionVariance() const
Returns the position variance.
Pure virtual interface class to equip a sample layer with scattering properties.
Definition: ILayout.h:32
const std::string & getName() const
Pure virtual 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 ISample.
Definition: ISample.cpp:23
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.
double rotationAngle() const
Definition: Lattice2D.h:39
virtual double latticeAngle() const =0
virtual double length2() const =0
virtual double length1() const =0
A lattice with three basis vectors.
Definition: Lattice.h:28
kvector_t getBasisVectorB() const
Returns basis vector b.
Definition: Lattice.h:47
kvector_t getBasisVectorC() const
Returns basis vector c.
Definition: Lattice.h:50
kvector_t getBasisVectorA() const
Returns basis vector a.
Definition: Lattice.h:44
Interface between two layers, possibly with roughness.
const LayerRoughness * getRoughness() const
Returns roughness of the interface.
A layer, with thickness (in nanometer) and material.
Definition: Layer.h:28
double thickness() const
Definition: Layer.h:39
const Material * material() const override final
Returns nullptr, unless overwritten to return a specific material.
Definition: Layer.h:41
unsigned int numberOfSlices() const
Definition: Layer.h:53
std::vector< const ILayout * > layouts() const
Definition: Layer.cpp:64
A wrapper for underlying material implementation.
Definition: Material.h:29
kvector_t magnetization() const
Get the magnetization (in A/m)
Definition: Material.cpp:79
bool isScalarMaterial() const
Indicates whether the interaction with the material is scalar.
Definition: Material.cpp:59
std::string getName() const
Returns the name of material.
Definition: Material.cpp:69
MATERIAL_TYPES typeID() const
Returns the type of underlying material implementation.
Definition: Material.cpp:74
complex_t materialData() const
Returns underlying material data.
Definition: Material.cpp:84
A particle with an internal structure of smaller particles.
Definition: MesoCrystal.h:26
Our sample model: a stack of layers one below the other.
Definition: MultiLayer.h:42
const_iterator end() const
Definition: OrderedMap.h:47
bool empty() const
Definition: OrderedMap.h:56
const_iterator begin() const
Definition: OrderedMap.h:46
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.
const Particle * shellParticle() const
const Particle * coreParticle() const
A particle type that is a parametric distribution of IParticle's.
ParameterDistribution parameterDistribution() const
Returns the distributed parameter data.
std::string mainUnits() const
Decorator class that adds particles to ISample objects.
A particle with a form factor and refractive index.
Definition: Particle.h:26
const Material * material() const override final
Returns nullptr, unless overwritten to return a specific material.
Definition: Particle.h:40
The handler which construct labels for sample variables during python script generation.
std::string defineLayers() const
std::string defineGetSample() const
std::string defineFormFactors() const
std::string generateSampleCode(const MultiLayer &multilayer)
std::string defineMaterials() const
std::string defineMesoCrystals() const
void initLabels(const MultiLayer &multilayer)
std::string defineCrystals() const
std::unique_ptr< SampleLabelHandler > m_label
std::string defineParticles() const
std::string defineParticleCompositions() const
std::string indent() const
std::string defineParticleDistributions() const
std::string addLayoutsToLayers() const
std::string defineParticleLayouts() const
void setRotationInformation(const IParticle *particle, std::string particle_name, std::ostringstream &result) const
void setPositionInformation(const IParticle *particle, std::string particle_name, std::ostringstream &result) const
std::string defineLattices() const
std::string defineCoreShellParticles() const
std::string defineInterferenceFunctions() const
std::string defineMultiLayers() const
std::string defineRoughnesses() const
double calculateRotateYAngle() const
Calculates the rotation angle for a rotation around the y-axis alone Only meaningfull if the actual r...
Definition: Transform3D.cpp:99
void calculateEulerAngles(double *p_alpha, double *p_beta, double *p_gamma) const
Calculates the Euler angles corresponding to the rotation.
Definition: Transform3D.cpp:81
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:94
double calculateRotateZAngle() const
Calculates the rotation angle for a rotation around the z-axis alone Only meaningfull if the actual r...
std::string printParameterDistribution(const ParameterDistribution &par_distr, const std::string &distVarName, const std::string &units)
Definition: PyFmt2.cpp:127
std::string argumentList(const IParameterized *ip)
Returns comma-separated list of parameter values, including unit multiplicator (like "* nm").
Definition: PyFmt2.cpp:106
std::string printDistribution(const IDistribution1D &par_distr, const std::string &units)
Prints distribution with constructor parameters in given units.
Definition: PyFmt2.cpp:117
std::string printNm(double input)
Definition: PyFmt.cpp:57
std::string getSampleFunctionName()
Definition: PyFmt.cpp:33
std::string printNm2(double input)
Definition: PyFmt.cpp:65
std::string printDegrees(double input)
Definition: PyFmt.cpp:94
std::string printDouble(double input)
Definition: PyFmt.cpp:43
std::string printScientificDouble(double input)
Definition: PyFmt.cpp:74