From 325cb6c179d818553a0a5783d76d82e1aa9f027a Mon Sep 17 00:00:00 2001 From: Matthew Newville Date: Tue, 15 Aug 2023 00:46:14 -0500 Subject: [PATCH] uniform options for CifParser, and pymatgen imports --- larch/xrd/amcsd_utils.py | 11 +++++++++++ larch/xrd/cif2feff.py | 18 ++++++------------ larch/xrd/structure2feff.py | 26 ++++++++++---------------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/larch/xrd/amcsd_utils.py b/larch/xrd/amcsd_utils.py index 12d00e102..b2831afc9 100644 --- a/larch/xrd/amcsd_utils.py +++ b/larch/xrd/amcsd_utils.py @@ -9,10 +9,21 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import SingletonThreadPool +try: + from pymatgen.io.cif import CifParser + from pymatgen.symmetry.analyzer import SpacegroupAnalyzer + from pymatgen.core import Molecule, IMolecule, IStructure +except: + CifParser = SpacegroupAnalyzer = None + Molecule = IMolecule = IStructure = None + from larch.utils.physical_constants import ATOM_SYMS, ATOM_NAMES __version__ = '1' +PMG_CIF_OPTS = dict(occupancy_tolerance=10, site_tolerance=5e-3) + + def make_engine(dbname): "create engine for sqlite connection" return create_engine('sqlite:///%s' % (dbname), diff --git a/larch/xrd/cif2feff.py b/larch/xrd/cif2feff.py index 81251191e..3519b675d 100644 --- a/larch/xrd/cif2feff.py +++ b/larch/xrd/cif2feff.py @@ -2,18 +2,12 @@ import random from io import StringIO -HAS_PYMATGEN = False -try: - from pymatgen.io.cif import CifParser - from pymatgen.symmetry.analyzer import SpacegroupAnalyzer - from pymatgen.core import Molecule - HAS_PYMATGEN = True -except: - HAS_PYMATGEN = False from xraydb import atomic_symbol, atomic_number, xray_edge from larch.utils import fix_varname, strict_ascii, gformat +from .amcsd_utils import PMG_CIF_OPTS, CifParser, Molecule, SpacegroupAnalyzer + def get_atom_map(structure): """generalization of pymatgen atom map Returns: @@ -43,10 +37,10 @@ def read_cif_structure(ciftext): ------- pymatgen Structure object """ - if not HAS_PYMATGEN: - raise ImportError('pymatgen required') + if CifParser is None: + raise ValueError("CifParser from pymatgen not available. Try 'pip install pymatgen'.") try: - cifstructs = CifParser(StringIO(ciftext), site_tolerance=5.e-4) + cifstructs = CifParser(StringIO(ciftext), **PMG_CIF_OPTS) parse_ok = True file_found = True except: @@ -55,7 +49,7 @@ def read_cif_structure(ciftext): if os.path.exists(ciftext): file_found = True try: - cifstructs = CifParser(ciftext, site_tolerance=5.e-4) + cifstructs = CifParser(ciftext, **PMG_CIF_OPTS) parse_ok = True except: parse_ok = False diff --git a/larch/xrd/structure2feff.py b/larch/xrd/structure2feff.py index 6aa0243e1..282beca7c 100644 --- a/larch/xrd/structure2feff.py +++ b/larch/xrd/structure2feff.py @@ -1,13 +1,7 @@ import os import random -HAS_PYMATGEN = False -try: - from pymatgen.symmetry.analyzer import SpacegroupAnalyzer - from pymatgen.core import Molecule, IMolecule, IStructure - HAS_PYMATGEN = True -except: - HAS_PYMATGEN = False +from .amcsd_utils import (SpacegroupAnalyzer, Molecule, IMolecule, IStructure) from xraydb import atomic_symbol, atomic_number, xray_edge from larch.utils.strutils import fix_varname, strict_ascii @@ -43,8 +37,8 @@ def read_structure(structure_text, fmt="cif"): ------- pymatgen Structure object or Molecule object """ - if not HAS_PYMATGEN: - raise ImportError('pymatgen required') + if Molecule is None: + raise ImportError("pymatgen required. Try 'pip install pymatgen'.") try: if fmt.lower() in ('cif', 'poscar', 'contcar', 'chgcar', 'locpot', 'cssr', 'vasprun.xml'): struct = IStructure.from_str(structure_text, fmt, merge_tol=5.e-4) @@ -52,7 +46,7 @@ def read_structure(structure_text, fmt="cif"): struct = IMolecule.from_str(structure_text, fmt) parse_ok = True file_found = True - + except: parse_ok = False file_found = False @@ -100,9 +94,9 @@ def parse_structure(structure_text, fmt='cif', fname="default.filename"): struct = read_structure(structure_text, fmt=fmt) except ValueError: return '# could not read structure file' - + return {'formula': struct.composition.reduced_formula, 'sites': struct.sites, 'structure_text': structure_text, 'fmt': fmt, 'fname': fname} - + def structure2feffinp(structure_text, absorber, edge=None, cluster_size=8.0, absorber_site=1, site_index=None, extra_titles=None, with_h=False, version8=True, fmt='cif'): @@ -146,16 +140,16 @@ def structure2feffinp(structure_text, absorber, edge=None, cluster_size=8.0, abs struct = read_structure(structure_text, fmt=fmt) except ValueError: return '# could not read structure file' - + is_molecule = False - + if isinstance(struct, IStructure): sgroup = SpacegroupAnalyzer(struct).get_symmetry_dataset() space_group = sgroup["international"] else: space_group = 'Molecule' is_molecule = True - + if isinstance(absorber, int): absorber = atomic_symbol(absorber_z) @@ -236,7 +230,7 @@ def structure2feffinp(structure_text, absorber, edge=None, cluster_size=8.0, abs out_text.append(f'* using absorber at site {1+absorber_index:d} in the list below') out_text.append(f'* selected as absorber="{absorber:s}", absorber_site={absorber_site:d}') out_text.append('* index X Y Z species') - + for i, site in enumerate(struct): # The method of obtaining the cooridanates depends on whether the structure is a molecule or not if is_molecule: