Skip to content

Commit

Permalink
fix bug with copy of settings in concentration simulations
Browse files Browse the repository at this point in the history
  • Loading branch information
pedvide committed Mar 4, 2017
1 parent d756682 commit e92b6b4
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 90 deletions.
1 change: 1 addition & 0 deletions simetuc/lattice.py
Expand Up @@ -85,6 +85,7 @@ def _check_lattice_settings(cte: Dict):
logger.error(msg)
raise LatticeError(msg)


def _create_lattice(spacegroup: Union[int, str], cell_par: List[float], num_uc: int,
sites_pos: List[float], sites_occ: List[float]) -> ase.Atoms:
'''Creates the lattice with the specified parameters.
Expand Down
69 changes: 28 additions & 41 deletions simetuc/settings.py
Expand Up @@ -97,7 +97,9 @@ def __contains__(self, key: Any) -> bool:
def __bool__(self) -> bool:
'''Instance is True if all its data structures have been filled out'''
for var in vars(self).keys():
if not var:
print(var)
# If the var is not literally False, but empty
if getattr(self, var) is not False and not getattr(self, var):
return False
return True

Expand All @@ -106,10 +108,7 @@ def __eq__(self, other: object) -> bool:
if not isinstance(other, Settings):
return NotImplemented
for attr in ['config_file', 'lattice', 'states', 'excitations', 'decay']:
try:
if self[attr] != other[attr]:
return False
except:
if self[attr] != other[attr]:
return False
return True

Expand Down Expand Up @@ -237,7 +236,7 @@ def _parse_states(dict_states: Dict) -> Dict:
return parsed_dict

@staticmethod
def _parse_excitations(dict_excitations: Dict) -> Dict:
def _parse_excitations(dict_states: Dict, dict_excitations: Dict) -> Dict:
'''Parses the excitation section
Returns the parsed excitations dict'''
logger = logging.getLogger(__name__)
Expand All @@ -247,6 +246,9 @@ def _parse_excitations(dict_excitations: Dict) -> Dict:
'degeneracy', 'pump_rate']
optional_keys = ['t_pulse']

sensitizer_labels = dict_states['sensitizer_states_labels']
activator_labels = dict_states['activator_states_labels']

# at least one excitation must exist
if dict_excitations is None:
msg = 'At least one excitation is mandatory'
Expand Down Expand Up @@ -297,33 +299,12 @@ def _parse_excitations(dict_excitations: Dict) -> Dict:
parsed_dict[excitation]['process'] = list_proc # processed in _parse_absorptions
parsed_dict[excitation]['active'] = exc_dict['active']

# at least one excitation must be active
if not any(dict_excitations[label]['active'] for label in dict_excitations.keys()):
msg = 'At least one excitation must be active'
logger.error(msg)
raise ConfigError(msg)

return parsed_dict

@staticmethod
def _parse_absorptions(dict_states: Dict, dict_excitations: Dict) -> None:
'''Parse the absorption and add to the excitation label the ion that is excited and
the inital and final states. It makes changes to the argument dictionaries
'''
logger = logging.getLogger(__name__)

sensitizer_labels = dict_states['sensitizer_states_labels']
activator_labels = dict_states['activator_states_labels']

# absorption
# for each excitation
for excitation in dict_excitations:
dict_excitations[excitation]['init_state'] = []
dict_excitations[excitation]['final_state'] = []
dict_excitations[excitation]['ion_exc'] = []
parsed_dict[excitation]['init_state'] = []
parsed_dict[excitation]['final_state'] = []
parsed_dict[excitation]['ion_exc'] = []

# for each process in the excitation
for process in dict_excitations[excitation]['process']:
for process in list_proc:
# get the ion and state labels of the process
ion_state_list = _get_ion_and_state_labels(process)

Expand All @@ -343,29 +324,37 @@ def _parse_absorptions(dict_states: Dict, dict_excitations: Dict) -> None:
final_ion_num = _get_state_index(sensitizer_labels, final_state,
section='excitation process')

dict_excitations[excitation]['ion_exc'].append('S')
parsed_dict[excitation]['ion_exc'].append('S')
elif init_ion == dict_states['activator_ion_label']: # ACTIVATOR
init_ion_num = _get_state_index(activator_labels, init_state,
section='excitation process')
final_ion_num = _get_state_index(activator_labels, final_state,
section='excitation process')

dict_excitations[excitation]['ion_exc'].append('A')
parsed_dict[excitation]['ion_exc'].append('A')
else:
msg = 'Incorrect ion label in excitation: {}'.format(process)
logger.error(msg)
raise ValueError(msg)
# add to list
dict_excitations[excitation]['init_state'].append(init_ion_num)
dict_excitations[excitation]['final_state'].append(final_ion_num)
parsed_dict[excitation]['init_state'].append(init_ion_num)
parsed_dict[excitation]['final_state'].append(final_ion_num)

# all ions must be the same in the list!
ion_list = dict_excitations[excitation]['ion_exc']
ion_list = parsed_dict[excitation]['ion_exc']
if not all(ion == ion_list[0] for ion in ion_list):
msg = 'All processes must involve the same ion in {}.'.format(excitation)
logger.error(msg)
raise ValueError(msg)

# at least one excitation must be active
if not any(dict_excitations[label]['active'] for label in dict_excitations.keys()):
msg = 'At least one excitation must be active'
logger.error(msg)
raise ConfigError(msg)

return parsed_dict

@staticmethod
def _parse_decay_rates(config_cte: Dict) -> Tuple[List[Tuple[int, float]],
List[Tuple[int, float]]]:
Expand Down Expand Up @@ -728,16 +717,14 @@ def load(self, filename: str) -> None:

# LATTICE
# parse lattice params
self.lattice =self._parse_lattice(config_cte['lattice'])
self.lattice = self._parse_lattice(config_cte['lattice'])

# NUMBER OF STATES
self.states = self._parse_states(config_cte['states'])

# EXCITATIONS
self.excitations = self._parse_excitations(config_cte['excitations'])

# ABSORPTIONS
self._parse_absorptions(self.states, self.excitations)
self.excitations = self._parse_excitations(config_cte['states'],
config_cte['excitations'])

# DECAY RATES
pos_value_S, pos_value_A = self._parse_decay_rates(config_cte)
Expand Down
57 changes: 27 additions & 30 deletions simetuc/simulations.py
Expand Up @@ -964,8 +964,6 @@ def simulate_steady_state(self, average: bool = False) -> SteadyStateSolution:
'''
logger = logging.getLogger(__name__)

