For binning in d-spacing, provide only the number of bins and calculate the min and max in the notebook for the different banks using Premek’s code.
def read_info_and_get_bins(wf: BeerPowderMcStasWorkflow, size_d: int = 3000, size_tth: int = 500) -> dict:
"""
Function that loads Sciline workflow upto RawDetector and return important
information used for further processing and creates d-spacing, two theta
and Q bins. Number of bins can be modified for d and Q and or two theta.
Parameters
----------
data_path : str
Path to the NeXus file without the file name but with the directory delimiter
size_d : int, optional
Number of the d-spacing and Q bins. Default is 3000.
size_tth : int, optional
Number of the two theta bins. Default is 500.
Returns
-------
dict
Dictionary containing the following variables
- 'wave_min/max' - values of accepted wavwlengthes
- 't_det_min/max' - values of accepted TOF
- 'd_lamda' - size of the accepted wavelength range
and bank ['north', 'south'] decicated
- 'tth' - value of two theta angle of the bank
- 'd_bank' - position name of the bank S1-3, N1-3
- 'd_bins' - scipp.DataArray of d-spacing bins
- 'tth_bins' - scipp.DataArray of two theta bins
- 'q_bins' - scipp.DataArray of Q bins
"""
# setup of the result dictionary
result = {}
# reading the Nexus file
print('Loading "RawDetector" for the Nexus file ... ', end='', flush=True)
start = time.perf_counter()
bank = DetectorBank.north
wf[DetectorBank] = bank
data = wf.compute(RawDetector[SampleRun])
duration = time.perf_counter() - start
print(f'DONE in {_format_time(duration)}')
print('')
print('Measurement information summary')
print('-------------------------------')
# adjsting the common variables
t = data.coords['nominal_time_at_chopper'] - sc.scalar(1.6, unit='ms').to(unit='s')
dist = data.coords['source_to_wavelength_definition_chopper_distance']
wave = (t * sc.constants.h / sc.constants.m_n / dist).to(unit='angstroms')
print(f'Source chopper distance: {dist.value:0.3f} [{dist.unit}]')
print(f'Nominal wavelength: {wave.value:0.1f} [{wave.unit}]')
print(f'Time when neutrons at chopper distance: {t.value:0.5f} [{t.unit}]')
det = sc.mean(data.coords['moderator_to_detector_distance'])-dist
d_lambda = 1.73*sc.Unit('angstrom')
result['d_lambda'] = d_lambda
print(f'Acceptance wavelength range fixed to: {d_lambda.value} [{d_lambda.unit}]')
wave_min = wave - d_lambda/2
wave_max = wave + d_lambda/2
t_det_min = (sc.constants.m_n / sc.constants.h * det * wave_min).to(unit='ms')
t_det_max = (sc.constants.m_n / sc.constants.h * det * wave_max).to(unit='ms')
L2 = sc.norm(sc.mean(data.coords['position'])-data.coords['sample_position'])
L1 = det - L2
result['wave_min'] = wave_min
result['wave_max'] = wave_max
result['t_det_min'] = t_det_min
result['t_det_max'] = t_det_max
print(f'Source-sample distance (L1): {L1.value:0.3f} [{L1.unit}]')
print(f'Sample-detector distance (L2): {L2.value:0.3f} [{L2.unit}]')
print(f'Source-detector distance (L1+L2): {det.value:0.3f} [{det.unit}]')
print(f'Minimal wavelength accepted: {wave_min.value:0.2f} [{wave_min.unit}]')
print(f'Maximal wavelength accepted: {wave_max.value:0.2f} [{wave_max.unit}]')
print(f'Wave_min travel time: {t_det_min.value:0.5f} [{t_det_min.unit}]')
print(f'Wave_max travel time: {t_det_max.value:0.5f} [{t_det_max.unit}]')
# setting the wavelength mask to get rid of the frame overlap
wf[WavelengthMask] = lambda wave: (wave_min > wave) | (wave_max < wave)
# getting info about the detector positions, expecting that the McStas model
# simulate the detectors in 180 deg alignement, ie. is one 45 deg then other -135 deg,
# when one 90 the second -90, etc.
det_pos = (sc.norm(data.coords['sample_position']) -
sc.norm(sc.mean(data.coords['detector_position']))).value
if det_pos < -0.5:
tth = {'north': 45, 'south': 135}
d_bank = {'north': 'N1', 'south': 'S3'}
elif det_pos > 0.5:
tth = {'north': 135, 'south': 45}
d_bank = {'north': 'N3', 'south': 'S1'}
else:
tth = {'north': 90, 'south': 90}
d_bank = {'north': 'N2', 'south': 'S2'}
print('')
print('Individual detector information')
d_min = {}
d_max = {}
q_min = {}
q_max = {}
d_bins = {}
tth_bins = {}
q_bins = {}
tth_bins = {}
for bank in [DetectorBank.north, DetectorBank.south]:
print('-------------------------------')
n = bank.name
print(f'"{n}" detector is {d_bank[n]} at {tth[n]} [deg]')
d_min[n] = wave_min / 2 / sc.sin(sc.scalar((tth[n] + 15)/2, unit='deg'))
d_max[n] = wave_max / 2 / sc.sin(sc.scalar((tth[n] - 15)/2, unit='deg'))
d_min[n].value = _truncate(d_min[n].value, 2)
d_max[n].value = _truncate(d_max[n].value, 2)
print(f'Minimal d-spacing accepted: {d_min[n].value:0.2f} [{d_min[n].unit}]')
print(f'Maximal d-spacing accepted: {d_max[n].value:0.2f} [{d_max[n].unit}]')
d_bins[n] = sc.linspace(dim='dspacing', start=d_min[n], stop=d_max[n], num=size_d, unit='angstrom')
print(f'D-spacing bins [{len(d_bins[n])}] between {d_min[n].value} and {d_max[n].value} ' +
f'with step {(d_bins[n][1]-d_bins[n][0]).value:0.6f} [{d_max[n].unit}]')
tth_bins[n] = sc.linspace(dim='two_theta', start=tth[n] - 15, stop=tth[n] + 15, num=size_tth, unit='deg')
print(f'TwoTheta bins [{len(tth_bins[n])}] between {tth_bins[n][0].value:0.1f} and {tth_bins[n][-1].value:0.1f} ' +
f'with step {(tth_bins[n][1]-tth_bins[n][0]).value:0.4f} [{tth_bins[n].unit}]')
# QBins is not part of the BEER Sciline workflow
# The calculations related to Q below will be used for the final 1D Q-plots
q_min[n] = 2 * np.pi / d_max[n]
q_max[n] = 2 * np.pi / d_min[n]
q_min[n].value = _truncate(q_min[n].value, 2)
q_max[n].value = _truncate(q_max[n].value, 2)
q_bins[n] = sc.linspace(dim='Q', start=q_min[n], stop=q_max[n], num=size_d, unit='1/angstrom')
print(f'Q bins [{len(q_bins[n])}] between {q_min[n].value} and {q_max[n].value} ' +
f'with step {(q_bins[n][1]-q_bins[n][0]).value:0.6f} [{q_max[n].unit}]')
print('-------------------------------')
result['d_bins'] = d_bins
result['tth_bins'] = tth_bins
result['q_bins'] = q_bins
result['d_bank'] = d_bank
result['tth'] = tth
return result
This function describes all necessary steps needed before starting the full workflow.
We have to set up the mask, get proper bins depending on the detector position…. All this could also be part of the workflow.
For binning in d-spacing, provide only the number of bins and calculate the min and max in the notebook for the different banks using Premek’s code.
This function describes all necessary steps needed before starting the full workflow.
We have to set up the mask, get proper bins depending on the detector position…. All this could also be part of the workflow.