forked from AmbaPant/mantid
-
Notifications
You must be signed in to change notification settings - Fork 1
/
SaveP2D.py
202 lines (180 loc) · 8.23 KB
/
SaveP2D.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
98
99
100
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2020 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source,
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
import numpy as np
import math
from scipy.special import lambertw
from mantid import mtd
from mantid.api import (AlgorithmFactory, PythonAlgorithm, FileAction, FileProperty, WorkspaceProperty, Progress)
from mantid.kernel import Direction
class SaveP2D(PythonAlgorithm):
def category(self):
return 'Diffraction\\DataHandling'
def summary(self):
"""
summary of the algorithm
:return:
"""
return "The algorithm used to create a multidimensional '.p2d' file from a 2D workspace."
def name(self):
return "SaveP2D"
def seeAlso(self):
return ["Bin2DPowderDiffraction"]
def PyInit(self):
# Input file
self.declareProperty(WorkspaceProperty('Workspace',
'',
direction=Direction.Input),
doc='Workspace that should be used.')
# Output File
self.declareProperty(FileProperty('OutputFile',
'',
action=FileAction.Save,
direction=Direction.Input),
doc='Output File for ".p2d" Data.')
# Manipulating Data ranges
self.declareProperty(
'RemoveNaN',
True,
direction=Direction.Input,
doc='Remove DataPoints with NaN as intensity value')
self.declareProperty(
'RemoveNegatives',
True,
direction=Direction.Input,
doc='Remove data points with negative intensity values')
self.declareProperty(
'CutData',
False,
direction=Direction.Input,
doc=
'Use the following inputs to limit data in Theta, lambda, d and dp'
)
self.declareProperty('TthMin',
50,
direction=Direction.Input,
doc='Minimum for tth values')
self.declareProperty('TthMax',
120,
direction=Direction.Input,
doc='Maximum for tth values')
self.declareProperty('LambdaMin',
0.3,
direction=Direction.Input,
doc='Minimum for lambda values')
self.declareProperty('LambdaMax',
1.1,
direction=Direction.Input,
doc='Maximum for lambda values')
self.declareProperty('DMin',
0.11,
direction=Direction.Input,
doc='Minimum for d values')
self.declareProperty('DMax',
1.37,
direction=Direction.Input,
doc='Maximum for d values')
self.declareProperty('DpMin',
0.48,
direction=Direction.Input,
doc='Minimum for dp values')
self.declareProperty('DpMax',
1.76,
direction=Direction.Input,
doc='Maximum for dp values')
def set_data_bounds(self):
self.lambdaMin = self.getProperty('LambdaMin').value
self.lambdaMax = self.getProperty('LambdaMax').value
self.dMin = self.getProperty('DMin').value
self.dMax = self.getProperty('DMax').value
self.dpMin = self.getProperty('DpMin').value
self.dpMax = self.getProperty('DpMax').value
self.tthMin = self.getProperty('TthMin').value
self.tthMax = self.getProperty('TthMax').value
def check_data_ranges(self, d, dp, lhkl, thkl):
return self.check_d_bounds(d) & self.check_dp_bounds(dp) & self.check_lambda_bounds(lhkl) & \
self.check_tth_bounds(thkl)
def check_d_bounds(self, d):
return self.dMin < d < self.dMax
def check_dp_bounds(self, dp):
return self.dpMin < dp < self.dpMax
def check_lambda_bounds(self, lhkl):
return self.lambdaMin < lhkl < self.lambdaMax
def check_tth_bounds(self, thkl):
return self.tthMin < thkl < self.tthMax
# Create output file
def PyExec(self):
def wo_real(x):
return np.real(lambertw(np.exp(x), 0))
if self.getPropertyValue('CutData') == '1':
self.set_data_bounds()
# Workspace name
Workspace = self.getPropertyValue('Workspace')
# Create Output File
OutFile = self.getPropertyValue('OutputFile') + '.p2d'
# Load Workspace data
Data = mtd[Workspace]
# output style
form = '{:12.7f}'
lform = '{:12.7f} {:12.7f} {:12.7f} {:12.7f} {:12.7f}\n'
with open(OutFile, 'w') as of:
print('Exporting: ' + OutFile + '\n')
# Create File header with additional information
of.write('#Title: ' + Data.getTitle() + "\n")
of.write('#Inst: ' + Data.getInstrument().getName() + ".prm\n")
binning = form.format(
Data.getDimension(0).getBinWidth()) + ' ' + form.format(
Data.getDimension(1).getBinWidth()) + "\n"
of.write('#Binning: ddperp' + binning)
of.write('#Bank: 1\n')
of.write('#2theta lambda d-value dp-value counts\n')
# Get number of bins
ndp = Data.getDimension(1).getNBins()
# create progress reporter
pr = Progress(None, start=0.0, end=1.0, nreports=ndp)
last_dp = -1
last_d = -1
# iterate over all dPerpendicular cuts
for cdp in range(ndp):
dp = Data.getDimension(1).getX(cdp)
# skip if no new dPerpendicular cut
if (dp == last_dp):
continue
# create value of bin center from left and right border
dp_center = (dp + Data.getDimension(1).getX(cdp + 1)) / 2.
last_dp = dp
pr.report("Processing")
print("{:4.0f}%".format(cdp * 100. / ndp))
# iterate over all dSpacing values for the selected dPerpendicular value
for cd in range(Data.getDimension(0).getNBins()):
d = Data.dataX(cdp)[cd]
# skip if d is the same as before
if (d == last_d):
break
last_d = d
Y = Data.dataY(cdp)[cd]
# skip NaN values for intensity if option is activated
if self.getPropertyValue('RemoveNaN') == '1':
if math.isnan(Y):
continue
# skip intensities <= 0 if option is selected
if self.getPropertyValue('RemoveNegatives') == '1':
if Y <= 0:
continue
# calculate 2theta and lambda from d and dPerpendicular
dsq = d**2
lhkl = np.sqrt(4. * dsq - wo_real(4. * dsq - np.log(0.25 / dsq) - dp_center**2))
thkl = 2. * np.arcsin(lhkl / 2. / d) / np.pi * 180.
# skip Values outside of specified data ranges if the option is activated
if self.getPropertyValue('CutData') == '1':
if self.check_data_ranges(d, dp_center, lhkl, thkl):
# write data into outfile after checking all data ranges positive
of.write(lform.format(thkl, lhkl, d, dp_center, Y))
else:
# Write data into outfile
of.write(lform.format(thkl, lhkl, d, dp_center, Y))
print('\n\nExported: ' + OutFile + '\n')
AlgorithmFactory.subscribe(SaveP2D)