Skip to content

Commit

Permalink
Merge pull request #292 from libAtoms/dft_SCF_convergence_status
Browse files Browse the repository at this point in the history
DFT calculator convergence test
  • Loading branch information
bernstei authored Feb 8, 2024
2 parents 2b95c14 + d363155 commit 5b6a5ea
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 15 deletions.
2 changes: 1 addition & 1 deletion complete_pytest.tin
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ echo "summary line $l"
# ===== 152 passed, 17 skipped, 3 xpassed, 78 warnings in 4430.81s (1:13:50) =====
lp=$( echo $l | sed -E -e 's/ in .*//' -e 's/\s*,\s*/\n/g' )

declare -A expected_n=( ["passed"]="163" ["skipped"]="21" ["warnings"]=803 ["xfailed"]=2 ["xpassed"]=1 )
declare -A expected_n=( ["passed"]="164" ["skipped"]="21" ["warnings"]=803 ["xfailed"]=2 ["xpassed"]=1 )
IFS=$'\n'
for out in $lp; do
out_n=$(echo $out | sed -e 's/^=* //' -e 's/ .*//' -e 's/,//')
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setuptools.setup(
name="wfl",
version="0.2.1",
version="0.2.2",
packages=setuptools.find_packages(exclude=["tests"]),
install_requires=["click>=7.0", "numpy", "ase>=3.21", "pyyaml", "spglib", "docstring_parser",
"expyre-wfl @ https://github.com/libAtoms/ExPyRe/tarball/main",
Expand Down
37 changes: 37 additions & 0 deletions tests/calculators/test_vasp.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,40 @@ def test_vasp_multi_calc(tmp_path):

assert np.abs(e_GGA - e_test) < 1.0e-4
assert n_loop_test < n_loop_GGA - 2


def test_vasp_unconverged(tmp_path):
ase.io.write(tmp_path / 'vasp_in.xyz', Atoms('Si', cell=(2, 2, 2), pbc=[True] * 3), format='extxyz')

configs_eval = generic.calculate(
inputs=ConfigSet(tmp_path / 'vasp_in.xyz'),
outputs=OutputSpec('vasp_out.regular.xyz', file_root=tmp_path),
calculator=Vasp(workdir=tmp_path, encut=200, kspacing=1.0, pp=os.environ['PYTEST_VASP_POTCAR_DIR'],
keep_files=True),
output_prefix='TEST_')

run_dir = list(tmp_path.glob('run_VASP_*'))
nfiles = len(list(os.scandir(run_dir[0])))

assert nfiles == 18

ats = list(configs_eval)
print("initial run converged?", ats[0].info["TEST_converged"])
assert ats[0].info["TEST_converged"]


configs_eval = generic.calculate(
inputs=ConfigSet(tmp_path / 'vasp_in.xyz'),
outputs=OutputSpec('vasp_out.unconverged.xyz', file_root=tmp_path),
calculator=Vasp(workdir=tmp_path, encut=200, nelm=6, kspacing=1.0, pp=os.environ['PYTEST_VASP_POTCAR_DIR'],
keep_files=True),
output_prefix='TEST_')

run_dir = list(tmp_path.glob('run_VASP_*'))
nfiles = len(list(os.scandir(run_dir[0])))

assert nfiles == 18

ats = list(configs_eval)
print("second run converged?", ats[0].info["TEST_converged"])
assert not ats[0].info["TEST_converged"]
2 changes: 1 addition & 1 deletion tests/test_optimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def test_relax_fixed_vol(cu_slab):

def test_subselect_from_traj(cu_slab):

calc = EMT()
calc = (EMT, [], {})

cu_slab_optimised = cu_slab.copy()
cu_slab_optimised.set_positions(expected_relaxed_positions_constant_pressure)
Expand Down
15 changes: 6 additions & 9 deletions tests/test_remote_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def do_generic_calc(tmp_path, sys_name, monkeypatch, remoteinfo_env):
monkeypatch.setenv('WFL_EXPYRE_NO_MARK_PROCESSED', '1')

t0 = time.time()
results = generic.calculate(inputs=ci, outputs=co, calculator=calc, properties=["energy", "forces"],
results = generic.calculate(inputs=ci, outputs=co, calculator=(EMT, [], {}), properties=["energy", "forces"],
autopara_info={"remote_info": ri})
dt = time.time() - t0
print('remote parallel calc_time', dt)
Expand All @@ -161,7 +161,7 @@ def do_generic_calc(tmp_path, sys_name, monkeypatch, remoteinfo_env):
co = OutputSpec(tmp_path / f'ats_o_{sys_name}.xyz')

t0 = time.time()
results = generic.calculate(inputs=ci, outputs=co, calculator=calc, properties=["energy", "forces"],
results = generic.calculate(inputs=ci, outputs=co, calculator=(EMT, [], {}), properties=["energy", "forces"],
autopara_info={"remote_info": ri})
dt_rerun = time.time() - t0
print('remote parallel calc_time', dt_rerun)
Expand Down Expand Up @@ -293,18 +293,18 @@ def test_resubmit_killed_jobs(tmp_path, expyre_systems, monkeypatch, remoteinfo_
def do_resubmit_killed_jobs(tmp_path, sys_name, monkeypatch, remoteinfo_env):
# make sure that jobs that time out can be resubmitted automatically
ri = {'sys_name': sys_name, 'job_name': 'pytest_'+sys_name,
'resources': {'max_time': '1m', 'num_nodes': 1},
'resources': {'max_time': '10s', 'num_nodes': 1},
'num_inputs_per_queued_job': 1, 'check_interval': 10}
remoteinfo_env(ri)

print("RemoteInfo", ri)

ats = [Atoms('C') for _ in range(3)]
n = 20
n = 40
ats[1] = Atoms(f'C{n**3}', positions=np.asarray(np.meshgrid(range(n), range(n), range(n))).reshape((3, -1)).T,
cell=[n]*3, pbc=[True]*3)

calc = EMT()
calc = (EMT, [], {})

# first just ignore failures
ri['ignore_failed_jobs'] = True
Expand All @@ -324,12 +324,9 @@ def do_resubmit_killed_jobs(tmp_path, sys_name, monkeypatch, remoteinfo_env):
ri['resubmit_killed_jobs'] = True
monkeypatch.setenv('WFL_EXPYRE_INFO', json.dumps({"test_resubmit_killed_jobs": ri}))
print("BOB ######### second run, should time out")
try:
with pytest.raises(ExPyReJobDiedError):
results = generic.calculate(inputs=ConfigSet(ats), outputs=OutputSpec(), calculator=calc, properties=["energy", "forces"],
raise_calc_exceptions=True, autopara_info=AutoparaInfo(remote_label="test_resubmit_killed_jobs"))
except ExPyReJobDiedError:
# ignore timeout in initial call
pass

# now resubmit with longer time
ri['resources']['max_time'] = '5m'
Expand Down
8 changes: 7 additions & 1 deletion wfl/calculators/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ def _run_autopara_wrappable(atoms, calculator, properties=None, output_prefix='_
calculator_default = None

if output_prefix == '_auto_':
output_prefix = calculator.__class__.__name__ + '_'
if isinstance(calculator, tuple):
# constructor, get name directly
calc_class = calculator[0].__name__
else:
# calculator object, get name from class
calc_class = calculator.__class__.__name__
output_prefix = calc_class + '_'

at_out = []
for at in atoms_to_list(atoms):
Expand Down
7 changes: 5 additions & 2 deletions wfl/calculators/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ def save_results(atoms, properties, results_prefix=None):
config_results['dipole'] = atoms.get_dipole_moment()
if 'magmom' in properties:
config_results['magmom'] = atoms.get_magnetic_moment()
try:
if results_prefix is not None:
config_results['converged'] = atoms.calc.converged
except AttributeError as exc:
pass

# copy per-atom results
if 'forces' in properties:
Expand All @@ -78,8 +83,6 @@ def save_results(atoms, properties, results_prefix=None):
atoms_results['magmoms'] = atoms.get_magnetic_moments()
if 'energies' in properties:
atoms_results['energies'] = atoms.get_potential_energies()
if 'converged' in properties and results_prefix is not None:
config_results['converged'] = atoms.get_calculator().read_convergence()

if "extra_results" in dir(atoms.calc):
if results_prefix is None and (len(atoms.calc.extra_results.get("config", {})) > 0 or
Expand Down

0 comments on commit 5b6a5ea

Please sign in to comment.