Commit 04a0c4ca authored by Malthe Kjær Bisbo's avatar Malthe Kjær Bisbo
Browse files

improved logging

parent 6af2c65a
......@@ -27,7 +27,7 @@ this (propperly modified for your setup)::
source <GPAW stuff>
source <DFTB stuff> # if running DFTB
mpiexec --mca mpi_warn_on_fork 0 gpaw-python run_search.py > search.log
mpiexec --mca mpi_warn_on_fork 0 gpaw-python run_search.py
echo "========= Job finished at `date` =========="
This job will be run locally in the submission folder on 10 cpu cores.
......
No preview for this file type
.. _au_on_cu_search:
=======================
Au7 in Cu(111) with EMT
=======================
In this tutorial we carry out a search for Au7-clusters on
the Cu(111) surface.
In this search we will utilize an :class:`OperationConstraint`
to constraint the :class:`RattleMutation` to only rattle the
atoms within a certain box in space that we define.
......@@ -13,6 +13,7 @@ from ase.io import read, write, Trajectory
from ase.calculators.singlepoint import SinglePointCalculator
from ase.calculators.dftb import Dftb
from utils import array_to_string
from parallel_utils import split, parallel_function_eval
from bfgslinesearch_constrained import relax
......@@ -63,6 +64,10 @@ class GOFEE():
Name of trajectory to which all structures,
evaluated during the search, is saved.
logfile: file object or str
If *logfile* is a string, a file with that name will be opened.
Use '-' for stdout.
kappa: float
How much to weigh predicted uncertainty in the acquisition
function.
......@@ -104,6 +109,7 @@ class GOFEE():
startgenerator=None,
candidate_generator=None,
trajectory='structures.traj',
logfile='search.log',
kappa=2,
max_steps=200,
Ninit=10,
......@@ -132,7 +138,6 @@ class GOFEE():
assert structures is not None
calc = structures[0].get_calculator()
assert calc is not None and not isinstance(calc, SinglePointCalculator)
print('Using calculator from supplied structure(s)')
self.calc = calc
if startgenerator is None:
......@@ -177,6 +182,17 @@ class GOFEE():
if self.restart:
self.traj_name = trajectory
if not self.master:
logfile = None
elif isinstance(logfile, str):
if logfile == "-":
logfile = sys.stdout
else:
logfile = open(logfile, "a")
self.logfile = logfile
self.log_msg = ''
if restart is None or not isfile(restart):
self.initialize()
......@@ -257,11 +273,14 @@ class GOFEE():
self.evaluate_initial_structures()
while self.steps < self.max_steps:
self.print_master('\n ### steps: {} ###\n'.format(self.steps))
self.log_msg += (f"\n##### STEPS: {self.steps} #####\n\n")
t0 = time()
self.train_surrogate()
t1 = time()
self.update_population()
t2 = time()
relaxed_candidates = self.get_surrogate_relaxed_candidates()
t3 = time()
kappa = self.kappa
a_add = []
for _ in range(5):
......@@ -280,6 +299,11 @@ class GOFEE():
traceback.print_exc(file=sys.stderr)
self.gpr.memory.save_data(a_add)
# log timing
self.log_msg += "Timing:\n"
self.log_msg += f"{'Training':12}{'Relax pop.':12}{'Relax candidates':18}{'Evaluate':12}\n"
self.log_msg += f"{t1-t0:12.2e}\t{t2-t1:12.2e}\t{t3-t2:16.2e}\t{time()-t3:12.2e}\n\n"
# Add structure to population
index_lowest = np.argmin([a.get_potential_energy() for a in a_add])
self.population.add([a_add[index_lowest]])
......@@ -287,11 +311,13 @@ class GOFEE():
# Save search state
self.save_state()
if self.master:
print('anew pred:', anew.info['key_value_pairs']['Epred'], anew.info['key_value_pairs']['Epred_std'])
print('E_true:', [a.get_potential_energy() for a in a_add])
print('pop:', [a.get_potential_energy() for a in self.population.pop])
self.log_msg += (f"Prediction:\nenergy = {anew.info['key_value_pairs']['Epred']:.5f}eV, energy_std = {anew.info['key_value_pairs']['Epred_std']:.5f}eV\n")
self.log_msg += (f"E_true:\n{array_to_string([a.get_potential_energy() for a in a_add], unit='eV')}\n\n")
#self.log_msg += (f"E_true: {[a.get_potential_energy() for a in a_add]}\n")
self.log_msg += (f"Energy of population:\n{array_to_string([a.get_potential_energy() for a in self.population.pop], unit='eV')}\n")
self.log_msg += (f"Max force of ML-relaxed population:\n{array_to_string([(a.get_forces()**2).sum(axis=1).max()**0.5 for a in self.population.pop_MLrelaxed], unit='eV/A')}\n")
self.log()
self.steps += 1
def get_dualpoint(self, a, lmax=0.10, Fmax_flat=5):
......@@ -315,11 +341,6 @@ class GOFEE():
a_dp.set_positions(pos_dp)
return a_dp
def print_master(self, *args):
self.comm.barrier()
if self.master:
print(*args, flush=True)
def get_surrogate_relaxed_candidates(self):
""" Method supplying a number of surrogate-relaxed new
candidates. The method combines the generation of new
......@@ -338,13 +359,6 @@ class GOFEE():
relaxed_candidates = self.certainty_filter(relaxed_candidates)
relaxed_candidates = self.population.pop_MLrelaxed + relaxed_candidates
"""
if self.master:
Epred = np.array([a.info['key_value_pairs']['Epred'] for a in relaxed_candidates])
Epred_std = np.array([a.info['key_value_pairs']['Epred_std'] for a in relaxed_candidates])
fitness = Epred - self.kappa*Epred_std
print(np.c_[Epred, Epred_std, fitness])
"""
return relaxed_candidates
def generate_candidate(self):
......@@ -397,9 +411,8 @@ class GOFEE():
Fmax=0.001, steps=200, kappa=None)
for i in task_split[self.comm.rank]]
self.population.pop_MLrelaxed = parallel_function_eval(self.comm, func)
if self.master:
print('ML-relaxed pop forces:\n',
[(a.get_forces()**2).sum(axis=1).max()**0.5 for a in self.population.pop_MLrelaxed])
Fmax_pop_relaxed = [(a.get_forces()**2).sum(axis=1).max()**0.5
for a in self.population.pop_MLrelaxed]
def train_surrogate(self):
""" Method to train the surrogate model.
......@@ -411,13 +424,11 @@ class GOFEE():
# Train
if self.steps < 50 or (self.steps % 10) == 0:
self.gpr.optimize_hyperparameters(comm=self.comm)
if self.master:
print('lml:', self.gpr.lml)
print('kernel optimized:\n\tTheta =', list(np.exp(self.gpr.kernel.theta)))
self.log_msg += (f"lml: {self.gpr.lml}\n")
self.log_msg += (f"kernel optimized:\nTheta = {[f'{x:.2e}' for x in np.exp(self.gpr.kernel.theta)]}\n\n")
else:
self.gpr.train()
if self.master:
print('kernel fixed:\n\tTheta =', list(np.exp(self.gpr.kernel.theta)))
self.log_msg += (f"kernel fixed:\nTheta = {[f'{x:.2e}' for x in np.exp(self.gpr.kernel.theta)]}\n\n")
def select_with_acquisition(self, structures, kappa):
""" Method to select single most "promizing" candidate
......@@ -450,14 +461,11 @@ class GOFEE():
a.set_calculator(calc_sp)
success = True
except:
print('dftb failed on master', flush=True)
success = False
else:
success = None
success = self.comm.bcast(success, root=0)
if success == False:
write('fail.traj', a)
print('Raising error rank', self.comm.rank, flush=True)
raise RuntimeError('DFTB evaluation failed')
a = self.comm.bcast(a, root=0)
else:
......@@ -506,3 +514,16 @@ class GOFEE():
self.gpr = GPR(template_structure=training_structures[0])
self.gpr.memory.save_data(training_structures)
self.gpr.kernel.theta = theta
def log(self):
if self.logfile is not None:
if self.steps == 0:
msg = "GOFEE"
self.logfile.write(msg)
self.logfile.write(self.log_msg)
self.logfile.flush()
self.log_msg = ''
......@@ -76,4 +76,17 @@ def get_min_distances_as_fraction_of_covalent(a, indices=None, covalent_distance
# Filter away self interactions.
bl = bl[bl > 1e-6].reshape(bl.shape[0],bl.shape[1]-1)
return np.min(bl), bl.min(axis=1).argmin()
\ No newline at end of file
return np.min(bl), bl.min(axis=1).argmin()
def array_to_string(arr, unit='', format='0.4f', max_line_length=80):
msg = ''
line_length_counter = 0
for i, x in enumerate(arr):
string = f'{i} = {x:{format}}{unit}, '
#string = f"{f'{i}={x:{format}}{unit},':15}"
line_length_counter += len(string)
if line_length_counter >= max_line_length:
msg += '\n'
line_length_counter = len(string)
msg += string
return msg
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment