Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b80a01325b | |||
| a22732c612 | |||
| 443cb30b79 | |||
| 057742cabd | |||
| 2689a969f1 | |||
| aff4c5b603 | |||
| 887ec6fa23 | |||
| 6102ed7123 | |||
| bbac3bc943 | |||
| bacbd18854 | |||
|
|
aa7919b83d | ||
| f65651d0e5 | |||
| 1b0df0ec45 | |||
| 5f94cc7b92 | |||
| a947a70d2d | |||
| 729332f49d | |||
| 500d53a9b2 | |||
| dac76efdd1 | |||
| e78200a39d | |||
| c6bde8cd85 | |||
| 8e9c03a4fb |
22
.github/workflows/release.yml
vendored
22
.github/workflows/release.yml
vendored
@@ -19,12 +19,14 @@ on:
|
||||
- all
|
||||
- windows
|
||||
- linux
|
||||
- mac
|
||||
- all_incl_release
|
||||
|
||||
jobs:
|
||||
build-ubuntu-latest:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ (github.event_name != 'workflow_dispatch') || (contains(fromJson('["all", "linux"]'), github.event.inputs.build-items)) }}
|
||||
if: ${{ (github.event_name != 'workflow_dispatch') || (contains(fromJson('["all", "linux", "all_incl_release"]'), github.event.inputs.build-items)) }}
|
||||
permissions:
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
@@ -45,16 +47,16 @@ jobs:
|
||||
path: |
|
||||
dist/*.tar.gz
|
||||
- name: Upload to PyPI
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
#if: github.event_name != 'workflow_dispatch'
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.PYPI_TOKEN }}
|
||||
# user: __token__
|
||||
# password: ${{ secrets.PYPI_TOKEN }}
|
||||
skip-existing: true
|
||||
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
if: ${{ (github.event_name != 'workflow_dispatch') || (contains(fromJson('["all", "windows"]'), github.event.inputs.build-items)) }}
|
||||
if: ${{ (github.event_name != 'workflow_dispatch') || (contains(fromJson('["all", "windows", "all_incl_release"]'), github.event.inputs.build-items)) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -79,19 +81,25 @@ jobs:
|
||||
eos.zip
|
||||
|
||||
release:
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
if: ${{ (github.event_name != 'workflow_dispatch') || (contains(fromJson('["all_incl_release"]'), github.event.inputs.build-items)) }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-ubuntu-latest, build-windows]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux-dist
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: windows-dist
|
||||
- name: get latest version tag
|
||||
run: echo "RELEASE_TAG=$(git describe --abbrev=0 --tags)" >> $GITHUB_ENV
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "amor*.tar.gz,*.zip"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
allowUpdates: true
|
||||
tag: ${{ env.RELEASE_TAG }}
|
||||
|
||||
1082
e2h_new.py
Normal file
1082
e2h_new.py
Normal file
File diff suppressed because it is too large
Load Diff
1051
events2histogram_2025.py
Executable file
1051
events2histogram_2025.py
Executable file
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,6 @@
|
||||
Package to handle data redction at AMOR instrument to be used by eos.py script.
|
||||
"""
|
||||
|
||||
__version__ = '2.1.4'
|
||||
__date__ = '2025-01-30'
|
||||
__version__ = '2.2.0'
|
||||
__date__ = '2025-09-16'
|
||||
|
||||
|
||||
@@ -185,6 +185,7 @@ def command_line_options():
|
||||
)
|
||||
experiment_config = ExperimentConfig(
|
||||
sampleModel = clas.sampleModel,
|
||||
chopperSpeed = clas.chopperSpeed,
|
||||
chopperPhase = clas.chopperPhase,
|
||||
chopperPhaseOffset = clas.chopperPhaseOffset,
|
||||
yRange = clas.yRange,
|
||||
|
||||
@@ -34,6 +34,8 @@ class AmorData:
|
||||
chopperDistance: float
|
||||
chopperPhase: float
|
||||
chopperSpeed: float
|
||||
chopper1TriggerPhase: float
|
||||
chopper2TriggerPhase: float
|
||||
div: float
|
||||
data_file_numbers: List[int]
|
||||
delta_z: np.ndarray
|
||||
@@ -96,22 +98,6 @@ class AmorData:
|
||||
self.monitorPerPulse = _monitorPerPulse
|
||||
self.pulseTimeS = _pulseTimeS
|
||||
|
||||
#-------------------------------------------------------------------------------------------------
|
||||
#def path_generator(self, number):
|
||||
# fileName = f'amor{self.reader_config.year}n{number:06d}.hdf'
|
||||
# if os.path.exists(os.path.join(self.reader_config.dataPath,fileName)):
|
||||
# path = self.reader_config.dataPath
|
||||
# elif os.path.exists(fileName):
|
||||
# path = '.'
|
||||
# elif os.path.exists(os.path.join('.','raw', fileName)):
|
||||
# path = os.path.join('.','raw')
|
||||
# elif os.path.exists(os.path.join('..','raw', fileName)):
|
||||
# path = os.path.join('..','raw')
|
||||
# elif os.path.exists(f'/afs/psi.ch/project/sinqdata/{self.reader_config.year}/amor/{int(number/1000)}/{fileName}'):
|
||||
# path = f'/afs/psi.ch/project/sinqdata/{self.reader_config.year}/amor/{int(number/1000)}'
|
||||
# else:
|
||||
# sys.exit(f'# ERROR: the file {fileName} is nowhere to be found!')
|
||||
# return os.path.join(path, fileName)
|
||||
#-------------------------------------------------------------------------------------------------
|
||||
def path_generator(self, number):
|
||||
fileName = f'amor{self.reader_config.year}n{number:06d}.hdf'
|
||||
@@ -175,7 +161,8 @@ class AmorData:
|
||||
round(self.mu+self.kap+self.kad+0.5*self.div, 3),
|
||||
'deg'),
|
||||
wavelength = fileio.ValueRange(const.lamdaCut, self.config.lambdaRange[1], 'angstrom'),
|
||||
polarization = fileio.Polarization.unpolarized,
|
||||
#polarization = fileio.Polarization.unpolarized,
|
||||
polarization = self.polarizationConfig
|
||||
)
|
||||
self.header.measurement_instrument_settings.mu = fileio.Value(round(self.mu, 3), 'deg', comment='sample angle to horizon')
|
||||
self.header.measurement_instrument_settings.nu = fileio.Value(round(self.nu, 3), 'deg', comment='detector angle to horizon')
|
||||
@@ -190,18 +177,17 @@ class AmorData:
|
||||
logging.info(f' mu = {self.mu:6.3f}, nu = {self.nu:6.3f}, kap = {self.kap:6.3f}, kad = {self.kad:6.3f}')
|
||||
|
||||
self.read_event_stream()
|
||||
totalNumber = np.shape(self.tof_e)[0]
|
||||
# check for empty event stream
|
||||
if totalNumber == 0:
|
||||
logging.error('empty event stream: can not determine end time')
|
||||
sys.exit()
|
||||
|
||||
self.sort_pulses()
|
||||
self.correct_for_chopper_phases()
|
||||
|
||||
self.associate_pulse_with_monitor()
|
||||
self.read_chopper_trigger_stream()
|
||||
|
||||
self.extract_walltime(norm)
|
||||
|
||||
self.read_proton_current_stream()
|
||||
|
||||
self.associate_pulse_with_monitor()
|
||||
|
||||
# following lines: debugging output to trace the time-offset of proton current and neutron pulses
|
||||
if self.config.monitorType == 'x':
|
||||
cpp, t_bins = np.histogram(self.wallTime_e, self.pulseTimeS)
|
||||
@@ -213,7 +199,7 @@ class AmorData:
|
||||
|
||||
self.filter_strange_times()
|
||||
|
||||
self.merge_frames()
|
||||
self.merge_time_frames()
|
||||
|
||||
self.filter_project_x()
|
||||
|
||||
@@ -223,73 +209,17 @@ class AmorData:
|
||||
|
||||
self.filter_qz_range(norm)
|
||||
|
||||
logging.info(f' number of events: total = {totalNumber:7d}, filtered = {np.shape(self.lamda_e)[0]:7d}')
|
||||
logging.info(f' number of events: total = {self.totalNumber:7d}, filtered = {np.shape(self.lamda_e)[0]:7d}')
|
||||
|
||||
def sort_pulses(self):
|
||||
chopperPeriod = np.int64(2*self.tau*1e9)
|
||||
pulseTime = np.sort(self.dataPacketTime_p)
|
||||
pulseTime = pulseTime[np.abs(pulseTime[:]-np.roll(pulseTime, 1)[:])>5]
|
||||
def read_event_stream(self):
|
||||
self.tof_e = np.array(self.hdf['/entry1/Amor/detector/data/event_time_offset'][:])/1.e9
|
||||
self.pixelID_e = np.array(self.hdf['/entry1/Amor/detector/data/event_id'][:], dtype=np.int64)
|
||||
self.dataPacket_p = np.array(self.hdf['/entry1/Amor/detector/data/event_index'][:], dtype=np.uint64)
|
||||
self.dataPacketTime_p = np.array(self.hdf['/entry1/Amor/detector/data/event_time_zero'][:], dtype=np.int64)
|
||||
|
||||
pulseTime -= np.int64(self.seriesStartTime)
|
||||
self.stopTime = pulseTime[-1]
|
||||
pulseTime = pulseTime[pulseTime>=0]
|
||||
|
||||
# fill in missing pulse times
|
||||
# TODO: check for real end time
|
||||
try:
|
||||
# further files
|
||||
# TODO: use the first pulse of the respective measurement
|
||||
#nextPulseTime = startTime % np.int64(self.tau*2e9)
|
||||
#nextPulseTime = self.pulseTimeS[-1] + chopperPeriod
|
||||
nextPulseTime = pulseTime[0]
|
||||
except AttributeError:
|
||||
# first file
|
||||
nextPulseTime = pulseTime[0] % np.int64(self.tau*2e9)
|
||||
|
||||
# calculate where time tiefference between pulses exceeds its time by more than 1/2
|
||||
# this yields the number of missing pulses
|
||||
pulseLengths = pulseTime[1:]-pulseTime[:-1]
|
||||
pulseExtra = (pulseLengths-np.int64(self.tau*1e9))//np.int64(self.tau*2e9)
|
||||
gap_indices = np.where(pulseExtra>0)[0]
|
||||
|
||||
if len(gap_indices)==0:
|
||||
# no missing pulses, just use given array
|
||||
self.pulseTimeS = np.array(pulseTime, dtype=np.int64)
|
||||
return
|
||||
self.pulseTimeS = np.array(pulseTime[:gap_indices[0]+1], dtype=np.int64)
|
||||
last_index = gap_indices[0]
|
||||
for gapi in gap_indices[1:]:
|
||||
# insert missing pulses into each gap
|
||||
gap_pulses = pulseTime[last_index]+np.arange(1, pulseExtra[last_index]+1)*chopperPeriod
|
||||
self.pulseTimeS = np.append(self.pulseTimeS, gap_pulses)
|
||||
self.pulseTimeS = np.append(self.pulseTimeS, pulseTime[last_index+1:gapi+1])
|
||||
last_index = gapi
|
||||
if last_index<len(pulseTime):
|
||||
self.pulseTimeS = np.append(self.pulseTimeS, pulseTime[last_index:-1])
|
||||
|
||||
def get_current_per_pulse(self, pulseTimeS, currentTimeS, currents):
|
||||
# add currents for early pulses and current time value after last pulse (j+1)
|
||||
currentTimeS = np.hstack([[0], currentTimeS, [pulseTimeS[-1]+1]])
|
||||
currents = np.hstack([[0], currents])
|
||||
pulseCurrentS = np.zeros(pulseTimeS.shape[0], dtype=float)
|
||||
j = 0
|
||||
for i, ti in enumerate(pulseTimeS):
|
||||
if ti >= currentTimeS[j+1]:
|
||||
j += 1
|
||||
pulseCurrentS[i] = currents[j]
|
||||
#print(f' {i} {pulseTimeS[i]} {pulseCurrentS[i]}')
|
||||
return pulseCurrentS
|
||||
|
||||
def associate_pulse_with_monitor(self):
|
||||
if self.config.monitorType == 'p': # protonCharge
|
||||
self.currentTime -= np.int64(self.seriesStartTime)
|
||||
self.monitorPerPulse = self.get_current_per_pulse(self.pulseTimeS, self.currentTime, self.current) * 2*self.tau * 1e-3
|
||||
# filter low-current pulses
|
||||
self.monitorPerPulse = np.where(self.monitorPerPulse > 2*self.tau * self.config.lowCurrentThreshold * 1e-3, self.monitorPerPulse, 0)
|
||||
elif self.config.monitorType == 't': # countingTime
|
||||
self.monitorPerPulse = np.ones(np.shape(self.pulseTimeS)[0])*self.tau
|
||||
else:
|
||||
self.monitorPerPulse = 1./np.shape(pulseTimeS)[1]
|
||||
def correct_for_chopper_phases(self):
|
||||
#print(f'chopperTriggerPhase: {self.ch1TriggerPhase}')
|
||||
self.tof_e += self.tau * (self.ch1TriggerPhase + self.chopperPhase/2)/180
|
||||
|
||||
def extract_walltime(self, norm):
|
||||
if nb_helpers:
|
||||
@@ -302,6 +232,54 @@ class AmorData:
|
||||
self.wallTime_e -= np.int64(self.seriesStartTime)
|
||||
logging.debug(f' wall time from {self.wallTime_e[0]/1e9:6.1f} s to {self.wallTime_e[-1]/1e9:6.1f} s')
|
||||
|
||||
def read_chopper_trigger_stream(self):
|
||||
self.chopper1TriggerTime = np.array(self.hdf['entry1/Amor/chopper/ch2_trigger/event_time_zero'][:-2], dtype=np.int64)
|
||||
#self.chopper2TriggerTime = self.chopper1TriggerTime + np.array(self.hdf['entry1/Amor/chopper/ch2_trigger/event_time'][:-2], dtype=np.int64)
|
||||
# + np.array(self.hdf['entry1/Amor/chopper/ch2_trigger/event_time_offset'][:], dtype=np.int64)
|
||||
if np.shape(self.chopper1TriggerTime)[0] > 2:
|
||||
self.startTime = self.chopper1TriggerTime[0]
|
||||
self.stopTime = self.chopper1TriggerTime[-1]
|
||||
self.pulseTimeS = self.chopper1TriggerTime
|
||||
else:
|
||||
logging.warn(' no chopper trigger data available, using event steram instead')
|
||||
self.startTime = np.array(self.hdf['/entry1/Amor/detector/data/event_time_zero'][0], dtype=np.int64)
|
||||
self.stopTime = np.array(self.hdf['/entry1/Amor/detector/data/event_time_zero'][-2], dtype=np.int64)
|
||||
self.pulseTimeS = np.arange(self.startTime, self.stopTime, self.tau*1e9)
|
||||
if self.seriesStartTime is None:
|
||||
self.seriesStartTime = self.startTime
|
||||
logging.debug(f' series start time (epoch): {self.seriesStartTime/1e9:13.2f} s')
|
||||
self.pulseTimeS -= self.seriesStartTime
|
||||
logging.debug(f' epoch time from {self.startTime/1e9:13.2f} s to {self.stopTime/1e9:13.2f} s')
|
||||
logging.debug(f' => counting time {self.stopTime/1e9-self.startTime/1e9:8.2f} s')
|
||||
|
||||
def read_proton_current_stream(self):
|
||||
self.currentTime = np.array(self.hdf['entry1/Amor/detector/proton_current/time'][:], dtype=np.int64)
|
||||
self.current = np.array(self.hdf['entry1/Amor/detector/proton_current/value'][:,0], dtype=float)
|
||||
|
||||
def get_current_per_pulse(self, pulseTimeS, currentTimeS, currents):
|
||||
# add currents for early pulses and current time value after last pulse (j+1)
|
||||
currentTimeS = np.hstack([[0], currentTimeS, [pulseTimeS[-1]+1]])
|
||||
currents = np.hstack([[0], currents])
|
||||
pulseCurrentS = np.zeros(pulseTimeS.shape[0], dtype=float)
|
||||
j = 0
|
||||
for i, ti in enumerate(pulseTimeS):
|
||||
while ti >= currentTimeS[j+1]:
|
||||
j += 1
|
||||
pulseCurrentS[i] = currents[j]
|
||||
#print(f' {i} {pulseTimeS[i]} {pulseCurrentS[i]}')
|
||||
return pulseCurrentS
|
||||
|
||||
def associate_pulse_with_monitor(self):
|
||||
if self.config.monitorType == 'p': # protonCharge
|
||||
self.currentTime -= np.int64(self.seriesStartTime)
|
||||
self.monitorPerPulse = self.get_current_per_pulse(self.pulseTimeS, self.currentTime, self.current) * 2*self.tau * 1e-3
|
||||
# filter low-current pulses
|
||||
self.monitorPerPulse = np.where(self.monitorPerPulse > 2*self.tau * self.config.lowCurrentThreshold * 1e-3, self.monitorPerPulse, 0)
|
||||
elif self.config.monitorType == 't': # countingTime
|
||||
self.monitorPerPulse = np.ones(np.shape(self.pulseTimeS)[0])*2*self.tau
|
||||
else: # pulses
|
||||
self.monitorPerPulse = np.ones(np.shape(self.pulseTimeS)[0])
|
||||
|
||||
def average_events_per_pulse(self):
|
||||
if self.config.monitorType == 'p':
|
||||
for i, time in enumerate(self.pulseTimeS):
|
||||
@@ -309,18 +287,20 @@ class AmorData:
|
||||
logging.info(f'pulse: {i:6.0f}, events: {events:6.0f}, monitor: {self.monitorPerPulse[i]:6.2f}')
|
||||
|
||||
def monitor_threshold(self):
|
||||
if self.config.monitorType == 'p': # fix to check for file compatibility
|
||||
#if self.config.monitorType == 'p': # fix to check for file compatibility
|
||||
self.totalNumber = np.shape(self.tof_e[self.tof_e<=self.stopTime])[0]
|
||||
if True:
|
||||
goodTimeS = self.pulseTimeS[self.monitorPerPulse!=0]
|
||||
filter_e = np.where(np.isin(self.wallTime_e, goodTimeS), True, False)
|
||||
self.tof_e = self.tof_e[filter_e]
|
||||
self.pixelID_e = self.pixelID_e[filter_e]
|
||||
self.wallTime_e = self.wallTime_e[filter_e]
|
||||
logging.info(f' rejected {np.shape(self.monitorPerPulse)[0]-np.shape(goodTimeS)[0]} out of {np.shape(self.monitorPerPulse)[0]} pulses')
|
||||
logging.info(f' with {np.shape(filter_e)[0]-np.shape(self.tof_e)[0]} events due to low beam current')
|
||||
logging.info(f' low-beam rejected pulses: {np.shape(self.monitorPerPulse)[0]-1-np.shape(goodTimeS)[0]} out of {np.shape(self.monitorPerPulse)[0]-1}')
|
||||
logging.info(f' with {np.shape(filter_e)[0]-np.shape(self.tof_e)[0]} events')
|
||||
logging.info(f' average counts per pulse = {np.shape(self.tof_e)[0] / np.shape(goodTimeS[goodTimeS!=0])[0]:7.1f}')
|
||||
|
||||
def filter_qz_range(self, norm):
|
||||
if self.config.qzRange[1]<0.3 and not norm:
|
||||
if self.config.qzRange[1]<0.5 and not norm:
|
||||
self.mask_e = np.logical_and(self.mask_e,
|
||||
(self.config.qzRange[0]<=self.qz_e) & (self.qz_e<=self.config.qzRange[1]))
|
||||
self.detZ_e = self.detZ_e[self.mask_e]
|
||||
@@ -329,7 +309,8 @@ class AmorData:
|
||||
|
||||
def calculate_derived_properties(self):
|
||||
self.lamdaMax = const.lamdaCut+1.e13*self.tau*const.hdm/(self.chopperDetectorDistance+124.)
|
||||
if nb_helpers:
|
||||
#if nb_helpers:
|
||||
if False:
|
||||
self.lamda_e, self.qz_e, self.mask_e = nb_helpers.calculate_derived_properties_focussing(
|
||||
self.tof_e, self.detXdist_e, self.delta_e, self.mask_e,
|
||||
self.config.lambdaRange[0], self.config.lambdaRange[1], self.nu, self.mu,
|
||||
@@ -379,8 +360,9 @@ class AmorData:
|
||||
# define mask and filter y range
|
||||
self.mask_e = (self.config.yRange[0]<=detY_e) & (detY_e<=self.config.yRange[1])
|
||||
|
||||
def merge_frames(self):
|
||||
total_offset = self.tofCut+self.tau*self.config.chopperPhaseOffset/180.
|
||||
# TODO: - handle each neutron pulse individually, - associate with correct monitor also for slow neutrons
|
||||
def merge_time_frames(self):
|
||||
total_offset = self.tofCut + self.tau * (self.ch1TriggerPhase + self.chopperPhase/2)/180
|
||||
if nb_helpers:
|
||||
self.tof_e = nb_helpers.merge_frames(self.tof_e, self.tofCut, self.tau, total_offset)
|
||||
else:
|
||||
@@ -395,44 +377,45 @@ class AmorData:
|
||||
if np.shape(filter_e)[0]-np.shape(self.tof_e)[0]>0.5:
|
||||
logging.warning(f' strange times: {np.shape(filter_e)[0]-np.shape(self.tof_e)[0]}')
|
||||
|
||||
def read_event_stream(self):
|
||||
self.tof_e = np.array(self.hdf['/entry1/Amor/detector/data/event_time_offset'][:])/1.e9
|
||||
self.pixelID_e = np.array(self.hdf['/entry1/Amor/detector/data/event_id'][:], dtype=np.int64)
|
||||
self.dataPacket_p = np.array(self.hdf['/entry1/Amor/detector/data/event_index'][:], dtype=np.uint64)
|
||||
self.dataPacketTime_p = np.array(self.hdf['/entry1/Amor/detector/data/event_time_zero'][:], dtype=np.int64)
|
||||
if self.config.monitorType in ['auto', 'p']:
|
||||
try:
|
||||
self.currentTime = np.array(self.hdf['entry1/Amor/detector/proton_current/time'][:], dtype=np.int64)
|
||||
self.current = np.array(self.hdf['entry1/Amor/detector/proton_current/value'][:,0], dtype=float)
|
||||
if len(self.current)>4:
|
||||
self.config.monitorType = 'p'
|
||||
else:
|
||||
self.config.monitorType = 't'
|
||||
except(KeyError, IndexError):
|
||||
self.config.monitorType = 't'
|
||||
else:
|
||||
self.config.monitorType = 't'
|
||||
#TODO: protonMonitor
|
||||
|
||||
def read_individual_header(self):
|
||||
self.chopperDistance = float(np.take(self.hdf['entry1/Amor/chopper/pair_separation'], 0))
|
||||
self.detectorDistance = float(np.take(self.hdf['entry1/Amor/detector/transformation/distance'], 0))
|
||||
self.chopperDetectorDistance = self.detectorDistance-float(np.take(self.hdf['entry1/Amor/chopper/distance'], 0))
|
||||
self.tofCut = const.lamdaCut*self.chopperDetectorDistance/const.hdm*1.e-13
|
||||
|
||||
polarizationConfigs = ['undefined', 'unpolarized', 'po', 'mo', 'op', 'pp', 'mp', 'om', 'pm', 'mm']
|
||||
try:
|
||||
self.mu = float(np.take(self.hdf['/entry1/Amor/master_parameters/mu/value'], 0))
|
||||
self.nu = float(np.take(self.hdf['/entry1/Amor/master_parameters/nu/value'], 0))
|
||||
self.kap = float(np.take(self.hdf['/entry1/Amor/master_parameters/kap/value'], 0))
|
||||
self.kad = float(np.take(self.hdf['/entry1/Amor/master_parameters/kad/value'], 0))
|
||||
self.div = float(np.take(self.hdf['/entry1/Amor/master_parameters/div/value'], 0))
|
||||
self.chopperSpeed = float(np.take(self.hdf['/entry1/Amor/chopper/rotation_speed/value'], 0))
|
||||
self.chopperPhase = float(np.take(self.hdf['/entry1/Amor/chopper/phase/value'], 0))
|
||||
self.mu = float(np.take(self.hdf['/entry1/Amor/instrument_control_parameters/mu'], 0))
|
||||
self.nu = float(np.take(self.hdf['/entry1/Amor/instrument_control_parameters/nu'], 0))
|
||||
self.kap = float(np.take(self.hdf['/entry1/Amor/instrument_control_parameters/kap'], 0))
|
||||
self.kad = float(np.take(self.hdf['/entry1/Amor/instrument_control_parameters/kad'], 0))
|
||||
self.div = float(np.take(self.hdf['/entry1/Amor/instrument_control_parameters/div'], 0))
|
||||
self.ch1TriggerPhase = float(np.take(self.hdf['/entry1/Amor/chopper/ch1_trigger_phase'], 0))
|
||||
self.ch2TriggerPhase = float(np.take(self.hdf['/entry1/Amor/chopper/ch2_trigger_phase'], 0))
|
||||
try:
|
||||
chopperTriggerTime = float(self.hdf['entry1/Amor/chopper/ch2_trigger/event_time_zero'][2])\
|
||||
- float(self.hdf['entry1/Amor/chopper/ch2_trigger/event_time_zero'][1])
|
||||
self.tau = int(1e-6*chopperTriggerTime/2+0.5)*(1e-3)
|
||||
self.chopperSpeed = 30/self.tau
|
||||
chopperTriggerTimeDiff = float(self.hdf['entry1/Amor/chopper/ch2_trigger/event_time_offset'][2])
|
||||
chopperTriggerPhase = 180e-9*chopperTriggerTimeDiff/self.tau
|
||||
#TODO: check the next line
|
||||
self.chopperPhase = chopperTriggerPhase + self.ch1TriggerPhase - self.ch2TriggerPhase
|
||||
except(KeyError, IndexError):
|
||||
logging.debug(' chopper speed and phase taken from .hdf file')
|
||||
self.chopperSpeed = float(np.take(self.hdf['/entry1/Amor/chopper/rotation_speed'], 0))
|
||||
self.chopperPhase = float(np.take(self.hdf['/entry1/Amor/chopper/phase'], 0))
|
||||
self.tau = 30/self.chopperSpeed
|
||||
try:
|
||||
polarizationConfigLabel = int(self.hdf['/entry1/Amor/polarization/configuration/value'][0])
|
||||
except(KeyError, IndexError):
|
||||
polarizationConfigLabel = 0
|
||||
self.polarizationConfig = polarizationConfigs[polarizationConfigLabel]
|
||||
logging.debug(f' polarization configuration: {self.polarizationConfig} (index {polarizationConfigLabel} (index {polarizationConfigLabel}))')
|
||||
except(KeyError, IndexError):
|
||||
logging.warning(" using parameters from nicos cache")
|
||||
year_date = str(self.start_date).replace('-', '/', 1)
|
||||
#cachePath = '/home/amor/nicosdata/amor/cache/'
|
||||
#cachePath = '/home/nicos/amorcache/'
|
||||
# TODO: check new cache pathes
|
||||
cachePath = '/home/amor/cache/'
|
||||
value = str(subprocess.getoutput(f'/usr/bin/grep "value" {cachePath}nicos-mu/{year_date}')).split('\t')[-1]
|
||||
self.mu = float(value)
|
||||
@@ -446,22 +429,35 @@ class AmorData:
|
||||
self.div = float(value)
|
||||
value = str(subprocess.getoutput(f'/usr/bin/grep "value" {cachePath}nicos-ch1_speed/{year_date}')).split('\t')[-1]
|
||||
self.chopperSpeed = float(value)
|
||||
self.chopperPhase = self.config.chopperPhase
|
||||
self.tau = 30. / self.chopperSpeed
|
||||
value = str(subprocess.getoutput(f'/usr/bin/grep "value" {cachePath}nicos-chopper_phase/{year_date}')).split('\t')[-1]
|
||||
self.chopperPhase = float(value)
|
||||
value = str(subprocess.getoutput(f'/usr/bin/grep "value" {cachePath}nicos-ch1_trigger_phase/{year_date}')).split('\t')[-1]
|
||||
self.ch1TriggerPhase = float(value)
|
||||
value = str(subprocess.getoutput(f'/usr/bin/grep "value" {cachePath}nicos-ch2_trigger_phase/{year_date}')).split('\t')[-1]
|
||||
self.ch2TriggerPhase = float(value)
|
||||
|
||||
self.tau = 30. / self.chopperSpeed
|
||||
|
||||
logging.debug(f' tau = {self.tau} s')
|
||||
if self.config.muOffset:
|
||||
logging.debug(f' set muOffset = {self.config.muOffset}')
|
||||
self.mu += self.config.muOffset
|
||||
if self.config.mu:
|
||||
logging.debug(f' replaced mu = {self.mu} with {self.config.mu}')
|
||||
self.mu = self.config.mu
|
||||
if self.config.nu:
|
||||
logging.debug(f' replaced nu = {self.nu} with {self.config.nu}')
|
||||
self.nu = self.config.nu
|
||||
if self.config.chopperPhaseOffset:
|
||||
logging.debug(f' replaced ch1TriggerPhase = {self.ch1TriggerPhase} with {self.config.chopperPhaseOffset}')
|
||||
self.ch1TriggerPhase = self.config.chopperPhaseOffset
|
||||
|
||||
# extract start time as unix time, adding UTC offset of 1h to time string
|
||||
dz = datetime.fromisoformat(self.hdf['/entry1/start_time'][0].decode('utf-8'))
|
||||
self.fileDate=dz.replace(tzinfo=AMOR_LOCAL_TIMEZONE)
|
||||
self.startTime = np.int64( (self.fileDate.timestamp() ) * 1e9 )
|
||||
if self.seriesStartTime is None:
|
||||
self.seriesStartTime = self.startTime
|
||||
#self.startTime = np.int64( (self.fileDate.timestamp() ) * 1e9 )
|
||||
#if self.seriesStartTime is None:
|
||||
# self.seriesStartTime = self.startTime
|
||||
|
||||
def read_header_info(self):
|
||||
# read general information and first data set
|
||||
|
||||
@@ -29,10 +29,10 @@ class Defaults:
|
||||
thetaRange = [-12., 12.]
|
||||
thetaRangeR = [-0.75, 0.75]
|
||||
yRange = [11, 41]
|
||||
qzRange = [0.005, 0.30]
|
||||
qzRange = [0.005, 0.51]
|
||||
chopperSpeed = 500
|
||||
chopperPhase = -13.5
|
||||
chopperPhaseOffset = 7
|
||||
chopperPhase = 0.0
|
||||
chopperPhaseOffset = -9.1
|
||||
muOffset = 0
|
||||
mu = 0
|
||||
nu = 0
|
||||
@@ -52,6 +52,7 @@ class ReaderConfig:
|
||||
class ExperimentConfig:
|
||||
incidentAngle: str
|
||||
chopperPhase: float
|
||||
chopperSpeed: float
|
||||
yRange: Tuple[float, float]
|
||||
lambdaRange: Tuple[float, float]
|
||||
qzRange: Tuple[float, float]
|
||||
|
||||
@@ -22,7 +22,7 @@ class AmorReduction:
|
||||
self.header = Header()
|
||||
self.header.reduction.call = config.call_string()
|
||||
|
||||
self.monitorUnit = {'n': 'cnts', 'p': 'mC', 't': 's'}
|
||||
self.monitorUnit = {'n': 'cnts', 'p': 'mC', 't': 's', 'auto': 'pulses'}
|
||||
|
||||
def reduce(self):
|
||||
if not os.path.exists(f'{self.output_config.outputPath}'):
|
||||
|
||||
Reference in New Issue
Block a user