Newer
Older
from __future__ import (absolute_import, division, print_function)
from six import iteritems
import math
class SampleDetails(object):
def __init__(self, height, radius, center):
# Currently we only support cylinders
self.shape_type = "cylinder"
SampleDetails._validate_sample_details_constructor_inputs(height=height, radius=radius, center=center)
self.height = height
self.radius = radius
self.center = center # List of X, Y, Z position
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
self._material_object = None
def print_sample_details(self):
self._print()
def reset_sample_material(self):
self._material_object = None
def set_material(self, chemical_formula, number_density=None):
if self._material_object is not None:
self.print_sample_details()
raise RuntimeError("The material has already been set to the above details. If the properties"
" have not been set they can be modified with 'set_material_properties()'. Otherwise"
" to change the material call 'reset_sample_material()'")
self._material_object = _Material(chemical_formula=chemical_formula, numeric_density=number_density)
def set_material_properties(self, absorption_cross_section, scattering_cross_section):
if self._material_object is None:
raise RuntimeError("The material has not been set (or reset). Please set it by calling "
" 'set_material()' to set the material details of the sample.")
self._material_object.set_material_properties(abs_cross_sect=absorption_cross_section,
scattering_cross_sect=scattering_cross_section)
def _print(self):
print("Sample Details:")
print("------------------------")
print("Cylinder:")
print("Height: {}").format(self.height)
print("Radius: {}").format(self.radius)
print("Center X:{}, Y:{}, Z{}").format(self.center[0], self.center[1], self.center[2])
print("------------------------")
if self._material_object is None:
print("Material has not been set (or has been reset).")
else:
self._material_object.print_material()
print() # Newline for visual spacing
@staticmethod
def _validate_sample_details_constructor_inputs(height, radius, center):
# Ensure we got double (or int) types and they are sane
values_to_check = {'height': height, 'radius': radius}
# Attempt to convert them all to floating point relying on the fact on
# the way Python has aliases to an object
for key, value in iteritems(values_to_check):
_check_value_is_physical(property_name=key, value=value)
# Center has to be checked specially - it has to be a list of floating point values
if not isinstance(center, list):
raise ValueError("The center of the cylinder must be specified as a list of X, Y, Z co-ordinates."
" For example [0., 1., 2.]")
if len(center) != 3:
raise ValueError("The center must have three values corresponding to X, Y, Z position of the sample."
" For example [0. ,1., 2.]")
center_name = "center"
for value in center:
_check_value_is_physical(property_name=center_name, value=value)
# All properties validated at this point
class _Material(object):
def __init__(self, chemical_formula, numeric_density=None):
self._chemical_formula = chemical_formula
# If it is not an element Mantid requires us to provide the numeric density
# which is required for absorption corrections.
if len(chemical_formula) > 2 and numeric_density is None:
raise ValueError("A numeric density formula must be set on a chemical formula which is not elemental."
" An elemental chemical formula can only be a maximum of 2 characters "
"(e.g. 'Si' or 'V')")
if numeric_density:
# Always check value is sane if user has given one
_check_value_is_physical(property_name="numeric_density", value=numeric_density)
self._numeric_density = numeric_density
# Advanced material properties
self._absorption_cross_section = None
self._scattering_cross_section = None
# Internal flags so we are only allowed to set the material properties once
self._is_material_props_set = False
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
def print_material(self):
print("Material properties:")
print("------------------------")
print("Chemical formula: {}").format(self._chemical_formula)
if self._numeric_density:
print("Numeric Density: {}").format(self._numeric_density)
else:
print("Numeric Density: Set from elemental properties by Mantid")
self._print_material_properties()
def _print_material_properties(self):
if self._is_material_props_set:
print("Absorption cross section: {}").format(self._absorption_cross_section)
print("Scattering cross section: {}").format(self._scattering_cross_section)
else:
print("Absorption cross section: Calculated by Mantid based on chemical/elemental formula")
print("Scattering cross section: Calculated by Mantid based on chemical/elemental formula")
print("Note to manually override these call 'set_material_properties()'")
def set_material_properties(self, abs_cross_sect, scattering_cross_sect):
if self._is_material_props_set:
self.print_material()
raise RuntimeError("The material properties have already been set to the above."
" To reset the material and its properties call 'reset_sample_material()' on the "
"properties object.")
_check_value_is_physical("absorption_cross_section", abs_cross_sect)
_check_value_is_physical("scattering_cross_section", scattering_cross_sect)
self._absorption_cross_section = abs_cross_sect
self._scattering_cross_section = scattering_cross_sect
self._is_material_props_set = True
def _check_value_is_physical(property_name, value):
value = convert_to_float(value)
if not value:
raise ValueError("Could not convert the " + property_name + " to a number. The input was: " + str(value))
if value <= 0 or math.isnan(value):
raise ValueError("The value set for " + property_name + " was: " + str(value)
+ " which is impossible for a physical object")
def convert_to_float(val):
try:
val = float(val)
return val
except ValueError:
return None