BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
RealSpaceBuilderUtils.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/coregui/Views/RealSpaceWidgets/RealSpaceBuilderUtils.cpp
6 //! @brief Implements RealSpaceBuilderUtils namespace
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/Const/Units.h"
45 
46 namespace {
47 const double layerBorderWidth = 10.0;
48 
49 const IFormFactor* getUnderlyingFormFactor(const IFormFactor* ff)
50 {
51  // TRUE as long as ff is of IFormFactorDecorator (or its derived) type
52  while (dynamic_cast<const IFormFactorDecorator*>(ff))
53  ff = dynamic_cast<const IFormFactorDecorator*>(ff)->getFormFactor();
54 
55  return ff;
56 }
57 
58 kvector_t to_kvector(const QVector3D& origin)
59 {
60  return kvector_t(static_cast<double>(origin.x()), static_cast<double>(origin.y()),
61  static_cast<double>(origin.z()));
62 }
63 
64 } // namespace
65 
66 // compute cumulative abundances of particles
68 {
69  // Retrieving abundances of particles
70  double total_abundance = 0.0;
71  QVector<double> cumulative_abundances;
72 
73  for (auto particle : layoutItem.getItems(ParticleLayoutItem::T_PARTICLES)) {
74  total_abundance =
75  total_abundance + particle->getItemValue(ParticleItem::P_ABUNDANCE).toDouble();
76 
77  cumulative_abundances.append(total_abundance);
78  }
79 
80  return cumulative_abundances;
81 }
82 
84  const std::vector<std::vector<double>>& lattice_positions,
85  const std::vector<Particle3DContainer>& particle3DContainer_vector, RealSpaceModel* model,
86  const SceneGeometry& sceneGeometry, const RealSpaceBuilder* builder3D)
87 {
88  double layer_size = sceneGeometry.layer_size();
89  double layer_thickness =
90  std::max(sceneGeometry.layer_top_thickness(), sceneGeometry.layer_bottom_thickness());
91 
92  for (std::vector<double> position : lattice_positions) {
93  // for random selection of particles based on their abundances
94  double rand_num = (rand() / static_cast<double>(RAND_MAX)); // (between 0 and 1)
95  int k = 0;
96 
97  for (const auto& particle3DContainer : particle3DContainer_vector) {
98  if (rand_num <= particle3DContainer.cumulativeAbundance()) {
99  // lattice position + location (TO BE ADDED)
100  double pos_x = position[0];
101  double pos_y = position[1];
102  double pos_z = 0;
103 
104  if (std::abs(pos_x) <= layer_size - layerBorderWidth
105  && std::abs(pos_y) <= layer_size - layerBorderWidth
106  && std::abs(pos_z) <= layer_thickness) {
107 
109  model, particle3DContainer,
110  QVector3D(static_cast<float>(position[0]), static_cast<float>(position[1]),
111  static_cast<float>(0)));
112  }
113  break;
114  } else
115  ++k;
116  }
117  }
118 }
119 
120 // Implement Rotation of a 3D particle using parameters from IRotation Object
123 {
124  double alpha = 0.0;
125  double beta = 0.0;
126  double gamma = 0.0;
127 
128  if (auto rotX = dynamic_cast<const RotationX*>(rotation)) {
129  beta = rotX->getAngle(); // about x-axis
130  } else if (auto rotY = dynamic_cast<const RotationY*>(rotation)) {
131  alpha = Units::deg2rad(90.0);
132  beta = rotY->getAngle(); // about y-axis
133  gamma = Units::deg2rad(-90.0);
134  } else if (auto rotZ = dynamic_cast<const RotationZ*>(rotation)) {
135  alpha = rotZ->getAngle(); // about z-axis
136  } else if (auto rotEuler = dynamic_cast<const RotationEuler*>(rotation)) {
137  alpha = rotEuler->getAlpha();
138  beta = rotEuler->getBeta();
139  gamma = rotEuler->getGamma();
140  }
141  return RealSpace::Vector3D(static_cast<float>(alpha), static_cast<float>(beta),
142  static_cast<float>(gamma));
143 }
144 
146  RealSpace::Particles::Particle& particle3D,
147  const kvector_t& origin)
148 {
149  // rotation
150  RealSpace::Vector3D particle_rotate;
151  const IRotation* rotation = particle.rotation();
152 
153  if (rotation)
154  particle_rotate = implementParticleRotationfromIRotation(rotation);
155 
156  // translation
157  float x = static_cast<float>(particle.position().x());
158  float y = static_cast<float>(particle.position().y());
159  float z = static_cast<float>(particle.position().z());
160  RealSpace::Vector3D position(x + static_cast<float>(origin.x()),
161  y + static_cast<float>(origin.y()),
162  z + static_cast<float>(origin.z()));
163 
164  // If the particle belongs to a particle composition, along with the particle's
165  // intrinsic transformations, position() and rotation() methods also account for the
166  // translation and rotation (if present) of the particle composition as the
167  // particleComposition's decompose() method already does this
168 
169  particle3D.addTransform(particle_rotate, position);
170 }
171 
173  const Particle& particle, RealSpace::Particles::Particle& particle3D,
174  const ParticleCoreShell& particleCoreShell, const kvector_t& origin)
175 {
176  std::unique_ptr<Particle> P_clone(particle.clone()); // clone of the current particle
177 
178  // rotation
179  RealSpace::Vector3D particle_rotate;
180  const IRotation* rotationCoreShell = particleCoreShell.rotation();
181 
182  if (rotationCoreShell)
183  P_clone->rotate(*rotationCoreShell);
184 
185  const IRotation* rotation = P_clone->rotation();
186 
187  if (rotation)
188  particle_rotate = implementParticleRotationfromIRotation(rotation);
189 
190  // translation
191  kvector_t positionCoreShell = particleCoreShell.position();
192 
193  P_clone->translate(positionCoreShell);
194 
195  RealSpace::Vector3D position(static_cast<float>(P_clone->position().x() + origin.x()),
196  static_cast<float>(P_clone->position().y() + origin.y()),
197  static_cast<float>(P_clone->position().z() + origin.z()));
198 
199  particle3D.transform(particle_rotate, position);
200 }
201 
203  RealSpace::Particles::Particle& particle3D,
204  double alpha)
205 {
206  // assign correct color to the particle from the knowledge of its material
207  const Material* particle_material = particle.material();
208  QString material_name = QString::fromStdString(particle_material->getName());
209  auto materialItem = AppSvc::materialModel()->materialFromName(material_name);
210  QColor color = materialItem->color();
211  color.setAlphaF(alpha);
212  particle3D.color = color;
213 }
214 
215 std::vector<Particle3DContainer>
217  const QVector3D& origin)
218 {
219  std::vector<Particle3DContainer> particle3DContainer_vector;
220 
221  double total_abundance = computeCumulativeAbundances(layoutItem).last();
222 
223  double cumulative_abundance = 0;
224 
225  for (auto particleItem : layoutItem.getItems(ParticleLayoutItem::T_PARTICLES)) {
226 
227  Particle3DContainer particle3DContainer;
228 
229  if (particleItem->modelType() == "Particle") {
230  auto pItem = dynamic_cast<const ParticleItem*>(particleItem);
231  auto particle = pItem->createParticle();
232  particle3DContainer = singleParticle3DContainer(*particle, total_abundance, origin);
233  } else if (particleItem->modelType() == "ParticleCoreShell") {
234  auto particleCoreShellItem = dynamic_cast<const ParticleCoreShellItem*>(particleItem);
235  // If there is no CORE or SHELL to populate inside ParticleCoreShellItem
236  if (!particleCoreShellItem->getItem(ParticleCoreShellItem::T_CORE)
237  || !particleCoreShellItem->getItem(ParticleCoreShellItem::T_SHELL))
238  continue;
239  auto particleCoreShell = particleCoreShellItem->createParticleCoreShell();
240  particle3DContainer =
241  particleCoreShell3DContainer(*particleCoreShell, total_abundance, origin);
242  } else if (particleItem->modelType() == "ParticleComposition") {
243  auto particleCompositionItem =
244  dynamic_cast<const ParticleCompositionItem*>(particleItem);
245  // If there is no particle to populate inside ParticleCompositionItem
246  if (!particleCompositionItem->getItem(ParticleCompositionItem::T_PARTICLES))
247  continue;
248  auto particleComposition = particleCompositionItem->createParticleComposition();
249  particle3DContainer =
250  particleComposition3DContainer(*particleComposition, total_abundance, origin);
251  } else if (particleItem->modelType() == "ParticleDistribution") {
252  auto particleDistributionItem =
253  dynamic_cast<const ParticleDistributionItem*>(particleItem);
254  // If there is no particle to populate inside ParticleDistributionItem
255  if (!particleDistributionItem->getItem(ParticleDistributionItem::T_PARTICLES))
256  continue;
257  auto particleDistribution = particleDistributionItem->createParticleDistribution();
258  std::vector<Particle3DContainer> pd_ContainerVector =
259  particleDistribution3DContainer(*particleDistribution, total_abundance, origin);
260  for (size_t i = 0; i < pd_ContainerVector.size(); ++i) {
261  cumulative_abundance += pd_ContainerVector[i].cumulativeAbundance();
262  pd_ContainerVector[i].setCumulativeAbundance(cumulative_abundance);
263  particle3DContainer_vector.emplace_back(std::move(pd_ContainerVector[i]));
264  }
265  continue;
266  } else if (particleItem->modelType() == "MesoCrystal") {
267  auto mesoCrystalItem = dynamic_cast<const MesoCrystalItem*>(particleItem);
268  // If there is no particle to populate inside MesoCrystalItem
269  if (!mesoCrystalItem->getItem(MesoCrystalItem::T_BASIS_PARTICLE))
270  continue;
271  particle3DContainer = RealSpaceBuilderUtils::mesoCrystal3DContainer(
272  *mesoCrystalItem, total_abundance, origin);
273  }
274 
275  cumulative_abundance += particle3DContainer.cumulativeAbundance();
276  particle3DContainer.setCumulativeAbundance(cumulative_abundance);
277  particle3DContainer_vector.emplace_back(std::move(particle3DContainer));
278  }
279 
280  return particle3DContainer_vector;
281 }
282 
284  double total_abundance,
285  const QVector3D& origin)
286 {
287  std::unique_ptr<Particle> P_clone(particle.clone()); // clone of the particle
288 
289  std::unique_ptr<const IFormFactor> particleff(P_clone->createFormFactor());
290  auto ff = getUnderlyingFormFactor(particleff.get());
291 
292  auto particle3D = TransformTo3D::createParticlefromIFormFactor(ff);
293  applyParticleTransformations(*P_clone, *particle3D, to_kvector(origin));
294  applyParticleColor(*P_clone, *particle3D);
295 
297  singleParticle3DContainer.addParticle(particle3D.release(), false);
298  singleParticle3DContainer.setCumulativeAbundance(P_clone->abundance() / total_abundance);
300 
302 }
303 
306  double total_abundance, const QVector3D& origin)
307 {
308  // clone of the particleCoreShell
309  std::unique_ptr<ParticleCoreShell> PCS_clone(particleCoreShell.clone());
310 
311  std::unique_ptr<const IFormFactor> coreParticleff(
312  PCS_clone->coreParticle()->createFormFactor());
313  std::unique_ptr<const IFormFactor> shellParticleff(
314  PCS_clone->shellParticle()->createFormFactor());
315 
316  auto coreff = getUnderlyingFormFactor(coreParticleff.get());
317  auto shellff = getUnderlyingFormFactor(shellParticleff.get());
318 
319  auto coreParticle3D = TransformTo3D::createParticlefromIFormFactor(coreff);
320  auto shellParticle3D = TransformTo3D::createParticlefromIFormFactor(shellff);
321 
322  // core
323  applyParticleCoreShellTransformations(*PCS_clone->coreParticle(), *coreParticle3D, *PCS_clone,
324  to_kvector(origin));
325  applyParticleColor(*PCS_clone->coreParticle(), *coreParticle3D);
326 
327  // shell (set an alpha value of 0.5 for transparency)
328  applyParticleCoreShellTransformations(*PCS_clone->shellParticle(), *shellParticle3D, *PCS_clone,
329  to_kvector(origin));
330  applyParticleColor(*PCS_clone->shellParticle(), *shellParticle3D, 0.5);
331 
333 
334  particleCoreShell3DContainer.addParticle(coreParticle3D.release(), false); // index 0
335  particleCoreShell3DContainer.addParticle(shellParticle3D.release(), true); // index 1
336  particleCoreShell3DContainer.setCumulativeAbundance(PCS_clone->abundance() / total_abundance);
337  particleCoreShell3DContainer.setParticleType("ParticleCoreShell");
338 
340 }
341 
343  const ParticleComposition& particleComposition, double total_abundance, const QVector3D& origin)
344 {
345  // clone of the particleComposition
346  std::unique_ptr<ParticleComposition> PC_clone(particleComposition.clone());
347 
348  SafePointerVector<IParticle> pc_vector = PC_clone->decompose();
349 
351 
352  for (const IParticle* pc_particle : pc_vector) {
353  Particle3DContainer particle3DContainer;
354  // no abundances are associated with the individual components of ParticleComposition
355  if (dynamic_cast<const ParticleCoreShell*>(pc_particle)) {
356  auto particleCoreShell = dynamic_cast<const ParticleCoreShell*>(pc_particle);
357  particle3DContainer = particleCoreShell3DContainer(*particleCoreShell, 1.0, origin);
358  } else if (dynamic_cast<const MesoCrystal*>(pc_particle)) {
359  // TODO: Implement method to populate MesoCrystal from CORE and NOT from MesoCrystalItem
360  // as it is done currently in RealSpaceBuilderUtils::mesoCrystal3DContainer
361  std::ostringstream ostr;
362  ostr << "Sorry, MesoCrystal inside ParticleComposition not yet implemented";
363  ostr << "\n\nStay tuned!";
364  throw std::runtime_error(ostr.str());
365  } else {
366  auto particle = dynamic_cast<const Particle*>(pc_particle);
367  particle3DContainer = singleParticle3DContainer(*particle, 1.0, origin);
368  }
369  // add particles from 3Dcontainer of core-shell/particle into particleComposition3DContainer
370  for (size_t i = 0; i < particle3DContainer.containerSize(); ++i) {
372  particle3DContainer.createParticle(i).release(),
373  particle3DContainer.particle3DBlend(i));
374  }
375  }
376  // set the correct abundance for the entire ParticleComposition
377  particleComposition3DContainer.setCumulativeAbundance(PC_clone->abundance() / total_abundance);
378  particleComposition3DContainer.setParticleType("ParticleComposition");
380 }
381 
383  const ParticleDistribution& particleDistribution, double total_abundance,
384  const QVector3D& origin)
385 {
386  auto pd_vector = particleDistribution.generateParticles();
387 
388  std::vector<Particle3DContainer> particleDistribution3DContainer_vector;
389 
390  for (auto pd_particle : pd_vector) {
391  Particle3DContainer particle3DContainer;
392  if (dynamic_cast<const ParticleComposition*>(pd_particle)) {
393  auto particleComposition = dynamic_cast<const ParticleComposition*>(pd_particle);
394  particle3DContainer =
395  particleComposition3DContainer(*particleComposition, total_abundance, origin);
396  } else if (dynamic_cast<const ParticleCoreShell*>(pd_particle)) {
397  auto particleCoreShell = dynamic_cast<const ParticleCoreShell*>(pd_particle);
398  particle3DContainer =
399  particleCoreShell3DContainer(*particleCoreShell, total_abundance, origin);
400  } else if (dynamic_cast<const MesoCrystal*>(pd_particle)) {
401  // TODO: Implement method to populate MesoCrystal from CORE and NOT from MesoCrystalItem
402  // as it is done currently in RealSpaceBuilderUtils::mesoCrystal3DContainer
403  std::ostringstream ostr;
404  ostr << "Sorry, MesoCrystal inside ParticleDistribution not yet implemented";
405  ostr << "\n\nStay tuned!";
406  throw std::runtime_error(ostr.str());
407  } else {
408  auto particle = dynamic_cast<const Particle*>(pd_particle);
409  particle3DContainer = singleParticle3DContainer(*particle, total_abundance, origin);
410  }
411  particleDistribution3DContainer_vector.emplace_back(std::move(particle3DContainer));
412  }
413  return particleDistribution3DContainer_vector;
414 }
415 
418  double total_abundance, const QVector3D& origin)
419 {
420  RealSpaceMesoCrystal mesoCrystalUtils(&mesoCrystalItem, total_abundance, origin);
421 
423 
424  return mesoCrystal3DContainer;
425 }
Defines class AppSvc.
Defines class FormFactorCrystal.
Defines and implements interface class IFormFactorDecorator.
Defines InterferenceFunctionItems's classes.
Includes all interference function definitions.
Defines classes Lattice2DItems.
Defines class LayerItem.
Defines class MaterialItem.
Defines class MaterialModel.
Defines class MesoCrystalItem.
Defines class MesoCrystal.
Defines class MultiLayerItem.
Implements namespace TransformTo3D.
Defines class ParticleCompositionItem.
Defines class ParticleCoreShellItem.
Defines ParticleCoreShell.
Defines class ParticleDistributionItem.
Defines class ParticleItem.
Defines class ParticleLayoutItem.
Defines class Particle.
Defines RealSpaceBuilderUtils namespace.
Defines class RealSpaceBuilder.
Defines class RealSpaceCanvas.
Defines RealSpaceBuilderUtils namespace.
Defines RealSpaceModel namespace.
Defines class RotationItems.
Defines namespace TransformTo3D.
Defines class TransformationItem.
Defines some unit conversion factors and other constants in namespace Units.
Defines class VectorItem.
BasicVector3D< double > kvector_t
Definition: Vectors3D.h:21
static MaterialModel * materialModel()
Definition: AppSvc.cpp:33
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
Encapsulates another formfactor and adds extra functionality (a scalar factor, a position-dependent p...
Abstract base class for all form factors.
Definition: IFormFactor.h:36
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
Abstract base class for rotations.
Definition: Rotations.h:28
QColor color() const
MaterialItem * materialFromName(const QString &name)
A wrapper for underlying material implementation.
Definition: Material.h:29
std::string getName() const
Returns the name of material.
Definition: Material.cpp:66
static const QString T_BASIS_PARTICLE
A particle with an internal structure of smaller particles.
Definition: MesoCrystal.h:25
double cumulativeAbundance() const
void setCumulativeAbundance(double cumulativeAbundance)
std::unique_ptr< RealSpace::Particles::Particle > createParticle(const size_t &index) const
void addParticle(RealSpace::Particles::Particle *particle3D, bool blend)
size_t containerSize() const
void setParticleType(QString particleType)
bool particle3DBlend(const size_t &index) const
static const QString T_PARTICLES
std::unique_ptr< ParticleComposition > createParticleComposition() const
A composition of particles at fixed positions.
ParticleComposition * clone() const final
Returns a clone of this ISampleNode object.
static const QString T_CORE
static const QString T_SHELL
std::unique_ptr< ParticleCoreShell > createParticleCoreShell() const
A particle with a core/shell geometry.
ParticleCoreShell * clone() const final
Returns a clone of this ISampleNode object.
std::unique_ptr< ParticleDistribution > createParticleDistribution() const
static const QString T_PARTICLES
A particle type that is a parametric distribution of IParticle's.
SafePointerVector< IParticle > generateParticles() const
Returns list of new particles generated according to a distribution.
std::unique_ptr< Particle > createParticle() const
static const QString P_ABUNDANCE
Definition: ParticleItem.h:26
static const QString T_PARTICLES
A particle with a form factor and refractive index.
Definition: Particle.h:24
Particle * clone() const final
Returns a clone of this ISampleNode object.
Definition: Particle.cpp:45
const Material * material() const final
Returns nullptr, unless overwritten to return a specific material.
Definition: Particle.h:39
void populateParticleFromParticle3DContainer(RealSpaceModel *model, const Particle3DContainer &particle3DContainer, const QVector3D &lattice_position={}) const
Particle3DContainer populateMesoCrystal()
QColor color
Definition: object.h:34
void addTransform(Vector3D rotate, Vector3D translate)
Definition: particles.cpp:78
void transform(Vector3D rotate, Vector3D translate)
Definition: particles.cpp:68
A sequence of rotations about the z-x'-z'' axes.
Definition: Rotations.h:133
A rotation about the x axis.
Definition: Rotations.h:73
A rotation about the y axis.
Definition: Rotations.h:93
A rotation about the z axis.
Definition: Rotations.h:113
A vector of pointers, owned by *this, with methods to handle them safely.
double layer_top_thickness() const
double layer_bottom_thickness() const
double layer_size() const
QVector< SessionItem * > getItems(const QString &tag="") const
Returns vector of all items of given tag.
QVector< double > computeCumulativeAbundances(const SessionItem &layoutItem)
Particle3DContainer particleCoreShell3DContainer(const ParticleCoreShell &particleCoreShell, double total_abundance=1.0, const QVector3D &origin={})
Particle3DContainer particleComposition3DContainer(const ParticleComposition &particleComposition3DContainer, double total_abundance=1.0, const QVector3D &origin={})
void populateParticlesAtLatticePositions(const std::vector< std::vector< double >> &lattice_positions, const std::vector< Particle3DContainer > &particle3DContainer_vector, RealSpaceModel *model, const SceneGeometry &sceneGeometry, const RealSpaceBuilder *builder3D)
std::vector< Particle3DContainer > particle3DContainerVector(const SessionItem &layoutItem, const QVector3D &origin={})
void applyParticleTransformations(const Particle &particle, RealSpace::Particles::Particle &particle3D, const kvector_t &origin=kvector_t(0, 0, 0))
Apply transformations (translation, rotation) to a 3D Particle or to a particle belonging to a Partic...
std::vector< Particle3DContainer > particleDistribution3DContainer(const ParticleDistribution &particleDistribution, double total_abundance=1.0, const QVector3D &origin={})
void applyParticleCoreShellTransformations(const Particle &particle, RealSpace::Particles::Particle &particle3D, const ParticleCoreShell &particleCoreShell, const kvector_t &origin=kvector_t(0, 0, 0))
Apply transformations (translation, rotation) to a particle (core/shell) in a ParticleCoreShell.
Particle3DContainer mesoCrystal3DContainer(const MesoCrystalItem &mesoCrystalItem, double total_abundance=1.0, const QVector3D &origin={})
RealSpace::Vector3D implementParticleRotationfromIRotation(const IRotation *&rotation)
void applyParticleColor(const Particle &particle, RealSpace::Particles::Particle &particle3D, double alpha=1)
Particle3DContainer singleParticle3DContainer(const Particle &particle, double total_abundance=1.0, const QVector3D &origin={})
std::unique_ptr< RealSpace::Particles::Particle > createParticlefromIFormFactor(const IFormFactor *ff)
double deg2rad(double angle)
Definition: Units.h:59