diff --git a/janus_core/calculations/geom_opt.py b/janus_core/calculations/geom_opt.py index 1b41c338..30e3ffa8 100644 --- a/janus_core/calculations/geom_opt.py +++ b/janus_core/calculations/geom_opt.py @@ -17,13 +17,15 @@ from janus_core.helpers.janus_types import ASEOptArgs, ASEWriteArgs from janus_core.helpers.log import config_logger -from janus_core.helpers.utils import none_to_dict +from janus_core.helpers.utils import none_to_dict, spacegroup def optimize( # pylint: disable=too-many-arguments,too-many-locals,too-many-branches struct: Atoms, fmax: float = 0.1, steps: int = 1000, + symmetry_precision=0.0001, + angle_precision=-1, filter_func: Optional[Callable] = DefaultFilter, filter_kwargs: Optional[dict[str, Any]] = None, optimizer: Callable = LBFGS, @@ -45,6 +47,12 @@ def optimize( # pylint: disable=too-many-arguments,too-many-locals,too-many-bra Default is 0.1. steps : int Set maximum number of optimization steps to run. Default is 1000. + symmetry_precision : float + Set symmtery precision crieria for spacegroup determination. + Default is 0.0001. + angle_precision : float + Set angle precision crieria for spacegroup determination. + Default is =1. filter_func : Optional[callable] Apply constraints to atoms through ASE filter function. Default is `FrechetCellFilter` if available otherwise `ExpCellFilter`. @@ -93,6 +101,12 @@ def optimize( # pylint: disable=too-many-arguments,too-many-locals,too-many-bra log_kwargs.setdefault("name", __name__) logger = config_logger(**log_kwargs) + sg = spacegroup(struct, symmetry_precision, angle_precision) + message = f"Before optimisation spacegroup {sg}" + print(message) + if logger: + logger.info(message) + if filter_func is not None: filtered_struct = filter_func(struct, **filter_kwargs) dyn = optimizer(filtered_struct, **opt_kwargs) @@ -114,6 +128,10 @@ def optimize( # pylint: disable=too-many-arguments,too-many-locals,too-many-bra converged = dyn.run(fmax=fmax, steps=steps) + sg = spacegroup(struct, symmetry_precision, angle_precision) + message = f"After optimisation spacegroup {sg}" + print(message) + # Calculate current maximum force if filter_func is not None: max_force = linalg.norm(filtered_struct.get_forces(), axis=1).max() @@ -121,6 +139,7 @@ def optimize( # pylint: disable=too-many-arguments,too-many-locals,too-many-bra max_force = linalg.norm(struct.get_forces(), axis=1).max() if logger: + logger.info(message) logger.info("Max force: %.6f", max_force) if not converged: diff --git a/janus_core/helpers/utils.py b/janus_core/helpers/utils.py index b675926a..c93d9188 100644 --- a/janus_core/helpers/utils.py +++ b/janus_core/helpers/utils.py @@ -3,6 +3,42 @@ from pathlib import Path from typing import Optional +from ase import Atoms +from spglib import get_spacegroup + + +def spacegroup( + struct: Atoms, sym_precision: float = 0.001, angle_precision: float = -1.0 +) -> str: + """ + Determine the spacegroup for a structure. + + Parameters + ---------- + struct : Atoms + Structure as an ase Atoms object. + sym_precision : float + Symmetry precision for spglib symmetry determination. + Default 0.001. + angle_precision : float + Angle precision for spglib symmetry determination. + Default: -1. + + Returns + ------- + str + Spacegroup name. + """ + return get_spacegroup( + cell=( + struct.get_cell(), + struct.get_scaled_positions(), + struct.get_atomic_numbers(), + ), + symprec=sym_precision, + angle_tolerance=angle_precision, + ) + def none_to_dict(dictionaries: list[Optional[dict]]) -> list[dict]: """