Enabling OFR Analyser class to include timestamp of sample, commencing Helper file with some functions and classes that can be used to handle data formats delivered by several instruments.
This commit is contained in:
1 parent
1ab5362d2b
commit
f66e1d50e5
5 files changed
+82
-50
No files matched your search
@@ -1,9 +1,9 @@
|
||||
# GENERAL SETTINGS
|
||||
font.size: 10
|
||||
text.usetex: True
|
||||
text.latex.preamble: "\usepackage{arev}\usepackage{siunitx}\usepackage{mhchem}\newcommand{\der}[1]{\ensuremath{\textnormal{d}\,{#1}}}"
|
||||
lines.linewidth: 0.75 # line width in points
|
||||
lines.linestyle: - # solid line
|
||||
text.latex.preamble: "\usepackage{arev}\usepackage{accents}\usepackage{siunitx}\usepackage{mhchem}\newcommand{\der}[1]{\ensuremath{\textnormal{d}\,{#1}}}"
|
||||
lines.linewidth: 1.00 # line width in points
|
||||
lines.linestyle: - # solid line
|
||||
|
||||
# AXES AND BOX
|
||||
axes.facecolor: white # axes background color
|
||||
@@ -64,7 +64,6 @@ ytick.alignment: center_baseline # alignment of yticks
|
||||
|
||||
# TITLE
|
||||
axes.titlelocation: left
|
||||
axes.titlesize: large # font size of the axes title
|
||||
axes.titleweight: normal # font weight of title
|
||||
|
||||
# LEGEND
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import pandas as pd
|
||||
|
||||
class DATFile():
|
||||
|
||||
|
||||
def __init__(self, file, data_name = 'value'):
|
||||
|
||||
self.file = file
|
||||
self.data_name = data_name
|
||||
self.data = None
|
||||
|
||||
def read(self):
|
||||
|
||||
dates = []
|
||||
times = []
|
||||
values = []
|
||||
|
||||
with open(self.file, 'r', errors='ignore') as f:
|
||||
for i, line in enumerate(f.readlines()):
|
||||
|
||||
if i >= 3:
|
||||
|
||||
items = line.split()
|
||||
dates.append(items[0])
|
||||
times.append(items[1])
|
||||
values.append(float(items[2]))
|
||||
|
||||
pre_datetimes = [date + ' ' + time for date, time in zip(dates, times)]
|
||||
datetimes = pd.to_datetime(pre_datetimes, format=r'%d.%m.%Y %H:%M:%S')
|
||||
self.data = pd.DataFrame({'timestamp': datetimes, self.data_name: values})
|
||||
+43
-37
@@ -149,6 +149,8 @@ class OFRSample:
|
||||
|
||||
number: int
|
||||
The sample number
|
||||
start_time: pd.datetime
|
||||
The starting time of the sample recording
|
||||
sourcefile: str
|
||||
The path to the data file
|
||||
headlines: int
|
||||
@@ -177,8 +179,17 @@ class OFRSample:
|
||||
midpoints = []
|
||||
counts = []
|
||||
|
||||
date_line = None
|
||||
time_line = None
|
||||
|
||||
with open(self.source_file, 'r', errors = 'ignore') as file:
|
||||
for i, line in enumerate(file.readlines()):
|
||||
if i == 18:
|
||||
date_line = line
|
||||
continue
|
||||
if i == 19:
|
||||
time_line = line
|
||||
continue
|
||||
if i == 20:
|
||||
data_flag = True
|
||||
continue
|
||||
@@ -212,6 +223,16 @@ class OFRSample:
|
||||
self.sampling_time = self.scan_up_time + self.scan_down_time
|
||||
data_lines.pop(-1)
|
||||
|
||||
# obtaining the starting time
|
||||
raw_date_items = date_line.split(self.__data_separator)
|
||||
raw_time_items = time_line.split(self.__data_separator)
|
||||
del raw_date_items[0]
|
||||
del raw_time_items[0]
|
||||
|
||||
raw_date = raw_date_items[(self.sample_number - 1) * 2].splitlines()[0]
|
||||
raw_time = raw_time_items[(self.sample_number - 1) * 2].splitlines()[0]
|
||||
self.start_time = pd.to_datetime(raw_date + ' ' + raw_time, format=r'%m/%d/%y %H:%M:%S')
|
||||
|
||||
for line in data_lines:
|
||||
items = line.split(self.__data_separator)
|
||||
local_diameter_midpoint = float(items[0])
|
||||
@@ -227,7 +248,6 @@ class OFRSample:
|
||||
self.lower_diameter_bound = self.lower_diameter_bound * 1E-9
|
||||
self.upper_diameter_bound = self.upper_diameter_bound * 1E-9
|
||||
|
||||
|
||||
# Input data from file is in (nm)
|
||||
return [np.array(midpoints), np.array(counts)]
|
||||
|
||||
@@ -239,6 +259,7 @@ class OFRSample:
|
||||
# Sample information
|
||||
self.source_file = source_file # where the data is stored, i.e. "C:/Users/tschan_d/..."
|
||||
self.sample_number = sample_number # sample number, i.e. 33
|
||||
self.start_time = None
|
||||
self.__data_separator = data_separator
|
||||
|
||||
self.scan_up_time = None # Time to scan up the voltage range in DMA, in (s)
|
||||
@@ -280,7 +301,7 @@ class OFRAnalyser:
|
||||
----------
|
||||
data_source_file: str
|
||||
A string pointing to the data source file
|
||||
flows_source_file: str
|
||||
flow_source_file: str
|
||||
A string pointing to the flow data source file
|
||||
sample_number_list: [int]
|
||||
A list of integers indicating which samples to consider
|
||||
@@ -290,11 +311,11 @@ class OFRAnalyser:
|
||||
A dataframe containing all the data
|
||||
"""
|
||||
|
||||
def __init__(self, data_source_file, flows_source_file, sample_number_list, data_separator = ',') -> None:
|
||||
def __init__(self, data_source_file, flow_source_file, smpl_number_list, data_separator = ',') -> None:
|
||||
|
||||
self.data_source_file = data_source_file
|
||||
self.flows_source_file = flows_source_file
|
||||
self.sample_number_list = sample_number_list
|
||||
self.flow_source_file = flow_source_file
|
||||
self.smpl_number_list = smpl_number_list
|
||||
self.__data_separator = data_separator
|
||||
|
||||
with open(self.data_source_file, 'r', errors = 'ignore') as file:
|
||||
@@ -308,11 +329,11 @@ class OFRAnalyser:
|
||||
self.max_samples = max_sample_number
|
||||
self.data = None
|
||||
|
||||
def __sample_number_list_check(self, sample_number_list) -> None:
|
||||
def __smpl_number_list_check(self, smpl_number_list) -> None:
|
||||
|
||||
# TODO: implement a similar check for the flow data file!
|
||||
|
||||
last_sample = sample_number_list[-1]
|
||||
last_sample = smpl_number_list[-1]
|
||||
|
||||
if last_sample > self.max_samples:
|
||||
raise IndexError("The last sample(s) are out of range of the number of recorded samples")
|
||||
@@ -329,32 +350,29 @@ class OFRAnalyser:
|
||||
# TODO make this work also for a specific sample!
|
||||
# TODO convert everything is SI units, making live a lot easier...
|
||||
|
||||
self.__sample_number_list_check(self.sample_number_list)
|
||||
self.__smpl_number_list_check(self.smpl_number_list)
|
||||
|
||||
# Quantities of interest:
|
||||
numbers_of_sample = [] # (-)
|
||||
starting_times = [] # (timestamp)
|
||||
sampling_times = [] # (s)
|
||||
number_concentrations = [] # (#/m^3)
|
||||
length_concentrations = [] # (m/m^3)
|
||||
surface_concentrations = [] # (m^2/m^3)
|
||||
volume_concentrations = [] # (m^3/m^3)
|
||||
aerosol_densities = [] # (kg/m^3)
|
||||
mass_concentrations = [] # (kg/m^3)
|
||||
starting_times = [] # (s)
|
||||
stopping_times = [] # (s)
|
||||
sampling_times = [] # (s)
|
||||
dry_air_flows = [] # (m^3/s)
|
||||
species_flows = [] # (m^3/s)
|
||||
ozone_flows = [] # (m^3/s)
|
||||
total_flows = None # (m^3/s)
|
||||
cpc_flows = [] # (m^3/s)
|
||||
filter_flows = [] # (m^3/s)
|
||||
mass_production_rate = None # (kg/s)
|
||||
mass_produced = None # (kg)
|
||||
cumulative_mass_produced = None # (kg)
|
||||
|
||||
|
||||
for sample_number in self.sample_number_list:
|
||||
for sample_number in self.smpl_number_list:
|
||||
sample = OFRSample(source_file=self.data_source_file, sample_number = sample_number, data_separator = self.__data_separator)
|
||||
|
||||
numbers_of_sample.append(sample_number)
|
||||
starting_times.append(sample.start_time)
|
||||
|
||||
number_concentrations.append(sample.Count.integrate())
|
||||
length_concentrations.append(sample.Length.integrate())
|
||||
surface_concentrations.append(sample.Surface.integrate())
|
||||
@@ -362,14 +380,11 @@ class OFRAnalyser:
|
||||
aerosol_densities.append(sample.SOA_density)
|
||||
mass_concentrations.append(sample.Mass.integrate())
|
||||
|
||||
starting_times.append((sample_number - 1) * sample.sampling_time)
|
||||
stopping_times.append(sample_number * sample.sampling_time)
|
||||
|
||||
sampling_times.append(sample.sampling_time)
|
||||
|
||||
out_flag = False
|
||||
|
||||
with open(self.flows_source_file, 'r', errors='ignore') as file:
|
||||
with open(self.flow_source_file, 'r', errors='ignore') as file:
|
||||
|
||||
j = 1
|
||||
|
||||
@@ -389,11 +404,8 @@ class OFRAnalyser:
|
||||
|
||||
while i < int(items[-1]):
|
||||
|
||||
if j in self.sample_number_list:
|
||||
dry_air_flows.append(float(items[0]) * 6E-4)
|
||||
species_flows.append(float(items[1]) * 6E-4)
|
||||
ozone_flows.append(float(items[2]) * 6E-4)
|
||||
cpc_flows.append(float(items[3]) * 6E-4)
|
||||
if j in self.smpl_number_list:
|
||||
filter_flows.append(float(items[0]) * 6E-4)
|
||||
|
||||
i += 1
|
||||
j += 1
|
||||
@@ -401,26 +413,20 @@ class OFRAnalyser:
|
||||
else:
|
||||
continue
|
||||
|
||||
total_flows = [(flow_1 + flow_2 + flow_3) for flow_1, flow_2, flow_3 in zip(dry_air_flows, species_flows, ozone_flows)]
|
||||
mass_production_rate = [(mass * flow) for mass, flow in zip(mass_concentrations, total_flows)]
|
||||
mass_production_rate = [(mass * flow) for mass, flow in zip(mass_concentrations, filter_flows)]
|
||||
mass_produced = [(mpr * duration) for mpr, duration in zip(mass_production_rate, sampling_times)]
|
||||
cumulative_mass_produced = np.cumsum(np.array(mass_produced)).tolist()
|
||||
|
||||
self.data = pd.DataFrame({'Sample (-)': numbers_of_sample,
|
||||
'Starting Time (-)': starting_times,
|
||||
'Sampling Time (s)': sampling_times,
|
||||
'Number (#/m^3)': number_concentrations,
|
||||
'Length (m/m^3)': length_concentrations,
|
||||
'Surface (m^2/m^3)': surface_concentrations,
|
||||
'Volume (m^3/m^3)': volume_concentrations,
|
||||
'Density (kg/m^3)': aerosol_densities,
|
||||
'Mass (kg/m^3)': mass_concentrations,
|
||||
'Start (s)': starting_times,
|
||||
'Stop (s)': stopping_times,
|
||||
'Duration (s)': sampling_times,
|
||||
'Dry Air Flow (m^3/s)': dry_air_flows,
|
||||
'Species Flow (m^3/s)': species_flows,
|
||||
'Ozone Flow (m^3/s)': ozone_flows,
|
||||
'Total Flow (m^3/s)': total_flows,
|
||||
'CPC Flow (m^3/s)': cpc_flows,
|
||||
'Filter Flow (m^3/s)': filter_flows,
|
||||
'Mass Production Rate (kg/s)': mass_production_rate,
|
||||
'Mass Produced (kg)': mass_produced,
|
||||
'Cumulative Mass Produced (kg)': cumulative_mass_produced})
|
||||
|
||||
File renamed without changes.
@@ -1,14 +1,11 @@
|
||||
# Imports
|
||||
from defs.OFR import OFRSample, OFRAnalyser
|
||||
import numpy as np
|
||||
from pathlib import Path
|
||||
|
||||
# Path to the source file
|
||||
source_file = Path(r"Z:\People\David_Tschan\data\OFR_SMPS\2026\processed\07_July\20260709\20260709_aPinene_SOA_full.txt")
|
||||
flows_source_file = Path(r"Z:\People\David_Tschan\data\OFR_SMPS\2026\processed\07_July\20260709\20260709_aPinene_SOA_flows.txt")
|
||||
# Linking to the data
|
||||
|
||||
# Code to debug
|
||||
sample_number_list = range(1, 609)
|
||||
analyser = OFRAnalyser(data_source_file=source_file, flows_source_file=flows_source_file, sample_number_list=sample_number_list, data_separator=',')
|
||||
analyser.GetData()
|
||||
print(analyser.data)
|
||||
# Specify the source file paths to for SMPS data
|
||||
smps_analyser = OFRAnalyser(data_source_file = Path(r"Z:\Data\SMPS\processed\2026\09_September\20260902\20260902_aPinene_SOA.txt"),
|
||||
flow_source_file = Path(r"Z:\People\David_Tschan\OFR_SMPS\flow_files\20260902_SET02_EXP13_flow_file.txt"),
|
||||
smpl_number_list = range(1, 60))
|
||||
smps_analyser.GetData()
|
||||
Reference in new issue
Block a user