diff --git a/atomistics/calculators/ase.py b/atomistics/calculators/ase.py index d24fec03..a4de5cef 100644 --- a/atomistics/calculators/ase.py +++ b/atomistics/calculators/ase.py @@ -25,47 +25,6 @@ from atomistics.calculators.interface import TaskName -class ASEExecutor(object): - def __init__(self, ase_structure, ase_calculator): - self.structure = ase_structure - self.structure.calc = ase_calculator - - def forces(self): - return self.structure.get_forces() - - def energy(self): - return self.structure.get_potential_energy() - - def energy_pot(self): - return self.structure.get_potential_energy() - - def energy_tot(self): - return ( - self.structure.get_potential_energy() + self.structure.get_kinetic_energy() - ) - - def stress(self): - return self.structure.get_stress(voigt=False) - - def pressure(self): - return self.structure.get_stress(voigt=False) - - def cell(self): - return self.structure.get_cell() - - def positions(self): - return self.structure.get_positions() - - def velocities(self): - return self.structure.get_velocities() - - def temperature(self): - return self.structure.get_temperature() - - def volume(self): - return self.structure.get_volume() - - @as_task_dict_evaluator def evaluate_with_ase( structure: Atoms, @@ -107,10 +66,17 @@ def calc_static_with_ase( ase_calculator, output_keys=OutputStatic.keys(), ): - ase_exe = ASEExecutor(ase_structure=structure, ase_calculator=ase_calculator) - return OutputStatic(**{k: getattr(ase_exe, k) for k in OutputStatic.keys()}).get( - output_keys=output_keys - ) + structure.calc = ase_calculator + output_dict = {} + if "forces" in output_keys: + output_dict["forces"] = structure.get_forces() + if "energy" in output_keys: + output_dict["energy"] = structure.get_potential_energy() + if "stress" in output_keys: + output_dict["stress"] = structure.get_stress(voigt=False) + if "volume" in output_keys: + output_dict["volume"] = structure.get_volume() + return output_dict def calc_molecular_dynamics_npt_with_ase( @@ -244,12 +210,24 @@ def _calc_molecular_dynamics_with_ase( cache = {q: [] for q in output_keys} for i in range(int(run / thermo)): dyn.run(thermo) - ase_instance = ASEExecutor( - ase_structure=structure, ase_calculator=ase_calculator - ) - calc_dict = OutputMolecularDynamics( - **{k: getattr(ase_instance, k) for k in OutputMolecularDynamics.keys()} - ).get(output_keys=output_keys) - for k, v in calc_dict.items(): - cache[k].append(v) + if "positions" in output_keys: + cache["positions"].append(structure.get_positions()) + if "cell" in output_keys: + cache["cell"].append(structure.get_cell()) + if "forces" in output_keys: + cache["forces"].append(structure.get_forces()) + if "temperature" in output_keys: + cache["temperature"].append(structure.get_temperature()) + if "energy_pot" in output_keys: + cache["energy_pot"].append(structure.get_potential_energy()) + if "energy_tot" in output_keys: + cache["energy_tot"].append( + structure.get_potential_energy() + structure.get_kinetic_energy() + ) + if "pressure" in output_keys: + cache["pressure"].append(structure.get_stress(voigt=False)) + if "velocities" in output_keys: + cache["velocities"].append(structure.get_velocities()) + if "volume" in output_keys: + cache["volume"].append(structure.get_volume()) return {q: np.array(cache[q]) for q in output_keys} diff --git a/atomistics/calculators/lammps/calculator.py b/atomistics/calculators/lammps/calculator.py index 01ebee44..2453135e 100644 --- a/atomistics/calculators/lammps/calculator.py +++ b/atomistics/calculators/lammps/calculator.py @@ -28,8 +28,11 @@ LAMMPS_MINIMIZE_VOLUME, ) from atomistics.calculators.wrapper import as_task_dict_evaluator -from atomistics.shared.thermal_expansion import OutputThermalExpansion -from atomistics.shared.output import OutputStatic, OutputMolecularDynamics +from atomistics.shared.output import ( + OutputThermalExpansion, + OutputStatic, + OutputMolecularDynamics, +) if TYPE_CHECKING: @@ -132,12 +135,15 @@ def calc_static_with_lammps( lmp=lmp, **kwargs, ) - result_dict = OutputStatic( - forces=lmp_instance.interactive_forces_getter, - energy=lmp_instance.interactive_energy_pot_getter, - stress=lmp_instance.interactive_pressures_getter, - volume=lmp_instance.interactive_volume_getter, - ).get(output_keys=output_keys) + result_dict = {} + if "forces" in output_keys: + result_dict["forces"] = lmp_instance.interactive_forces_getter() + if "energy" in output_keys: + result_dict["energy"] = lmp_instance.interactive_energy_pot_getter() + if "stress" in output_keys: + result_dict["stress"] = lmp_instance.interactive_pressures_getter() + if "volume" in output_keys: + result_dict["volume"] = lmp_instance.interactive_volume_getter() lammps_shutdown(lmp_instance=lmp_instance, close_instance=lmp is None) return result_dict diff --git a/atomistics/calculators/lammps/helpers.py b/atomistics/calculators/lammps/helpers.py index 34568d28..c6af1165 100644 --- a/atomistics/calculators/lammps/helpers.py +++ b/atomistics/calculators/lammps/helpers.py @@ -47,17 +47,26 @@ def lammps_calc_md_step( ): run_str_rendered = Template(run_str).render(run=run) lmp_instance.interactive_lib_command(run_str_rendered) - return OutputMolecularDynamics( - positions=lmp_instance.interactive_positions_getter, - cell=lmp_instance.interactive_cells_getter, - forces=lmp_instance.interactive_forces_getter, - temperature=lmp_instance.interactive_temperatures_getter, - energy_pot=lmp_instance.interactive_energy_pot_getter, - energy_tot=lmp_instance.interactive_energy_tot_getter, - pressure=lmp_instance.interactive_pressures_getter, - velocities=lmp_instance.interactive_velocities_getter, - volume=lmp_instance.interactive_volume_getter, - ).get(output_keys=output_keys) + result_dict = {} + if "positions" in output_keys: + result_dict["positions"] = lmp_instance.interactive_positions_getter() + if "cell" in output_keys: + result_dict["cell"] = lmp_instance.interactive_cells_getter() + if "forces" in output_keys: + result_dict["forces"] = lmp_instance.interactive_forces_getter() + if "temperature" in output_keys: + result_dict["temperature"] = lmp_instance.interactive_temperatures_getter() + if "energy_pot" in output_keys: + result_dict["energy_pot"] = lmp_instance.interactive_energy_pot_getter() + if "energy_tot" in output_keys: + result_dict["energy_tot"] = lmp_instance.interactive_energy_tot_getter() + if "pressure" in output_keys: + result_dict["pressure"] = lmp_instance.interactive_pressures_getter() + if "velocities" in output_keys: + result_dict["velocities"] = lmp_instance.interactive_velocities_getter() + if "volume" in output_keys: + result_dict["volume"] = lmp_instance.interactive_volume_getter() + return result_dict def lammps_calc_md( diff --git a/atomistics/calculators/qe.py b/atomistics/calculators/qe.py index 95bb4b7f..ff4b3058 100644 --- a/atomistics/calculators/qe.py +++ b/atomistics/calculators/qe.py @@ -207,10 +207,17 @@ def calc_static_with_qe( call_qe_via_ase_command( calculation_name=calculation_name, working_directory=working_directory ) - parser = QEStaticParser(filename=output_file_name) - return OutputStatic(**{k: getattr(parser, k) for k in OutputStatic.keys()}).get( - output_keys=output_keys - ) + parser = io.read_pw_scf(filename=output_file_name, use_alat=True) + result_dict = {} + if "forces" in output_keys: + result_dict["forces"] = parser.forces + if "energy" in output_keys: + result_dict["energy"] = parser.etot + if "stress" in output_keys: + result_dict["stress"] = parser.stress + if "volume" in output_keys: + result_dict["forces"] = parser.volume + return result_dict @as_task_dict_evaluator diff --git a/atomistics/shared/thermal_expansion.py b/atomistics/shared/thermal_expansion.py index a9886234..2f2162d3 100644 --- a/atomistics/shared/thermal_expansion.py +++ b/atomistics/shared/thermal_expansion.py @@ -1,22 +1,7 @@ -from atomistics.shared.output import OutputThermalExpansion - - -class ThermalExpansionProperties: - def __init__(self, temperatures_lst, volumes_lst): - self._temperatures_lst = temperatures_lst - self._volumes_lst = volumes_lst - - def volumes(self): - return self._volumes_lst - - def temperatures(self): - return self._temperatures_lst - - def get_thermal_expansion_output(temperatures_lst, volumes_lst, output_keys): - thermal = ThermalExpansionProperties( - temperatures_lst=temperatures_lst, volumes_lst=volumes_lst - ) - return OutputThermalExpansion( - **{k: getattr(thermal, k) for k in OutputThermalExpansion.keys()} - ).get(output_keys=output_keys) + result_dict = {} + if "volumes" in output_keys: + result_dict["volumes"] = volumes_lst + if "temperatures" in output_keys: + result_dict["temperatures"] = temperatures_lst + return result_dict diff --git a/atomistics/workflows/elastic/workflow.py b/atomistics/workflows/elastic/workflow.py index 06c87a45..4c0ccc6b 100644 --- a/atomistics/workflows/elastic/workflow.py +++ b/atomistics/workflows/elastic/workflow.py @@ -62,6 +62,4 @@ def analyse_structures(self, output_dict, output_keys=OutputElastic.keys()): self._data["e0"] = ene0 self._data["A2"] = A2 elastic = ElasticProperties(elastic_matrix=elastic_matrix) - return OutputElastic( - **{k: getattr(elastic, k) for k in OutputElastic.keys()} - ).get(output_keys=output_keys) + return {k: getattr(elastic, k)() for k in output_keys} diff --git a/atomistics/workflows/evcurve/workflow.py b/atomistics/workflows/evcurve/workflow.py index 6e91e0d7..b9842303 100644 --- a/atomistics/workflows/evcurve/workflow.py +++ b/atomistics/workflows/evcurve/workflow.py @@ -175,19 +175,24 @@ def generate_structures(self): def analyse_structures( self, output_dict, output_keys=OutputEnergyVolumeCurve.keys() ): - evcurve = EnergyVolumeCurveProperties( - fit_module=fit_ev_curve_internal( - volume_lst=get_volume_lst(structure_dict=self._structure_dict), - energy_lst=get_energy_lst( - output_dict=output_dict, structure_dict=self._structure_dict - ), - fit_type=self.fit_type, - fit_order=self.fit_order, - ) + fit_module = fit_ev_curve_internal( + volume_lst=get_volume_lst(structure_dict=self._structure_dict), + energy_lst=get_energy_lst( + output_dict=output_dict, structure_dict=self._structure_dict + ), + fit_type=self.fit_type, + fit_order=self.fit_order, ) - self._fit_dict = OutputEnergyVolumeCurve( - **{k: getattr(evcurve, k) for k in OutputEnergyVolumeCurve.keys()} - ).get(output_keys=output_keys) + self._fit_dict = {} + for key in OutputEnergyVolumeCurve.keys(): + if key == "fit_dict" and key in output_keys: + self._fit_dict[key] = { + k: fit_module.fit_dict[k] + for k in ["fit_type", "least_square_error", "poly_fit", "fit_order"] + if k in fit_module.fit_dict.keys() + } + elif key in output_keys: + self._fit_dict[key] = fit_module.fit_dict[key] return self.fit_dict def get_volume_lst(self): diff --git a/atomistics/workflows/phonons/workflow.py b/atomistics/workflows/phonons/workflow.py index 24f45f69..6bfff670 100644 --- a/atomistics/workflows/phonons/workflow.py +++ b/atomistics/workflows/phonons/workflow.py @@ -117,30 +117,6 @@ def force_constants(self): return self._force_constants -class PhonopyThermalProperties(object): - def __init__(self, phonopy_instance): - self._phonopy = phonopy_instance - self._thermal_properties = phonopy_instance.get_thermal_properties_dict() - - def free_energy(self): - return self._thermal_properties["free_energy"] * kJ_mol_to_eV - - def temperatures(self): - return self._thermal_properties["temperatures"] - - def entropy(self): - return self._thermal_properties["entropy"] - - def heat_capacity(self): - return self._thermal_properties["heat_capacity"] - - def volumes(self): - return np.array( - [self._phonopy.unitcell.get_volume()] - * len(self._thermal_properties["temperatures"]) - ) - - class PhonopyWorkflow(Workflow): """ Phonopy wrapper for the calculation of free energy in the framework of quasi harmonic approximation. @@ -250,9 +226,7 @@ def analyse_structures(self, output_dict, output_keys=OutputPhonons.keys()): use_tetrahedron_method=True, npoints=101, ) - self._phonopy_dict = OutputPhonons( - **{k: getattr(phono, k) for k in OutputPhonons.keys()} - ).get(output_keys=output_keys) + self._phonopy_dict = {k: getattr(phono, k)() for k in output_keys} return self._phonopy_dict def get_thermal_properties( @@ -291,10 +265,19 @@ def get_thermal_properties( band_indices=band_indices, is_projection=is_projection, ) - phono = PhonopyThermalProperties(phonopy_instance=self.phonopy) - return OutputThermodynamic( - **{k: getattr(phono, k) for k in OutputThermodynamic.keys()} - ).get(output_keys=output_keys) + thermal_properties = self.phonopy.get_thermal_properties_dict() + output_dict = {} + for key in OutputThermodynamic.keys(): + if key == "free_energy" and key in output_keys: + output_dict[key] = thermal_properties[key] * kJ_mol_to_eV + elif key == "volumes" and key in output_keys: + output_dict["volumes"] = np.array( + [self.phonopy.unitcell.get_volume()] + * len(thermal_properties["temperatures"]) + ) + elif key in output_keys: + output_dict[key] = thermal_properties[key] + return output_dict def get_dynamical_matrix(self, npoints=101): """ diff --git a/atomistics/workflows/quasiharmonic.py b/atomistics/workflows/quasiharmonic.py index a3ce75cc..30deaf41 100644 --- a/atomistics/workflows/quasiharmonic.py +++ b/atomistics/workflows/quasiharmonic.py @@ -1,6 +1,6 @@ import numpy as np -from atomistics.shared.output import OutputThermodynamic, OutputPhonons +from atomistics.shared.output import OutputThermodynamic from atomistics.workflows.evcurve.workflow import ( EnergyVolumeCurveWorkflow, fit_ev_curve,