Mantid
Loading...
Searching...
No Matches
SetSample.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 +
8
10#include "MantidAPI/Run.h"
11#include "MantidAPI/Sample.h"
24#include "MantidKernel/Logger.h"
27#include "MantidKernel/Matrix.h"
30
31#include <boost/algorithm/string/case_conv.hpp>
32#include <boost/algorithm/string/predicate.hpp>
33#include <filesystem>
34
35namespace Mantid::DataHandling {
36
37using API::ExperimentInfo;
39using Geometry::Container;
40using Geometry::Goniometer;
41using Geometry::ReferenceFrame;
42using Geometry::SampleEnvironment;
43using Geometry::ShapeFactory;
44using Kernel::Logger;
45using Kernel::MaterialBuilder;
46using Kernel::PropertyManager;
48using Kernel::PropertyWithValue;
49using Kernel::V3D;
50
51namespace {
52constexpr double CUBIC_METRE_TO_CM = 100. * 100. * 100.;
53constexpr double degToRad(const double x) { return x * M_PI / 180.; }
54
56namespace PropertyNames {
58const std::string INPUT_WORKSPACE("InputWorkspace");
60const std::string GEOMETRY("Geometry");
62const std::string MATERIAL("Material");
64const std::string ENVIRONMENT("Environment");
66const std::string CONTAINER_GEOMETRY("ContainerGeometry");
68const std::string CONTAINER_MATERIAL("ContainerMaterial");
69} // namespace PropertyNames
71namespace SEArgs {
73const std::string NAME("Name");
75const std::string CONTAINER("Container");
77const std::string PATH("Path");
78} // namespace SEArgs
80namespace GeometryArgs {
82const std::string SHAPE("Shape");
84const std::string VALUE("Value");
85} // namespace GeometryArgs
86
88namespace ShapeArgs {
90const std::string FLAT_PLATE("FlatPlate");
92const std::string CYLINDER("Cylinder");
94const std::string HOLLOW_CYLINDER("HollowCylinder");
96const std::string SPHERE("Sphere");
98const std::string FLAT_PLATE_HOLDER("FlatPlateHolder");
100const std::string HOLLOW_CYLINDER_HOLDER("HollowCylinderHolder");
102const std::string CSG("CSG");
104const std::string WIDTH("Width");
106const std::string HEIGHT("Height");
108const std::string THICK("Thick");
110const std::string FRONT_THICK("FrontThick");
112const std::string BACK_THICK("BackThick");
114const std::string AXIS("Axis");
116const std::string ANGLE("Angle");
118const std::string CENTER("Center");
120const std::string RADIUS("Radius");
122const std::string INNER_RADIUS("InnerRadius");
124const std::string OUTER_RADIUS("OuterRadius");
126const std::string INNER_OUTER_RADIUS("InnerOuterRadius");
128const std::string OUTER_INNER_RADIUS("OuterInnerRadius");
129} // namespace ShapeArgs
130
138V3D cylBaseCentre(const std::vector<double> &cylCentre, double height, unsigned axisIdx) {
139 const V3D halfHeight = [&]() {
140 switch (axisIdx) {
141 case 0:
142 return V3D(0.5 * height, 0, 0);
143 case 1:
144 return V3D(0, 0.5 * height, 0);
145 case 2:
146 return V3D(0, 0, 0.5 * height);
147 default:
148 return V3D();
149 }
150 }();
151 return V3D(cylCentre[0], cylCentre[1], cylCentre[2]) - halfHeight;
152}
153
161V3D cylBaseCentre(const std::vector<double> &cylCentre, double height, const std::vector<double> &axis) {
162 using Kernel::V3D;
163 V3D axisVector = V3D{axis[0], axis[1], axis[2]};
164 axisVector.normalize();
165 return V3D(cylCentre[0], cylCentre[1], cylCentre[2]) - axisVector * height * 0.5;
166}
167
173std::string axisXML(unsigned axisIdx) {
174 switch (axisIdx) {
175 case 0:
176 return R"(<axis x="1" y="0" z="0" />)";
177 case 1:
178 return R"(<axis x="0" y="1" z="0" />)";
179 case 2:
180 return R"(<axis x="0" y="0" z="1" />)";
181 default:
182 return "";
183 }
184}
185
191std::string axisXML(const std::vector<double> &axis) {
192 std::ostringstream str;
193 str << "<axis x=\"" << axis[0] << "\" y=\"" << axis[1] << "\" z=\"" << axis[2] << "\" /> ";
194 return str.str();
195}
196
205double getPropertyAsDouble(const Kernel::PropertyManager &args, const std::string &name) {
206 return std::stod(args.getPropertyValue(name));
207}
208
217std::vector<double> getPropertyAsVectorDouble(const Kernel::PropertyManager &args, const std::string &name) {
218 std::string vectorAsString = args.getPropertyValue(name);
219 std::vector<double> vectorOfDoubles;
220 std::stringstream ss(vectorAsString);
221 std::string elementAsString;
222 while (std::getline(ss, elementAsString, ',')) {
223 vectorOfDoubles.push_back(std::stod(elementAsString));
224 }
225 return vectorOfDoubles;
226}
227
234bool existsAndNotEmptyString(const PropertyManager &pm, const std::string &name) {
235 if (pm.existsProperty(name)) {
236 const auto value = pm.getPropertyValue(name);
237 return !value.empty();
238 }
239 return false;
240}
241
248bool existsAndNegative(const PropertyManager &pm, const std::string &name) {
249 if (pm.existsProperty(name)) {
250 const auto value = pm.getPropertyValue(name);
251 if (boost::lexical_cast<double>(value) < 0.0) {
252 return true;
253 }
254 }
255 return false;
256}
257
258} // namespace
259
260// Register the algorithm into the AlgorithmFactory
261DECLARE_ALGORITHM(SetSample)
262
263
264const std::string SetSample::name() const { return "SetSample"; }
265
267int SetSample::version() const { return 1; }
268
270const std::string SetSample::category() const { return "Sample"; }
271
273const std::string SetSample::summary() const {
274 return "Set properties of the sample and its environment for a workspace";
275}
276
283void SetSample::validateGeometry(std::map<std::string, std::string> &errors, const Kernel::PropertyManager &geomArgs,
284 const std::string &flavour) {
285
286 // Validate as much of the shape information as possible
287 if (existsAndNotEmptyString(geomArgs, GeometryArgs::SHAPE)) {
288 auto shape = geomArgs.getPropertyValue(GeometryArgs::SHAPE);
289 if (shape == ShapeArgs::CSG) {
290 if (!existsAndNotEmptyString(geomArgs, GeometryArgs::VALUE)) {
291 errors[flavour] = "For " + shape + " shape " + GeometryArgs::VALUE + " is required";
292 } else {
293 // check if the value is a valid shape XML
294 ShapeFactory shapeFactory;
295 auto shapeFromValue = shapeFactory.createShape(geomArgs.getPropertyValue(GeometryArgs::VALUE));
296 if (!shapeFromValue || !shapeFromValue->hasValidShape()) {
297 errors[flavour] = "Invalid XML for CSG shape value";
298 }
299 }
300 } else {
301 if (shape == ShapeArgs::FLAT_PLATE || shape == ShapeArgs::FLAT_PLATE_HOLDER) {
302 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::WIDTH)) {
303 errors[flavour] = "For " + shape + " shape " + ShapeArgs::WIDTH + " is required";
304 }
305 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::THICK)) {
306 errors[flavour] = "For " + shape + " shape " + ShapeArgs::THICK + " is required";
307 }
308 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::HEIGHT)) {
309 errors[flavour] = "For " + shape + " shape " + ShapeArgs::HEIGHT + " is required";
310 }
311 }
312 if (shape == ShapeArgs::CYLINDER) {
313 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::RADIUS)) {
314 errors[flavour] = "For " + shape + " shape " + ShapeArgs::RADIUS + " is required";
315 }
316 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::HEIGHT)) {
317 errors[flavour] = "For " + shape + " shape " + ShapeArgs::HEIGHT + " is required";
318 }
319 }
320 if (shape == ShapeArgs::HOLLOW_CYLINDER || shape == ShapeArgs::HOLLOW_CYLINDER_HOLDER) {
321 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::INNER_RADIUS)) {
322 errors[flavour] = "For " + shape + " shape " + ShapeArgs::INNER_RADIUS + " is required";
323 }
324 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::OUTER_RADIUS)) {
325 errors[flavour] = "For " + shape + " shape " + ShapeArgs::OUTER_RADIUS + " is required";
326 }
327 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::HEIGHT)) {
328 errors[flavour] = "For " + shape + " shape " + ShapeArgs::HEIGHT + " is required";
329 }
330 }
331 if (shape == ShapeArgs::FLAT_PLATE_HOLDER) {
332 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::WIDTH)) {
333 errors[flavour] = "For " + shape + " shape " + ShapeArgs::WIDTH + " is required";
334 }
335 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::FRONT_THICK)) {
336 errors[flavour] = "For " + shape + " shape " + ShapeArgs::FRONT_THICK + " is required";
337 }
338 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::BACK_THICK)) {
339 errors[flavour] = "For " + shape + " shape " + ShapeArgs::BACK_THICK + " is required";
340 }
341 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::HEIGHT)) {
342 errors[flavour] = "For " + shape + " shape " + ShapeArgs::HEIGHT + " is required";
343 }
344 }
345 if (shape == ShapeArgs::HOLLOW_CYLINDER_HOLDER) {
346 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::INNER_OUTER_RADIUS)) {
347 errors[flavour] = "For " + shape + " shape " + ShapeArgs::INNER_OUTER_RADIUS + " is required";
348 }
349 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::OUTER_INNER_RADIUS)) {
350 errors[flavour] = "For " + shape + " shape " + ShapeArgs::OUTER_INNER_RADIUS + " is required";
351 }
352 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::HEIGHT)) {
353 errors[flavour] = "For " + shape + " shape " + ShapeArgs::HEIGHT + " is required";
354 }
355 }
356 if (shape == ShapeArgs::SPHERE) {
357 if (!existsAndNotEmptyString(geomArgs, ShapeArgs::RADIUS)) {
358 errors[flavour] = "For " + shape + " shape " + ShapeArgs::RADIUS + " is required";
359 }
360 }
361 }
362 } else {
363 errors[flavour] = GeometryArgs::SHAPE + " is required";
364 }
365}
366
373void SetSample::validateMaterial(std::map<std::string, std::string> &errors, const Kernel::PropertyManager &inputArgs,
374 const std::string &flavour) {
377 setMaterial(materialParams, args);
378 auto materialErrors = ReadMaterial::validateInputs(materialParams);
379 if (!materialErrors.empty()) {
380 std::stringstream ss;
381 for (const auto &error : materialErrors) {
382 ss << error.first << ":" << error.second << "\n";
383 }
384 errors[flavour] = ss.str();
385 }
386}
387
395void SetSample::assertNonNegative(std::map<std::string, std::string> &errors, const Kernel::PropertyManager &geomArgs,
396 const std::string &flavour, const std::vector<const std::string *> &keys) {
397 if (existsAndNotEmptyString(geomArgs, GeometryArgs::SHAPE)) {
398 for (const auto &arg : keys) {
399 if (existsAndNegative(geomArgs, *arg)) {
400 errors[flavour] = *arg + " argument < 0.0";
401 }
402 }
403 }
404}
405
411 bool isPopulated = false;
412 if (dict)
413 if (dict->propertyCount() > 0)
414 isPopulated = true;
415 return isPopulated;
416}
417
419std::map<std::string, std::string> SetSample::validateInputs() {
420 std::map<std::string, std::string> errors;
421 // Check workspace type has ExperimentInfo fields
424 Workspace_sptr inputWS = getProperty(PropertyNames::INPUT_WORKSPACE);
425 if (!std::dynamic_pointer_cast<ExperimentInfo>(inputWS)) {
426 errors[PropertyNames::INPUT_WORKSPACE] = "InputWorkspace type invalid. "
427 "Expected MatrixWorkspace, "
428 "PeaksWorkspace.";
429 }
430
431 const PropertyManager_const_sptr geomArgs = getProperty(PropertyNames::GEOMETRY);
432
433 const PropertyManager_const_sptr materialArgs = getProperty(PropertyNames::MATERIAL);
434
435 const PropertyManager_const_sptr environArgs = getProperty(PropertyNames::ENVIRONMENT);
436
437 const PropertyManager_const_sptr canGeomArgs = getProperty(PropertyNames::CONTAINER_GEOMETRY);
438
439 const PropertyManager_const_sptr canMaterialArgs = getProperty(PropertyNames::CONTAINER_MATERIAL);
440
441 const std::vector<const std::string *> positiveValues = {{&ShapeArgs::HEIGHT, &ShapeArgs::WIDTH, &ShapeArgs::THICK,
442 &ShapeArgs::RADIUS, &ShapeArgs::INNER_RADIUS,
443 &ShapeArgs::OUTER_RADIUS}};
444
445 if (!isDictionaryPopulated(geomArgs) && !isDictionaryPopulated(materialArgs) && !isDictionaryPopulated(environArgs) &&
446 !isDictionaryPopulated(canGeomArgs) && !isDictionaryPopulated(canMaterialArgs)) {
447 errors["Geometry"] = "At least one of the input parameters must be populated";
448 }
449
450 if (isDictionaryPopulated(environArgs)) {
451 if (!existsAndNotEmptyString(*environArgs, SEArgs::NAME)) {
452 errors[PropertyNames::ENVIRONMENT] = "Environment flags require a non-empty 'Name' entry.";
453 } else {
454 // If specifying the environment through XML file, we can not strictly
455 // validate the sample settings, since only the overriding properties
456 // are specified. Hence we just make sure that whatever is specified is
457 // at least positive
458 if (isDictionaryPopulated(geomArgs)) {
459 assertNonNegative(errors, *geomArgs, PropertyNames::GEOMETRY, positiveValues);
460 }
461 }
462 } else {
463 // We cannot strictly require geometry and material to be defined
464 // simultaneously; it can be that one is defined at a later time
465 if (isDictionaryPopulated(geomArgs)) {
466 assertNonNegative(errors, *geomArgs, PropertyNames::GEOMETRY, positiveValues);
467 validateGeometry(errors, *geomArgs, PropertyNames::GEOMETRY);
468 }
469 if (isDictionaryPopulated(materialArgs)) {
470 validateMaterial(errors, *materialArgs, PropertyNames::MATERIAL);
471 }
472 }
473 if (isDictionaryPopulated(canGeomArgs)) {
474 assertNonNegative(errors, *canGeomArgs, PropertyNames::CONTAINER_GEOMETRY, positiveValues);
475 validateGeometry(errors, *canGeomArgs, PropertyNames::CONTAINER_GEOMETRY);
476 }
477
478 if (isDictionaryPopulated(canMaterialArgs)) {
479 validateMaterial(errors, *canMaterialArgs, PropertyNames::CONTAINER_MATERIAL);
480 }
481 return errors;
482}
483
488 using API::Workspace;
490 using Kernel::Direction;
492
493 // Inputs
494 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>(PropertyNames::INPUT_WORKSPACE, "", Direction::InOut),
495 "A workspace whose sample properties will be updated");
496 declareProperty(std::make_unique<PropertyManagerProperty>(PropertyNames::GEOMETRY, Direction::Input),
497 "A dictionary of geometry parameters for the sample.");
498 declareProperty(std::make_unique<PropertyManagerProperty>(PropertyNames::MATERIAL, Direction::Input),
499 "A dictionary of material parameters for the sample. See "
500 "SetSampleMaterial for all accepted parameters");
501 declareProperty(std::make_unique<PropertyManagerProperty>(PropertyNames::ENVIRONMENT, Direction::Input),
502 "A dictionary of parameters to configure the sample environment");
503 declareProperty(std::make_unique<PropertyManagerProperty>(PropertyNames::CONTAINER_GEOMETRY, Direction::Input),
504 "A dictionary of geometry parameters for the container.");
505 declareProperty(std::make_unique<PropertyManagerProperty>(PropertyNames::CONTAINER_MATERIAL, Direction::Input),
506 "A dictionary of material parameters for the container.");
507}
508
515
516 Workspace_sptr workspace = getProperty(PropertyNames::INPUT_WORKSPACE);
517 PropertyManager_sptr environArgs = getProperty(PropertyNames::ENVIRONMENT);
518 PropertyManager_sptr geometryArgs = getProperty(PropertyNames::GEOMETRY);
519 PropertyManager_sptr materialArgs = getProperty(PropertyNames::MATERIAL);
520 PropertyManager_sptr canGeometryArgs = getProperty(PropertyNames::CONTAINER_GEOMETRY);
521 PropertyManager_sptr canMaterialArgs = getProperty(PropertyNames::CONTAINER_MATERIAL);
522
523 // validateInputs guarantees this will be an ExperimentInfo object
524 auto experimentInfo = std::dynamic_pointer_cast<ExperimentInfo>(workspace);
525 // The order here is important. Set the environment first. If this
526 // defines a sample geometry then we can process the Geometry flags
527 // combined with this
528 const SampleEnvironment *sampleEnviron(nullptr);
529 if (isDictionaryPopulated(environArgs)) {
530 sampleEnviron = setSampleEnvironmentFromFile(*experimentInfo, environArgs);
531 } else if (isDictionaryPopulated(canGeometryArgs)) {
532 setSampleEnvironmentFromXML(*experimentInfo, canGeometryArgs, canMaterialArgs);
533 }
534
535 double sampleVolume = 0.;
536 if (isDictionaryPopulated(geometryArgs) || sampleEnviron) {
537 setSampleShape(*experimentInfo, geometryArgs, sampleEnviron);
538 if (experimentInfo->sample().getShape().hasValidShape()) {
539 // get the volume back out to use in setting the material
540 sampleVolume = CUBIC_METRE_TO_CM * experimentInfo->sample().getShape().volume();
541 }
542 }
543
544 // Finally the material arguments
545 if (isDictionaryPopulated(materialArgs)) {
546 PropertyManager materialArgsCompatible = materialSettingsEnsureLegacyCompatibility(*materialArgs);
547 // add the sample volume if it was defined/determined
548 if (sampleVolume > 0.) {
549 // only add the volume if it isn't already specfied
550 if (!materialArgsCompatible.existsProperty("Volume")) {
551 materialArgsCompatible.declareProperty(std::make_unique<PropertyWithValue<double>>("Volume", sampleVolume));
552 }
553 }
554 // this does what SetSampleMaterial would do, but without calling it
556 setMaterial(materialParams, materialArgsCompatible);
557 ReadMaterial reader;
558 reader.setMaterialParameters(materialParams);
559 const auto sampleMaterial = reader.buildMaterial();
560 auto shapeObject =
561 std::shared_ptr<Geometry::IObject>(experimentInfo->sample().getShape().cloneWithMaterial(*sampleMaterial));
562 experimentInfo->mutableSample().setShape(shapeObject);
563 }
564}
565
576
577 const std::string envName = args->getPropertyValue(SEArgs::NAME);
578 std::string canName = "";
579 if (args->existsProperty(SEArgs::CONTAINER)) {
580 canName = args->getPropertyValue(SEArgs::CONTAINER);
581 }
582 // The specifications need to be qualified by the facility and instrument.
583 // Check instrument for name and then lookup facility if facility
584 // is unknown then set to default facility & instrument.
585 auto instrument = exptInfo.getInstrument();
586 const auto &instOnWS = instrument->getName();
587 const auto &config = ConfigService::Instance();
588 std::string facilityName, instrumentName;
589 try {
590 const auto &instInfo = config.getInstrument(instOnWS);
591 instrumentName = instInfo.name();
592 facilityName = instInfo.facility().name();
593 } catch (std::runtime_error &) {
594 // use default facility/instrument
595 facilityName = config.getFacility().name();
596 instrumentName = config.getInstrument().name();
597 }
598
599 const auto &instDirs = config.getInstrumentDirectories();
600 std::vector<std::string> environDirs(instDirs);
601 for (auto &direc : environDirs) {
602 direc = (std::filesystem::path(direc) / "sampleenvironments").string();
603 }
604 auto finder = std::make_unique<SampleEnvironmentSpecFileFinder>(environDirs);
605 SampleEnvironmentFactory factory(std::move(finder));
607 if (args->existsProperty(SEArgs::PATH)) {
608 auto sampleEnvironSpec = factory.parseSpec(envName, args->getPropertyValue(SEArgs::PATH));
609 sampleEnviron = sampleEnvironSpec->buildEnvironment(canName);
610 } else {
611 sampleEnviron = factory.create(facilityName, instrumentName, envName, canName);
612 }
613 exptInfo.mutableSample().setEnvironment(std::move(sampleEnviron));
614 return &(exptInfo.sample().getEnvironment());
615}
616
626 const Kernel::PropertyManager_const_sptr &canGeomArgs,
627 const Kernel::PropertyManager_const_sptr &canMaterialArgs) {
628 const auto refFrame = exptInfo.getInstrument()->getReferenceFrame();
629 const auto xml = tryCreateXMLFromArgsOnly(*canGeomArgs, *refFrame);
630 if (!xml.empty()) {
631 ShapeFactory sFactory;
632 // Create the object
633 auto shape = sFactory.createShape(xml);
634 if (shape->hasValidShape()) {
635 if (canMaterialArgs) {
636 PropertyManager canMaterialCompatible = materialSettingsEnsureLegacyCompatibility(*canMaterialArgs);
638 setMaterial(materialParams, canMaterialCompatible);
639 if (materialParams.volume <= 0.) {
640 materialParams.volume = shape->volume() * CUBIC_METRE_TO_CM;
641 }
642 ReadMaterial reader;
643 reader.setMaterialParameters(materialParams);
644 auto canMaterial = reader.buildMaterial();
645 shape->setMaterial(*canMaterial);
646 }
647 const SampleEnvironment se("unnamed", std::make_shared<Container>(shape));
648 exptInfo.mutableSample().setEnvironment(std::make_unique<SampleEnvironment>(se));
649 }
650 }
651 return &(exptInfo.sample().getEnvironment());
652}
653
661 const Kernel::PropertyManager &materialArgs) {
662 if (materialArgs.existsProperty("ChemicalFormula")) {
663 materialParams.chemicalSymbol = materialArgs.getPropertyValue("ChemicalFormula");
664 }
665 if (materialArgs.existsProperty("AtomicNumber")) {
666 materialParams.atomicNumber = materialArgs.getProperty("AtomicNumber");
667 }
668 if (materialArgs.existsProperty("MassNumber")) {
669 materialParams.massNumber = materialArgs.getProperty("MassNumber");
670 }
671 if (materialArgs.existsProperty("CoherentXSection")) {
672 materialParams.coherentXSection = materialArgs.getProperty("CoherentXSection");
673 }
674 if (materialArgs.existsProperty("IncoherentXSection")) {
675 materialParams.incoherentXSection = materialArgs.getProperty("IncoherentXSection");
676 }
677 if (materialArgs.existsProperty("AttenuationXSection")) {
678 materialParams.attenuationXSection = materialArgs.getProperty("AttenuationXSection");
679 }
680 if (materialArgs.existsProperty("ScatteringXSection")) {
681 materialParams.scatteringXSection = materialArgs.getProperty("ScatteringXSection");
682 }
683 if (materialArgs.existsProperty("NumberDensityUnit")) {
684 const std::string numberDensityUnit = materialArgs.getProperty("NumberDensityUnit");
685 if (numberDensityUnit == "Atoms") {
687 } else {
689 }
690 }
691 if (materialArgs.existsProperty("ZParameter")) {
692 materialParams.zParameter = materialArgs.getProperty("ZParameter");
693 }
694 if (materialArgs.existsProperty("UnitCellVolume")) {
695 materialParams.unitCellVolume = materialArgs.getProperty("UnitCellVolume");
696 }
697 if (materialArgs.existsProperty("NumberDensity")) {
698 materialParams.numberDensity = materialArgs.getProperty("NumberDensity");
699 }
700 if (materialArgs.existsProperty("MassDensity")) {
701 materialParams.massDensity = materialArgs.getProperty("MassDensity");
702 }
703 if (materialArgs.existsProperty("EffectiveNumberDensity")) {
704 materialParams.numberDensityEffective = materialArgs.getProperty("EffectiveNumberDensity");
705 }
706 if (materialArgs.existsProperty("PackingFraction")) {
707 materialParams.packingFraction = materialArgs.getProperty("packingFraction");
708 }
709 if (materialArgs.existsProperty("Mass")) {
710 materialParams.mass = materialArgs.getProperty("Mass");
711 }
712 if (materialArgs.existsProperty("Volume")) {
713 materialParams.volume = materialArgs.getProperty("Volume");
714 }
715}
716
723 const Geometry::SampleEnvironment *sampleEnv) {
725 /* The sample geometry can be specified in two ways:
726 - a known set of primitive shapes with values or CSG string
727 - or a <samplegeometry> field sample environment can, with values possible
728 overridden by the Geometry flags
729 */
730
731 // Try known shapes or CSG first if supplied
732 if (isDictionaryPopulated(args)) {
733 const auto refFrame = experiment.getInstrument()->getReferenceFrame();
734 auto xml = tryCreateXMLFromArgsOnly(*args, *refFrame);
735 if (!xml.empty()) {
736 Kernel::Matrix<double> rotationMatrix = experiment.run().getGoniometer().getR();
737 if (rotationMatrix != Kernel::Matrix<double>(3, 3, true) && !sampleEnv) {
738 // Only add goniometer tag if rotationMatrix is not the Identity,
739 // and this shape is not defined within a sample environment
740 xml = Geometry::ShapeFactory().addGoniometerTag(rotationMatrix, xml);
741 }
742 CreateSampleShape::setSampleShape(experiment, xml);
743 return;
744 }
745 }
746 // Any arguments in the args dict are assumed to be values that should
747 // override the default set by the sampleEnv samplegeometry if it exists
748 if (sampleEnv) {
749 const auto &can = sampleEnv->getContainer();
750 if (sampleEnv->getContainer().hasCustomizableSampleShape()) {
751 Container::ShapeArgs shapeArgs;
752 if (isDictionaryPopulated(args)) {
753 const auto &props = args->getProperties();
754 for (const auto &prop : props) {
755 // assume in cm
756 const double val = getPropertyAsDouble(*args, prop->name());
757 shapeArgs.emplace(boost::algorithm::to_lower_copy(prop->name()), val * 0.01);
758 }
759 }
760 auto shapeObject = can.createSampleShape(shapeArgs);
761 // Given that the object is a CSG object, set the object
762 // directly on the sample ensuring we preserve the
763 // material.
764 const auto mat = experiment.sample().getMaterial();
765 if (auto csgObj = std::dynamic_pointer_cast<Geometry::CSGObject>(shapeObject)) {
766 csgObj->setMaterial(mat);
767 }
768 experiment.mutableSample().setShape(shapeObject);
769 } else if (sampleEnv->getContainer().hasFixedSampleShape()) {
770 if (isDictionaryPopulated(args)) {
771 throw std::runtime_error("The can has a fixed sample shape that cannot "
772 "be adjusted using the Geometry parameter.");
773 }
774 auto shapeObject = can.getSampleShape();
775
776 // apply Goniometer rotation
777 // Rotate only implemented on mesh objects so far
778 if (typeid(shapeObject) == typeid(std::shared_ptr<Geometry::MeshObject>)) {
779 const std::vector<double> rotationMatrix = experiment.run().getGoniometer().getR();
780 std::dynamic_pointer_cast<Geometry::MeshObject>(shapeObject)->rotate(rotationMatrix);
781 }
782
783 const auto mat = experiment.sample().getMaterial();
784 shapeObject->setMaterial(mat);
785
786 experiment.mutableSample().setShape(shapeObject);
787 } else {
788 if (isDictionaryPopulated(args)) {
789 throw std::runtime_error("Cannot override the sample shape because the "
790 "environment definition does not define a "
791 "default sample shape. Please either provide "
792 "a 'Shape' argument in the dictionary for the "
793 "Geometry parameter or update the environment "
794 "definition with this information.");
795 }
796 }
797 } else {
798 throw std::runtime_error("No sample environment defined, please provide "
799 "a 'Shape' argument to define the sample "
800 "shape.");
801 }
802}
803
811 const Geometry::ReferenceFrame &refFrame) {
812 std::string result;
813 if (!args.existsProperty(GeometryArgs::SHAPE)) {
814 return result;
815 }
816
817 const auto shape = args.getPropertyValue(GeometryArgs::SHAPE);
818 if (shape == ShapeArgs::CSG) {
819 result = args.getPropertyValue("Value");
820 } else if (shape == ShapeArgs::FLAT_PLATE) {
821 result = createFlatPlateXML(args, refFrame);
822 } else if (shape.ends_with(ShapeArgs::CYLINDER)) {
823 result = createCylinderLikeXML(args, refFrame, boost::algorithm::equals(shape, ShapeArgs::HOLLOW_CYLINDER));
824 } else if (shape.ends_with(ShapeArgs::FLAT_PLATE_HOLDER)) {
825 result = createFlatPlateHolderXML(args, refFrame);
826 } else if (shape.ends_with(ShapeArgs::HOLLOW_CYLINDER_HOLDER)) {
827 result = createHollowCylinderHolderXML(args, refFrame);
828 } else if (shape.ends_with(ShapeArgs::SPHERE)) {
829 result = createSphereXML(args);
830 } else {
831 std::stringstream msg;
832 msg << "Unknown 'Shape' argument '" << shape << "' provided in 'Geometry' property. Allowed values are "
833 << ShapeArgs::CSG << ", " << ShapeArgs::FLAT_PLATE << ", " << ShapeArgs::CYLINDER << ", "
834 << ShapeArgs::HOLLOW_CYLINDER << ", " << ShapeArgs::FLAT_PLATE_HOLDER << ", "
835 << ShapeArgs::HOLLOW_CYLINDER_HOLDER << ", " << ShapeArgs::SPHERE;
836 throw std::invalid_argument(msg.str());
837 }
838 if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
839 g_log.debug("XML shape definition:\n" + result + '\n');
840 }
841 return result;
842}
843
852 const std::string &id) const {
853 // Helper to take 3 coordinates and turn them to a V3D respecting the
854 // current reference frame
855 auto makeV3D = [&refFrame](double x, double y, double z) {
856 V3D v;
857 v[refFrame.pointingHorizontal()] = x;
858 v[refFrame.pointingUp()] = y;
859 v[refFrame.pointingAlongBeam()] = z;
860 return v;
861 };
862 const double widthInCM = getPropertyAsDouble(args, ShapeArgs::WIDTH);
863 const double heightInCM = getPropertyAsDouble(args, ShapeArgs::HEIGHT);
864 const double thickInCM = getPropertyAsDouble(args, ShapeArgs::THICK);
865
866 // Convert to half-"width" in metres
867 const double szX = (widthInCM * 5e-3);
868 const double szY = (heightInCM * 5e-3);
869 const double szZ = (thickInCM * 5e-3);
870 // Contruct cuboid corners. Define points about origin, rotate and then
871 // translate to final center position
872 auto lfb = makeV3D(szX, -szY, -szZ);
873 auto lft = makeV3D(szX, szY, -szZ);
874 auto lbb = makeV3D(szX, -szY, szZ);
875 auto rfb = makeV3D(-szX, -szY, -szZ);
876 if (args.existsProperty(ShapeArgs::ANGLE)) {
877 const double angleInDegrees = getPropertyAsDouble(args, ShapeArgs::ANGLE);
878 Goniometer gr;
879 const auto upAxis = makeV3D(0, 1, 0);
880 gr.pushAxis("up", upAxis.X(), upAxis.Y(), upAxis.Z(), angleInDegrees, Geometry::CCW, Geometry::angDegrees);
881 auto &rotation = gr.getR();
882 lfb.rotate(rotation);
883 lft.rotate(rotation);
884 lbb.rotate(rotation);
885 rfb.rotate(rotation);
886 }
887 std::vector<double> center = {0., 0., 0.};
888 if (args.existsProperty(ShapeArgs::CENTER)) {
889 center = getPropertyAsVectorDouble(args, ShapeArgs::CENTER);
890 const V3D centrePos(center[0] * 0.01, center[1] * 0.01, center[2] * 0.01);
891 // translate to true center after rotation
892 lfb += centrePos;
893 lft += centrePos;
894 lbb += centrePos;
895 rfb += centrePos;
896 }
897 std::ostringstream xmlShapeStream;
898 xmlShapeStream << " <cuboid id=\"" << id << "\"> "
899 << "<left-front-bottom-point x=\"" << lfb.X() << "\" y=\"" << lfb.Y() << "\" z=\"" << lfb.Z()
900 << "\" /> "
901 << "<left-front-top-point x=\"" << lft.X() << "\" y=\"" << lft.Y() << "\" z=\"" << lft.Z()
902 << "\" /> "
903 << "<left-back-bottom-point x=\"" << lbb.X() << "\" y=\"" << lbb.Y() << "\" z=\"" << lbb.Z()
904 << "\" /> "
905 << "<right-front-bottom-point x=\"" << rfb.X() << "\" y =\"" << rfb.Y() << "\" z=\"" << rfb.Z()
906 << "\" /> "
907 << "</cuboid>";
908 return xmlShapeStream.str();
909}
910
923 const Geometry::ReferenceFrame &refFrame) const {
924
925 std::vector<double> centre = {0., 0., 0.};
926 if (args.existsProperty(ShapeArgs::CENTER)) {
927 centre = getPropertyAsVectorDouble(args, ShapeArgs::CENTER);
928 }
929
930 const double sampleThickness = getPropertyAsDouble(args, ShapeArgs::THICK);
931 const double frontPlateThickness = getPropertyAsDouble(args, ShapeArgs::FRONT_THICK);
932 const double backPlateThickness = getPropertyAsDouble(args, ShapeArgs::BACK_THICK);
933 double angle = 0.;
934 if (args.existsProperty(ShapeArgs::ANGLE)) {
935 angle = degToRad(getPropertyAsDouble(args, ShapeArgs::ANGLE));
936 }
937 const auto pointingAlongBeam = refFrame.pointingAlongBeam();
938 const auto pointingHorizontal = refFrame.pointingHorizontal();
939 const auto handedness = refFrame.getHandedness();
940 const int signHorizontal = (handedness == Mantid::Geometry::Handedness::Right) ? 1 : -1;
941
942 auto frontPlate = args;
943 frontPlate.setProperty(ShapeArgs::THICK, frontPlateThickness);
944 auto frontCentre = centre;
945 const double frontCentreOffset = (frontPlateThickness + sampleThickness) * 0.5;
946 frontCentre[pointingAlongBeam] -= frontCentreOffset * std::cos(angle);
947 frontCentre[pointingHorizontal] -= signHorizontal * frontCentreOffset * std::sin(angle);
948 if (!frontPlate.existsProperty(ShapeArgs::CENTER)) {
949 frontPlate.declareProperty(ShapeArgs::CENTER, frontCentre);
950 }
951 frontPlate.setProperty(ShapeArgs::CENTER, frontCentre);
952 const std::string frontPlateXML = createFlatPlateXML(frontPlate, refFrame, "front");
953
954 auto backPlate = args;
955 backPlate.setProperty(ShapeArgs::THICK, backPlateThickness);
956 auto backCentre = centre;
957 const double backCentreOffset = (backPlateThickness + sampleThickness) * 0.5;
958 backCentre[pointingAlongBeam] += backCentreOffset * std::cos(angle);
959 backCentre[pointingHorizontal] += signHorizontal * backCentreOffset * std::sin(angle);
960 if (!backPlate.existsProperty(ShapeArgs::CENTER)) {
961 backPlate.declareProperty(ShapeArgs::CENTER, backCentre);
962 }
963 backPlate.setProperty(ShapeArgs::CENTER, backCentre);
964 const std::string backPlateXML = createFlatPlateXML(backPlate, refFrame, "back");
965
966 return frontPlateXML + backPlateXML + "<algebra val=\"back:front\"/>";
967}
968
980 const Geometry::ReferenceFrame &refFrame) const {
981 auto innerCylinder = args;
982 const double innerOuterRadius = getPropertyAsDouble(args, ShapeArgs::INNER_OUTER_RADIUS);
983 innerCylinder.setProperty(ShapeArgs::OUTER_RADIUS, innerOuterRadius);
984 const std::string innerCylinderXML = createCylinderLikeXML(innerCylinder, refFrame, true, "inner");
985 auto outerCylinder = args;
986 const double outerInnerRadius = getPropertyAsDouble(args, ShapeArgs::OUTER_INNER_RADIUS);
987 outerCylinder.setProperty(ShapeArgs::INNER_RADIUS, outerInnerRadius);
988 const std::string outerCylinderXML = createCylinderLikeXML(outerCylinder, refFrame, true, "outer");
989 return innerCylinderXML + outerCylinderXML + "<algebra val=\"inner:outer\"/>";
990}
991
1001 const Geometry::ReferenceFrame &refFrame, bool hollow,
1002 const std::string &id) const {
1003 const std::string tag = hollow ? "hollow-cylinder" : "cylinder";
1004 double height = getPropertyAsDouble(args, ShapeArgs::HEIGHT);
1005 double innerRadius = hollow ? getPropertyAsDouble(args, ShapeArgs::INNER_RADIUS) : 0.0;
1006 double outerRadius =
1007 hollow ? getPropertyAsDouble(args, ShapeArgs::OUTER_RADIUS) : getPropertyAsDouble(args, "Radius");
1008 std::vector<double> centre = {0., 0., 0.};
1009 if (args.existsProperty(ShapeArgs::CENTER)) {
1010 centre = getPropertyAsVectorDouble(args, ShapeArgs::CENTER);
1011 std::transform(centre.begin(), centre.end(), centre.begin(), [](double val) { return val *= 0.01; });
1012 }
1013 // convert to metres
1014 height *= 0.01;
1015 innerRadius *= 0.01;
1016 outerRadius *= 0.01;
1017 // XML needs center position of bottom base but user specifies center of
1018 // cylinder
1019 V3D baseCentre;
1020 std::ostringstream XMLString;
1021 if (args.existsProperty(ShapeArgs::AXIS)) {
1022 const std::string axis = args.getPropertyValue(ShapeArgs::AXIS);
1023 if (axis.length() == 1) {
1024 const auto axisId = static_cast<unsigned>(std::stoi(axis));
1025 XMLString << axisXML(axisId);
1026 baseCentre = cylBaseCentre(centre, height, axisId);
1027 } else {
1028 const std::vector<double> axisVector = getPropertyAsVectorDouble(args, ShapeArgs::AXIS);
1029 XMLString << axisXML(axisVector);
1030 baseCentre = cylBaseCentre(centre, height, axisVector);
1031 }
1032 } else {
1033 const auto axisId = static_cast<unsigned>(refFrame.pointingUp());
1034 XMLString << axisXML(axisId);
1035 baseCentre = cylBaseCentre(centre, height, axisId);
1036 }
1037
1038 std::ostringstream xmlShapeStream;
1039 xmlShapeStream << "<" << tag << " id=\"" << id << "\"> "
1040 << "<centre-of-bottom-base x=\"" << baseCentre.X() << "\" y=\"" << baseCentre.Y() << "\" z=\""
1041 << baseCentre.Z() << "\" /> " << XMLString.str() << "<height val=\"" << height << "\" /> ";
1042 if (hollow) {
1043 xmlShapeStream << "<inner-radius val=\"" << innerRadius << "\"/>"
1044 << "<outer-radius val=\"" << outerRadius << "\"/>";
1045 } else {
1046 xmlShapeStream << "<radius val=\"" << outerRadius << "\"/>";
1047 }
1048 xmlShapeStream << "</" << tag << ">";
1049 return xmlShapeStream.str();
1050}
1051
1058 const double radius = static_cast<double>(args.getProperty(ShapeArgs::RADIUS)) * 0.01;
1059 std::vector<double> center = getPropertyAsVectorDouble(args, ShapeArgs::CENTER);
1060 std::transform(center.begin(), center.end(), center.begin(), [](double val) { return val *= 0.01; });
1061
1062 std::ostringstream xmlShapeStream;
1063 const std::string tag{"sphere"};
1064 const auto id = "sphere";
1065 xmlShapeStream << "<" << tag << " id=\"" << id << "\"> "
1066 << "<center x=\"" << center[0] << "\" y=\"" << center[1] << "\" z=\"" << center[2] << "\" /> "
1067 << "<radius val=\"" << radius << "\" /> ";
1068 xmlShapeStream << "</" << tag << ">";
1069 return xmlShapeStream.str();
1070}
1071
1078 PropertyManager compatible(materialArgs);
1079
1080 // The material should be agnostic whether it's sample's material or
1081 // container's so in the properties below there should be no sample prefix,
1082 // i.e. NumberDensity instead of SampleNumberDensity.
1083 // However, for legacy compatibility, those prefixed with Sample are still
1084 // considered through aliases
1085 if (materialArgs.existsProperty("SampleNumberDensity")) {
1086 const double numberDensity = materialArgs.getProperty("SampleNumberDensity");
1087 if (!compatible.existsProperty("NumberDensity")) {
1088 compatible.declareProperty("NumberDensity", numberDensity);
1089 } else {
1090 compatible.setProperty("NumberDensity", numberDensity);
1091 }
1092 }
1093 if (materialArgs.existsProperty("SampleEffectiveNumberDensity")) {
1094 const double numberDensityEff = materialArgs.getProperty("SampleEffectiveNumberDensity");
1095 if (!compatible.existsProperty("EffectiveNumberDensity")) {
1096 compatible.declareProperty("EffectiveNumberDensity", numberDensityEff);
1097 } else {
1098 compatible.setProperty("EffectiveNumberDesnity", numberDensityEff);
1099 }
1100 }
1101 if (materialArgs.existsProperty("SamplePackingFraction")) {
1102 const double packingFraction = materialArgs.getProperty("SamplePackingFraction");
1103 if (!compatible.existsProperty("PackingFraction")) {
1104 compatible.declareProperty("PackingFraction", packingFraction);
1105 } else {
1106 compatible.setProperty("PackingFraction", packingFraction);
1107 }
1108 }
1109 if (materialArgs.existsProperty("SampleMassDensity")) {
1110 const double massDensity = materialArgs.getProperty("SampleMassDensity");
1111 if (!compatible.existsProperty("MassDensity")) {
1112 compatible.declareProperty("MassDensity", massDensity);
1113 } else {
1114 compatible.setProperty("MassDensity", massDensity);
1115 }
1116 }
1117 if (materialArgs.existsProperty("SampleMass")) {
1118 const double mass = materialArgs.getProperty("SampleMass");
1119 if (!compatible.existsProperty("Mass")) {
1120 compatible.declareProperty("Mass", mass);
1121 } else {
1122 compatible.setProperty("Mass", mass);
1123 }
1124 }
1125 if (materialArgs.existsProperty("SampleVolume")) {
1126 const double volume = materialArgs.getProperty("SampleVolume");
1127 if (!compatible.existsProperty("Volume")) {
1128 compatible.declareProperty("Volume", volume);
1129 } else {
1130 compatible.setProperty("Volume", volume);
1131 }
1132 }
1133 return compatible;
1134}
1135} // namespace Mantid::DataHandling
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
double value
The value of the point.
Definition FitMW.cpp:51
double height
Definition GetAllEi.cpp:155
double error
IPeaksWorkspace_sptr workspace
Mantid::Kernel::Quat(ComponentInfo::* rotation)(const size_t) const
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:422
This class is shared by a few Workspace types and holds information related to a particular experimen...
const Run & run() const
Run details object access.
Geometry::Instrument_const_sptr getInstrument() const
Returns the parameterized instrument.
const Sample & sample() const
Sample accessors.
Sample & mutableSample()
Writable version of the sample object.
const Geometry::Goniometer & getGoniometer() const
Return reference to the first const Goniometer object for this run.
Definition Run.cpp:525
void setShape(const Geometry::IObject_sptr &shape)
Update the shape of the object.
Definition Sample.cpp:115
const Kernel::Material & getMaterial() const
Return the material (convenience method)
Definition Sample.cpp:126
void setEnvironment(std::shared_ptr< Geometry::SampleEnvironment > env)
Set the environment used to contain the sample.
Definition Sample.cpp:147
const Geometry::SampleEnvironment & getEnvironment() const
Get a reference to the sample's environment.
Definition Sample.cpp:135
A property class for workspaces.
Base Workspace Abstract Class.
Definition Workspace.h:29
static void setSampleShape(API::ExperimentInfo &expt, const std::string &shapeXML, bool addTypeTag=true)
Set the shape via an XML string on the given experiment.
This class contains code for interpreting a material input for SetSampleMaterial, validating the para...
std::unique_ptr< Kernel::Material > buildMaterial()
Construct the material,.
void setMaterialParameters(const MaterialParameters &params)
Set the parameters to build the material to the builder, taking into account which values were and we...
static ValidationErrors validateInputs(const MaterialParameters &params)
Validate the parameters to build the material from, this returns any errors in the inputs.
Create a single instance of a SampleEnvironment.
SampleEnvironmentSpec_uptr parseSpec(const std::string &filename, const std::string &filepath) const
Calls SampleEnvironmentSpecFileFinder::parseSpec.
Geometry::SampleEnvironment_uptr create(const std::string &facility, const std::string &instrument, const std::string &specName, const std::string &canName)
Create a new SampleEnvironment instance from the given specification and can.
High-level interface for setting sample metadata on a workspace.
Definition SetSample.h:27
std::string createHollowCylinderHolderXML(const Kernel::PropertyManager &args, const Geometry::ReferenceFrame &refFrame) const
Create the XML required to define a hollow cylinder holder from the given args Hollow cylinder holder...
std::string createSphereXML(const Kernel::PropertyManager &args) const
Create the XML required to define a sphere from the given args.
int version() const override final
Algorithm's version for identification.
bool isDictionaryPopulated(const Kernel::PropertyManager_const_sptr &dict) const
Checks if a json dictionary parameter is populated or not.
void init() override final
Initialize the algorithm's properties.
void validateMaterial(std::map< std::string, std::string > &errors, const Kernel::PropertyManager &inputArgs, const std::string &flavour)
Validates the material.
const std::string summary() const override final
Algorithm's summary for use in the GUI and help.
std::string createFlatPlateHolderXML(const Kernel::PropertyManager &args, const Geometry::ReferenceFrame &refFrame) const
Create the XML required to define a flat plate holder from the given args Flate plate holder is a CSG...
const Geometry::SampleEnvironment * setSampleEnvironmentFromFile(API::ExperimentInfo &experiment, const Kernel::PropertyManager_const_sptr &args)
Set the requested sample environment on the workspace from the environment file.
const std::string category() const override final
Algorithm's category for identification.
void setMaterial(ReadMaterial::MaterialParameters &materialParams, const Kernel::PropertyManager &materialArgs)
SetSample::setMaterial Configures a material from the parameters.
Kernel::PropertyManager materialSettingsEnsureLegacyCompatibility(const Kernel::PropertyManager &materialArgs)
Ensures the backwards compatibility of material arguments.
const Geometry::SampleEnvironment * setSampleEnvironmentFromXML(API::ExperimentInfo &experiment, const Kernel::PropertyManager_const_sptr &canGeometryArgs, const Kernel::PropertyManager_const_sptr &canMaterialArgs)
Set the requested sample environment from shape XML string.
void validateGeometry(std::map< std::string, std::string > &errors, const Kernel::PropertyManager &args, const std::string &flavour)
Validates the geometry.
void setSampleShape(API::ExperimentInfo &experiment, const Kernel::PropertyManager_const_sptr &args, const Geometry::SampleEnvironment *sampleEnv)
void assertNonNegative(std::map< std::string, std::string > &errors, const Kernel::PropertyManager &args, const std::string &flavour, const std::vector< const std::string * > &keys)
Ensures there is no specified property with negative value.
std::string tryCreateXMLFromArgsOnly(const Kernel::PropertyManager &args, const Geometry::ReferenceFrame &refFrame)
Create the required XML for a given shape type plus its arguments.
std::map< std::string, std::string > validateInputs() override final
Validate the inputs against each other.
void exec() override final
Execute the algorithm.
std::string createCylinderLikeXML(const Kernel::PropertyManager &args, const Geometry::ReferenceFrame &refFrame, bool hollow, const std::string &id="sample-shape") const
Create the XML required to define a cylinder from the given args.
std::string createFlatPlateXML(const Kernel::PropertyManager &args, const Geometry::ReferenceFrame &refFrame, const std::string &id="sample-shape") const
Create the XML required to define a flat plate from the given args.
Models a Container is used to hold a sample in the beam.
Definition Container.h:24
bool hasFixedSampleShape() const
Definition Container.cpp:84
std::unordered_map< std::string, double > ShapeArgs
Definition Container.h:26
bool hasCustomizableSampleShape() const
Definition Container.cpp:78
Class to represent a particular goniometer setting, which is described by the rotation matrix.
Definition Goniometer.h:55
void pushAxis(const std::string &name, double axisx, double axisy, double axisz, double angle=0., int sense=CCW, int angUnit=angDegrees)
Add an additional axis to the goniometer, closer to the sample.
const Kernel::DblMatrix & getR() const
Return global rotation matrix.
ReferenceFrame : Holds reference frame information from the geometry description file.
PointingAlong pointingUp() const
Gets the pointing up direction.
PointingAlong pointingHorizontal() const
Gets the pointing horizontal direction, i.e perpendicular to up & along beam.
Handedness getHandedness() const
Gets the handedness.
PointingAlong pointingAlongBeam() const
Gets the beam pointing along direction.
Defines a single instance of a SampleEnvironment.
const Container & getContainer() const
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...
std::string addGoniometerTag(const Kernel::Matrix< double > &rotateMatrix, std::string xml)
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
bool is(int level) const
Returns true if at least the given log level is set.
Definition Logger.cpp:177
Numerical Matrix class.
Definition Matrix.h:42
void rotate(double const, double const, int const, int const, int const, int const)
Applies a rotation to a particular point of tan(theta)=tau.
Definition Matrix.cpp:699
Property manager helper class.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
bool existsProperty(const std::string &name) const override
Checks whether the named property is already in the list of managed property.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
void declareProperty(std::unique_ptr< Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
The concrete, templated class for properties.
Class for 3D vectors.
Definition V3D.h:34
constexpr double X() const noexcept
Get x.
Definition V3D.h:238
double normalize()
Make a normalized vector (return norm value)
Definition V3D.cpp:129
constexpr double Y() const noexcept
Get y.
Definition V3D.h:239
constexpr double Z() const noexcept
Get z.
Definition V3D.h:240
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< ExperimentInfo > ExperimentInfo_sptr
Shared pointer to ExperimentInfo.
@ CCW
Clockwise rotation.
Definition Goniometer.h:34
std::unique_ptr< SampleEnvironment > SampleEnvironment_uptr
Mantid::Kernel::SingletonHolder< ConfigServiceImpl > ConfigService
std::shared_ptr< const PropertyManager > PropertyManager_const_sptr
shared pointer to Mantid::Kernel::PropertyManager(const version)
std::shared_ptr< PropertyManager > PropertyManager_sptr
Typedef for a shared pointer to a PropertyManager.
STL namespace.
This struct contains the parameters for constructing a material, and gives them a default value for e...
double numberDensity
The sample number density to set, defaults to EMPTY_DBL()
double coherentXSection
The coherent scattering cross section to set, defaults to EMPTY_DBL()
int massNumber
The mass number to set, defaults to 0.
double mass
The sample mass to set, defaults to EMPTY_DBL()
double packingFraction
The sample packing fraction.
double attenuationXSection
The absorption cross section to set, defaults to EMPTY_DBL()
Kernel::MaterialBuilder::NumberDensityUnit numberDensityUnit
A flag indicating the unit of sampleNumberDensity.
double volume
The sample volume to set, defaults to EMPTY_DBL()
double massDensity
The sample mass density to set, defaults to EMPTY_DBL()
double scatteringXSection
The total scattering cross section to set, defaults to EMPTY_DBL()
double incoherentXSection
The incoherent scattering cross section to set, defaults to EMPTY_DBL()
double zParameter
The zParameter to set, defaults to EMPTY_DBL()
std::string chemicalSymbol
The chemical formula to set, defaults to the empty string.
double numberDensityEffective
The sample effective number density.
double unitCellVolume
The unit cell volume to set, defaults to EMPTY_DBL()
int atomicNumber
The atomic number to set, defaults to 0.
Describes the direction (within an algorithm) of a Property.
Definition Property.h:50
@ InOut
Both an input & output workspace.
Definition Property.h:55
@ Input
An input workspace.
Definition Property.h:53