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 const auto instOnWS = exptInfo.getInstrumentName();
586 const auto &config = ConfigService::Instance();
587 std::string facilityName, instrumentName;
588 try {
589 const auto &instInfo = config.getInstrument(instOnWS);
590 instrumentName = instInfo.name();
591 facilityName = instInfo.facility().name();
592 } catch (std::runtime_error &) {
593 // use default facility/instrument
594 facilityName = config.getFacility().name();
595 instrumentName = config.getInstrument().name();
596 }
597
598 const auto &instDirs = config.getInstrumentDirectories();
599 std::vector<std::string> environDirs(instDirs);
600 for (auto &direc : environDirs) {
601 direc = (std::filesystem::path(direc) / "sampleenvironments").string();
602 }
603 auto finder = std::make_unique<SampleEnvironmentSpecFileFinder>(environDirs);
604 SampleEnvironmentFactory factory(std::move(finder));
606 if (args->existsProperty(SEArgs::PATH)) {
607 auto sampleEnvironSpec = factory.parseSpec(envName, args->getPropertyValue(SEArgs::PATH));
608 sampleEnviron = sampleEnvironSpec->buildEnvironment(canName);
609 } else {
610 sampleEnviron = factory.create(facilityName, instrumentName, envName, canName);
611 }
612 exptInfo.mutableSample().setEnvironment(std::move(sampleEnviron));
613 return &(exptInfo.sample().getEnvironment());
614}
615
625 const Kernel::PropertyManager_const_sptr &canGeomArgs,
626 const Kernel::PropertyManager_const_sptr &canMaterialArgs) {
627 const auto refFrame = exptInfo.getInstrument()->getReferenceFrame();
628 const auto xml = tryCreateXMLFromArgsOnly(*canGeomArgs, *refFrame);
629 if (!xml.empty()) {
630 ShapeFactory sFactory;
631 // Create the object
632 auto shape = sFactory.createShape(xml);
633 if (shape->hasValidShape()) {
634 if (canMaterialArgs) {
635 PropertyManager canMaterialCompatible = materialSettingsEnsureLegacyCompatibility(*canMaterialArgs);
637 setMaterial(materialParams, canMaterialCompatible);
638 if (materialParams.volume <= 0.) {
639 materialParams.volume = shape->volume() * CUBIC_METRE_TO_CM;
640 }
641 ReadMaterial reader;
642 reader.setMaterialParameters(materialParams);
643 auto canMaterial = reader.buildMaterial();
644 shape->setMaterial(*canMaterial);
645 }
646 const SampleEnvironment se("unnamed", std::make_shared<Container>(shape));
647 exptInfo.mutableSample().setEnvironment(std::make_unique<SampleEnvironment>(se));
648 }
649 }
650 return &(exptInfo.sample().getEnvironment());
651}
652
660 const Kernel::PropertyManager &materialArgs) {
661 if (materialArgs.existsProperty("ChemicalFormula")) {
662 materialParams.chemicalSymbol = materialArgs.getPropertyValue("ChemicalFormula");
663 }
664 if (materialArgs.existsProperty("AtomicNumber")) {
665 materialParams.atomicNumber = materialArgs.getProperty("AtomicNumber");
666 }
667 if (materialArgs.existsProperty("MassNumber")) {
668 materialParams.massNumber = materialArgs.getProperty("MassNumber");
669 }
670 if (materialArgs.existsProperty("CoherentXSection")) {
671 materialParams.coherentXSection = materialArgs.getProperty("CoherentXSection");
672 }
673 if (materialArgs.existsProperty("IncoherentXSection")) {
674 materialParams.incoherentXSection = materialArgs.getProperty("IncoherentXSection");
675 }
676 if (materialArgs.existsProperty("AttenuationXSection")) {
677 materialParams.attenuationXSection = materialArgs.getProperty("AttenuationXSection");
678 }
679 if (materialArgs.existsProperty("ScatteringXSection")) {
680 materialParams.scatteringXSection = materialArgs.getProperty("ScatteringXSection");
681 }
682 if (materialArgs.existsProperty("NumberDensityUnit")) {
683 const std::string numberDensityUnit = materialArgs.getProperty("NumberDensityUnit");
684 if (numberDensityUnit == "Atoms") {
686 } else {
688 }
689 }
690 if (materialArgs.existsProperty("ZParameter")) {
691 materialParams.zParameter = materialArgs.getProperty("ZParameter");
692 }
693 if (materialArgs.existsProperty("UnitCellVolume")) {
694 materialParams.unitCellVolume = materialArgs.getProperty("UnitCellVolume");
695 }
696 if (materialArgs.existsProperty("NumberDensity")) {
697 materialParams.numberDensity = materialArgs.getProperty("NumberDensity");
698 }
699 if (materialArgs.existsProperty("MassDensity")) {
700 materialParams.massDensity = materialArgs.getProperty("MassDensity");
701 }
702 if (materialArgs.existsProperty("EffectiveNumberDensity")) {
703 materialParams.numberDensityEffective = materialArgs.getProperty("EffectiveNumberDensity");
704 }
705 if (materialArgs.existsProperty("PackingFraction")) {
706 materialParams.packingFraction = materialArgs.getProperty("packingFraction");
707 }
708 if (materialArgs.existsProperty("Mass")) {
709 materialParams.mass = materialArgs.getProperty("Mass");
710 }
711 if (materialArgs.existsProperty("Volume")) {
712 materialParams.volume = materialArgs.getProperty("Volume");
713 }
714}
715
722 const Geometry::SampleEnvironment *sampleEnv) {
724 /* The sample geometry can be specified in two ways:
725 - a known set of primitive shapes with values or CSG string
726 - or a <samplegeometry> field sample environment can, with values possible
727 overridden by the Geometry flags
728 */
729
730 // Try known shapes or CSG first if supplied
731 if (isDictionaryPopulated(args)) {
732 const auto refFrame = experiment.getInstrument()->getReferenceFrame();
733 auto xml = tryCreateXMLFromArgsOnly(*args, *refFrame);
734 if (!xml.empty()) {
735 Kernel::Matrix<double> rotationMatrix = experiment.run().getGoniometer().getR();
736 if (rotationMatrix != Kernel::Matrix<double>(3, 3, true) && !sampleEnv) {
737 // Only add goniometer tag if rotationMatrix is not the Identity,
738 // and this shape is not defined within a sample environment
739 xml = Geometry::ShapeFactory().addGoniometerTag(rotationMatrix, xml);
740 }
741 CreateSampleShape::setSampleShape(experiment, xml);
742 return;
743 }
744 }
745 // Any arguments in the args dict are assumed to be values that should
746 // override the default set by the sampleEnv samplegeometry if it exists
747 if (sampleEnv) {
748 const auto &can = sampleEnv->getContainer();
749 if (sampleEnv->getContainer().hasCustomizableSampleShape()) {
750 Container::ShapeArgs shapeArgs;
751 if (isDictionaryPopulated(args)) {
752 const auto &props = args->getProperties();
753 for (const auto &prop : props) {
754 // assume in cm
755 const double val = getPropertyAsDouble(*args, prop->name());
756 shapeArgs.emplace(boost::algorithm::to_lower_copy(prop->name()), val * 0.01);
757 }
758 }
759 auto shapeObject = can.createSampleShape(shapeArgs);
760 // Given that the object is a CSG object, set the object
761 // directly on the sample ensuring we preserve the
762 // material.
763 const auto mat = experiment.sample().getMaterial();
764 if (auto csgObj = std::dynamic_pointer_cast<Geometry::CSGObject>(shapeObject)) {
765 csgObj->setMaterial(mat);
766 }
767 experiment.mutableSample().setShape(shapeObject);
768 } else if (sampleEnv->getContainer().hasFixedSampleShape()) {
769 if (isDictionaryPopulated(args)) {
770 throw std::runtime_error("The can has a fixed sample shape that cannot "
771 "be adjusted using the Geometry parameter.");
772 }
773 auto shapeObject = can.getSampleShape();
774
775 // apply Goniometer rotation
776 // Rotate only implemented on mesh objects so far
777 if (typeid(shapeObject) == typeid(std::shared_ptr<Geometry::MeshObject>)) {
778 const std::vector<double> rotationMatrix = experiment.run().getGoniometer().getR();
779 std::dynamic_pointer_cast<Geometry::MeshObject>(shapeObject)->rotate(rotationMatrix);
780 }
781
782 const auto mat = experiment.sample().getMaterial();
783 shapeObject->setMaterial(mat);
784
785 experiment.mutableSample().setShape(shapeObject);
786 } else {
787 if (isDictionaryPopulated(args)) {
788 throw std::runtime_error("Cannot override the sample shape because the "
789 "environment definition does not define a "
790 "default sample shape. Please either provide "
791 "a 'Shape' argument in the dictionary for the "
792 "Geometry parameter or update the environment "
793 "definition with this information.");
794 }
795 }
796 } else {
797 throw std::runtime_error("No sample environment defined, please provide "
798 "a 'Shape' argument to define the sample "
799 "shape.");
800 }
801}
802
810 const Geometry::ReferenceFrame &refFrame) {
811 std::string result;
812 if (!args.existsProperty(GeometryArgs::SHAPE)) {
813 return result;
814 }
815
816 const auto shape = args.getPropertyValue(GeometryArgs::SHAPE);
817 if (shape == ShapeArgs::CSG) {
818 result = args.getPropertyValue("Value");
819 } else if (shape == ShapeArgs::FLAT_PLATE) {
820 result = createFlatPlateXML(args, refFrame);
821 } else if (shape.ends_with(ShapeArgs::CYLINDER)) {
822 result = createCylinderLikeXML(args, refFrame, boost::algorithm::equals(shape, ShapeArgs::HOLLOW_CYLINDER));
823 } else if (shape.ends_with(ShapeArgs::FLAT_PLATE_HOLDER)) {
824 result = createFlatPlateHolderXML(args, refFrame);
825 } else if (shape.ends_with(ShapeArgs::HOLLOW_CYLINDER_HOLDER)) {
826 result = createHollowCylinderHolderXML(args, refFrame);
827 } else if (shape.ends_with(ShapeArgs::SPHERE)) {
828 result = createSphereXML(args);
829 } else {
830 std::stringstream msg;
831 msg << "Unknown 'Shape' argument '" << shape << "' provided in 'Geometry' property. Allowed values are "
832 << ShapeArgs::CSG << ", " << ShapeArgs::FLAT_PLATE << ", " << ShapeArgs::CYLINDER << ", "
833 << ShapeArgs::HOLLOW_CYLINDER << ", " << ShapeArgs::FLAT_PLATE_HOLDER << ", "
834 << ShapeArgs::HOLLOW_CYLINDER_HOLDER << ", " << ShapeArgs::SPHERE;
835 throw std::invalid_argument(msg.str());
836 }
837 if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
838 g_log.debug("XML shape definition:\n" + result + '\n');
839 }
840 return result;
841}
842
851 const std::string &id) const {
852 // Helper to take 3 coordinates and turn them to a V3D respecting the
853 // current reference frame
854 auto makeV3D = [&refFrame](double x, double y, double z) {
855 V3D v;
856 v[refFrame.pointingHorizontal()] = x;
857 v[refFrame.pointingUp()] = y;
858 v[refFrame.pointingAlongBeam()] = z;
859 return v;
860 };
861 const double widthInCM = getPropertyAsDouble(args, ShapeArgs::WIDTH);
862 const double heightInCM = getPropertyAsDouble(args, ShapeArgs::HEIGHT);
863 const double thickInCM = getPropertyAsDouble(args, ShapeArgs::THICK);
864
865 // Convert to half-"width" in metres
866 const double szX = (widthInCM * 5e-3);
867 const double szY = (heightInCM * 5e-3);
868 const double szZ = (thickInCM * 5e-3);
869 // Contruct cuboid corners. Define points about origin, rotate and then
870 // translate to final center position
871 auto lfb = makeV3D(szX, -szY, -szZ);
872 auto lft = makeV3D(szX, szY, -szZ);
873 auto lbb = makeV3D(szX, -szY, szZ);
874 auto rfb = makeV3D(-szX, -szY, -szZ);
875 if (args.existsProperty(ShapeArgs::ANGLE)) {
876 const double angleInDegrees = getPropertyAsDouble(args, ShapeArgs::ANGLE);
877 Goniometer gr;
878 const auto upAxis = makeV3D(0, 1, 0);
879 gr.pushAxis("up", upAxis.X(), upAxis.Y(), upAxis.Z(), angleInDegrees, Geometry::CCW, Geometry::angDegrees);
880 auto &rotation = gr.getR();
881 lfb.rotate(rotation);
882 lft.rotate(rotation);
883 lbb.rotate(rotation);
884 rfb.rotate(rotation);
885 }
886 std::vector<double> center = {0., 0., 0.};
887 if (args.existsProperty(ShapeArgs::CENTER)) {
888 center = getPropertyAsVectorDouble(args, ShapeArgs::CENTER);
889 const V3D centrePos(center[0] * 0.01, center[1] * 0.01, center[2] * 0.01);
890 // translate to true center after rotation
891 lfb += centrePos;
892 lft += centrePos;
893 lbb += centrePos;
894 rfb += centrePos;
895 }
896 std::ostringstream xmlShapeStream;
897 xmlShapeStream << " <cuboid id=\"" << id << "\"> "
898 << "<left-front-bottom-point x=\"" << lfb.X() << "\" y=\"" << lfb.Y() << "\" z=\"" << lfb.Z()
899 << "\" /> "
900 << "<left-front-top-point x=\"" << lft.X() << "\" y=\"" << lft.Y() << "\" z=\"" << lft.Z()
901 << "\" /> "
902 << "<left-back-bottom-point x=\"" << lbb.X() << "\" y=\"" << lbb.Y() << "\" z=\"" << lbb.Z()
903 << "\" /> "
904 << "<right-front-bottom-point x=\"" << rfb.X() << "\" y =\"" << rfb.Y() << "\" z=\"" << rfb.Z()
905 << "\" /> "
906 << "</cuboid>";
907 return xmlShapeStream.str();
908}
909
922 const Geometry::ReferenceFrame &refFrame) const {
923
924 std::vector<double> centre = {0., 0., 0.};
925 if (args.existsProperty(ShapeArgs::CENTER)) {
926 centre = getPropertyAsVectorDouble(args, ShapeArgs::CENTER);
927 }
928
929 const double sampleThickness = getPropertyAsDouble(args, ShapeArgs::THICK);
930 const double frontPlateThickness = getPropertyAsDouble(args, ShapeArgs::FRONT_THICK);
931 const double backPlateThickness = getPropertyAsDouble(args, ShapeArgs::BACK_THICK);
932 double angle = 0.;
933 if (args.existsProperty(ShapeArgs::ANGLE)) {
934 angle = degToRad(getPropertyAsDouble(args, ShapeArgs::ANGLE));
935 }
936 const auto pointingAlongBeam = refFrame.pointingAlongBeam();
937 const auto pointingHorizontal = refFrame.pointingHorizontal();
938 const auto handedness = refFrame.getHandedness();
939 const int signHorizontal = (handedness == Mantid::Geometry::Handedness::Right) ? 1 : -1;
940
941 auto frontPlate = args;
942 frontPlate.setProperty(ShapeArgs::THICK, frontPlateThickness);
943 auto frontCentre = centre;
944 const double frontCentreOffset = (frontPlateThickness + sampleThickness) * 0.5;
945 frontCentre[pointingAlongBeam] -= frontCentreOffset * std::cos(angle);
946 frontCentre[pointingHorizontal] -= signHorizontal * frontCentreOffset * std::sin(angle);
947 if (!frontPlate.existsProperty(ShapeArgs::CENTER)) {
948 frontPlate.declareProperty(ShapeArgs::CENTER, frontCentre);
949 }
950 frontPlate.setProperty(ShapeArgs::CENTER, frontCentre);
951 const std::string frontPlateXML = createFlatPlateXML(frontPlate, refFrame, "front");
952
953 auto backPlate = args;
954 backPlate.setProperty(ShapeArgs::THICK, backPlateThickness);
955 auto backCentre = centre;
956 const double backCentreOffset = (backPlateThickness + sampleThickness) * 0.5;
957 backCentre[pointingAlongBeam] += backCentreOffset * std::cos(angle);
958 backCentre[pointingHorizontal] += signHorizontal * backCentreOffset * std::sin(angle);
959 if (!backPlate.existsProperty(ShapeArgs::CENTER)) {
960 backPlate.declareProperty(ShapeArgs::CENTER, backCentre);
961 }
962 backPlate.setProperty(ShapeArgs::CENTER, backCentre);
963 const std::string backPlateXML = createFlatPlateXML(backPlate, refFrame, "back");
964
965 return frontPlateXML + backPlateXML + "<algebra val=\"back:front\"/>";
966}
967
979 const Geometry::ReferenceFrame &refFrame) const {
980 auto innerCylinder = args;
981 const double innerOuterRadius = getPropertyAsDouble(args, ShapeArgs::INNER_OUTER_RADIUS);
982 innerCylinder.setProperty(ShapeArgs::OUTER_RADIUS, innerOuterRadius);
983 const std::string innerCylinderXML = createCylinderLikeXML(innerCylinder, refFrame, true, "inner");
984 auto outerCylinder = args;
985 const double outerInnerRadius = getPropertyAsDouble(args, ShapeArgs::OUTER_INNER_RADIUS);
986 outerCylinder.setProperty(ShapeArgs::INNER_RADIUS, outerInnerRadius);
987 const std::string outerCylinderXML = createCylinderLikeXML(outerCylinder, refFrame, true, "outer");
988 return innerCylinderXML + outerCylinderXML + "<algebra val=\"inner:outer\"/>";
989}
990
1000 const Geometry::ReferenceFrame &refFrame, bool hollow,
1001 const std::string &id) const {
1002 const std::string tag = hollow ? "hollow-cylinder" : "cylinder";
1003 double height = getPropertyAsDouble(args, ShapeArgs::HEIGHT);
1004 double innerRadius = hollow ? getPropertyAsDouble(args, ShapeArgs::INNER_RADIUS) : 0.0;
1005 double outerRadius =
1006 hollow ? getPropertyAsDouble(args, ShapeArgs::OUTER_RADIUS) : getPropertyAsDouble(args, "Radius");
1007 std::vector<double> centre = {0., 0., 0.};
1008 if (args.existsProperty(ShapeArgs::CENTER)) {
1009 centre = getPropertyAsVectorDouble(args, ShapeArgs::CENTER);
1010 std::transform(centre.begin(), centre.end(), centre.begin(), [](double val) { return val *= 0.01; });
1011 }
1012 // convert to metres
1013 height *= 0.01;
1014 innerRadius *= 0.01;
1015 outerRadius *= 0.01;
1016 // XML needs center position of bottom base but user specifies center of
1017 // cylinder
1018 V3D baseCentre;
1019 std::ostringstream XMLString;
1020 if (args.existsProperty(ShapeArgs::AXIS)) {
1021 const std::string axis = args.getPropertyValue(ShapeArgs::AXIS);
1022 if (axis.length() == 1) {
1023 const auto axisId = static_cast<unsigned>(std::stoi(axis));
1024 XMLString << axisXML(axisId);
1025 baseCentre = cylBaseCentre(centre, height, axisId);
1026 } else {
1027 const std::vector<double> axisVector = getPropertyAsVectorDouble(args, ShapeArgs::AXIS);
1028 XMLString << axisXML(axisVector);
1029 baseCentre = cylBaseCentre(centre, height, axisVector);
1030 }
1031 } else {
1032 const auto axisId = static_cast<unsigned>(refFrame.pointingUp());
1033 XMLString << axisXML(axisId);
1034 baseCentre = cylBaseCentre(centre, height, axisId);
1035 }
1036
1037 std::ostringstream xmlShapeStream;
1038 xmlShapeStream << "<" << tag << " id=\"" << id << "\"> "
1039 << "<centre-of-bottom-base x=\"" << baseCentre.X() << "\" y=\"" << baseCentre.Y() << "\" z=\""
1040 << baseCentre.Z() << "\" /> " << XMLString.str() << "<height val=\"" << height << "\" /> ";
1041 if (hollow) {
1042 xmlShapeStream << "<inner-radius val=\"" << innerRadius << "\"/>"
1043 << "<outer-radius val=\"" << outerRadius << "\"/>";
1044 } else {
1045 xmlShapeStream << "<radius val=\"" << outerRadius << "\"/>";
1046 }
1047 xmlShapeStream << "</" << tag << ">";
1048 return xmlShapeStream.str();
1049}
1050
1057 const double radius = static_cast<double>(args.getProperty(ShapeArgs::RADIUS)) * 0.01;
1058 std::vector<double> center = getPropertyAsVectorDouble(args, ShapeArgs::CENTER);
1059 std::transform(center.begin(), center.end(), center.begin(), [](double val) { return val *= 0.01; });
1060
1061 std::ostringstream xmlShapeStream;
1062 const std::string tag{"sphere"};
1063 const auto id = "sphere";
1064 xmlShapeStream << "<" << tag << " id=\"" << id << "\"> "
1065 << "<center x=\"" << center[0] << "\" y=\"" << center[1] << "\" z=\"" << center[2] << "\" /> "
1066 << "<radius val=\"" << radius << "\" /> ";
1067 xmlShapeStream << "</" << tag << ">";
1068 return xmlShapeStream.str();
1069}
1070
1077 PropertyManager compatible(materialArgs);
1078
1079 // The material should be agnostic whether it's sample's material or
1080 // container's so in the properties below there should be no sample prefix,
1081 // i.e. NumberDensity instead of SampleNumberDensity.
1082 // However, for legacy compatibility, those prefixed with Sample are still
1083 // considered through aliases
1084 if (materialArgs.existsProperty("SampleNumberDensity")) {
1085 const double numberDensity = materialArgs.getProperty("SampleNumberDensity");
1086 if (!compatible.existsProperty("NumberDensity")) {
1087 compatible.declareProperty("NumberDensity", numberDensity);
1088 } else {
1089 compatible.setProperty("NumberDensity", numberDensity);
1090 }
1091 }
1092 if (materialArgs.existsProperty("SampleEffectiveNumberDensity")) {
1093 const double numberDensityEff = materialArgs.getProperty("SampleEffectiveNumberDensity");
1094 if (!compatible.existsProperty("EffectiveNumberDensity")) {
1095 compatible.declareProperty("EffectiveNumberDensity", numberDensityEff);
1096 } else {
1097 compatible.setProperty("EffectiveNumberDesnity", numberDensityEff);
1098 }
1099 }
1100 if (materialArgs.existsProperty("SamplePackingFraction")) {
1101 const double packingFraction = materialArgs.getProperty("SamplePackingFraction");
1102 if (!compatible.existsProperty("PackingFraction")) {
1103 compatible.declareProperty("PackingFraction", packingFraction);
1104 } else {
1105 compatible.setProperty("PackingFraction", packingFraction);
1106 }
1107 }
1108 if (materialArgs.existsProperty("SampleMassDensity")) {
1109 const double massDensity = materialArgs.getProperty("SampleMassDensity");
1110 if (!compatible.existsProperty("MassDensity")) {
1111 compatible.declareProperty("MassDensity", massDensity);
1112 } else {
1113 compatible.setProperty("MassDensity", massDensity);
1114 }
1115 }
1116 if (materialArgs.existsProperty("SampleMass")) {
1117 const double mass = materialArgs.getProperty("SampleMass");
1118 if (!compatible.existsProperty("Mass")) {
1119 compatible.declareProperty("Mass", mass);
1120 } else {
1121 compatible.setProperty("Mass", mass);
1122 }
1123 }
1124 if (materialArgs.existsProperty("SampleVolume")) {
1125 const double volume = materialArgs.getProperty("SampleVolume");
1126 if (!compatible.existsProperty("Volume")) {
1127 compatible.declareProperty("Volume", volume);
1128 } else {
1129 compatible.setProperty("Volume", volume);
1130 }
1131 }
1132 return compatible;
1133}
1134} // namespace Mantid::DataHandling
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
double centre
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:426
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.
std::string getInstrumentName() const
Return the name of the instrument from the ComponentInfo object.
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:160
const Kernel::Material & getMaterial() const
Return the material (convenience method)
Definition Sample.cpp:171
void setEnvironment(std::shared_ptr< Geometry::SampleEnvironment > env)
Set the environment used to contain the sample.
Definition Sample.cpp:192
const Geometry::SampleEnvironment & getEnvironment() const
Get a reference to the sample's environment.
Definition Sample.cpp:180
A property class for workspaces.
Base Workspace Abstract Class.
Definition Workspace.h:30
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)
Replace or insert the <goniometer> tag, the TOTAL rotation applied to the shape's surfaces.
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:41
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:35
constexpr double X() const noexcept
Get x.
Definition V3D.h:239
double normalize()
Make a normalized vector (return norm value)
Definition V3D.cpp:129
constexpr double Y() const noexcept
Get y.
Definition V3D.h:240
constexpr double Z() const noexcept
Get z.
Definition V3D.h:241
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:51
@ InOut
Both an input & output workspace.
Definition Property.h:56
@ Input
An input workspace.
Definition Property.h:54