@@ -52,6 +52,11 @@ def PyInit(self):
52
52
direction = Direction .Input ),
53
53
doc = "Workspace to fit Neutron Compton Profiles." )
54
54
55
+ self .declareProperty (TableWorkspaceProperty (name = "InputProfiles" ,
56
+ defaultValue = "" ,
57
+ direction = Direction .Input ),
58
+ doc = "Table workspace containing starting parameters for profiles" )
59
+
55
60
self .declareProperty (FileProperty (name = 'InstrumentParametersFile' ,
56
61
defaultValue = '' ,
57
62
action = FileAction .Load ,
@@ -90,17 +95,14 @@ def PyInit(self):
90
95
self .declareProperty ("ResultsPath" , "" , doc = "Directory to store results, to be deleted later" )
91
96
self .declareProperty ("FiguresPath" , "" , doc = "Directory to store figures, to be deleted later" )
92
97
93
- self .declareProperty (TableWorkspaceProperty (name = "InputProfiles" ,
94
- defaultValue = "" ,
95
- direction = Direction .Input ),
96
- doc = "Table workspace containing starting parameters for profiles" )
97
98
98
99
def PyExec (self ):
99
100
self ._setup ()
101
+ self .run ()
100
102
101
103
def _setup (self ):
102
104
self ._name = self .getProperty ("InputWorkspace" ).value .name ()
103
- self ._ip_file = self .getPropertY ("InstrumentParametersFile" ).value
105
+ self ._ip_file = self .getProperty ("InstrumentParametersFile" ).value
104
106
self ._number_of_iterations = self .getProperty ("NumberOfIterations" ).value
105
107
self ._mask_spectra = self .getProperty ("InvalidDetectors" ).value
106
108
self ._transmission_guess = self .getProperty ("TransmissionGuess" ).value
@@ -133,76 +135,32 @@ def _setup(self):
133
135
self ._run_norm_voigt = False
134
136
135
137
136
- def add_profiles (self , * args : NeutronComptonProfile ):
137
- for profile in args :
138
- self ._profiles [profile .label ] = profile
139
-
140
-
141
- @property
142
- def profiles (self ):
143
- return self ._profiles
144
-
145
-
146
- def set_initial_profiles_from (self , source : 'AnalysisRoutine' ):
147
-
148
- # Set intensities
149
- for p in self ._profiles .values ():
150
- if np .isclose (p .mass , 1 , atol = 0.1 ): # Hydrogen present
151
- p .intensity = source ._h_ratio * source ._get_lightest_profile ().mean_intensity
152
- continue
153
- p .intensity = source .profiles [p .label ].mean_intensity
154
-
155
- # Normalise intensities
156
- sum_intensities = sum ([p .intensity for p in self ._profiles .values ()])
157
- for p in self ._profiles .values ():
158
- p .intensity /= sum_intensities
159
-
160
- # Set widths
161
- for p in self ._profiles .values ():
162
- try :
163
- p .width = source .profiles [p .label ].mean_width
164
- except KeyError :
165
- continue
166
-
167
- # Fix all widths except lightest mass
168
- for p in self ._profiles .values ():
169
- if p == self ._get_lightest_profile ():
170
- continue
171
- p .width_bounds = [p .width , p .width ]
172
-
173
- return
174
-
175
-
176
- def _get_lightest_profile (self ):
177
- profiles = [p for p in self ._profiles .values ()]
178
- masses = [p .mass for p in self ._profiles .values ()]
179
- return profiles [np .argmin (masses )]
180
-
181
-
182
138
def calculate_h_ratio (self ):
183
139
184
- if not np .isclose (self ._get_lightest_profile (). mass , 1 , atol = 0.1 ): # Hydrogen present
140
+ if not np .isclose (min ( self ._profiles_table . column ( " mass" )) , 1 , atol = 0.1 ): # Hydrogen not present
185
141
return None
186
142
187
- # Hydrogen is present
188
- intensities = np .array ([p .mean_intensity for p in self ._profiles .values ()])
189
- masses = np .array ([p .mass for p in self ._profiles .values ()])
143
+ # Hydrogen present
144
+ # intensities = np.array([p.mean_intensity for p in self._profiles.values()])
145
+ intensities = self .mean_intensity_ratios
146
+ # masses = np.array([p.mass for p in self._profiles.values()])
147
+ masses = self ._profiles_table .column ("mass" )
190
148
191
149
sorted_intensities = intensities [np .argsort (masses )]
192
150
return sorted_intensities [0 ] / sorted_intensities [1 ]
193
151
194
152
195
- @property
196
- def profiles (self ):
197
- return self ._profiles
153
+ # @property
154
+ # def profiles(self):
155
+ # return self._profiles
198
156
199
157
200
- @profiles .setter
201
- def profiles (self , incoming_profiles ):
202
- assert (isinstance (incoming_profiles , dict ))
203
- common_keys = self ._profiles .keys () & incoming_profiles .keys ()
204
- common_keys_profiles = {k : incoming_profiles [k ] for k in common_keys }
205
- self ._profiles = {** self ._profiles , ** common_keys_profiles }
158
+ # @profiles.setter
159
+ # def profiles(self, incoming_profiles):
160
+ # assert(isinstance(incoming_profiles, dict))
161
+ # common_keys = self._profiles.keys() & incoming_profiles.keys()
162
+ # common_keys_profiles = {k: incoming_profiles[k] for k in common_keys}
163
+ # self._profiles = {**self._profiles, **common_keys_profiles}
206
164
207
165
208
166
def _update_workspace_data (self ):
@@ -216,13 +174,13 @@ def _update_workspace_data(self):
216
174
217
175
self ._set_up_kinematic_arrays ()
218
176
219
- self ._fit_parameters = np .zeros ((len (self ._dataY ), 3 * len ( self ._profiles ) + 3 ))
177
+ self ._fit_parameters = np .zeros ((len (self ._dataY ), 3 * self ._profiles_table . rowCount ( ) + 3 ))
220
178
self ._row_being_fit = 0
221
179
self ._table_fit_results = self ._initialize_table_fit_parameters ()
222
180
223
181
# Initialise workspaces for fitted ncp
224
182
self ._fit_profiles_workspaces = {}
225
- for element , p in self ._profiles . items ( ):
183
+ for element in self ._profiles_table . column ( "label" ):
226
184
self ._fit_profiles_workspaces [element ] = self ._create_emtpy_ncp_workspace (f'_{ element } _ncp' )
227
185
self ._fit_profiles_workspaces ['total' ] = self ._create_emtpy_ncp_workspace (f'_total_ncp' )
228
186
@@ -239,10 +197,10 @@ def _initialize_table_fit_parameters(self):
239
197
)
240
198
table .setTitle ("SciPy Fit Parameters" )
241
199
table .addColumn (type = "float" , name = "Spectrum" )
242
- for key in self ._profiles . keys ( ):
243
- table .addColumn (type = "float" , name = f"{ key } Intensity" )
244
- table .addColumn (type = "float" , name = f"{ key } Width" )
245
- table .addColumn (type = "float" , name = f"{ key } Center " )
200
+ for label in self ._profiles_table . column ( "label" ):
201
+ table .addColumn (type = "float" , name = f"{ label } Intensity" )
202
+ table .addColumn (type = "float" , name = f"{ label } Width" )
203
+ table .addColumn (type = "float" , name = f"{ label } Center " )
246
204
table .addColumn (type = "float" , name = "Normalised Chi2" )
247
205
table .addColumn (type = "float" , name = "Number of Iterations" )
248
206
return table
@@ -256,8 +214,8 @@ def mean_widths(self):
256
214
@mean_widths .setter
257
215
def mean_widths (self , value ):
258
216
self ._mean_widths = value
259
- for i , p in enumerate (self ._profiles .values ()):
260
- p .mean_width = self ._mean_widths [i ]
217
+ # for i, p in enumerate(self._profiles.values()):
218
+ # p.mean_width = self._mean_widths[i]
261
219
return
262
220
263
221
@@ -268,8 +226,8 @@ def mean_intensity_ratios(self):
268
226
@mean_intensity_ratios .setter
269
227
def mean_intensity_ratios (self , value ):
270
228
self ._mean_intensity_ratios = value
271
- for i , p in enumerate (self .profiles .values ()):
272
- p .mean_intensity = self ._mean_intensity_ratios [i ]
229
+ # for i, p in enumerate(self.profiles.values()):
230
+ # p.mean_intensity = self._mean_intensity_ratios[i]
273
231
return
274
232
275
233
@@ -294,7 +252,7 @@ def _set_up_kinematic_arrays(self):
294
252
295
253
def run (self ):
296
254
297
- assert len ( self .profiles ) > 0 , "Add profiles before attempting to run the routine!"
255
+ assert self ._profiles_table . rowCount ( ) > 0 , "Need at least one profile to run the routine!"
298
256
299
257
# Legacy code from Bootstrap
300
258
# if self.runningSampleWS:
@@ -442,7 +400,7 @@ def convertDataXToYSpacesForEachMass(self, dataX, delta_Q, delta_E):
442
400
delta_E = delta_E [np .newaxis , :, :]
443
401
444
402
mN , Ef , en_to_vel , vf , hbar = loadConstants ()
445
- masses = np .array ([ p . mass for p in self ._profiles . values ()] ).reshape (- 1 , 1 , 1 )
403
+ masses = np .array (self ._profiles_table . column ( "mass" ) ).reshape (- 1 , 1 , 1 )
446
404
447
405
energyRecoil = np .square (hbar * delta_Q ) / 2.0 / masses
448
406
ySpacesForEachMass = (
@@ -475,7 +433,7 @@ def _save_plots(self):
475
433
ax .legend ()
476
434
477
435
fileName = self ._workspace_being_fit .name () + "_profiles_sum.pdf"
478
- savePath = self ._save_figures_path / fileName
436
+ savePath = self ._save_figures_path + fileName
479
437
plt .savefig (savePath , bbox_inches = "tight" )
480
438
plt .close (fig )
481
439
return
@@ -497,11 +455,11 @@ def _set_means_and_std(self):
497
455
"""Calculate mean widths and intensities from tableWorkspace"""
498
456
499
457
fitParsTable = self ._table_fit_results
500
- widths = np .zeros ((len ( self ._profiles ), fitParsTable .rowCount ()))
458
+ widths = np .zeros ((self ._profiles_table . rowCount ( ), fitParsTable .rowCount ()))
501
459
intensities = np .zeros (widths .shape )
502
- for i , p in enumerate (self ._profiles . values ( )):
503
- widths [i ] = fitParsTable .column (f"{ p . label } Width" )
504
- intensities [i ] = fitParsTable .column (f"{ p . label } Intensity" )
460
+ for i , label in enumerate (self ._profiles_table . column ( "label" )):
461
+ widths [i ] = fitParsTable .column (f"{ label } Width" )
462
+ intensities [i ] = fitParsTable .column (f"{ label } Intensity" )
505
463
(
506
464
meanWidths ,
507
465
stdWidths ,
@@ -510,7 +468,7 @@ def _set_means_and_std(self):
510
468
) = self .calculateMeansAndStds (widths , intensities )
511
469
512
470
assert (
513
- len (meanWidths ) == len ( self ._profiles )
471
+ len (meanWidths ) == self ._profiles_table . rowCount ()
514
472
), "Number of mean widths must match number of profiles!"
515
473
516
474
self .mean_widths = meanWidths # Use setter
@@ -534,15 +492,15 @@ def createMeansAndStdTableWS(self):
534
492
535
493
print ("\n Created Table with means and std:" )
536
494
print ("\n Mass Mean \u00B1 Std Widths Mean \u00B1 Std Intensities\n " )
537
- for p , mean_width , std_width , mean_intensity , std_intensity in zip (
538
- self ._profiles . values ( ),
495
+ for label , mean_width , std_width , mean_intensity , std_intensity in zip (
496
+ self ._profiles_table . column ( "label" ),
539
497
self ._mean_widths ,
540
498
self ._std_widths ,
541
499
self ._mean_intensity_ratios ,
542
500
self ._std_intensity_ratios ,
543
501
):
544
- meansTableWS .addRow ([p . label , mean_width , std_width , mean_intensity , std_intensity ])
545
- print (f"{ p . label :5s} { mean_width :10.5f} \u00B1 { std_width :7.5f} \
502
+ meansTableWS .addRow ([label , mean_width , std_width , mean_intensity , std_intensity ])
503
+ print (f"{ label :5s} { mean_width :10.5f} \u00B1 { std_width :7.5f} \
546
504
{ mean_intensity :10.5f} \u00B1 { std_intensity :7.5f} \n " )
547
505
return
548
506
@@ -613,17 +571,31 @@ def filterWidthsAndIntensities(self, widthsIn, intensitiesIn):
613
571
def _fit_neutron_compton_profiles_to_row (self ):
614
572
615
573
if np .all (self ._dataY [self ._row_being_fit ] == 0 ):
616
- self ._table_fit_results .addRow (np .zeros (3 * len ( self ._profiles )+ 3 ))
574
+ self ._table_fit_results .addRow (np .zeros (3 * self ._profiles_table . rowCount ( )+ 3 ))
617
575
return
618
576
619
577
# Need to transform profiles into parameter array for minimize
620
578
initial_parameters = []
579
+ for intensity , width , center in zip (
580
+ self ._profiles_table .column ("intensity" ),
581
+ self ._profiles_table .column ("width" ),
582
+ self ._profiles_table .column ("center" )
583
+ ):
584
+ initial_parameters .extend ([intensity , width , center ])
585
+
621
586
bounds = []
622
- for p in self ._profiles .values ():
623
- for attr in ['intensity' , 'width' , 'center' ]:
624
- initial_parameters .append (getattr (p , attr ))
625
- for attr in ['intensity_bounds' , 'width_bounds' , 'center_bounds' ]:
626
- bounds .append (getattr (p , attr ))
587
+ for intensity_bounds , width_bounds , center_bounds in zip (
588
+ self ._profiles_table .column ("intensity_bounds" ),
589
+ self ._profiles_table .column ("width_bounds" ),
590
+ self ._profiles_table .column ("center_bounds" )
591
+ ):
592
+ bounds .extend ([eval (intensity_bounds ), eval (width_bounds ), eval (center_bounds )])
593
+
594
+ # for p in self._profiles.values():
595
+ # for attr in ['intensity', 'width', 'center']:
596
+ # initial_parameters.append(getattr(p, attr))
597
+ # for attr in ['intensity_bounds', 'width_bounds', 'center_bounds']:
598
+ # bounds.append(getattr(p, attr))
627
599
628
600
result = optimize .minimize (
629
601
self .errorFunction ,
@@ -649,7 +621,7 @@ def _fit_neutron_compton_profiles_to_row(self):
649
621
650
622
# Pass fit profiles into workspaces
651
623
individual_ncps = self ._neutron_compton_profiles (fitPars )
652
- for ncp , element in zip (individual_ncps , self ._profiles . keys ( )):
624
+ for ncp , element in zip (individual_ncps , self ._profiles_table . column ( "label" )):
653
625
self ._fit_profiles_workspaces [element ].dataY (self ._row_being_fit )[:] = ncp
654
626
655
627
self ._fit_profiles_workspaces ['total' ].dataY (self ._row_being_fit )[:] = np .sum (individual_ncps , axis = 0 )
@@ -683,7 +655,7 @@ def _neutron_compton_profiles(self, pars):
683
655
intensities = pars [::3 ].reshape (- 1 , 1 )
684
656
widths = pars [1 ::3 ].reshape (- 1 , 1 )
685
657
centers = pars [2 ::3 ].reshape (- 1 , 1 )
686
- masses = np .array ([ p . mass for p in self ._profiles . values ()] ).reshape (- 1 , 1 )
658
+ masses = np .array (self ._profiles_table . column ( "mass" ) ).reshape (- 1 , 1 )
687
659
688
660
v0 , E0 , deltaE , deltaQ = self ._kinematic_arrays [self ._row_being_fit ]
689
661
@@ -734,7 +706,7 @@ def kinematicsAtYCenters(self, centers):
734
706
735
707
736
708
def calcGaussianResolution (self , centers ):
737
- masses = np .array ([ p . mass for p in self ._profiles . values ()] ).reshape (- 1 , 1 )
709
+ masses = np .array (self ._profiles_table . column ( "mass" ) ).reshape (- 1 , 1 )
738
710
v0 , E0 , delta_E , delta_Q = self .kinematicsAtYCenters (centers )
739
711
det , plick , angle , T0 , L0 , L1 = self ._instrument_params [self ._row_being_fit ]
740
712
dE1 , dTOF , dTheta , dL0 , dL1 , dE1_lorz = self ._resolution_params [self ._row_being_fit ]
@@ -780,7 +752,7 @@ def calcGaussianResolution(self, centers):
780
752
781
753
782
754
def calcLorentzianResolution (self , centers ):
783
- masses = np .array ([ p . mass for p in self ._profiles . values ()] ).reshape (- 1 , 1 )
755
+ masses = np .array (self ._profiles_table . column ( "mass" ) ).reshape (- 1 , 1 )
784
756
v0 , E0 , delta_E , delta_Q = self .kinematicsAtYCenters (centers )
785
757
det , plick , angle , T0 , L0 , L1 = self ._instrument_params [self ._row_being_fit ]
786
758
dE1 , dTOF , dTheta , dL0 , dL1 , dE1_lorz = self ._resolution_params [self ._row_being_fit ]
@@ -949,7 +921,7 @@ def createSlabGeometry(self, wsNCPM):
949
921
950
922
951
923
def calcMSCorrectionSampleProperties (self , meanWidths , meanIntensityRatios ):
952
- masses = [ p . mass for p in self ._profiles . values ()]
924
+ masses = np . array ( self ._profiles_table . column ( "mass" ))
953
925
954
926
# If Backscattering mode and H is present in the sample, add H to MS properties
955
927
if self ._mode_running == "BACKWARD" :
@@ -1040,7 +1012,7 @@ def create_gamma_workspaces(self):
1040
1012
1041
1013
1042
1014
def calcGammaCorrectionProfiles (self , meanWidths , meanIntensityRatios ):
1043
- masses = [ p . mass for p in self ._profiles . values ()]
1015
+ masses = np . array ( self ._profiles_table . column ( "mass" ))
1044
1016
profiles = ""
1045
1017
for mass , width , intensity in zip (masses , meanWidths , meanIntensityRatios ):
1046
1018
profiles += (
@@ -1091,9 +1063,9 @@ def _set_results(self):
1091
1063
1092
1064
# Extract individual ncp
1093
1065
allNCP = []
1094
- for p in self ._profiles . values ( ):
1066
+ for label in self ._profiles_table . column ( "label" ):
1095
1067
ncpWsToAppend = mtd [
1096
- wsIterName + f"_{ p . label } _ncp"
1068
+ wsIterName + f"_{ label } _ncp"
1097
1069
]
1098
1070
allNCP .append (ncpWsToAppend .extractY ())
1099
1071
allNCP = np .swapaxes (np .array (allNCP ), 0 , 1 )
0 commit comments