1616from ase .constraints import FixSymmetry
1717from ase .filters import FrechetCellFilter
1818from ase .io import Trajectory as AseTrajectory
19- from ase .io import write
19+ from ase .io import write as ase_write
2020from ase .optimize import BFGS , FIRE , LBFGS , BFGSLineSearch , LBFGSLineSearch , MDMin
2121from ase .optimize .sciopt import SciPyFminBFGS , SciPyFminCG
2222from monty .serialization import dumpfn
@@ -329,15 +329,18 @@ def relax(
329329 fmax : float = 0.1 ,
330330 steps : int = 500 ,
331331 traj_file : str = None ,
332- final_atoms_object_file : str = "final_atoms_object.xyz" ,
332+ final_atoms_object_file : str | os . PathLike [ str ] = "final_atoms_object.xyz" ,
333333 interval : int = 1 ,
334334 verbose : bool = False ,
335335 cell_filter : Filter = FrechetCellFilter ,
336+ filter_kwargs : dict | None = None ,
336337 ** kwargs ,
337338 ) -> AseResult :
338339 """
339340 Relax the molecule or structure.
340341
342+ If steps <= 1, this will perform a single-point calculation.
343+
341344 Parameters
342345 ----------
343346 atoms : ASE Atoms, pymatgen Structure, or pymatgen Molecule
@@ -348,7 +351,7 @@ def relax(
348351 Max number of steps for relaxation.
349352 traj_file : str
350353 The trajectory file for saving.
351- final_atoms_object_file: str
354+ final_atoms_object_file: str | os.PathLike
352355 The final atoms object file for saving.
353356 interval : int
354357 The step interval for saving the trajectories.
@@ -374,14 +377,16 @@ def relax(
374377 atoms .calc = self .calculator
375378 with contextlib .redirect_stdout (sys .stdout if verbose else io .StringIO ()):
376379 obs = TrajectoryObserver (atoms )
377- if self .relax_cell and (not is_mol ):
378- atoms = cell_filter (atoms )
379- optimizer = self .opt_class (atoms , ** kwargs )
380- optimizer .attach (obs , interval = interval )
381380 t_i = time .perf_counter ()
382- optimizer .run (fmax = fmax , steps = steps )
383- t_f = time .perf_counter ()
381+ if steps > 1 :
382+ if self .relax_cell and (not is_mol ):
383+ atoms = cell_filter (atoms , ** (filter_kwargs or {}))
384+ optimizer = self .opt_class (atoms , ** kwargs )
385+ optimizer .attach (obs , interval = interval )
386+ optimizer .run (fmax = fmax , steps = steps )
384387 obs ()
388+ t_f = time .perf_counter ()
389+
385390 if traj_file is not None :
386391 obs .save (traj_file )
387392 if isinstance (atoms , cell_filter ):
@@ -402,7 +407,9 @@ def relax(
402407 write_atoms .calc = self .calculator
403408 else :
404409 write_atoms = atoms
405- write (final_atoms_object_file , write_atoms , format = "extxyz" , append = True )
410+ ase_write (
411+ final_atoms_object_file , write_atoms , format = "extxyz" , append = True
412+ )
406413
407414 return AseResult (
408415 final_mol_or_struct = struct ,
0 commit comments