cte = self.cte

start_time = time.time()
logger.info('Starting simulation...')

Expand All @@ -985,13 +983,13 @@ def simulate_steady_state(self, average: bool = False) -> SteadyStateSolution:

# initial and final times for excitation and relaxation
t0 = 0
tf = (10*np.max(precalculate.get_lifetimes(cte))).round(8) # total simulation time
tf = (10*np.max(precalculate.get_lifetimes(self.cte))).round(8) # total simulation time
t0_p = t0
tf_p = tf
N_steps_pulse = cte['simulation_params']['N_steps']
N_steps_pulse = self.cte['simulation_params']['N_steps']

rtol = cte['simulation_params']['rtol']
atol = cte['simulation_params']['atol']
rtol = self.cte['simulation_params']['rtol']
atol = self.cte['simulation_params']['atol']

start_time_ODE = time.time()
logger.info('Solving equations...')
Expand Down Expand Up @@ -1019,7 +1017,7 @@ def simulate_steady_state(self, average: bool = False) -> SteadyStateSolution:

# store solution and settings
steady_sol = SteadyStateSolution(t_pulse, y_pulse, index_S_i, index_A_j,
cte, average=average)
self.cte, average=average)
return steady_sol

def simulate_avg_steady_state(self) -> SteadyStateSolution:
Expand Down Expand Up @@ -1076,8 +1074,6 @@ def simulate_concentration_dependence(self, concentration_list: List[Tuple[float
logger = logging.getLogger(__name__)
logger.info('Simulating power dependence curves...')

cte = self.cte

start_time = time.time()

# make sure it's a list of tuple of two floats
Expand All @@ -1087,11 +1083,11 @@ def simulate_concentration_dependence(self, concentration_list: List[Tuple[float
solutions = [] # type: List[Solution]

for concs in tqdm(concentration_list, unit='points',
total=num_conc_steps, disable=cte['no_console'],
total=num_conc_steps, disable=self.cte['no_console'],
desc='Total progress'):
# update concentrations
cte['lattice']['S_conc'] = concs[0]
cte['lattice']['A_conc'] = concs[1]
self.cte['lattice']['S_conc'] = concs[0]
self.cte['lattice']['A_conc'] = concs[1]
# simulate
if dynamics:
sol = self.simulate_dynamics(average=average) # type: Solution
Expand All @@ -1109,21 +1105,21 @@ def simulate_concentration_dependence(self, concentration_list: List[Tuple[float
return conc_dep_solution


#if __name__ == "__main__":
# logger = logging.getLogger()
# logging.basicConfig(level=logging.DEBUG,
# format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
#
# logger.info('Called from cmd.')
#
# import simetuc.settings as settings
# cte = settings.load('config_file.cfg')
#
# cte['no_console'] = False
# cte['no_plot'] = False
#
# sim = Simulations(cte)
#
if __name__ == "__main__":
logger = logging.getLogger()
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s')

logger.info('Called from cmd.')

import simetuc.settings as settings
cte = settings.load('config_file.cfg')

cte['no_console'] = False
cte['no_plot'] = False

sim = Simulations(cte)

# solution = sim.simulate_dynamics()
# solution.log_errors()
# solution.plot()
Expand Down Expand Up @@ -1155,9 +1151,10 @@ def simulate_concentration_dependence(self, concentration_list: List[Tuple[float
#
# conc_list = [(0, 0.1), (0, 0.2), (0, 0.3)]
# conc_list = [(0, 0.1), (0, 0.2), (0, 0.3), (0.1, 0.1), (0.1, 0.2), (0.1, 0.3)]
# solution = sim.simulate_concentration_dependence(conc_list, dynamics=False)
# solution.plot()
# solution.save()
conc_list = [(0, 0.3), (0.1, 0.3), (0.1, 0)]
solution = sim.simulate_concentration_dependence(conc_list, dynamics=False)
solution.plot()
solution.save()
#
# new_sol = ConcentrationDependenceSolution()
# new_sol.load('results/bNaYF4/data_30uc_0.0S_0.3A_conc_dep.hdf5')
Expand Down
51 changes: 40 additions & 11 deletions simetuc/test/test_settings/test_settings.py
Expand Up @@ -15,12 +15,8 @@

test_folder_path = os.path.dirname(os.path.abspath(__file__))

def test_standard_config():
filename = os.path.join(test_folder_path, 'test_standard_config.txt')
cte = settings.load(filename)

with open(filename, 'rt') as file:
config_file = file.read()
@pytest.fixture(scope='function')
def setup_cte():

cte_good = dict([
('lattice',
Expand Down Expand Up @@ -144,18 +140,46 @@ def test_standard_config():
'mult': 6,
'type': 'SS',
'value': 45022061400.0})]))])
cte_good['config_file'] = config_file

assert cte == settings.Settings(cte_good)

def test_non_existing_config():
return cte_good

def test_standard_config(setup_cte):
''''Test that the returned Settings instance for a know config file is correct.'''
filename = os.path.join(test_folder_path, 'test_standard_config.txt')
cte = settings.load(filename)

with open(filename, 'rt') as file:
config_file = file.read()

setup_cte['config_file'] = config_file

assert cte == settings.Settings(setup_cte)


def test_settings_class(setup_cte):
'''Test the creation, bool, and equality of Settings instances.'''

empty_settings = settings.Settings()
assert not empty_settings

settings1 = settings.Settings(setup_cte)
settings2 = settings.Settings(setup_cte)
assert settings1 == settings2

setup_cte['lattice']['name'] = 'new_name'
settings3 = settings.Settings(setup_cte)
assert settings3 != settings1


def test_non_existing_file():
with pytest.raises(settings.ConfigError) as excinfo:
# load non existing file
settings.load(os.path.join(test_folder_path, 'test_non_existing_config.txt'))
assert excinfo.match(r"Error reading file")
assert excinfo.type == settings.ConfigError

def test_empty_config():
def test_empty_file():
with pytest.raises(settings.ConfigError) as excinfo:
with temp_config_filename('') as filename:
settings.load(filename)
Expand Down Expand Up @@ -612,7 +636,12 @@ def test_excitations_config8():
pump_rate: 9.3e-4 # cm2/J
'''
exc_dict = yaml.load(data_exc)
settings.Settings._parse_excitations(exc_dict)

states_dict = {'activator_states_labels': ['3H6', '3F4', '3H5', '3H4', '3F3', '1G4', '1D2'],
'sensitizer_states_labels': ['GS', 'ES'],
'activator_ion_label': 'Tm',
'sensitizer_ion_label': 'Yb'}
settings.Settings._parse_excitations(states_dict, exc_dict)

def test_abs_config1():
data = data_states_ok + '''excitations:
Expand Down

0 comments on commit e92b6b4

Please sign in to comment.