From 66caf5cceb29b6691885ce0fc000bbdd663f2074 Mon Sep 17 00:00:00 2001 From: Pepe Marquez Date: Tue, 6 Sep 2022 16:50:38 +0200 Subject: [PATCH] Adding ELN base section for crystal structure file --- nomad/datamodel/metainfo/eln/__init__.py | 44 ++++++ nomad/normalizing/method.py | 177 ++++++++++++----------- 2 files changed, 134 insertions(+), 87 deletions(-) diff --git a/nomad/datamodel/metainfo/eln/__init__.py b/nomad/datamodel/metainfo/eln/__init__.py index 4a4678cb8..b4152dca7 100644 --- a/nomad/datamodel/metainfo/eln/__init__.py +++ b/nomad/datamodel/metainfo/eln/__init__.py @@ -24,6 +24,8 @@ from nomad.metainfo.metainfo import SectionProxy from nomad.datamodel.results import ELN, Results, Material, BandGap from nomad.metainfo import Package, Quantity, Datetime, Reference, Section from nomad.datamodel.metainfo.eln.perovskite_solar_cell_database import addSolarCell +from nomad.datamodel.metainfo.simulation.system import System, Atoms +from nomad.datamodel.metainfo.simulation.run import Run m_package = Package(name='material_library') @@ -161,6 +163,48 @@ class ElnWithFormulaBaseSection(ElnBaseSection): logger.warn('could not analyse chemical formula', exc_info=e) +class ElnWithStructureFile(ElnBaseSection): + + structure_file = Quantity( + type=str, + description='The structure file.', + a_eln=dict(component='FileEditQuantity')) + + def normalize(self, archive, logger): + super(ElnWithStructureFile, self).normalize(archive, logger) + + if self.structure_file: + from pymatgen.core import Structure + from nomad.normalizing import ResultsNormalizer, SystemNormalizer, OptimadeNormalizer + + try: + with archive.m_context.raw_file(self.structure_file) as f: + structure = Structure.from_file(f.name) + + run = Run() + archive.run = [run] + system = System() + system.chemical_composition = structure.formula.format('hill') + system.chemical_composition_hill = structure.formula.format('hill') + system.chemical_composition_reduced = structure.formula.format('reduce') + system.atoms = Atoms() + system.atoms.lattice_vectors = np.array(structure.lattice.matrix).round(5) * ureg.angstrom + system.atoms.labels = [str(specie.value) for specie in structure.species] + system.atoms.species = [specie.number for specie in structure.species] + system.atoms.positions = np.array(structure.cart_coords).round(5) * ureg.angstrom + system.atoms.periodic = [True, True, True] + archive.run[0].system = [system] + system_normalizer = SystemNormalizer(archive) + system_normalizer.normalize() + optimade_normalizer = OptimadeNormalizer(archive) + optimade_normalizer.normalize() + results_normalizer = ResultsNormalizer(archive) + results_normalizer.normalize() + + except Exception as e: + logger.error('Could not parse structure file: {}'.format(e)) + + class Chemical(ElnWithFormulaBaseSection): ''' A ELN base section that can be used for chemicals.''' pass diff --git a/nomad/normalizing/method.py b/nomad/normalizing/method.py index d4b0d32b1..180683515 100644 --- a/nomad/normalizing/method.py +++ b/nomad/normalizing/method.py @@ -50,95 +50,98 @@ class MethodNormalizer(): Returns: Filled method section. """ - method = Method() - simulation = Simulation() - repr_method = None - method_name = config.services.unavailable_value - methods = self.run.method - n_methods = len(methods) - - def get_method_name(section_method): + try: + method = Method() + simulation = Simulation() + repr_method = None method_name = config.services.unavailable_value - if section_method.electronic and section_method.electronic.method: - method_name = section_method.electronic.method - else: - if section_method.gw is not None: - method_name = "GW" - return method_name - - # If only one method is specified, use it directly - if n_methods == 1: - repr_method = methods[0] - method_name = get_method_name(repr_method) - # If several methods have been declared, we need to find the "topmost" - # method and report it. - elif n_methods > 1: - # Method referencing another as "core_method". If core method was - # given, create new merged method containing all the information. - for sec_method in methods: - core_method = sec_method.core_method_ref - if core_method is not None: - if sec_method.electronic: - electronic = core_method.electronic - electronic = electronic if electronic else core_method.m_create(Electronic) - core_method.electronic.method = sec_method.electronic.method - repr_method = core_method - method_name = get_method_name(repr_method) - - # Perturbative methods: we report the "topmost" method (=method - # that is referencing something but is not itself being - # referenced). - referenced_methods = set() - for sec_method in methods: - starting_method_ref = sec_method.starting_method_ref - if starting_method_ref is not None: - referenced_methods.add(starting_method_ref.m_path()) - if len(referenced_methods) == n_methods - 1: + methods = self.run.method + n_methods = len(methods) + + def get_method_name(section_method): + method_name = config.services.unavailable_value + if section_method.electronic and section_method.electronic.method: + method_name = section_method.electronic.method + else: + if section_method.gw is not None: + method_name = "GW" + return method_name + + # If only one method is specified, use it directly + if n_methods == 1: + repr_method = methods[0] + method_name = get_method_name(repr_method) + # If several methods have been declared, we need to find the "topmost" + # method and report it. + elif n_methods > 1: + # Method referencing another as "core_method". If core method was + # given, create new merged method containing all the information. + for sec_method in methods: + core_method = sec_method.core_method_ref + if core_method is not None: + if sec_method.electronic: + electronic = core_method.electronic + electronic = electronic if electronic else core_method.m_create(Electronic) + core_method.electronic.method = sec_method.electronic.method + repr_method = core_method + method_name = get_method_name(repr_method) + + # Perturbative methods: we report the "topmost" method (=method + # that is referencing something but is not itself being + # referenced). + referenced_methods = set() for sec_method in methods: - if sec_method.m_path() not in referenced_methods: - method_name = get_method_name(sec_method) - if method_name != config.services.unavailable_value: - repr_method = sec_method - break - self.repr_method = repr_method - self.method_name = method_name - settings_basis_set = get_basis_set(self.entry_archive, self.repr_method, self.repr_system, self.logger) - functional_long_name = self.functional_long_name() - method.workflow_name = self.workflow_name() - - if method_name == "GW": - method.method_name = "GW" - gw = GW() - gw.type = repr_method.gw.type - gw.starting_point = repr_method.gw.starting_point.split() - simulation.gw = gw - elif method_name in {"DFT", "DFT+U"}: - method.method_name = "DFT" - dft = DFT() - dft.basis_set_type = self.basis_set_type() - dft.basis_set_name = self.basis_set_name() - method.method_id = self.method_id_dft(settings_basis_set, functional_long_name) - method.parameter_variation_id = self.parameter_variation_id_dft(settings_basis_set, functional_long_name) - dft.core_electron_treatment = self.core_electron_treatment() - if repr_method.electronic is not None: - if repr_method.electronic.smearing is not None: - dft.smearing_kind = repr_method.electronic.smearing.kind - dft.smearing_width = repr_method.electronic.smearing.width - if repr_method.electronic.n_spin_channels: - dft.spin_polarized = repr_method.electronic.n_spin_channels > 1 - dft.van_der_Waals_method = repr_method.electronic.van_der_waals_method - dft.relativity_method = repr_method.electronic.relativity_method - dft.xc_functional_names = self.xc_functional_names() - dft.xc_functional_type = self.xc_functional_type(dft.xc_functional_names) - if repr_method.scf is not None: - dft.scf_threshold_energy_change = repr_method.scf.threshold_energy_change - simulation.dft = dft - - method.equation_of_state_id = self.equation_of_state_id(method.method_id, self.material.chemical_formula_hill) - simulation.program_name = self.run.program.name - simulation.program_version = self.run.program.version - method.simulation = simulation - return method + starting_method_ref = sec_method.starting_method_ref + if starting_method_ref is not None: + referenced_methods.add(starting_method_ref.m_path()) + if len(referenced_methods) == n_methods - 1: + for sec_method in methods: + if sec_method.m_path() not in referenced_methods: + method_name = get_method_name(sec_method) + if method_name != config.services.unavailable_value: + repr_method = sec_method + break + self.repr_method = repr_method + self.method_name = method_name + settings_basis_set = get_basis_set(self.entry_archive, self.repr_method, self.repr_system, self.logger) + functional_long_name = self.functional_long_name() + method.workflow_name = self.workflow_name() + + if method_name == "GW": + method.method_name = "GW" + gw = GW() + gw.type = repr_method.gw.type + gw.starting_point = repr_method.gw.starting_point.split() + simulation.gw = gw + elif method_name in {"DFT", "DFT+U"}: + method.method_name = "DFT" + dft = DFT() + dft.basis_set_type = self.basis_set_type() + dft.basis_set_name = self.basis_set_name() + method.method_id = self.method_id_dft(settings_basis_set, functional_long_name) + method.parameter_variation_id = self.parameter_variation_id_dft(settings_basis_set, functional_long_name) + dft.core_electron_treatment = self.core_electron_treatment() + if repr_method.electronic is not None: + if repr_method.electronic.smearing is not None: + dft.smearing_kind = repr_method.electronic.smearing.kind + dft.smearing_width = repr_method.electronic.smearing.width + if repr_method.electronic.n_spin_channels: + dft.spin_polarized = repr_method.electronic.n_spin_channels > 1 + dft.van_der_Waals_method = repr_method.electronic.van_der_waals_method + dft.relativity_method = repr_method.electronic.relativity_method + dft.xc_functional_names = self.xc_functional_names() + dft.xc_functional_type = self.xc_functional_type(dft.xc_functional_names) + if repr_method.scf is not None: + dft.scf_threshold_energy_change = repr_method.scf.threshold_energy_change + simulation.dft = dft + + method.equation_of_state_id = self.equation_of_state_id(method.method_id, self.material.chemical_formula_hill) + simulation.program_name = self.run.program.name + simulation.program_version = self.run.program.version + method.simulation = simulation + return method + except Exception: + return None def workflow_name(self): workflow_name = None -- GitLab