"""Provides general functionality for Agent objects for SIMsalabim simulations"""
######### Package Imports #########################################################################
import numpy as np
import pandas as pd
import os, uuid, sys, copy
from scipy import interpolate
from optimpv import *
from optimpv.general.general import calc_metric, loss_function
from optimpv.general.BaseAgent import BaseAgent
from pySIMsalabim import *
######### Agent Definition #######################################################################
[docs]
class SIMsalabimAgent(BaseAgent):
""" Provides general functionality for Agent objects for SIMsalabim simulations
"""
def __init__(self) -> None:
pass
[docs]
def get_SIMsalabim_clean_cmd_pars(self, parameters):
"""Get the clean cmd_pars list for the SIMsalabim simulation with properly formatted parameters
Parameters
----------
parameters : dict or list of Fitparam() objects
dictionary of parameter names and values or list of Fitparam() objects
Returns
-------
list of dict
list of dictionaries containing the parameters that have a direct match in the SIMsalabim parameter files with the following form {'par': string, 'val': string}
Raises
------
ValueError
Parameter name is not defined in the SIMsalabim parameter files. Please check the parameter names.
ValueError
Parameter name is defined in both the parameters and cmd_pars. Please remove one of them.
UserWarning
Parameter name is not defined in the SIMsalabim parameter files. Please check the parameter names. The optimization will proceed but the parameter will not be used by SIMsalabim.
"""
# if parameters is not a dict:
if not isinstance(parameters, dict):
dummy_pars = {}
for param in parameters:
if param.value_type == 'float':
if param.force_log:
dummy_pars[param.name] = np.log10(param.value)
else:
dummy_pars[param.name] = param.value/param.fscale
elif param.value_type == 'int':
dummy_pars[param.name] = param.value/param.stepsize
else:
dummy_pars[parameters.name] = parameters.value
# parameters = dummy_pars
else:
dummy_pars = copy.deepcopy(parameters)
VarNames,custom_pars,clean_pars = [],[],[]
# check if cmd_pars is in kwargs
if 'cmd_pars' in self.kwargs:
cmd_pars = self.kwargs['cmd_pars']
for cmd_par in cmd_pars:
if (cmd_par['par'] not in self.SIMsalabim_params['l1'].keys()) and (cmd_par['par'] not in self.SIMsalabim_params['setup'].keys()):
custom_pars.append(cmd_par)
else:
clean_pars.append(cmd_par)
VarNames.append(cmd_par['par'])
else:
cmd_pars = []
custom_pars, clean_pars, VarNames = self.prepare_cmd_pars(dummy_pars, custom_pars, clean_pars, VarNames)
clean_pars = self.energy_level_offsets(custom_pars, clean_pars)
clean_pars = self.Gamma_pre_reset(clean_pars,custom_pars)
return clean_pars
[docs]
def get_SIMsalabim_clean_cmd(self, parameters, sim_type='simss'):
"""Get the command line arguments for the SIMsalabim simulation with properly formatted parameters
Parameters
----------
parameters : dict or list of Fitparam() objects
dictionary of parameter names and values or list of Fitparam() objects
sim_type : str, optional
type of simulation ('simss' or 'zimt'), by default 'simss'
Returns
-------
str
command line arguments for the SIMsalabim simulation
"""
# get the clean cmd_pars
clean_pars = self.get_SIMsalabim_clean_cmd_pars(parameters)
self.check_duplicated_parameters(clean_pars)
# construct the command line arguments
return construct_cmd(sim_type, clean_pars)
[docs]
def package_SIMsalabim_files(self, parameters, sim_type, save_path = None):
""" Package the SIMsalabim files for the simulation
Parameters
----------
parameters : dict or list of Fitparam() objects
dictionary of parameter names and values or list of Fitparam() objects
sim_type : str
type of simulation ('simss' or 'zimt')
save_path : str, optional
path to save the simulation files, if None, it will be saved in the session_path/tmp_results, by default None
Raises
------
ValueError
if sim_type is not 'simss' or 'zimt'
"""
# if parameters is not a dict:
if not isinstance(parameters, dict):
dummy_pars = {}
for param in parameters:
if param.value_type == 'float':
dummy_pars[param.name] = param.value/param.fscale
elif param.value_type == 'int':
dummy_pars[param.name] = param.value/param.stepsize
else:
dummy_pars[parameters.name] = parameters.value
else:
dummy_pars = copy.deepcopy(parameters)
VarNames,custom_pars,clean_pars = [],[],[]
# check if cmd_pars is in kwargs
if 'cmd_pars' in self.kwargs:
cmd_pars = self.kwargs['cmd_pars']
for cmd_par in cmd_pars:
if (cmd_par['par'] not in self.SIMsalabim_params['l1'].keys()) and (cmd_par['par'] not in self.SIMsalabim_params['setup'].keys()):
custom_pars.append(cmd_par)
else:
clean_pars.append(cmd_par)
VarNames.append(cmd_par['par'])
else:
cmd_pars = []
custom_pars, clean_pars, VarNames = self.prepare_cmd_pars(dummy_pars, custom_pars, clean_pars, VarNames)
clean_pars = self.energy_level_offsets(custom_pars, clean_pars)
dum_dic= {}
for cmd in clean_pars:
dum_dic[cmd['par']] = cmd['val']
if save_path is None:
save_path = os.path.join(self.session_path,'tmp_results')
if not os.path.exists(save_path):
os.makedirs(save_path)
# copy sim_type file from session_path to save_path
if sim_type == 'simss':
if os.name == 'nt':
shutil.copy(os.path.join(self.session_path,'simss.exe'),os.path.join(save_path,'simss.exe'))
else:
shutil.copy(os.path.join(self.session_path,'simss'),os.path.join(save_path,'simss'))
elif sim_type == 'zimt':
if os.name == 'nt':
shutil.copy(os.path.join(self.session_path,'zimt.exe'),os.path.join(save_path,'zimt.exe'))
else:
shutil.copy(os.path.join(self.session_path,'zimt'),os.path.join(save_path,'zimt'))
else:
raise ValueError('sim_type must be either simss or zimt')
# get all input files that are needed for the simulation and copy them to save_path with their basename
InputFiles2copy = []
dev_par_new = copy.deepcopy(self.dev_par)
for layer in self.layers:
if layer[1] == 'setup':
for section in dev_par_new[layer[2]]:
# print(section[1:])
for param in section[1:]:
if param[0] == 'par':
if param[1] in dum_dic.keys():
if self.is_inputFile(param[1],dum_dic[param[1]]):
if os.path.basename(dum_dic[param[1]]) != 'none':
InputFiles2copy.append(dum_dic[param[1]])
param[2] = os.path.basename(dum_dic[param[1]])
else:
param[2] = dum_dic[param[1]]
else:
if self.is_inputFile(param[1],param[2]):
if os.path.basename(param[2]) != 'none':
InputFiles2copy.append(param[2])
param[2] = os.path.basename(param[2])
else:
param[2] = param[2]
else:
for section in dev_par_new[layer[2]]:
for param in section[1:]:
if param[0] == 'par':
if layer[1]+'.'+param[1] in dum_dic.keys():
if self.is_inputFile(param[1],dum_dic[layer[1]+'.'+param[1]]):
if os.path.basename(dum_dic[layer[1]+'.'+param[1]]) != 'none':
InputFiles2copy.append(dum_dic[layer[1]+'.'+param[1]])
param[2] = self.convert_parameter_to_basename(param[1],dum_dic[layer[1]+'.'+param[1]])
else:
param[2] = dum_dic[layer[1]+'.'+param[1]]
else:
if self.is_inputFile(param[1],param[2]):
if os.path.basename(param[2]) != 'none':
InputFiles2copy.append(param[2])
param[2] = self.convert_parameter_to_basename(param[1],param[2])
else:
param[2] = param[2]
#copy the simulation setup file
shutil.copy(os.path.join(self.session_path,self.simulation_setup),os.path.join(save_path,os.path.basename(self.simulation_setup)))
for file in InputFiles2copy:
if os.path.isfile(os.path.join(self.session_path,file)):
shutil.copy(os.path.join(self.session_path,file),os.path.join(save_path,os.path.basename(file)))
#update keys with new filenames by taking the basename
dum_dic = {}
for key in dev_par_new.keys():
dum_dic[os.path.basename(key)] = dev_par_new[key]
dev_par_new = dum_dic
keys = list(dev_par_new.keys())
for key in dev_par_new.keys():
with open(os.path.join(save_path,key),'w') as f:
f.write(devpar_write_to_txt(dev_par_new[key]))
[docs]
def energy_level_offsets(self, custom_pars, clean_pars):
"""Convert the energy level offsets to the SIMsalabim format energy levels
Parameters
----------
custom_pars : list of dict
list of dictionaries these contain all the parameters that are not explicitely in the SIMsalabim format and not in the ambipolar format (see ambi_param_transform). The dictionaries are of the form {'par': string, 'val': string}
clean_pars : list of dict
list of dictionaries these contain all the parameters that are explicitely in the SIMsalabim format. The dictionaries are of the form {'par': string, 'val': string}
Returns
-------
list of dict
list of dictionaries these contain all the parameters converted to the SIMsalabim format. The dictionaries are of the form {'par': string, 'val': string}
Raises
------
ValueError
Energy level offset between conduction bands must be defined from right to left
ValueError
Energy level offset between valence bands must be defined from left to right
ValueError
The offset of the work function of the left electrode with respect to the conduction band must be negative
ValueError
The offset of the work function of the left electrode with respect to the valence band must be positive
ValueError
The offset of the work function of the right electrode with respect to the conduction band must be negative
ValueError
The offset of the work function of the right electrode with respect to the valence band must be positive
"""
# make a deepcopy of self.SIMsalabim_params to avoid mixing the values of the energy levels when running in parallel
tmp_SIMsalabim_params = copy.deepcopy(self.SIMsalabim_params)
# search for energy level values defined in clean_pars and add them to the SIMsalabim_params
for cmd in clean_pars:
if ('E_c' in cmd['par']) and (not 'offset' in cmd['par']) and (not 'Egap' in cmd['par']):
layer, par = cmd['par'].split('.')
tmp_SIMsalabim_params[layer][par] = cmd['val']
if ('E_v' in cmd['par']) and (not 'offset' in cmd['par']) and (not 'Egap' in cmd['par']):
layer, par = cmd['par'].split('.')
tmp_SIMsalabim_params[layer][par] = cmd['val']
Ec_cmd_nrj, Ev_cmd_nrj, Ec_idx_in_stack, Ec_idx_in_cmd_pars, Ev_idx_in_stack, Ev_idx_in_cmd_pars = [],[],[],[],[],[]
Egap_cmd_nrj, W_L_offset, W_R_offset = [],[],[]
for idx, cmd in enumerate(custom_pars):
if '.' in cmd['par'] and 'offset' in cmd['par'] and not 'W_L' in cmd['par'] and not 'W_R' in cmd['par']:
layer, par = cmd['par'].split('.')
offset, layer1, layer2 = layer.split('_')
if par == 'E_c':
Ec_idx_in_stack.append(int(layer1[1:]))
Ec_idx_in_cmd_pars.append(idx)
if par == 'E_v':
Ev_idx_in_stack.append(int(layer1[1:]))
Ev_idx_in_cmd_pars.append(idx)
if '.' in cmd['par'] and 'Egap' in cmd['par']:
Egap_cmd_nrj.append(cmd)
if '.' in cmd['par'] and 'offset' in cmd['par'] and 'W_L' in cmd['par']:
W_L_offset.append(cmd)
if '.' in cmd['par'] and 'offset' in cmd['par'] and 'W_R' in cmd['par']:
W_R_offset.append(cmd)
# reoder the Ec and Ev in cmd_pars to match the order in the stack
dum_array = np.asarray([Ec_idx_in_stack, Ec_idx_in_cmd_pars])
dum_array = dum_array[:, dum_array[0].argsort()] # sort the array based on the first row
Ec_cmd_nrj = [custom_pars[dum_array[1][i]] for i in range(len(dum_array[1]))]
dum_array = np.asarray([Ev_idx_in_stack, Ev_idx_in_cmd_pars])
dum_array = dum_array[:, dum_array[0].argsort()] # sort the array based on the first row
Ev_cmd_nrj = [custom_pars[dum_array[1][i]] for i in range(len(dum_array[1]))]
# Set the energy levels of the layers
Ec_cmd_nrj = Ec_cmd_nrj[::-1] # invert order of cmd_nrj
for idx, cmd in enumerate(Ec_cmd_nrj):
layer, par = cmd['par'].split('.')
offset, layer1, layer2 = layer.split('_')
if int(layer1[1:]) <= int(layer2[1:]):
raise ValueError('The energy level offset between conduction bands must be define from right to left so the offset should be defined as offset_'+layer2+'_offset_'+layer1+' instead of offset_'+layer1+'_offset_'+layer2)
if par == 'E_c':
Ec_val = float(tmp_SIMsalabim_params[layer1]['E_c']) - float(cmd['val'])
clean_pars.append({'par': layer2+'.E_c', 'val': str(Ec_val)})
tmp_SIMsalabim_params[layer2]['E_c'] = str(Ec_val)
for idx, cmd in enumerate(Ev_cmd_nrj):
layer, par = cmd['par'].split('.')
offset, layer1, layer2 = layer.split('_')
if int(layer1[1:]) >= int(layer2[1:]):
raise ValueError('The energy level offset between valence bands must be define from left to right so the offset should be defined as offset_'+layer1+'_offset_'+layer2+' instead of offset_'+layer2+'_offset_'+layer1)
if par == 'E_v':
Ev_val = float(tmp_SIMsalabim_params[layer1]['E_v']) - float(cmd['val'])
clean_pars.append({'par': layer2+'.E_v', 'val': str(Ev_val)})
tmp_SIMsalabim_params[layer2]['E_v'] = str(Ev_val)
# Set the bandgap energy level of the layers
for idx, cmd in enumerate(Egap_cmd_nrj):
layer, par = cmd['par'].split('.')
Egap, layer_ = layer.split('_')
if par == 'E_c':
E_v = float(tmp_SIMsalabim_params[layer_]['E_v'])
E_c = E_v - float(cmd['val'])
clean_pars.append({'par': layer_+'.E_c', 'val': str(E_c)})
tmp_SIMsalabim_params[layer_]['E_c'] = str(E_c)
if par == 'E_v':
E_c = float(tmp_SIMsalabim_params[layer_]['E_c'])
E_v = E_c + float(cmd['val'])
clean_pars.append({'par': layer_+'.E_v', 'val': str(E_v)})
tmp_SIMsalabim_params[layer_]['E_v'] = str(E_v)
# finish with the electrode offsets
for idx, cmd in enumerate(W_L_offset):
layer, par = cmd['par'].split('.')
if par == 'E_c':
if float(cmd['val']) > 0:
raise ValueError('The offset of the work function of the left electrode with respect to the conduction band must be negative')
W_L = float(tmp_SIMsalabim_params['l1']['E_c']) - float(cmd['val'])
clean_pars.append({'par': 'W_L', 'val': str(W_L)})
tmp_SIMsalabim_params['setup']['W_L'] = str(W_L)
if par == 'E_v':
if float(cmd['val']) < 0:
raise ValueError('The offset of the work function of the left electrode with respect to the valence band must be positive')
W_L = float(tmp_SIMsalabim_params['l1']['E_v']) - float(cmd['val'])
clean_pars.append({'par': 'W_L', 'val': str(W_L)})
tmp_SIMsalabim_params['setup']['W_L'] = str(W_L)
for idx, cmd in enumerate(W_R_offset):
layer, par = cmd['par'].split('.')
keys_list = list(tmp_SIMsalabim_params.keys())
last_layer = keys_list[-1]
if par == 'E_c':
if float(cmd['val']) > 0:
raise ValueError('The offset of the work function of the right electrode with respect to the conduction band must be negative')
W_R = float(tmp_SIMsalabim_params[last_layer]['E_c']) - float(cmd['val'])
clean_pars.append({'par': 'W_R', 'val': str(W_R)})
tmp_SIMsalabim_params['l1']['W_R'] = str(W_R)
if par == 'E_v':
if float(cmd['val']) < 0:
raise ValueError('The offset of the work function of the right electrode with respect to the valence band must be positive')
W_R = float(tmp_SIMsalabim_params[last_layer ]['E_v']) - float(cmd['val'])
clean_pars.append({'par': 'W_R', 'val': str(W_R)})
tmp_SIMsalabim_params['setup']['W_R'] = str(W_R)
return clean_pars
[docs]
def Gamma_pre_reset(self, cmd_pars, custom_pars):
"""Prepare the Langevin pre-factor parameters for the SIMsalabim simulation but use it to calculate k_direct instead of passing preLangevin to SIMsalabim.
Parameters
----------
cmd_pars : list of dict
list of dictionaries with the following form {'par': string, 'val': string}
custom_pars : list of dict
list of dictionaries with the following form {'par': string, 'val': string}
Returns
-------
list of dict
list of dictionaries with the following form {'par': string, 'val': string}
"""
tmp_SIMsalabim_params = copy.deepcopy(self.SIMsalabim_params)
clean_pars, Gammas = [], []
for cmd in cmd_pars:
if '.' not in cmd['par'] :
clean_pars.append({'par': cmd['par'], 'val': cmd['val']})
continue
else:
if 'mu_n' in cmd['par'] or 'mu_p' in cmd['par']: # make sure we update the mobilities in the tmp_SIMsalabim_params
if '.' not in cmd['par']:
continue
layer, par = cmd['par'].split('.')
if par == 'mu_n':
tmp_SIMsalabim_params[layer]['mu_n'] = cmd['val']
elif par == 'mu_p':
tmp_SIMsalabim_params[layer]['mu_p'] = cmd['val']
clean_pars.append({'par': cmd['par'], 'val': cmd['val']})
else:
clean_pars.append({'par': cmd['par'], 'val': cmd['val']})
for cmd in custom_pars:
if 'Gamma_pre' in cmd['par']:
Gammas.append({'par': cmd['par'], 'val': cmd['val']})
# now we need to add the Gamma_pre parameters to the clean_pars
for gamma in Gammas:
layer, par = gamma['par'].split('.')
mob_n = tmp_SIMsalabim_params[layer]['mu_n']
mob_p = tmp_SIMsalabim_params[layer]['mu_p']
eps_r = tmp_SIMsalabim_params[layer]['eps_r']
eps_0 = 8.8542e-12 # same as in SIMsalabim
q = 1.6022e-19 # same as in SIMsalabim
k_direct = float(gamma['val']) * q * (float(mob_n) + float(mob_p)) / (float(eps_r) * eps_0)
clean_pars.append({'par': layer+'.k_direct', 'val': str(k_direct)})
return clean_pars
[docs]
def check_duplicated_parameters(self, cmd_pars):
"""Check if there are duplicated parameters in the cmd_pars
Parameters
----------
cmd_pars : list of dict
list of dictionaries with the following form {'par': string, 'val': string}
Raises
------
ValueError
There are duplicated parameters in the cmd_pars
"""
names = []
for cmd in cmd_pars:
if cmd['par'] in names:
raise ValueError('Parameter '+cmd['par']+' is defined more than once in the cmd_pars. Please remove the duplicates.')
names.append(cmd['par'])
[docs]
def prepare_cmd_pars(self, parameters, custom_pars, clean_pars,VarNames):
"""Prepare the cmd_pars for the SIMsalabim simulation
Parameters
----------
parameters : dict
dictionary of parameter names and values
custom_pars : list of dict
list of dictionaries containing the custom parameters that do not have a direct match in the SIMsalabim parameter files with the following form {'par': string, 'val': string}
clean_pars : list of dict
list of dictionaries containing the parameters that have a direct match in the SIMsalabim parameter files with the following form {'par': string, 'val': string}
VarNames : list of str
list of parameter names
Returns
-------
list of dict
list of dictionaries containing the custom parameters that do not have a direct match in the SIMsalabim parameter files with the following form {'par': string, 'val': string}
list of dict
list of dictionaries containing the parameters that have a direct match in the SIMsalabim parameter files with the following form {'par': string, 'val': string}
list of str
list of parameter names
Raises
------
ValueError
If the parameter name is not in the self.params list
ValueError
If the parameter name is in both the parameters and cmd_pars
"""
for param in self.params:
if param.name in parameters.keys():
if param.name not in VarNames:
VarNames.append(param.name)
if '.' in param.name and 'offset' not in param.name and 'Egap' not in param.name:
layer, par = param.name.split('.')
if par not in ['N_ions', 'mu_ions', 'mu_np', 'C_np_bulk', 'C_np_int']:
if par in self.SIMsalabim_params[layer].keys():
if param.value_type == 'float':
if param.force_log:
clean_pars.append({'par': param.name, 'val': str(10**parameters[param.name])})
else:
clean_pars.append({'par': param.name, 'val': str(parameters[param.name]*param.fscale)})
elif param.value_type == 'int':
clean_pars.append({'par': param.name, 'val': str(int(parameters[param.name]*param.stepsize))})
else:
clean_pars.append({'par': param.name, 'val': str(parameters[param.name])})
else:
# put in custom_pars
if param.value_type == 'float':
if param.force_log:
custom_pars.append({'par': param.name, 'val': str(10**parameters[param.name])})
else:
custom_pars.append({'par': param.name, 'val': str(parameters[param.name]*param.fscale)})
elif param.value_type == 'int':
custom_pars.append({'par': param.name, 'val': str(int(parameters[param.name]*param.stepsize))})
else:
custom_pars.append({'par': param.name, 'val': str(parameters[param.name])})
else:
clean_pars = self.ambi_param_transform(param, parameters[param.name], clean_pars)
else:
if param.name in self.SIMsalabim_params['setup'].keys():
if param.value_type == 'float':
if param.force_log:
clean_pars.append({'par': param.name, 'val': str(10**parameters[param.name])})
else:
clean_pars.append({'par': param.name, 'val': str(parameters[param.name]*param.fscale)})
elif param.value_type == 'int':
clean_pars.append({'par': param.name, 'val': str(int(parameters[param.name]*param.stepsize))})
else:
clean_pars.append({'par': param.name, 'val': str(parameters[param.name])})
else:
# put in custom_pars
if 'offset' in param.name or 'Egap' in param.name:
if param.value_type == 'float':
if param.force_log:
custom_pars.append({'par': param.name, 'val': str(10**parameters[param.name])})
else:
custom_pars.append({'par': param.name, 'val': str(parameters[param.name]*param.fscale)})
elif param.value_type == 'int':
custom_pars.append({'par': param.name, 'val': str(int(parameters[param.name]*param.stepsize))})
else:
custom_pars.append({'par': param.name, 'val': str(parameters[param.name])})
else:
warnings.warn('Parameter '+param.name+' is not defined in the SIMsalabim parameter files. Please check the parameter names. The optimization will proceed but '+param.name+' will not be used by SIMsalabim.', UserWarning)
# raise ValueError('Parameter '+param.name+' is not defined in the SIMsalabim parameter files. Please check the parameter names.')
else:
raise ValueError('Parameter '+param.name+' is defined in both the parameters and cmd_pars. Please remove one of them.')
else:
# if param is not in parameters we use the param.value
if param.name not in VarNames:
VarNames.append(param.name)
if '.' in param.name and 'offset' not in param.name and 'Egap' not in param.name:
layer, par = param.name.split('.')
if par not in ['N_ions', 'mu_ions', 'mu_np', 'C_np_bulk', 'C_np_int']:
if par in self.SIMsalabim_params[layer].keys():
clean_pars.append({'par': param.name, 'val': str(param.value)})
else:
custom_pars.append({'par': param.name, 'val': str(param.value)})
else:
clean_pars = self.ambi_param_transform(param, param.value, clean_pars, no_transform=True)
else:
if param.name in self.SIMsalabim_params['setup'].keys():
clean_pars.append({'par': param.name, 'val': str(param.value)})
else:
if 'offset' in param.name or 'Egap' in param.name:
custom_pars.append({'par': param.name, 'val': str(param.value)})
else:
warnings.warn('Parameter '+param.name+' is not defined in the SIMsalabim parameter files. Please check the parameter names. The optimization will proceed but '+param.name+' will not be used by SIMsalabim.', UserWarning)
else:
raise ValueError('Parameter '+param.name+' is defined in both the parameters and cmd_pars. Please remove one of them.')
# raise ValueError('There is no parameter named '+param.name+' in the self.params list. Please check the parameter names.')
return custom_pars, clean_pars, VarNames
[docs]
def convert_parameter_to_basename(self, name, value):
"""Convert the parameter value to its basename if it is a file
Parameters
----------
name : str
parameter name
value : str or float or int
parameter value
Returns
-------
str
parameter value in its basename
"""
if name.endswith('File'):
return os.path.basename(value)
elif name.startswith('l') and name[1:].isdigit():
return os.path.basename(value)
elif name == 'genProfile':
if value.lower() != 'calc' and value.lower() != 'none':
return os.path.basename(value)
elif name.lower() == 'expjv' and value.lower() != 'none':
return os.path.basename(value)
elif name.startswith('nk'):
return os.path.basename(value)
elif name.lower() == 'spectrum':
return os.path.basename(value)
else:
return value