cleanup and documenting more code
This commit is contained in:
+86
-72
@@ -14,8 +14,6 @@ from .Drawable import Drawable
|
||||
from .DamarisFFT import DamarisFFT
|
||||
from .Signalpath import Signalpath
|
||||
|
||||
#from DataPool import DataPool
|
||||
|
||||
import sys
|
||||
import threading
|
||||
import tables
|
||||
@@ -25,7 +23,30 @@ import ctypes # added by Oleg Petrov
|
||||
import struct # added by Oleg Petrov
|
||||
import os # added by Oleg Petrov
|
||||
|
||||
|
||||
class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
"""
|
||||
Represents an accumulation of sampled data with various attributes and methods
|
||||
for data manipulation, analysis, and exporting.
|
||||
|
||||
This class handles statistical computations and provides mechanisms for thread-safe operations
|
||||
and data interaction.
|
||||
|
||||
Attributes:
|
||||
xlabel (str): Label for the x-axis.
|
||||
ylabel (str): Label for the y-axis.
|
||||
lock (threading.RLock): A reentrant lock to ensure thread-safe operations.
|
||||
common_descriptions (dict|None): A dictionary containing common descriptions of the data.
|
||||
time_period (list): A list to store the periods of time relevant to the accumulation.
|
||||
job_id (int|None): An identifier for the job associated with this accumulation.
|
||||
use_error (bool): Indicates whether statistical error calculations are enabled.
|
||||
sampling_rate (float): Sampling frequency of the data.
|
||||
n (int): Number of accumulations.
|
||||
cont_data (bool): Indicates whether the object contains valid data.
|
||||
index (list): List of index bounds for data segments.
|
||||
x (list): The x-axis data points.
|
||||
y (list): The y-axis data points.
|
||||
"""
|
||||
def __init__(self, x = None, y = None, y_2 = None, n = None, index = None, sampl_freq = None, error = False):
|
||||
Errorable.__init__(self)
|
||||
Drawable.__init__(self)
|
||||
@@ -33,8 +54,8 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
# Title of this accumulation (plotted in GUI -> look Drawable)
|
||||
self.__title_pattern = "Accumulation: n = %d"
|
||||
|
||||
# Axis-Labels (inherited from Drawable)
|
||||
self.xlabel = "Time (s)"
|
||||
# Axis-Labels (inherited from Drawable, overridden)
|
||||
self.xlabel = "Time / s"
|
||||
self.ylabel = "Avg. Samples [Digits]"
|
||||
self.lock=threading.RLock()
|
||||
|
||||
@@ -43,7 +64,6 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
self.job_id = None
|
||||
|
||||
self.use_error = error
|
||||
|
||||
if self.uses_statistics():
|
||||
if (y_2 is not None):
|
||||
self.y_square = y_2
|
||||
@@ -74,12 +94,10 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
|
||||
self.index = index
|
||||
self.cont_data = True
|
||||
|
||||
else:
|
||||
raise ValueError("Wrong usage of __init__!")
|
||||
|
||||
|
||||
def get_accu_by_index(self, index):
|
||||
def get_accu_by_index(self, index: int):
|
||||
self.lock.acquire()
|
||||
try:
|
||||
start = self.index[index][0]
|
||||
@@ -101,27 +119,27 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
def get_ysquare(self, channel):
|
||||
if self.uses_statistics():
|
||||
try:
|
||||
return (self.y_square)[channel]
|
||||
return self.y_square[channel]
|
||||
except:
|
||||
raise
|
||||
else:
|
||||
return None
|
||||
|
||||
def contains_data(self):
|
||||
def contains_data(self) -> bool:
|
||||
return self.cont_data
|
||||
|
||||
|
||||
def get_sampling_rate(self):
|
||||
"Returns the samplingfrequency"
|
||||
return self.sampling_rate + 0
|
||||
def get_sampling_rate(self) -> float:
|
||||
"""Returns the sampling frequency"""
|
||||
return self.sampling_rate
|
||||
|
||||
|
||||
def get_index_bounds(self, index):
|
||||
"Returns a tuple with (start, end) of the wanted result"
|
||||
def get_index_bounds(self, index) -> tuple[int,int]:
|
||||
"""Returns a tuple with (start, end) of the wanted result"""
|
||||
return self.index[index]
|
||||
|
||||
|
||||
def uses_statistics(self):
|
||||
def uses_statistics(self) -> bool:
|
||||
return self.use_error
|
||||
|
||||
# external interface --------------------------------------------------------------------
|
||||
@@ -185,8 +203,10 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
return min(tmp_min)
|
||||
|
||||
|
||||
def get_ymax(self):
|
||||
|
||||
def get_ymax(self) -> float|int:
|
||||
"""
|
||||
Returns the global maximum value of all channels.
|
||||
"""
|
||||
if not self.contains_data():
|
||||
return 0
|
||||
|
||||
@@ -201,17 +221,14 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
self.lock.release()
|
||||
return max(tmp_max)
|
||||
|
||||
def get_job_id(self):
|
||||
# return None
|
||||
def get_job_id(self) -> int:
|
||||
return self.job_id # modified by Oleg Petrov
|
||||
|
||||
def write_to_csv(self, destination=sys.stdout, delimiter=" "):
|
||||
"""
|
||||
writes the data to a file or to sys.stdout
|
||||
destination can be a file or a filename
|
||||
suitable for further processing
|
||||
writes the data to a file.
|
||||
destination can be a filehandle or a filename, default sys.stdout
|
||||
"""
|
||||
|
||||
the_destination=destination
|
||||
if isinstance(destination, str):
|
||||
the_destination=open(destination, "w")
|
||||
@@ -254,9 +271,8 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
for further processing with the NMRnotebook software;
|
||||
destination can be a file or a filename
|
||||
"""
|
||||
# write sorted
|
||||
the_destination=destination
|
||||
if type(destination) in (str,):
|
||||
if isinstance(destination, str):
|
||||
the_destination=open(destination, "w")
|
||||
|
||||
self.lock.acquire()
|
||||
@@ -275,8 +291,7 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
the_destination.write("%g%s"%(ydata[j][i], delimiter))
|
||||
the_destination.write("\n")
|
||||
the_destination.write("END\n")
|
||||
the_destination=None
|
||||
xdata=ydata=None
|
||||
the_destination.close()
|
||||
finally:
|
||||
self.lock.release()
|
||||
|
||||
@@ -409,6 +424,17 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
def write_to_hdf(self, hdffile, where, name, title, complib=None, complevel=None):
|
||||
"""
|
||||
Write the accumulation data to an HDF5 file.
|
||||
|
||||
Parameters:
|
||||
- hdffile: The HDF5 file object to write to.
|
||||
- where: The location within the HDF5 file where the data should be stored.
|
||||
- name: The name of the dataset within the HDF5 file.
|
||||
- title: The title or description of the dataset.
|
||||
- complib: Compression library to use for the dataset.
|
||||
- complevel: Compression level for the dataset.
|
||||
"""
|
||||
accu_group=hdffile.create_group(where=where,name=name,title=title)
|
||||
accu_group._v_attrs.damaris_type="Accumulation"
|
||||
if self.contains_data():
|
||||
@@ -416,20 +442,8 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
try:
|
||||
# save time stamps
|
||||
if self.time_period is not None and len(self.time_period)>0:
|
||||
accu_group._v_attrs.earliest_time="%04d%02d%02d %02d:%02d:%02d.%03d"%(self.time_period[0].year,
|
||||
self.time_period[0].month,
|
||||
self.time_period[0].day,
|
||||
self.time_period[0].hour,
|
||||
self.time_period[0].minute,
|
||||
self.time_period[0].second,
|
||||
self.time_period[0].microsecond/1000)
|
||||
accu_group._v_attrs.oldest_time="%04d%02d%02d %02d:%02d:%02d.%03d"%(self.time_period[1].year,
|
||||
self.time_period[1].month,
|
||||
self.time_period[1].day,
|
||||
self.time_period[1].hour,
|
||||
self.time_period[1].minute,
|
||||
self.time_period[1].second,
|
||||
self.time_period[1].microsecond/1000)
|
||||
accu_group._v_attrs.earliest_time = self.time_period[0].isoformat(sep=' ', timespec='milliseconds')
|
||||
accu_group._v_attrs.oldest_time = self.time_period[1].isoformat(sep=' ', timespec='milliseconds')
|
||||
if self.common_descriptions is not None:
|
||||
for (key,value) in self.common_descriptions.items():
|
||||
accu_group._v_attrs.__setattr__("description_"+key,str(value))
|
||||
@@ -519,7 +533,7 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
# External interfaces ------------------------------------------------------------------
|
||||
# Overloaded operators -----------------------------------------------------------------
|
||||
|
||||
def __len__(self):
|
||||
def __len__(self) -> int:
|
||||
"""
|
||||
return number of samples per channel, 0 if empty
|
||||
"""
|
||||
@@ -527,8 +541,8 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
return len(self.y[0])
|
||||
return 0
|
||||
|
||||
def __repr__(self):
|
||||
"Redefining repr(Accumulation)"
|
||||
def __repr__(self) -> str:
|
||||
"""Redefining repr(Accumulation)"""
|
||||
|
||||
if not self.contains_data():
|
||||
return "Empty"
|
||||
@@ -551,17 +565,22 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
|
||||
|
||||
def __add__(self, other):
|
||||
"Redefining self + other"
|
||||
# Float or int
|
||||
"""
|
||||
Redefining self + other
|
||||
We define this for different types of other:
|
||||
1) Accumulation + number
|
||||
2) Accumulation + ADC_Result
|
||||
3) Accumulation + Accumulation
|
||||
|
||||
This returns a new Accumulation object.
|
||||
"""
|
||||
# Float or int: add to each channel
|
||||
if isinstance(other, int) or isinstance(other, float):
|
||||
if not self.contains_data():
|
||||
raise ValueError("Accumulation: You cant add integers/floats to an empty accumulation")
|
||||
else:
|
||||
|
||||
tmp_y = []
|
||||
tmp_ysquare = []
|
||||
|
||||
|
||||
self.lock.acquire()
|
||||
for i in range(self.get_number_of_channels()):
|
||||
# Dont change errors and mean value
|
||||
@@ -579,15 +598,12 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
|
||||
# ADC_Result
|
||||
elif str(other.__class__) == "damaris.data.ADC_Result.ADC_Result":
|
||||
|
||||
# Other empty (return)
|
||||
# todo: this is seems to be bugy!!!! (Achim)
|
||||
if not other.contains_data():
|
||||
return
|
||||
|
||||
# Self empty (copy)
|
||||
if not self.contains_data():
|
||||
|
||||
tmp_y = []
|
||||
tmp_ysquare = []
|
||||
|
||||
@@ -597,14 +613,13 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
tmp_y.append(numpy.array(other.y[i], dtype="float32"))
|
||||
if self.uses_statistics():
|
||||
tmp_ysquare.append(tmp_y[i] ** 2)
|
||||
|
||||
|
||||
if self.uses_statistics():
|
||||
r = Accumulation(x = numpy.array(other.x, dtype="float32"), y = tmp_y, y_2 = tmp_ysquare, n = 1, index = other.index, sampl_freq = other.sampling_rate, error = True)
|
||||
else:
|
||||
r = Accumulation(x = numpy.array(other.x, dtype="float32"), y = tmp_y, index = other.index, sampl_freq = other.sampling_rate, n = 1, error = False)
|
||||
r.time_period=[other.job_date,other.job_date]
|
||||
r.job_id = other.job_id # added by Oleg Petrov
|
||||
r.job_id = other.job_id
|
||||
r.common_descriptions=other.description.copy()
|
||||
self.lock.release()
|
||||
return r
|
||||
@@ -614,14 +629,14 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
self.lock.acquire()
|
||||
|
||||
if self.sampling_rate != other.get_sampling_rate():
|
||||
raise ValueError("Accumulation: You cant add ADC-Results with diffrent sampling-rates")
|
||||
raise ValueError("Accumulation: You cant add ADC_Results with different sampling-rates")
|
||||
if len(self.y[0]) != len(other):
|
||||
raise ValueError("Accumulation: You cant add ADC-Results with diffrent number of samples")
|
||||
raise ValueError("Accumulation: You cant add ADC_Results with different number of samples")
|
||||
if len(self.y) != other.get_number_of_channels():
|
||||
raise ValueError("Accumulation: You cant add ADC-Results with diffrent number of channels")
|
||||
raise ValueError("Accumulation: You cant add ADC_Results with different number of channels")
|
||||
for i in range(len(self.index)):
|
||||
if self.index[i] != other.get_index_bounds(i):
|
||||
raise ValueError("Accumulation: You cant add ADC-Results with diffrent indexing")
|
||||
raise ValueError("Accumulation: You cant add ADC_Results with different indexing")
|
||||
|
||||
tmp_y = []
|
||||
tmp_ysquare = []
|
||||
@@ -637,7 +652,7 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
r = Accumulation(x = numpy.array(self.x, dtype="float32"), y = tmp_y, n = self.n + 1, index = self.index, sampl_freq = self.sampling_rate, error = False)
|
||||
r.time_period=[min(self.time_period[0],other.job_date),
|
||||
max(self.time_period[1],other.job_date)]
|
||||
r.job_id = other.job_id # added by Oleg Petrov
|
||||
r.job_id = other.job_id
|
||||
if self.common_descriptions is not None:
|
||||
r.common_descriptions={}
|
||||
for key in list(self.common_descriptions.keys()):
|
||||
@@ -649,7 +664,6 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
|
||||
# Accumulation
|
||||
elif str(other.__class__) == "damaris.data.Accumulation.Accumulation":
|
||||
|
||||
# Other empty (return)
|
||||
if not other.contains_data():
|
||||
return
|
||||
@@ -670,7 +684,7 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
tmp_y.append(other.y[i])
|
||||
tmp_ysquare.append(other.y_square[i])
|
||||
r.time_period=other.time_period[:]
|
||||
r.job_id = other.job_id # added by Oleg Petrov
|
||||
r.job_id = other.job_id
|
||||
if other.common_descriptions is not None:
|
||||
r.common_descriptions=other.common_descriptions.copy()
|
||||
else:
|
||||
@@ -684,14 +698,14 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
self.lock.acquire()
|
||||
|
||||
if self.sampling_rate != other.get_sampling_rate():
|
||||
raise ValueError("Accumulation: You cant add accumulations with diffrent sampling-rates")
|
||||
raise ValueError("Accumulation: You cant add accumulations with different sampling-rates")
|
||||
if len(self.y[0]) != len(other):
|
||||
raise ValueError("Accumulation: You cant add accumulations with diffrent number of samples")
|
||||
raise ValueError("Accumulation: You cant add accumulations with different number of samples")
|
||||
if len(self.y) != other.get_number_of_channels():
|
||||
raise ValueError("Accumulation: You cant add accumulations with diffrent number of channels")
|
||||
raise ValueError("Accumulation: You cant add accumulations with different number of channels")
|
||||
for i in range(len(self.index)):
|
||||
if self.index[i] != other.get_index_bounds(i):
|
||||
raise ValueError("Accumulation: You cant add accumulations with diffrent indexing")
|
||||
raise ValueError("Accumulation: You cant add accumulations with different indexing")
|
||||
if self.uses_statistics() and not other.uses_statistics():
|
||||
raise ValueError("Accumulation: You cant add non-error accumulations to accumulations with error")
|
||||
|
||||
@@ -722,22 +736,22 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
|
||||
|
||||
def __radd__(self, other):
|
||||
"Redefining other + self"
|
||||
"""Redefining other + self"""
|
||||
return self.__add__(other)
|
||||
|
||||
|
||||
def __sub__(self, other):
|
||||
"Redefining self - other"
|
||||
"""Redefining self - other"""
|
||||
return self.__add__(-other)
|
||||
|
||||
|
||||
def __rsub__(self, other):
|
||||
"Redefining other - self"
|
||||
"""Redefining other - self"""
|
||||
return self.__neg__(self.__add__(-other))
|
||||
|
||||
|
||||
def __iadd__(self, other):
|
||||
"Redefining self += other"
|
||||
"""Redefining self += other"""
|
||||
# Float or int
|
||||
if isinstance(other, int) or isinstance(other, float):
|
||||
if not self.contains_data():
|
||||
@@ -892,12 +906,12 @@ class Accumulation(Errorable, Drawable, DamarisFFT, Signalpath):
|
||||
|
||||
|
||||
def __isub__(self, other):
|
||||
"Redefining self -= other"
|
||||
"""Redefining self -= other"""
|
||||
return self.__iadd__(-other)
|
||||
|
||||
|
||||
def __neg__(self):
|
||||
"Redefining -self"
|
||||
"""Redefining -self"""
|
||||
|
||||
if not self.contains_data():
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user