Mantid
Loading...
Searching...
No Matches
Sample.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7#include "MantidAPI/Sample.h"
18#include <utility>
19
20namespace Mantid::API {
21using namespace Mantid::Kernel;
29
30namespace {
31void saveShapeToFile(Nexus::File *file, const IObject_const_sptr &shape, const std::string &tag = "") {
32 std::string shapeXML;
33 if (auto csgObject = std::dynamic_pointer_cast<const Mantid::Geometry::CSGObject>(shape)) {
34 shapeXML = csgObject->getShapeXML();
35 }
36 file->putAttr(tag + "shape_xml", shapeXML);
37 if (auto meshObject = std::dynamic_pointer_cast<const Mantid::Geometry::MeshObject>(shape)) {
38 meshObject->saveNexus(file, tag + "shape_mesh");
39 }
40 file->putAttr(tag + "shape_id", shape->id());
41}
42
43IObject_sptr loadShapeFromFile(Nexus::File *file, const std::string &tag = "") {
44 Kernel::Material material;
45 IObject_sptr shape;
46 material.loadNexus(file, tag + "material");
47 // Shape (from XML)
48 std::string shape_xml;
49 file->getAttr(tag + "shape_xml", shape_xml);
50 shape_xml = Strings::strip(shape_xml);
51 if (!shape_xml.empty()) {
52 ShapeFactory shapeMaker;
53 shape = shapeMaker.createShape(std::move(shape_xml), false /*Don't wrap with <type> tag*/);
54 } else if (file->hasGroup(tag + "shape_mesh", "NXoff_geometry")) {
55 shape = Mantid::Geometry::MeshObject::loadNexus(file, tag + "shape_mesh", material);
56 } else {
57 // if neither shape xml or shape mesh can be found this should return nullptr to be checked
58 return nullptr;
59 }
60 shape->setMaterial(material);
61 // Restore the shape id if it was saved (absent in older files)
62 if (file->hasAttr(tag + "shape_id")) {
63 std::string id;
64 file->getAttr(tag + "shape_id", id);
65 shape->setID(id);
66 }
67 return shape;
68}
69} // namespace
70
75 : m_name(), m_shape(ShapeFactory().createShape("")), m_environment(), m_lattice(nullptr), m_crystalStructure(),
76 m_samples(), m_geom_id(0), m_thick(0.0), m_height(0.0), m_width(0.0) {}
77
83 : m_name(copy.m_name), m_shape(copy.m_shape), m_environment(copy.m_environment), m_lattice(nullptr),
84 m_crystalStructure(), m_samples(copy.m_samples), m_geom_id(copy.m_geom_id), m_thick(copy.m_thick),
85 m_height(copy.m_height), m_width(copy.m_width) {
86 if (copy.m_lattice)
87 m_lattice = std::make_unique<OrientedLattice>(copy.getOrientedLattice());
88
89 if (copy.hasCrystalStructure()) {
90 m_crystalStructure = std::make_unique<Geometry::CrystalStructure>(copy.getCrystalStructure());
91 }
92}
93
95Sample::~Sample() = default;
96
103 if (this == &rhs)
104 return *this;
105 m_name = rhs.m_name;
106 m_shape = rhs.m_shape;
107 m_environment = rhs.m_environment;
108 m_geom_id = rhs.m_geom_id;
109 m_samples = std::vector<std::shared_ptr<Sample>>(rhs.m_samples);
110 m_thick = rhs.m_thick;
111 m_height = rhs.m_height;
112 m_width = rhs.m_width;
113 if (rhs.m_lattice)
114 m_lattice = std::make_unique<OrientedLattice>(rhs.getOrientedLattice());
115 else
116 m_lattice.reset(nullptr);
117
118 m_crystalStructure.reset();
119 if (rhs.hasCrystalStructure()) {
120 m_crystalStructure.reset(new Geometry::CrystalStructure(rhs.getCrystalStructure()));
121 }
122
123 return *this;
124}
125
130const std::string &Sample::getName() const { return m_name; }
131
136void Sample::setName(const std::string &name) { m_name = name; }
137
138bool Sample::hasShape() const { return (m_shape != nullptr); }
139
146const IObject &Sample::getShape() const { return *m_shape; }
147
154const IObject_sptr Sample::getShapePtr() const { return m_shape; }
155
160void Sample::setShape(const IObject_sptr &shape) {
161 if (!shape) {
163 } else if (shape != m_shape) {
164 m_shape = shape; // share ownership safely
165 }
166}
167
171const Material &Sample::getMaterial() const { return m_shape->material(); }
172
173bool Sample::hasEnvironment() const { return (m_environment != nullptr); }
174
181 if (!m_environment) {
182 throw std::runtime_error("Sample::getEnvironment - No sample enviroment has been defined.");
183 }
184 return *m_environment;
185}
186
192void Sample::setEnvironment(std::shared_ptr<SampleEnvironment> env) { m_environment = std::move(env); }
193
199 if (!m_lattice) {
200 throw std::runtime_error("Sample::getOrientedLattice - No OrientedLattice has been defined.");
201 }
202 return *m_lattice;
203}
204
210 if (!m_lattice) {
211 throw std::runtime_error("Sample::getOrientedLattice - No OrientedLattice has been defined.");
212 }
213 return *m_lattice;
214}
215
220void Sample::setOrientedLattice(std::unique_ptr<Geometry::OrientedLattice> lattice) { m_lattice = std::move(lattice); }
221
223bool Sample::hasOrientedLattice() const { return (m_lattice != nullptr); }
224
226 if (!hasCrystalStructure()) {
227 throw std::runtime_error("Sample::getCrystalStructure - No CrystalStructure has been defined.");
228 }
229
230 return *m_crystalStructure;
231}
232
235 m_crystalStructure.reset(new Geometry::CrystalStructure(newCrystalStructure));
236}
237
240 // Conversion to bool seems to be a problem in VS2012, so this is a bit more
241 // verbose than it should be.
242 return static_cast<bool>(m_crystalStructure);
243}
244
247
253void Sample::setGeometryFlag(int geom_id) { m_geom_id = geom_id; }
254
260int Sample::getGeometryFlag() const { return m_geom_id; }
261
266void Sample::setThickness(double thick) { m_thick = thick; }
267
272double Sample::getThickness() const { return m_thick; }
273
279
284double Sample::getHeight() const { return m_height; }
285
290void Sample::setWidth(double width) { m_width = width; }
291
296double Sample::getWidth() const { return m_width; }
297
304 if (index == 0) {
305 return *this;
306 } else if ((static_cast<std::size_t>(index) > m_samples.size()) || (index < 0)) {
307 throw std::out_of_range("The index value provided was out of range");
308 } else {
309 return *m_samples[index - 1];
310 }
311}
312
317std::size_t Sample::size() const { return m_samples.size() + 1; }
318
323void Sample::addSample(const std::shared_ptr<Sample> &childSample) { m_samples.emplace_back(childSample); }
324
325//--------------------------------------------------------------------------------------------
330void Sample::saveNexus(Nexus::File *file, const std::string &group) const {
331 file->makeGroup(group, "NXsample", true);
332 file->putAttr("name", m_name);
333 if (m_name.empty()) {
334 file->putAttr("name_empty", 1);
335 }
336 file->putAttr("version", 1);
337 saveShapeToFile(file, m_shape);
338 m_shape->material().saveNexus(file, "material");
339
340 // Write out the other (indexes 1+) samples
341 file->writeData("num_other_samples", int(m_samples.size()));
342 for (size_t i = 0; i < m_samples.size(); i++)
343 m_samples[i]->saveNexus(file, "sample" + Strings::toString(i + 1));
344
345 if (m_environment) {
346 file->putAttr("env_name", m_environment->name());
347 auto const nElem = m_environment->nelements();
348 file->writeData("num_env_comp", int(nElem));
349 for (size_t i = 0; i < nElem; ++i) {
350 const std::string tag = "env_" + Strings::toString(i) + "_";
351 // Component 0 is the Container wrapper; save its inner shape so it can be
352 // re-wrapped on load. Other components are stored as plain shapes.
353 IObject_const_sptr comp =
354 (i == 0) ? m_environment->getContainer().getShapePtr() : m_environment->getComponentPtr(i);
355 saveShapeToFile(file, comp, tag);
356 comp->material().saveNexus(file, tag + "material");
357 }
358 }
359
360 // OrientedLattice
361 if (hasOrientedLattice()) {
362 file->writeData("num_oriented_lattice", 1);
363 m_lattice->saveNexus(file, "oriented_lattice");
364 } else
365 file->writeData("num_oriented_lattice", 0);
366
367 // Legacy info from RAW file (I think)
368 file->writeData("geom_id", m_geom_id);
369 file->writeData("geom_thickness", m_thick);
370 file->writeData("geom_height", m_height);
371 file->writeData("geom_width", m_width);
372
373 file->closeGroup();
374}
375
376//--------------------------------------------------------------------------------------------
382int Sample::loadNexus(Nexus::File *file, const std::string &group) {
383 file->openGroup(group, "NXsample");
384
385 // Version 0 = saveNexusProcessed before Sep 8, 2011
386 int version = 0;
387 if (file->hasAttr("version")) {
388 file->getAttr("version", version);
389 } else {
390 version = 0;
391 }
392
393 if (version == 0) {
394 // Sample NAME field may/may not be present
395 if (file->hasData("name")) {
396 file->readData("name", m_name);
397 } else {
398 m_name = "";
399 }
400 }
401
402 if (version > 0) {
403 // Name is an attribute
404 file->getAttr("name", m_name);
405 if (file->hasAttr("name_empty")) {
406 int isEmpty;
407 file->getAttr("name_empty", isEmpty);
408 if (isEmpty) {
409 m_name.clear();
410 }
411 }
412
413 // Only replace the default shape if the file actually defines one; otherwise
414 // keep the valid (empty) shape so callers never observe a null m_shape.
415 if (IObject_sptr loadedShape = loadShapeFromFile(file))
416 m_shape = std::move(loadedShape);
417
418 // sample environment
419 if (file->hasAttr("env_name")) {
420 std::string env_name;
421 file->getAttr("env_name", env_name);
422
423 int nElem;
424 file->readData("num_env_comp", nElem);
425 // component 0 is the container; without a valid shape there is no environment to build
426 if (IObject_sptr container_shape = (nElem > 0) ? loadShapeFromFile(file, "env_0_") : nullptr) {
427 auto env = std::make_shared<SampleEnvironment>(env_name, std::make_shared<Container>(container_shape));
428 for (int i = 1; i < nElem; ++i) {
429 const std::string tag = "env_" + Strings::toString(i) + "_";
430 if (IObject_sptr comp = loadShapeFromFile(file, tag))
431 env->add(comp);
432 }
433 m_environment = std::move(env);
434 }
435 }
436
437 // Load other samples
438 int num_other_samples;
439 file->readData("num_other_samples", num_other_samples);
440 for (int i = 0; i < num_other_samples; i++) {
441 auto extra = std::make_shared<Sample>();
442 extra->loadNexus(file, "sample" + Strings::toString(i + 1));
443 this->addSample(extra);
444 }
445
446 // OrientedLattice
447 int num_oriented_lattice;
448 file->readData("num_oriented_lattice", num_oriented_lattice);
449 if (num_oriented_lattice > 0) {
450 m_lattice = std::make_unique<OrientedLattice>();
451 m_lattice->loadNexus(file, "oriented_lattice");
452 }
453 }
454
455 try {
456 // Legacy info from RAW file (I think)
457 file->readData("geom_id", m_geom_id);
458 file->readData("geom_thickness", m_thick);
459 file->readData("geom_height", m_height);
460 file->readData("geom_width", m_width);
461 } catch (...) { /* Very old files don't have them. Ignore. */
462 }
463
464 file->closeGroup();
465
466 return version;
467}
468
473 if (m_lattice) {
474 m_lattice.reset(nullptr);
475 }
476}
477
478bool Sample::operator==(const Sample &other) const {
479 if (m_samples.size() != other.m_samples.size())
480 return false;
481 for (size_t i = 0; i < m_samples.size(); ++i) {
482 if (*m_samples[i] != *other.m_samples[i])
483 return false;
484 }
485 auto compare = [](const auto &a, const auto &b, auto call_on) {
486 // both null or both not null
487 if (bool(a) ^ bool(b))
488 return false;
489 if (a)
490 return call_on(a) == call_on(b);
491 else
492 return true;
493 };
494 return *m_lattice == *other.m_lattice && this->m_name == other.m_name && this->m_height == other.m_height &&
495 this->m_width == other.m_width && this->m_thick == other.m_thick && m_geom_id == other.m_geom_id &&
496 compare(m_environment, other.m_environment, [](const auto &x) { return x->name(); }) &&
497 compare(m_shape, other.m_shape, [](const auto &x) { return x->shape(); }) &&
498 compare(m_crystalStructure, other.m_crystalStructure, [](const auto &x) { return *(x->spaceGroup()); });
499}
500bool Sample::operator!=(const Sample &other) const { return !this->operator==(other); }
501} // namespace Mantid::API
std::string name
Definition Run.cpp:60
const std::vector< double > & rhs
double height
Definition GetAllEi.cpp:155
std::map< DeltaEMode::Type, std::string > index
This class stores information about the sample used in particular run.
Definition Sample.h:33
void setShape(const Geometry::IObject_sptr &shape)
Update the shape of the object.
Definition Sample.cpp:160
double m_width
The sample width from the SPB_STRUCT in the raw file.
Definition Sample.h:148
double m_thick
The sample thickness from the SPB_STRUCT in the raw file.
Definition Sample.h:144
void clearOrientedLattice()
Delete the oriented lattice.
Definition Sample.cpp:472
const Kernel::Material & getMaterial() const
Return the material (convenience method)
Definition Sample.cpp:171
std::string m_name
The sample name.
Definition Sample.h:127
bool hasEnvironment() const
Definition Sample.cpp:173
int loadNexus(Nexus::File *file, const std::string &group)
Load the object from an open NeXus file.
Definition Sample.cpp:382
void saveNexus(Nexus::File *file, const std::string &group) const
Save the object to an open NeXus file.
Definition Sample.cpp:330
const std::string & getName() const
Returns the name of the sample.
Definition Sample.cpp:130
const Geometry::IObject & getShape() const
Return the sample shape.
Definition Sample.cpp:146
bool operator!=(const Sample &other) const
Definition Sample.cpp:500
void setEnvironment(std::shared_ptr< Geometry::SampleEnvironment > env)
Set the environment used to contain the sample.
Definition Sample.cpp:192
int getGeometryFlag() const
Returns the geometry flag.
Definition Sample.cpp:260
void setOrientedLattice(std::unique_ptr< Geometry::OrientedLattice > lattice)
Set the pointer to OrientedLattice defining the sample's lattice and orientation.
Definition Sample.cpp:220
Sample & operator[](const int index)
index operator for accessing multiple samples
Definition Sample.cpp:303
std::unique_ptr< Geometry::OrientedLattice > m_lattice
Pointer to the OrientedLattice of the sample, NULL if not set.
Definition Sample.h:133
const Geometry::OrientedLattice & getOrientedLattice() const
Get a reference to the sample's OrientedLattice.
Definition Sample.cpp:198
void addSample(const std::shared_ptr< Sample > &childSample)
Adds a sample to the list.
Definition Sample.cpp:323
std::shared_ptr< Geometry::SampleEnvironment > m_environment
An owned pointer to the SampleEnvironment object.
Definition Sample.h:131
void setCrystalStructure(const Geometry::CrystalStructure &newCrystalStructure)
Resets the internal pointer to the new CrystalStructure (it's copied).
Definition Sample.cpp:234
bool hasOrientedLattice() const
Definition Sample.cpp:223
~Sample()
Destructor.
std::unique_ptr< Geometry::CrystalStructure > m_crystalStructure
CrystalStructure of the sample.
Definition Sample.h:136
void setGeometryFlag(int geom_id)
Sets the geometry flag.
Definition Sample.cpp:253
void setName(const std::string &name)
Set the name of the sample.
Definition Sample.cpp:136
Sample()
Default constructor.
Definition Sample.cpp:74
std::size_t size() const
the number of samples
Definition Sample.cpp:317
std::vector< std::shared_ptr< Sample > > m_samples
Vector of child samples.
Definition Sample.h:139
void setWidth(double width)
Sets the width.
Definition Sample.cpp:290
double getWidth() const
Returns the width.
Definition Sample.cpp:296
bool hasCrystalStructure() const
Returns true if the sample actually holds a CrystalStructure.
Definition Sample.cpp:239
void setHeight(double height)
Sets the height.
Definition Sample.cpp:278
int m_geom_id
The sample geometry flag.
Definition Sample.h:142
double getHeight() const
Returns the height.
Definition Sample.cpp:284
void clearCrystalStructure()
Destroys the internally stored CrystalStructure-object.
Definition Sample.cpp:246
double m_height
The sample height from the SPB_STRUCT in the raw file.
Definition Sample.h:146
Geometry::IObject_sptr m_shape
The sample shape object.
Definition Sample.h:129
const Geometry::SampleEnvironment & getEnvironment() const
Get a reference to the sample's environment.
Definition Sample.cpp:180
Sample & operator=(const Sample &rhs)
Assignment operator.
Definition Sample.cpp:102
void setThickness(double thick)
Sets the thickness.
Definition Sample.cpp:266
const Geometry::CrystalStructure & getCrystalStructure() const
Definition Sample.cpp:225
double getThickness() const
Returns the thickness.
Definition Sample.cpp:272
bool operator==(const Sample &other) const
Definition Sample.cpp:478
const Geometry::IObject_sptr getShapePtr() const
Return a pointer to the sample shape.
Definition Sample.cpp:154
bool hasShape() const
Check if sample has a valid shape.
Definition Sample.cpp:138
Models a Container is used to hold a sample in the beam.
Definition Container.h:24
Three components are required to describe a crystal structure:
IObject : Interface for geometry objects.
Definition IObject.h:42
static std::shared_ptr< MeshObject > loadNexus(Nexus::File *file, const std::string &group, const Kernel::Material &material)
Load mesh from an NXoff_geometry group in a NeXus file.
Class to implement UB matrix.
Defines a single instance of a SampleEnvironment.
Class originally intended to be used with the DataHandling 'LoadInstrument' algorithm.
std::shared_ptr< CSGObject > createShape(Poco::XML::Element *pElem)
Creates a geometric object from a DOM-element-node pointing to an element whose child nodes contain t...
A material is defined as being composed of a given element, defined as a PhysicalConstants::NeutronAt...
Definition Material.h:50
void loadNexus(Nexus::File *file, const std::string &group)
Load the object from an open NeXus file.
Definition Material.cpp:544
bool compare(const mypair &left, const mypair &right)
std::shared_ptr< const IObject > IObject_const_sptr
Typdef for a shared pointer to a const object.
Definition IObject.h:95
std::shared_ptr< IObject > IObject_sptr
Typdef for a shared pointer.
Definition IObject.h:93
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
Definition Strings.cpp:419
std::string toString(const T &value)
Convert a number to a string.
Definition Strings.cpp:734