Module src.PyOghma_ML.Input
This module provides a framework for handling and processing input data from various laboratories.
It includes a base class, Input
, which defines a structure for parsing and standardizing data.
Subclasses are implemented for specific laboratories, allowing for tailored data parsing and
characterization. The module supports various characterization types, such as JV, TPV, CE, and CELIV,
and provides methods for calculating device parameters and standardizing inputs for further analysis.
Classes
class Brabec (device_dir: str, characterisation_type: str, **kwargs: Any)
-
Expand source code
class Brabec(Input): """ Subclass for handling data from the Brabec laboratory. This class provides methods for parsing and processing data specific to the Brabec laboratory. """ _source_laboratory = 'Brabec' def __init__(self, device_dir: str, characterisation_type: str, **kwargs: Any) -> None: """ Initialize a Brabec instance. Args: device_dir (str): Directory containing device data. characterisation_type (str): Type of characterisation (e.g., 'JV'). **kwargs: Additional keyword arguments for subclass initialization. """ self.device_dir = device_dir self.characterisation_type = characterisation_type self.kwargs = kwargs self.parse() def parse(self) -> None: """ Parse the data based on the characterisation type. Raises: ValueError: If the characterisation type is not supported. """ match self.characterisation_type: case 'JV': self.JV() case 'TPV': self.TPV() case 'CE': self.CE() case 'CELIV': self.CELIV() case _: raise ValueError('The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type)) def JV(self) -> None: """ Parse JV data. Returns: None """ self.Device_Population = 1 self.metadata = {} data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=1) hour = self.kwargs['hour'] data_sorted = data.iloc[(data[0] - hour).abs().argsort()].iloc[0][1:].to_numpy() self.current_density = data_sorted * 10 self.voltage = pd.read_csv(self.device_dir, delimiter='\t').columns[1:].astype(float).to_numpy() self.calcluate_JV_Params(self.voltage, self.current_density) return def TPV(self) -> None: """ Parse TPV data. Returns: None """ self.Device_Population = 1 self.metadata = {} data = pd.read_csv(self.device_dir, delimiter='\t', header=None, nrows=1).dropna(axis=1).to_numpy()[0] OD = data if 'OD' in self.kwargs: OD_idx = np.argsort(np.abs(OD - self.kwargs['OD']))[0] OD = OD[OD_idx] idx = (OD_idx) * 2 data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=1) self.time = data[idx].to_numpy() self.voltage = data[idx + 1].to_numpy() return def CE(self) -> None: """ Parse CE data. Returns: None """ self.Device_Population = 1 self.metadata = {} data = pd.read_csv(self.device_dir, delimiter='\t', header=None, nrows=2).T.set_index(0).to_dict(orient='dict')[1] self.metadata = data data = pd.read_csv(self.device_dir, delimiter='\t', header=None, nrows=1, skiprows=2).dropna(axis=1).to_numpy()[0] self.time = data data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=3) if 'hour' in self.kwargs: hour = self.kwargs['hour'] else: raise Warning('Degradation Hour must be specified!') data_sorted = data.iloc[(data[0] - hour).abs().argsort()].iloc[0][1:].to_numpy() self.current = data_sorted return def CELIV(self) -> None: """ Parse CELIV data. Returns: None """ self.Device_Population = 1 self.metadata = {} data = pd.read_csv(self.device_dir, delimiter='\t', header=None, nrows=9).dropna(axis=1).set_index(0).to_dict(orient='dict')[1] self.metadata = data data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=10, nrows=1) data = (data.drop(columns=[0, data.shape[1] - 1]).to_numpy() * 1e-6)[0] self.delay_time = data data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=11, nrows=1) data = data.drop(columns=[0, data.shape[1] - 1]).to_numpy()[0] self.voc = data match self.kwargs: case k if 'voc' in k: idx = np.argsort(np.abs(self.voc - k['voc']))[0] + 1 case k if 'delay' in k: idx = np.argsort(np.abs(self.delay_time - k['delay']))[0] + 1 case _: idx = 1 data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=12) self.time = data[0].to_numpy() self.current_desnity = data[idx].to_numpy() return def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ match self.characterisation_type: case 'JV': self.x = self.voltage self.y = self.current_density case 'CELIV': self.x = self.time self.y = self.current_desnity case 'CE': self.x = self.time self.y = self.current case 'TPV': self.x = self.time self.y = self.voltage
Subclass for handling data from the Brabec laboratory.
This class provides methods for parsing and processing data specific to the Brabec laboratory.
Initialize a Brabec instance.
Args
device_dir
:str
- Directory containing device data.
characterisation_type
:str
- Type of characterisation (e.g., 'JV').
**kwargs
- Additional keyword arguments for subclass initialization.
Ancestors
Methods
def CE(self) ‑> None
-
Expand source code
def CE(self) -> None: """ Parse CE data. Returns: None """ self.Device_Population = 1 self.metadata = {} data = pd.read_csv(self.device_dir, delimiter='\t', header=None, nrows=2).T.set_index(0).to_dict(orient='dict')[1] self.metadata = data data = pd.read_csv(self.device_dir, delimiter='\t', header=None, nrows=1, skiprows=2).dropna(axis=1).to_numpy()[0] self.time = data data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=3) if 'hour' in self.kwargs: hour = self.kwargs['hour'] else: raise Warning('Degradation Hour must be specified!') data_sorted = data.iloc[(data[0] - hour).abs().argsort()].iloc[0][1:].to_numpy() self.current = data_sorted return
Parse CE data.
Returns
None
def CELIV(self) ‑> None
-
Expand source code
def CELIV(self) -> None: """ Parse CELIV data. Returns: None """ self.Device_Population = 1 self.metadata = {} data = pd.read_csv(self.device_dir, delimiter='\t', header=None, nrows=9).dropna(axis=1).set_index(0).to_dict(orient='dict')[1] self.metadata = data data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=10, nrows=1) data = (data.drop(columns=[0, data.shape[1] - 1]).to_numpy() * 1e-6)[0] self.delay_time = data data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=11, nrows=1) data = data.drop(columns=[0, data.shape[1] - 1]).to_numpy()[0] self.voc = data match self.kwargs: case k if 'voc' in k: idx = np.argsort(np.abs(self.voc - k['voc']))[0] + 1 case k if 'delay' in k: idx = np.argsort(np.abs(self.delay_time - k['delay']))[0] + 1 case _: idx = 1 data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=12) self.time = data[0].to_numpy() self.current_desnity = data[idx].to_numpy() return
Parse CELIV data.
Returns
None
def JV(self) ‑> None
-
Expand source code
def JV(self) -> None: """ Parse JV data. Returns: None """ self.Device_Population = 1 self.metadata = {} data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=1) hour = self.kwargs['hour'] data_sorted = data.iloc[(data[0] - hour).abs().argsort()].iloc[0][1:].to_numpy() self.current_density = data_sorted * 10 self.voltage = pd.read_csv(self.device_dir, delimiter='\t').columns[1:].astype(float).to_numpy() self.calcluate_JV_Params(self.voltage, self.current_density) return
Parse JV data.
Returns
None
def TPV(self) ‑> None
-
Expand source code
def TPV(self) -> None: """ Parse TPV data. Returns: None """ self.Device_Population = 1 self.metadata = {} data = pd.read_csv(self.device_dir, delimiter='\t', header=None, nrows=1).dropna(axis=1).to_numpy()[0] OD = data if 'OD' in self.kwargs: OD_idx = np.argsort(np.abs(OD - self.kwargs['OD']))[0] OD = OD[OD_idx] idx = (OD_idx) * 2 data = pd.read_csv(self.device_dir, delimiter='\t', header=None, skiprows=1) self.time = data[idx].to_numpy() self.voltage = data[idx + 1].to_numpy() return
Parse TPV data.
Returns
None
def parse(self) ‑> None
-
Expand source code
def parse(self) -> None: """ Parse the data based on the characterisation type. Raises: ValueError: If the characterisation type is not supported. """ match self.characterisation_type: case 'JV': self.JV() case 'TPV': self.TPV() case 'CE': self.CE() case 'CELIV': self.CELIV() case _: raise ValueError('The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type))
Parse the data based on the characterisation type.
Raises
ValueError
- If the characterisation type is not supported.
def standardise_inputs(self) ‑> None
-
Expand source code
def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ match self.characterisation_type: case 'JV': self.x = self.voltage self.y = self.current_density case 'CELIV': self.x = self.time self.y = self.current_desnity case 'CE': self.x = self.time self.y = self.current case 'TPV': self.x = self.time self.y = self.voltage
Standardize inputs for further processing.
Returns
None
Inherited members
class Deibel (device_dir: str, characterisation_type: str)
-
Expand source code
class Deibel(Input): """ Subclass for handling data from the Deibel laboratory. This class provides methods for parsing and processing data specific to the Deibel laboratory. """ _source_laboratory = 'Deibel' def __init__(self, device_dir: str, characterisation_type: str) -> None: """ Initialize a Deibel instance. Args: device_dir (str): Directory containing device data. characterisation_type (str): Type of characterisation (e.g., 'JV'). """ self.device_dir = device_dir self.characterisation_type = characterisation_type self.parse() def parse(self) -> None: """ Parse the data based on the characterisation type. This method acts as a dispatcher, calling the appropriate parsing method based on the characterisation type specified during initialization. Supported types include 'IV', 'JV', 'JV_I4', and 'batch_JV'. Raises: ValueError: If the characterisation type is not supported by this laboratory. """ match self.characterisation_type: case 'IV': self.current_voltage_area() case 'JV': self.current_voltage() case 'JV_I4': self.current_voltage_I4() case 'batch_JV': self.batch_current_voltage() case _: raise ValueError('The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type)) def batch_current_voltage(self) -> None: """ Parse batch current-voltage data for multiple devices. This method processes JV data for multiple devices, storing voltage, current density, and metadata for each device in the batch. It validates that multiple devices are present before processing. Raises: ValueError: If one or fewer devices are detected in the batch. Sets: self.Device_Population (int): Number of devices in the batch self.voltage (numpy.ndarray): Voltage data for all devices self.current_density (numpy.ndarray): Current density data for all devices self.metadata (numpy.ndarray): Metadata for all devices """ Device_Population = len(self.device_dir) self.Device_Population = Device_Population if Device_Population <= 1: raise ValueError('One or less devices detected!') else: voltage = np.zeros(Device_Population, dtype=object) current_density = np.zeros(Device_Population, dtype=object) metadata = np.zeros(Device_Population, dtype=object) for index in range(Device_Population): self.current_voltage(index) self.Device_Population = Device_Population voltage[index] = self.voltage current_density[index] = self.current_density metadata[index] = self.metadata self.voltage = voltage self.current_density = current_density self.metadata = metadata def current_voltage_area(self, index: Optional[int] = None) -> None: """ Parse current-voltage data with area correction. Args: index (int, optional): Index of the device directory. Returns: None """ self.Device_Population = 1 metadata_list = [] if index is not None: d = self.device_dir[index] else: d = self.device_dir with open(d, 'r') as f: for line in f: if line[0:9] == '##columns': line = line[2:] line = line.replace('\n', '') line = line.replace(';', '') line = line.replace(' ', ',') metadata_list.append([line]) else: if line[0] == '#': line = line[2:] line = line.replace('\n', '') line = line.replace('\t', '') line = line.replace(' ', '') metadata_list.append(line.split(';')[:-1]) metadata_list = np.concatenate(metadata_list) group_metadata = {} for parameter in metadata_list: parameter = parameter.split('=') match parameter[0]: case 'SMU|ILLUMINATOR': temporary_keys = parameter[0].split('|') temporary_values = parameter[1].split('|') for i in range(len(temporary_keys)): group_metadata[temporary_keys[i]] = temporary_values[i] case 'columns': parameter[-1] = parameter[-1].split(',') group_metadata['columns'] = parameter[1:] group_metadata['columns'] = group_metadata['columns'][0] case _: temporary_keys = parameter[1].split(',') if "/" in temporary_keys[0]: temporary_keys = temporary_keys[0].split('/') if len(temporary_keys) == 1: group_metadata[parameter[0]] = temporary_keys[0] else: group_metadata[parameter[0]] = temporary_keys data = pd.read_csv(d, sep='\t', header=None, comment='#', names=group_metadata['columns']) voltage = data['V'].to_numpy() current_density = data['I'].to_numpy() current_density = current_density * 1000 / 0.04 * 10 metadata = {} self.voltage = voltage self.current_density = current_density self.metadata = metadata def current_voltage(self, index: Optional[int] = None) -> None: """ Parse current-voltage data. Args: index (int, optional): Index of the device directory. Returns: None """ self.Device_Population = 1 metadata_list = [] if index is not None: d = self.device_dir[index] else: d = self.device_dir with open(d, 'r') as f: for line in f: if line[0:9] == '##columns': line = line[2:] line = line.replace('\n', '') line = line.replace(';', '') line = line.replace(' ', ',') metadata_list.append([line]) else: if line[0] == '#': line = line[2:] line = line.replace('\n', '') line = line.replace('\t', '') line = line.replace(' ', '') metadata_list.append(line.split(';')[:-1]) metadata_list = np.concatenate(metadata_list) group_metadata = {} for parameter in metadata_list: parameter = parameter.split('=') match parameter[0]: case 'SMU|ILLUMINATOR': temporary_keys = parameter[0].split('|') temporary_values = parameter[1].split('|') for i in range(len(temporary_keys)): group_metadata[temporary_keys[i]] = temporary_values[i] case 'columns': parameter[-1] = parameter[-1].split(',') group_metadata['columns'] = parameter[1:] group_metadata['columns'] = group_metadata['columns'][0] case _: temporary_keys = parameter[1].split(',') if "/" in temporary_keys[0]: temporary_keys = temporary_keys[0].split('/') if len(temporary_keys) == 1: group_metadata[parameter[0]] = temporary_keys[0] else: group_metadata[parameter[0]] = temporary_keys data = pd.read_csv(d, sep='\t', header=None, comment='#', names=group_metadata['columns']) voltage = data['V'].to_numpy() current_density = data['J'].to_numpy() metadata = {} light_source = group_metadata['ILLUMINATOR'] if group_metadata['incidentIntensity[%]'] == 'dark': group_metadata['incidentIntensity[%]'] = 0 elif group_metadata['incidentIntensity[%]'] == light_source: group_metadata['incidentIntensity[%]'] = 1 match group_metadata['incidentIntensity[%]']: case 0: metadata['intensity'] = 0 case 1: metadata['intensity'] = 1 case _: metadata['intensity'] = group_metadata['incidentIntensity[%]'] / 100 metadata = metadata self.voltage = voltage self.current_density = current_density self.metadata = metadata def current_voltage_I4(self, index: Optional[int] = None) -> None: """ Parse current-voltage data with I4 scaling. Args: index (int, optional): Index of the device directory. Returns: None """ self.Device_Population = 1 metadata_list = [] if index is not None: d = self.device_dir[index] else: d = self.device_dir d = d.replace(' ', '') with open(d, 'r') as f: for line in f: if line[0:9] == '##columns': line = line[2:] line = line.replace('\n', '') line = line.replace(';', '') line = line.replace(' ', ',') metadata_list.append([line]) else: if line[0] == '#': line = line[2:] line = line.replace('\n', '') line = line.replace('\t', '') line = line.replace(' ', '') metadata_list.append(line.split(';')[:-1]) metadata_list = np.concatenate(metadata_list) group_metadata = {} for parameter in metadata_list: parameter = parameter.split('=') match parameter[0]: case 'SMU|ILLUMINATOR': temporary_keys = parameter[0].split('|') temporary_values = parameter[1].split('|') for i in range(len(temporary_keys)): group_metadata[temporary_keys[i]] = temporary_values[i] case 'columns': parameter[-1] = parameter[-1].split(',') group_metadata['columns'] = parameter[1:] group_metadata['columns'] = group_metadata['columns'][0] case _: temporary_keys = parameter[1].split(',') if "/" in temporary_keys[0]: temporary_keys = temporary_keys[0].split('/') if len(temporary_keys) == 1: group_metadata[parameter[0]] = temporary_keys[0] else: group_metadata[parameter[0]] = temporary_keys data = pd.read_csv(d, sep='\t', header=None, comment='#', names=group_metadata['columns']) voltage = data['V'].to_numpy() current = data['I'].to_numpy() * 1000 / 0.04 * 10 # Convert to current density in mA/cm^2 # voltage, current_density, light_intensity = self.I4_scaler(voltage, current) metadata = {} # metadata['intensity'] = light_intensity self.voltage = voltage self.current_density = current self.metadata = metadata def I4_scaler(self, voltage: np.ndarray, current: np.ndarray) -> tuple[np.ndarray, np.ndarray, float]: """ Scale current-voltage data using I4 methodology. Args: voltage (numpy.ndarray): Array of voltage values. current (numpy.ndarray): Array of current values. Returns: tuple: Scaled voltage, current density, and light intensity. """ dir = os.path.dirname(self.device_dir) name = os.path.basename(self.device_dir) #name = name.split('_') #name = name[0:-1] # illumination = name[-1].replace('uIllu', '') # illumination = float(illumination) / 1e6 # name[-1] = 'sunsVoc.dat' # name_sunsVoc = '_'.join(name) # name[-1] = 'am15.dat' # name = [name[0], name[-1]] # name_JV = '_'.join(name) data_JV = pd.read_csv(os.path.join(dir, name), comment='#', sep='\t', names=['V', 'I', 'J']) JV_voltage = data_JV['V'].to_numpy() JV_current = data_JV['I'].to_numpy() self.calcluate_JV_Params(-JV_voltage, JV_current) self.Jsc = -self.Jsc data_sunsVoc = pd.read_csv(os.path.join(dir, name), comment='#', sep='\t', names=['filters', 'power', 'relIllu', 'Voc', 'Isc', 'Iphoto']) data_sunsVoc = data_sunsVoc.drop(columns=['power']) data_sunsVoc['Isc'] = data_sunsVoc['Isc'] * -1 data_sunsVoc['Isc'] = np.log(data_sunsVoc['Isc']) function = interpolate.PchipInterpolator(data_sunsVoc['Voc'], data_sunsVoc['Isc'], extrapolate=True) y = np.linspace(0, 0.8, 1000) x = function(self.Voc) sfactor = (1e3 / (self.Jsc)) * (np.exp(x)) current_density = current * (1e3 / sfactor) data_sunsVoc['Iphoto'] = np.log(data_sunsVoc['Iphoto']) function = interpolate.PchipInterpolator(data_sunsVoc['Voc'], data_sunsVoc['Iphoto'], extrapolate=True) light_intensity = np.exp(data_sunsVoc['Iphoto']) / np.exp(function(self.Voc)) function = interpolate.PchipInterpolator(data_sunsVoc['relIllu'], light_intensity, extrapolate=True) light_intensity = function(illumination) return voltage, current_density, light_intensity def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ self.x = np.array(self.voltage) self.y = np.array(self.current_density) self.metadata = self.metadata
Subclass for handling data from the Deibel laboratory.
This class provides methods for parsing and processing data specific to the Deibel laboratory.
Initialize a Deibel instance.
Args
device_dir
:str
- Directory containing device data.
characterisation_type
:str
- Type of characterisation (e.g., 'JV').
Ancestors
Methods
def I4_scaler(self, voltage: numpy.ndarray, current: numpy.ndarray) ‑> tuple[numpy.ndarray, numpy.ndarray, float]
-
Expand source code
def I4_scaler(self, voltage: np.ndarray, current: np.ndarray) -> tuple[np.ndarray, np.ndarray, float]: """ Scale current-voltage data using I4 methodology. Args: voltage (numpy.ndarray): Array of voltage values. current (numpy.ndarray): Array of current values. Returns: tuple: Scaled voltage, current density, and light intensity. """ dir = os.path.dirname(self.device_dir) name = os.path.basename(self.device_dir) #name = name.split('_') #name = name[0:-1] # illumination = name[-1].replace('uIllu', '') # illumination = float(illumination) / 1e6 # name[-1] = 'sunsVoc.dat' # name_sunsVoc = '_'.join(name) # name[-1] = 'am15.dat' # name = [name[0], name[-1]] # name_JV = '_'.join(name) data_JV = pd.read_csv(os.path.join(dir, name), comment='#', sep='\t', names=['V', 'I', 'J']) JV_voltage = data_JV['V'].to_numpy() JV_current = data_JV['I'].to_numpy() self.calcluate_JV_Params(-JV_voltage, JV_current) self.Jsc = -self.Jsc data_sunsVoc = pd.read_csv(os.path.join(dir, name), comment='#', sep='\t', names=['filters', 'power', 'relIllu', 'Voc', 'Isc', 'Iphoto']) data_sunsVoc = data_sunsVoc.drop(columns=['power']) data_sunsVoc['Isc'] = data_sunsVoc['Isc'] * -1 data_sunsVoc['Isc'] = np.log(data_sunsVoc['Isc']) function = interpolate.PchipInterpolator(data_sunsVoc['Voc'], data_sunsVoc['Isc'], extrapolate=True) y = np.linspace(0, 0.8, 1000) x = function(self.Voc) sfactor = (1e3 / (self.Jsc)) * (np.exp(x)) current_density = current * (1e3 / sfactor) data_sunsVoc['Iphoto'] = np.log(data_sunsVoc['Iphoto']) function = interpolate.PchipInterpolator(data_sunsVoc['Voc'], data_sunsVoc['Iphoto'], extrapolate=True) light_intensity = np.exp(data_sunsVoc['Iphoto']) / np.exp(function(self.Voc)) function = interpolate.PchipInterpolator(data_sunsVoc['relIllu'], light_intensity, extrapolate=True) light_intensity = function(illumination) return voltage, current_density, light_intensity
Scale current-voltage data using I4 methodology.
Args
voltage
:numpy.ndarray
- Array of voltage values.
current
:numpy.ndarray
- Array of current values.
Returns
tuple
- Scaled voltage, current density, and light intensity.
def batch_current_voltage(self) ‑> None
-
Expand source code
def batch_current_voltage(self) -> None: """ Parse batch current-voltage data for multiple devices. This method processes JV data for multiple devices, storing voltage, current density, and metadata for each device in the batch. It validates that multiple devices are present before processing. Raises: ValueError: If one or fewer devices are detected in the batch. Sets: self.Device_Population (int): Number of devices in the batch self.voltage (numpy.ndarray): Voltage data for all devices self.current_density (numpy.ndarray): Current density data for all devices self.metadata (numpy.ndarray): Metadata for all devices """ Device_Population = len(self.device_dir) self.Device_Population = Device_Population if Device_Population <= 1: raise ValueError('One or less devices detected!') else: voltage = np.zeros(Device_Population, dtype=object) current_density = np.zeros(Device_Population, dtype=object) metadata = np.zeros(Device_Population, dtype=object) for index in range(Device_Population): self.current_voltage(index) self.Device_Population = Device_Population voltage[index] = self.voltage current_density[index] = self.current_density metadata[index] = self.metadata self.voltage = voltage self.current_density = current_density self.metadata = metadata
Parse batch current-voltage data for multiple devices.
This method processes JV data for multiple devices, storing voltage, current density, and metadata for each device in the batch. It validates that multiple devices are present before processing.
Raises
ValueError
- If one or fewer devices are detected in the batch.
Sets
self.Device_Population (int): Number of devices in the batch self.voltage (numpy.ndarray): Voltage data for all devices self.current_density (numpy.ndarray): Current density data for all devices self.metadata (numpy.ndarray): Metadata for all devices
def current_voltage(self, index: int | None = None) ‑> None
-
Expand source code
def current_voltage(self, index: Optional[int] = None) -> None: """ Parse current-voltage data. Args: index (int, optional): Index of the device directory. Returns: None """ self.Device_Population = 1 metadata_list = [] if index is not None: d = self.device_dir[index] else: d = self.device_dir with open(d, 'r') as f: for line in f: if line[0:9] == '##columns': line = line[2:] line = line.replace('\n', '') line = line.replace(';', '') line = line.replace(' ', ',') metadata_list.append([line]) else: if line[0] == '#': line = line[2:] line = line.replace('\n', '') line = line.replace('\t', '') line = line.replace(' ', '') metadata_list.append(line.split(';')[:-1]) metadata_list = np.concatenate(metadata_list) group_metadata = {} for parameter in metadata_list: parameter = parameter.split('=') match parameter[0]: case 'SMU|ILLUMINATOR': temporary_keys = parameter[0].split('|') temporary_values = parameter[1].split('|') for i in range(len(temporary_keys)): group_metadata[temporary_keys[i]] = temporary_values[i] case 'columns': parameter[-1] = parameter[-1].split(',') group_metadata['columns'] = parameter[1:] group_metadata['columns'] = group_metadata['columns'][0] case _: temporary_keys = parameter[1].split(',') if "/" in temporary_keys[0]: temporary_keys = temporary_keys[0].split('/') if len(temporary_keys) == 1: group_metadata[parameter[0]] = temporary_keys[0] else: group_metadata[parameter[0]] = temporary_keys data = pd.read_csv(d, sep='\t', header=None, comment='#', names=group_metadata['columns']) voltage = data['V'].to_numpy() current_density = data['J'].to_numpy() metadata = {} light_source = group_metadata['ILLUMINATOR'] if group_metadata['incidentIntensity[%]'] == 'dark': group_metadata['incidentIntensity[%]'] = 0 elif group_metadata['incidentIntensity[%]'] == light_source: group_metadata['incidentIntensity[%]'] = 1 match group_metadata['incidentIntensity[%]']: case 0: metadata['intensity'] = 0 case 1: metadata['intensity'] = 1 case _: metadata['intensity'] = group_metadata['incidentIntensity[%]'] / 100 metadata = metadata self.voltage = voltage self.current_density = current_density self.metadata = metadata
Parse current-voltage data.
Args
index
:int
, optional- Index of the device directory.
Returns
None
def current_voltage_I4(self, index: int | None = None) ‑> None
-
Expand source code
def current_voltage_I4(self, index: Optional[int] = None) -> None: """ Parse current-voltage data with I4 scaling. Args: index (int, optional): Index of the device directory. Returns: None """ self.Device_Population = 1 metadata_list = [] if index is not None: d = self.device_dir[index] else: d = self.device_dir d = d.replace(' ', '') with open(d, 'r') as f: for line in f: if line[0:9] == '##columns': line = line[2:] line = line.replace('\n', '') line = line.replace(';', '') line = line.replace(' ', ',') metadata_list.append([line]) else: if line[0] == '#': line = line[2:] line = line.replace('\n', '') line = line.replace('\t', '') line = line.replace(' ', '') metadata_list.append(line.split(';')[:-1]) metadata_list = np.concatenate(metadata_list) group_metadata = {} for parameter in metadata_list: parameter = parameter.split('=') match parameter[0]: case 'SMU|ILLUMINATOR': temporary_keys = parameter[0].split('|') temporary_values = parameter[1].split('|') for i in range(len(temporary_keys)): group_metadata[temporary_keys[i]] = temporary_values[i] case 'columns': parameter[-1] = parameter[-1].split(',') group_metadata['columns'] = parameter[1:] group_metadata['columns'] = group_metadata['columns'][0] case _: temporary_keys = parameter[1].split(',') if "/" in temporary_keys[0]: temporary_keys = temporary_keys[0].split('/') if len(temporary_keys) == 1: group_metadata[parameter[0]] = temporary_keys[0] else: group_metadata[parameter[0]] = temporary_keys data = pd.read_csv(d, sep='\t', header=None, comment='#', names=group_metadata['columns']) voltage = data['V'].to_numpy() current = data['I'].to_numpy() * 1000 / 0.04 * 10 # Convert to current density in mA/cm^2 # voltage, current_density, light_intensity = self.I4_scaler(voltage, current) metadata = {} # metadata['intensity'] = light_intensity self.voltage = voltage self.current_density = current self.metadata = metadata
Parse current-voltage data with I4 scaling.
Args
index
:int
, optional- Index of the device directory.
Returns
None
def current_voltage_area(self, index: int | None = None) ‑> None
-
Expand source code
def current_voltage_area(self, index: Optional[int] = None) -> None: """ Parse current-voltage data with area correction. Args: index (int, optional): Index of the device directory. Returns: None """ self.Device_Population = 1 metadata_list = [] if index is not None: d = self.device_dir[index] else: d = self.device_dir with open(d, 'r') as f: for line in f: if line[0:9] == '##columns': line = line[2:] line = line.replace('\n', '') line = line.replace(';', '') line = line.replace(' ', ',') metadata_list.append([line]) else: if line[0] == '#': line = line[2:] line = line.replace('\n', '') line = line.replace('\t', '') line = line.replace(' ', '') metadata_list.append(line.split(';')[:-1]) metadata_list = np.concatenate(metadata_list) group_metadata = {} for parameter in metadata_list: parameter = parameter.split('=') match parameter[0]: case 'SMU|ILLUMINATOR': temporary_keys = parameter[0].split('|') temporary_values = parameter[1].split('|') for i in range(len(temporary_keys)): group_metadata[temporary_keys[i]] = temporary_values[i] case 'columns': parameter[-1] = parameter[-1].split(',') group_metadata['columns'] = parameter[1:] group_metadata['columns'] = group_metadata['columns'][0] case _: temporary_keys = parameter[1].split(',') if "/" in temporary_keys[0]: temporary_keys = temporary_keys[0].split('/') if len(temporary_keys) == 1: group_metadata[parameter[0]] = temporary_keys[0] else: group_metadata[parameter[0]] = temporary_keys data = pd.read_csv(d, sep='\t', header=None, comment='#', names=group_metadata['columns']) voltage = data['V'].to_numpy() current_density = data['I'].to_numpy() current_density = current_density * 1000 / 0.04 * 10 metadata = {} self.voltage = voltage self.current_density = current_density self.metadata = metadata
Parse current-voltage data with area correction.
Args
index
:int
, optional- Index of the device directory.
Returns
None
def parse(self) ‑> None
-
Expand source code
def parse(self) -> None: """ Parse the data based on the characterisation type. This method acts as a dispatcher, calling the appropriate parsing method based on the characterisation type specified during initialization. Supported types include 'IV', 'JV', 'JV_I4', and 'batch_JV'. Raises: ValueError: If the characterisation type is not supported by this laboratory. """ match self.characterisation_type: case 'IV': self.current_voltage_area() case 'JV': self.current_voltage() case 'JV_I4': self.current_voltage_I4() case 'batch_JV': self.batch_current_voltage() case _: raise ValueError('The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type))
Parse the data based on the characterisation type.
This method acts as a dispatcher, calling the appropriate parsing method based on the characterisation type specified during initialization. Supported types include 'IV', 'JV', 'JV_I4', and 'batch_JV'.
Raises
ValueError
- If the characterisation type is not supported by this laboratory.
def standardise_inputs(self) ‑> None
-
Expand source code
def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ self.x = np.array(self.voltage) self.y = np.array(self.current_density) self.metadata = self.metadata
Standardize inputs for further processing.
Returns
None
Inherited members
class Herzig (device_dir: str, characterisation_type: str)
-
Expand source code
class Herzig(Input): """ Subclass for handling data from the Herzig laboratory. This class provides methods for parsing and processing data specific to the Herzig laboratory. """ _source_laboratory = 'Herzig' def __init__(self, device_dir: str, characterisation_type: str) -> None: """ Initialize a Herzig instance. Args: device_dir (str): Directory containing device data. characterisation_type (str): Type of characterisation (e.g., '2D_JV'). """ self.device_dir = device_dir self.characterisation_type = characterisation_type self.parse() def parse(self) -> None: """ Parse the data based on the characterisation type. Raises: ValueError: If the characterisation type is not supported. """ match self.characterisation_type: case '2D_JV': self.mapped_current_voltage() case _: raise ValueError('The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type)) def current_voltage(self, index: Optional[int] = None) -> None: """ Parse current-voltage data. Args: index (int, optional): Index of the data. Raises: ValueError: If the function is called for single JVs. Returns: None """ if index is not None: d = self.data[index] else: raise ValueError('This function does not currently handle single JVs') metadata = {} metadata['intensity'] = self.intensity[index] self.voltage = -self.data[index, :, 0] self.current = -self.data[index, :, 1] self.metadata = metadata def mapped_current_voltage(self) -> None: """ Parse mapped current-voltage data. Returns: None """ data = h5py.File(self.device_dir, 'r') data = data['data'] shape = data[:, :, 0, :, :].shape dark = data[:, :, 0, :, :].reshape((shape[0] * shape[1], shape[2], shape[3])) dark_intensity = np.zeros(len(dark)) light = data[:, :, 2, :, :].reshape((shape[0] * shape[1], shape[2], shape[3])) light_intensity = np.ones(len(light)) data = np.concatenate([dark, light]) intensity = np.concatenate((dark_intensity, light_intensity)) self.data = data self.intensity = intensity voltage = np.zeros((shape[0] * shape[1] * 2), dtype=object) current = np.zeros((shape[0] * shape[1] * 2), dtype=object) metadata = np.zeros((shape[0] * shape[1] * 2), dtype=object) for index in range(int(shape[0] * shape[1] * 2)): self.current_voltage(index) voltage[index] = self.voltage current[index] = self.current metadata[index] = self.metadata self.voltage = voltage self.current = current self.metadata = metadata def current_to_current_density(self, area: float = 8e-7) -> None: """ Convert current to current density. Args: area (float): Area size for conversion. Returns: None """ self.current_density = self.current / area self.current_density_flat = True def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ self.x = self.voltage if self.current_density_flat: self.y = self.current_density else: self.y = self.current self.metadata = self.metadata
Subclass for handling data from the Herzig laboratory.
This class provides methods for parsing and processing data specific to the Herzig laboratory.
Initialize a Herzig instance.
Args
device_dir
:str
- Directory containing device data.
characterisation_type
:str
- Type of characterisation (e.g., '2D_JV').
Ancestors
Methods
def current_to_current_density(self, area: float = 8e-07) ‑> None
-
Expand source code
def current_to_current_density(self, area: float = 8e-7) -> None: """ Convert current to current density. Args: area (float): Area size for conversion. Returns: None """ self.current_density = self.current / area self.current_density_flat = True
Convert current to current density.
Args
area
:float
- Area size for conversion.
Returns
None
def current_voltage(self, index: int | None = None) ‑> None
-
Expand source code
def current_voltage(self, index: Optional[int] = None) -> None: """ Parse current-voltage data. Args: index (int, optional): Index of the data. Raises: ValueError: If the function is called for single JVs. Returns: None """ if index is not None: d = self.data[index] else: raise ValueError('This function does not currently handle single JVs') metadata = {} metadata['intensity'] = self.intensity[index] self.voltage = -self.data[index, :, 0] self.current = -self.data[index, :, 1] self.metadata = metadata
Parse current-voltage data.
Args
index
:int
, optional- Index of the data.
Raises
ValueError
- If the function is called for single JVs.
Returns
None
def mapped_current_voltage(self) ‑> None
-
Expand source code
def mapped_current_voltage(self) -> None: """ Parse mapped current-voltage data. Returns: None """ data = h5py.File(self.device_dir, 'r') data = data['data'] shape = data[:, :, 0, :, :].shape dark = data[:, :, 0, :, :].reshape((shape[0] * shape[1], shape[2], shape[3])) dark_intensity = np.zeros(len(dark)) light = data[:, :, 2, :, :].reshape((shape[0] * shape[1], shape[2], shape[3])) light_intensity = np.ones(len(light)) data = np.concatenate([dark, light]) intensity = np.concatenate((dark_intensity, light_intensity)) self.data = data self.intensity = intensity voltage = np.zeros((shape[0] * shape[1] * 2), dtype=object) current = np.zeros((shape[0] * shape[1] * 2), dtype=object) metadata = np.zeros((shape[0] * shape[1] * 2), dtype=object) for index in range(int(shape[0] * shape[1] * 2)): self.current_voltage(index) voltage[index] = self.voltage current[index] = self.current metadata[index] = self.metadata self.voltage = voltage self.current = current self.metadata = metadata
Parse mapped current-voltage data.
Returns
None
def parse(self) ‑> None
-
Expand source code
def parse(self) -> None: """ Parse the data based on the characterisation type. Raises: ValueError: If the characterisation type is not supported. """ match self.characterisation_type: case '2D_JV': self.mapped_current_voltage() case _: raise ValueError('The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type))
Parse the data based on the characterisation type.
Raises
ValueError
- If the characterisation type is not supported.
def standardise_inputs(self) ‑> None
-
Expand source code
def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ self.x = self.voltage if self.current_density_flat: self.y = self.current_density else: self.y = self.current self.metadata = self.metadata
Standardize inputs for further processing.
Returns
None
Inherited members
class Input
-
Expand source code
class Input: """ Base class for handling input data from various laboratories. This class provides a framework for parsing and processing data from different laboratories. It includes methods for registering subclasses and calculating JV parameters. """ subclasses = {} def __init_subclass__(cls, **kwargs: Any) -> None: """ Automatically register subclasses for different laboratories. Args: **kwargs: Additional keyword arguments for subclass initialization. """ super().__init_subclass__(**kwargs) cls.subclasses[cls.__name__] = cls @classmethod def experiment(cls, device_dir: str, characterisation_type: Optional[str] = None, source_laboratory: Optional[str] = None, **kwargs: Any) -> "Input": """ Factory method to create an instance of a specific laboratory subclass. Args: device_dir (str): Directory containing device data. characterisation_type (str, optional): Type of characterisation (e.g., 'JV'). source_laboratory (str, optional): Name of the source laboratory. **kwargs: Additional keyword arguments for subclass initialization. Returns: Input: An instance of the appropriate subclass. Raises: ValueError: If the source laboratory is not recognized. """ if source_laboratory not in cls.subclasses: raise ValueError('Source laboratory: {} Not recognized'.format(source_laboratory)) return cls.subclasses[source_laboratory](device_dir, characterisation_type, **kwargs) def calcluate_JV_Params(self, voltage: np.ndarray, current: np.ndarray) -> None: """ Calculate JV parameters such as Jsc, Voc, P_max, FF, and PCE. This method calculates key photovoltaic parameters from JV curves: - Jsc (Short-circuit current density): Current at V=0 - Voc (Open-circuit voltage): Voltage at J=0 - P_max (Maximum power): Peak power point - FF (Fill factor): Ratio of maximum power to theoretical maximum - PCE (Power conversion efficiency): Overall efficiency percentage Args: voltage (numpy.ndarray): Array of voltage values in volts. current (numpy.ndarray): Array of current density values in mA/cm². Returns: None: Parameters are stored as instance attributes. Note: The calculated parameters are accessible as instance attributes: self.Jsc, self.Voc, self.P_max, self.FF, self.PCE """ V = voltage J = current self.Jsc = -J[np.argmin(np.abs(V - 0))] self.Voc = V[np.argmin(np.abs(J - 0))] self.P_max = np.abs(np.min(V * J)) self.FF = self.P_max / (self.Voc * self.Jsc) self.PCE = self.Jsc * self.Voc * self.FF / 10 return
Base class for handling input data from various laboratories.
This class provides a framework for parsing and processing data from different laboratories. It includes methods for registering subclasses and calculating JV parameters.
Subclasses
Class variables
var subclasses
Static methods
def experiment(device_dir: str,
characterisation_type: str | None = None,
source_laboratory: str | None = None,
**kwargs: Any) ‑> Input-
Factory method to create an instance of a specific laboratory subclass.
Args
device_dir
:str
- Directory containing device data.
characterisation_type
:str
, optional- Type of characterisation (e.g., 'JV').
source_laboratory
:str
, optional- Name of the source laboratory.
**kwargs
- Additional keyword arguments for subclass initialization.
Returns
Input
- An instance of the appropriate subclass.
Raises
ValueError
- If the source laboratory is not recognized.
Methods
def calcluate_JV_Params(self, voltage: numpy.ndarray, current: numpy.ndarray) ‑> None
-
Expand source code
def calcluate_JV_Params(self, voltage: np.ndarray, current: np.ndarray) -> None: """ Calculate JV parameters such as Jsc, Voc, P_max, FF, and PCE. This method calculates key photovoltaic parameters from JV curves: - Jsc (Short-circuit current density): Current at V=0 - Voc (Open-circuit voltage): Voltage at J=0 - P_max (Maximum power): Peak power point - FF (Fill factor): Ratio of maximum power to theoretical maximum - PCE (Power conversion efficiency): Overall efficiency percentage Args: voltage (numpy.ndarray): Array of voltage values in volts. current (numpy.ndarray): Array of current density values in mA/cm². Returns: None: Parameters are stored as instance attributes. Note: The calculated parameters are accessible as instance attributes: self.Jsc, self.Voc, self.P_max, self.FF, self.PCE """ V = voltage J = current self.Jsc = -J[np.argmin(np.abs(V - 0))] self.Voc = V[np.argmin(np.abs(J - 0))] self.P_max = np.abs(np.min(V * J)) self.FF = self.P_max / (self.Voc * self.Jsc) self.PCE = self.Jsc * self.Voc * self.FF / 10 return
Calculate JV parameters such as Jsc, Voc, P_max, FF, and PCE.
This method calculates key photovoltaic parameters from JV curves: - Jsc (Short-circuit current density): Current at V=0 - Voc (Open-circuit voltage): Voltage at J=0
- P_max (Maximum power): Peak power point - FF (Fill factor): Ratio of maximum power to theoretical maximum - PCE (Power conversion efficiency): Overall efficiency percentageArgs
voltage
:numpy.ndarray
- Array of voltage values in volts.
current
:numpy.ndarray
- Array of current density values in mA/cm².
Returns
None
- Parameters are stored as instance attributes.
Note
The calculated parameters are accessible as instance attributes: self.Jsc, self.Voc, self.P_max, self.FF, self.PCE
class Oghma (device_dir: str, characterisation_type: str)
-
Expand source code
class Oghma(Input): """ Subclass for handling data from the Oghma laboratory. This class provides methods for parsing and processing data specific to the Oghma laboratory. """ _source_laboratory = 'Oghma' def __init__(self, device_dir: str, characterisation_type: str) -> None: """ Initialize an Oghma instance. Args: device_dir (str): Directory containing device data. characterisation_type (str): Type of characterisation (e.g., 'JV'). """ self.device_dir = device_dir self.characterisation_type = characterisation_type self.parse() def parse(self) -> None: """ Parse the data based on the characterisation type. Raises: ValueError: If the characterisation type is not supported. """ match self.characterisation_type: case 'JV': self.current_voltage() case 'batch_JV': self.batch_current_voltage() case _: raise ValueError('The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type)) def current_voltage(self, index: Optional[int] = None) -> None: """ Parse current-voltage data. Args: index (int, optional): Index of the device directory. Returns: None """ self.Device_Population = 1 metadata_list = [] if index is not None: d = self.device_dir[index] else: d = self.device_dir data = pd.read_csv(d, sep=' ', header=None, comment='#', skiprows=2, names=['V', 'J']) voltage = data['V'].to_numpy() current_density = data['J'].to_numpy() metadata = {} self.voltage = voltage self.current_density = current_density self.metadata = metadata def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ self.x = np.array(self.voltage) self.y = np.array(self.current_density) self.metadata = self.metadata
Subclass for handling data from the Oghma laboratory.
This class provides methods for parsing and processing data specific to the Oghma laboratory.
Initialize an Oghma instance.
Args
device_dir
:str
- Directory containing device data.
characterisation_type
:str
- Type of characterisation (e.g., 'JV').
Ancestors
Methods
def current_voltage(self, index: int | None = None) ‑> None
-
Expand source code
def current_voltage(self, index: Optional[int] = None) -> None: """ Parse current-voltage data. Args: index (int, optional): Index of the device directory. Returns: None """ self.Device_Population = 1 metadata_list = [] if index is not None: d = self.device_dir[index] else: d = self.device_dir data = pd.read_csv(d, sep=' ', header=None, comment='#', skiprows=2, names=['V', 'J']) voltage = data['V'].to_numpy() current_density = data['J'].to_numpy() metadata = {} self.voltage = voltage self.current_density = current_density self.metadata = metadata
Parse current-voltage data.
Args
index
:int
, optional- Index of the device directory.
Returns
None
def parse(self) ‑> None
-
Expand source code
def parse(self) -> None: """ Parse the data based on the characterisation type. Raises: ValueError: If the characterisation type is not supported. """ match self.characterisation_type: case 'JV': self.current_voltage() case 'batch_JV': self.batch_current_voltage() case _: raise ValueError('The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type))
Parse the data based on the characterisation type.
Raises
ValueError
- If the characterisation type is not supported.
def standardise_inputs(self) ‑> None
-
Expand source code
def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ self.x = np.array(self.voltage) self.y = np.array(self.current_density) self.metadata = self.metadata
Standardize inputs for further processing.
Returns
None
Inherited members
class Riedl (device_dir: str, characterisation_type: str, **kwargs: Any)
-
Expand source code
class Riedl(Input): """ Subclass for handling data from the Riedl laboratory. This class provides methods for parsing and processing data specific to the Riedl laboratory. """ _source_laboratory = 'Riedl' def __init__(self, device_dir: str, characterisation_type: str, **kwargs: Any) -> None: """ Initialize a Riedl instance. Args: device_dir (str): Directory containing device data. characterisation_type (str): Type of characterisation (e.g., 'JV'). **kwargs: Additional keyword arguments for subclass initialization. """ self.device_dir = device_dir self.characterisation_type = characterisation_type self.kwargs = kwargs self.parse() def parse(self) -> None: """ Parse the data based on the characterisation type. Raises: ValueError: If the characterisation type is not supported. """ match self.characterisation_type: case 'JV': self.JV() case _: raise ValueError('The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type)) def JV(self) -> None: """ Parse JV data. Returns: None """ self.Device_Population = 1 data = pd.read_csv(self.device_dir, delimiter=';', comment='#', skiprows=5) pixel = self.kwargs['pixel'] name_V = 'Cell ' + str(pixel) name_J = 'Unnamed: ' + str((pixel * 2) + 1) self.voltage = data[name_V].to_numpy(dtype=float) self.current_density = data[name_J].to_numpy(dtype=float) * 10 self.calcluate_JV_Params(self.voltage, self.current_density) self.metadata = {} def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ self.x = self.voltage self.y = self.current_density self.metadata = self.metadata
Subclass for handling data from the Riedl laboratory.
This class provides methods for parsing and processing data specific to the Riedl laboratory.
Initialize a Riedl instance.
Args
device_dir
:str
- Directory containing device data.
characterisation_type
:str
- Type of characterisation (e.g., 'JV').
**kwargs
- Additional keyword arguments for subclass initialization.
Ancestors
Methods
def JV(self) ‑> None
-
Expand source code
def JV(self) -> None: """ Parse JV data. Returns: None """ self.Device_Population = 1 data = pd.read_csv(self.device_dir, delimiter=';', comment='#', skiprows=5) pixel = self.kwargs['pixel'] name_V = 'Cell ' + str(pixel) name_J = 'Unnamed: ' + str((pixel * 2) + 1) self.voltage = data[name_V].to_numpy(dtype=float) self.current_density = data[name_J].to_numpy(dtype=float) * 10 self.calcluate_JV_Params(self.voltage, self.current_density) self.metadata = {}
Parse JV data.
Returns
None
def parse(self) ‑> None
-
Expand source code
def parse(self) -> None: """ Parse the data based on the characterisation type. Raises: ValueError: If the characterisation type is not supported. """ match self.characterisation_type: case 'JV': self.JV() case _: raise ValueError('The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type))
Parse the data based on the characterisation type.
Raises
ValueError
- If the characterisation type is not supported.
def standardise_inputs(self) ‑> None
-
Expand source code
def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ self.x = self.voltage self.y = self.current_density self.metadata = self.metadata
Standardize inputs for further processing.
Returns
None
Inherited members
class Shoaee (device_dir: str, characterisation_type: str, **kwargs: Any)
-
Expand source code
class Shoaee(Input): """ Subclass for handling data from the Shoaee laboratory. This class provides methods for parsing and processing data specific to the Shoaee laboratory. """ _source_laboratory = 'Shoaee' def __init__(self, device_dir: str, characterisation_type: str, **kwargs: Any) -> None: """ Initialize a Shoaee instance. Args: device_dir (str): Directory containing device data. characterisation_type (str): Type of characterisation (e.g., 'SolarSim JV'). **kwargs: Additional keyword arguments for subclass initialization. """ self.device_dir = device_dir self.characterisation_type = characterisation_type self.kwargs = kwargs self.parse() def parse(self) -> None: """ Parse the data based on the characterisation type. Raises: ValueError: If the characterisation type is not supported. """ match self.characterisation_type: case 'SolarSim JV': self.solar_sim_jv() case 'SPO JV': self.spo_jv() case 'Denoised': self.denosied() case _: raise ValueError( 'The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type)) def solar_sim_jv(self) -> None: """ Parse solar simulator JV data. Returns: None """ self.Device_Population = 1 d = self.device_dir pixel = self.kwargs['pixel'].lower() tag = self.kwargs['tag'].lower() metadata = {} maxline = 0 with open(d, 'r', encoding="ISO-8859-1") as f: for idx, line in enumerate(f): if idx > maxline: maxline = idx match idx: case 4: metadata['num_average'] = int(line.split(' ')[3].strip('\n')) case 6: metadata['area_size'] = float(line.split(pixel + ':')[1].split(',')[0]) case 7: metadata['temperature'] = int(line.split(' ')[1].strip('°C\n')) case 8: if str(pixel + '_' + tag) in line: metadata['pixel'] = pixel + '_' + tag calculated_params = pd.read_csv(d, sep='\t', skiprows=8, skipfooter=maxline - 16, encoding="ISO-8859-1", engine='python') calculated_params = calculated_params.set_index('Pixel') calculated_params = calculated_params[metadata['pixel']].to_dict() metadata.update(calculated_params) characteristic_values = pd.read_csv(d, sep='\t', skiprows=17, encoding="ISO-8859-1").drop(0, axis=0) self.voltage = characteristic_values['Voltage'].to_numpy(dtype=float) self.current_density = characteristic_values['j' + '_' + metadata['pixel']].to_numpy(dtype=float) * 10 l = len(self.voltage) h = int(l / 2) self.voltage = self.voltage[:] self.current_density = self.current_density[:] self.metadata = metadata return def spo_jv(self) -> None: """ Parse SPO JV data. Returns: None """ self.Device_Population = 1 d = self.device_dir data = pd.read_csv(d, sep='\t', skiprows=51, encoding="ISO-8859-1", skipfooter=5, engine='python').drop(0, axis=0) self.voltage = data['Voltage setup'].to_numpy(dtype=float) self.current_density = data['Current Density'].to_numpy(dtype=float) * 10 data = pd.read_csv(d, sep='\t', skiprows=47, encoding="ISO-8859-1", skipfooter=170, engine='python', header=None).T.drop(0, axis=0) data.columns = ['Start Time', 'Start Date'] data = pd.to_datetime(data['Start Date'] + ' ' + data['Start Time'], dayfirst=True).values[0] self.metadata = {} self.metadata['datetime'] = data return def denosied(self) -> None: """ Parse denoised data. Returns: None """ self.Device_Population = 1 d = self.device_dir data = pd.read_csv(d) self.current_density = data['Mean'].to_numpy(dtype=float) self.voltage = np.linspace(0, 1, len(self.current_density)) self.metadata = {} return def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ self.x = self.voltage self.y = self.current_density self.metadata = self.metadata
Subclass for handling data from the Shoaee laboratory.
This class provides methods for parsing and processing data specific to the Shoaee laboratory.
Initialize a Shoaee instance.
Args
device_dir
:str
- Directory containing device data.
characterisation_type
:str
- Type of characterisation (e.g., 'SolarSim JV').
**kwargs
- Additional keyword arguments for subclass initialization.
Ancestors
Methods
def denosied(self) ‑> None
-
Expand source code
def denosied(self) -> None: """ Parse denoised data. Returns: None """ self.Device_Population = 1 d = self.device_dir data = pd.read_csv(d) self.current_density = data['Mean'].to_numpy(dtype=float) self.voltage = np.linspace(0, 1, len(self.current_density)) self.metadata = {} return
Parse denoised data.
Returns
None
def parse(self) ‑> None
-
Expand source code
def parse(self) -> None: """ Parse the data based on the characterisation type. Raises: ValueError: If the characterisation type is not supported. """ match self.characterisation_type: case 'SolarSim JV': self.solar_sim_jv() case 'SPO JV': self.spo_jv() case 'Denoised': self.denosied() case _: raise ValueError( 'The {} Laboratory does not support {}'.format(self._source_laboratory, self.characterisation_type))
Parse the data based on the characterisation type.
Raises
ValueError
- If the characterisation type is not supported.
def solar_sim_jv(self) ‑> None
-
Expand source code
def solar_sim_jv(self) -> None: """ Parse solar simulator JV data. Returns: None """ self.Device_Population = 1 d = self.device_dir pixel = self.kwargs['pixel'].lower() tag = self.kwargs['tag'].lower() metadata = {} maxline = 0 with open(d, 'r', encoding="ISO-8859-1") as f: for idx, line in enumerate(f): if idx > maxline: maxline = idx match idx: case 4: metadata['num_average'] = int(line.split(' ')[3].strip('\n')) case 6: metadata['area_size'] = float(line.split(pixel + ':')[1].split(',')[0]) case 7: metadata['temperature'] = int(line.split(' ')[1].strip('°C\n')) case 8: if str(pixel + '_' + tag) in line: metadata['pixel'] = pixel + '_' + tag calculated_params = pd.read_csv(d, sep='\t', skiprows=8, skipfooter=maxline - 16, encoding="ISO-8859-1", engine='python') calculated_params = calculated_params.set_index('Pixel') calculated_params = calculated_params[metadata['pixel']].to_dict() metadata.update(calculated_params) characteristic_values = pd.read_csv(d, sep='\t', skiprows=17, encoding="ISO-8859-1").drop(0, axis=0) self.voltage = characteristic_values['Voltage'].to_numpy(dtype=float) self.current_density = characteristic_values['j' + '_' + metadata['pixel']].to_numpy(dtype=float) * 10 l = len(self.voltage) h = int(l / 2) self.voltage = self.voltage[:] self.current_density = self.current_density[:] self.metadata = metadata return
Parse solar simulator JV data.
Returns
None
def spo_jv(self) ‑> None
-
Expand source code
def spo_jv(self) -> None: """ Parse SPO JV data. Returns: None """ self.Device_Population = 1 d = self.device_dir data = pd.read_csv(d, sep='\t', skiprows=51, encoding="ISO-8859-1", skipfooter=5, engine='python').drop(0, axis=0) self.voltage = data['Voltage setup'].to_numpy(dtype=float) self.current_density = data['Current Density'].to_numpy(dtype=float) * 10 data = pd.read_csv(d, sep='\t', skiprows=47, encoding="ISO-8859-1", skipfooter=170, engine='python', header=None).T.drop(0, axis=0) data.columns = ['Start Time', 'Start Date'] data = pd.to_datetime(data['Start Date'] + ' ' + data['Start Time'], dayfirst=True).values[0] self.metadata = {} self.metadata['datetime'] = data return
Parse SPO JV data.
Returns
None
def standardise_inputs(self) ‑> None
-
Expand source code
def standardise_inputs(self) -> None: """ Standardize inputs for further processing. Returns: None """ self.x = self.voltage self.y = self.current_density self.metadata = self.metadata
Standardize inputs for further processing.
Returns
None
Inherited members