From ae332ca469705a4618aa0056fe7d606fca1e8900 Mon Sep 17 00:00:00 2001 From: Jonathan Chico Date: Fri, 5 Aug 2022 13:30:07 +0200 Subject: [PATCH 1/4] Changes to ensure that aiida-lammps is compatible with aiida-2.x. Addresses #40. --- aiida_lammps/calculations/lammps/force.py | 8 +- aiida_lammps/common/input_generator.py | 2 +- aiida_lammps/data/lammps_potential.py | 50 ++++++------ aiida_lammps/data/potential.py | 43 +++++----- aiida_lammps/data/trajectory.py | 86 +++++++++----------- aiida_lammps/parsers/lammps/base.py | 17 ++-- aiida_lammps/parsers/lammps/lammps_parser.py | 10 +-- aiida_lammps/parsers/lammps/md.py | 3 +- aiida_lammps/parsers/lammps/md_multi.py | 8 +- aiida_lammps/validation/utils.py | 2 +- conftest.py | 2 +- examples/launch_lammps_base.py | 10 +-- tests/test_calculations.py | 32 ++++---- tests/test_parsers.py | 25 +++--- tests/test_potential_data.py | 7 +- tests/test_trajectory.py | 10 ++- tests/utils.py | 8 +- 17 files changed, 160 insertions(+), 163 deletions(-) diff --git a/aiida_lammps/calculations/lammps/force.py b/aiida_lammps/calculations/lammps/force.py index 9aacf4c..8950525 100644 --- a/aiida_lammps/calculations/lammps/force.py +++ b/aiida_lammps/calculations/lammps/force.py @@ -39,8 +39,8 @@ def create_main_input_content( ): # pylint: disable=too-many-arguments, too-many-locals version_date = convert_date_string( - parameter_data.get_attribute("lammps_version", "11 Aug 2017") - ) + parameter_data.base.attributes.get("lammps_version", + "11 Aug 2017")) lammps_input_file = f"units {potential_data.default_units}\n" lammps_input_file += "boundary p p p\n" @@ -55,7 +55,7 @@ def create_main_input_content( lammps_input_file += "neigh_modify every 1 delay 0 check no\n" thermo_keywords = ["step", "temp", "epair", "emol", "etotal", "press"] - for kwd in parameter_data.get_attribute("thermo_keywords", []): + for kwd in parameter_data.base.attributes.get("thermo_keywords", []): if kwd not in thermo_keywords: thermo_keywords.append(kwd) lammps_input_file += f'thermo_style custom {" ".join(thermo_keywords)}\n' @@ -85,7 +85,7 @@ def create_main_input_content( lammps_input_file += "run 0\n" - variables = parameter_data.get_attribute("output_variables", []) + variables = parameter_data.base.attributes.get("output_variables", []) for var in variables: var_alias = var.replace("[", "_").replace("]", "_") lammps_input_file += f"variable {var_alias} equal {var}\n" diff --git a/aiida_lammps/common/input_generator.py b/aiida_lammps/common/input_generator.py index 4e9d637..46894ba 100644 --- a/aiida_lammps/common/input_generator.py +++ b/aiida_lammps/common/input_generator.py @@ -319,7 +319,7 @@ def write_structure_block( structure_block += f'dimension {structure.get_dimensionality()["dim"]}\n' structure_block += "boundary " for _bound in ["pbc1", "pbc2", "pbc3"]: - structure_block += f'{"p" if structure.attributes[_bound] else "f"} ' + structure_block += f'{"p" if structure.base.attributes.all[_bound] else "f"} ' structure_block += "\n" structure_block += f'atom_style {parameters_structure["atom_style"]}\n' structure_block += f"read_data {structure_filename}\n" diff --git a/aiida_lammps/data/lammps_potential.py b/aiida_lammps/data/lammps_potential.py index 4b61440..708a51b 100644 --- a/aiida_lammps/data/lammps_potential.py +++ b/aiida_lammps/data/lammps_potential.py @@ -160,7 +160,7 @@ def get_entry_point_name(cls): def is_readable_byte_stream(stream) -> bool: """Return if object is a readable filelike object in binary mode or stream of bytes. - :param stream: the object to analyse. + :param stream: the object to analyze. :returns: True if ``stream`` appears to be a readable filelike object in binary mode, False otherwise. """ @@ -226,7 +226,7 @@ def validate_pair_style(self, pair_style: str): raise TypeError("The pair_style of the potential must be provided.") if pair_style not in self.default_potential_info.keys(): raise KeyError(f'The pair_style "{pair_style}" is not valid') - self.set_attribute("pair_style", pair_style) + self.base.attributes.set("pair_style", pair_style) def validate_species(self, species: list): """ @@ -243,7 +243,7 @@ def validate_species(self, species: list): raise TypeError("The species for this potential must be provided.") for _specie in species: self.validate_element(_specie) - self.set_attribute("species", species) + self.base.attributes.set("species", species) def validate_atom_style(self, atom_style: str, pair_style: str): """ @@ -262,7 +262,7 @@ def validate_atom_style(self, atom_style: str, pair_style: str): atom_style = self.default_potential_info[pair_style]["atom_style"] if atom_style not in self.default_atom_style_info: raise ValueError(f'The atom_style "{atom_style}" is not valid') - self.set_attribute("atom_style", atom_style) + self.base.attributes.set("atom_style", atom_style) @classmethod def validate_element(cls, element: str): @@ -300,7 +300,7 @@ def validate_units(self, units: str, pair_style: str): "nano", ]: raise ValueError(f'The units "{units}" is not valid') - self.set_attribute("default_units", units) + self.base.attributes.set("default_units", units) def validate_extra_tags(self, extra_tags: dict): """ @@ -343,7 +343,7 @@ def set_file( ): """Set the file content. - .. note:: this method will first analyse the type of the ``source`` + .. note:: this method will first analyze the type of the ``source`` and if it is a filepath will convert it to a binary stream of the content located at that filepath, which is then passed on to the superclass. This needs to be done first, because it will properly @@ -403,7 +403,7 @@ def set_file( if extra_tags is not None: self.validate_extra_tags(extra_tags=extra_tags) for key in self._extra_keys: - self.set_attribute(key, extra_tags.get(key, None)) + self.base.attributes.set(key, extra_tags.get(key, None)) super().set_file(source, filename, **kwargs) source.seek(0) @@ -428,7 +428,7 @@ def atom_style(self) -> str: :return: the default `atomic_style` of this potential :rtype: str """ - return self.get_attribute("atom_style") + return self.base.attributes.get("atom_style") @property def pair_style(self) -> str: @@ -437,7 +437,7 @@ def pair_style(self) -> str: :return: the `pair_style` of the potential :rtype: str """ - return self.get_attribute("pair_style") + return self.base.attributes.get("pair_style") @property def species(self) -> list: @@ -445,7 +445,7 @@ def species(self) -> list: :return: The list of chemical species which are contained in this potential. :rtype: list """ - return self.get_attribute("species") + return self.base.attributes.get("species") @property def default_units(self) -> str: @@ -454,7 +454,7 @@ def default_units(self) -> str: :return: the default units associated with this potential :rtype: str """ - return self.get_attribute("default_units") + return self.base.attributes.get("default_units") @property def content_origin(self) -> str: @@ -471,7 +471,7 @@ def content_origin(self) -> str: :return: the place where this potential information can be found. :rtype: str """ - return self.get_attribute("content_origin") + return self.base.attributes.get("content_origin") @property def content_other_locations(self) -> typing.Union[str, list]: @@ -484,7 +484,7 @@ def content_other_locations(self) -> typing.Union[str, list]: :return: other locations where the potential can be found. :rtype: typing.Union[str, list] """ - return self.get_attribute("content_other_locations") + return self.base.attributes.get("content_other_locations") @property def data_method(self) -> str: @@ -498,7 +498,7 @@ def data_method(self) -> str: :return: data_method used to generate the potential :rtype: str """ - return self.get_attribute("data_method") + return self.base.attributes.get("data_method") @property def description(self) -> str: @@ -513,7 +513,7 @@ def description(self) -> str: :return: description of the potential :rtype: str """ - return self.get_attribute("description") + return self.base.attributes.get("description") @property def developer(self) -> typing.Union[str, list]: @@ -529,7 +529,7 @@ def developer(self) -> typing.Union[str, list]: :return: developer information of this potential :rtype: typing.Union[str, list] """ - return self.get_attribute("developer") + return self.base.attributes.get("developer") @property def disclaimer(self) -> str: @@ -543,7 +543,7 @@ def disclaimer(self) -> str: :return: disclaimer regarding the usage of this potential :rtype: str """ - return self.get_attribute("disclaimer") + return self.base.attributes.get("disclaimer") @property def properties(self) -> typing.Union[str, list]: @@ -555,7 +555,7 @@ def properties(self) -> typing.Union[str, list]: :return: properties fow which this potential was devised. :rtype: typing.Union[str, list] """ - return self.get_attribute("properties") + return self.base.attributes.get("properties") @property def publication_year(self) -> typing.Union[str, datetime.datetime, int]: @@ -567,7 +567,7 @@ def publication_year(self) -> typing.Union[str, datetime.datetime, int]: :return: year of publication of this potential :rtype: typing.Union[str, datetime.datetime, int] """ - return self.get_attribute("publication_year") + return self.base.attributes.get("publication_year") @property def source_citations(self) -> typing.Union[str, list]: @@ -580,7 +580,7 @@ def source_citations(self) -> typing.Union[str, list]: :return: the citation where the potential was originally published. :rtype: typing.Union[str, list] """ - return self.get_attribute("source_citations") + return self.base.attributes.get("source_citations") @property def title(self) -> str: @@ -594,19 +594,19 @@ def title(self) -> str: :return: the title of the potential :rtype: str """ - return self.get_attribute("title") + return self.base.attributes.get("title") @property def md5(self) -> typing.Optional[int]: """Return the md5. :return: the md5 of the stored file. """ - return self.get_attribute(self._key_md5, None) + return self.base.attributes.get(self._key_md5, None) @property def generation_method(self) -> str: """ - Return the geneation method of the potential. + Return the generation method of the potential. In here one can describe how the potential itself was generated, if it was done via ML, fitting via specific codes, analytical fitting, etc. @@ -614,7 +614,7 @@ def generation_method(self) -> str: :return: the generation method of the potential :rtype: str """ - return self.get_attribute("generation_method") + return self.base.attributes.get("generation_method") @md5.setter def md5(self, value: str): @@ -623,4 +623,4 @@ def md5(self, value: str): :raises ValueError: if the md5 does not match that of the currently stored file. """ self.validate_md5(value) - self.set_attribute(self._key_md5, value) + self.base.attributes.set(self._key_md5, value) diff --git a/aiida_lammps/data/potential.py b/aiida_lammps/data/potential.py index 46b90fb..a38274a 100644 --- a/aiida_lammps/data/potential.py +++ b/aiida_lammps/data/potential.py @@ -59,57 +59,57 @@ def set_data(self, potential_type, data=None): external_contents = pot_class.get_external_content() or {} pot_lines = pot_class.get_input_potential_lines() - self.set_attribute("potential_type", potential_type) - self.set_attribute("atom_style", atom_style) - self.set_attribute("default_units", default_units) - self.set_attribute( + self.base.attributes.set("potential_type", potential_type) + self.base.attributes.set("atom_style", atom_style) + self.base.attributes.set("default_units", default_units) + self.base.attributes.set( "allowed_element_names", sorted(allowed_element_names) - if allowed_element_names - else allowed_element_names, + if allowed_element_names else allowed_element_names, ) # store potential section of main input file - self.set_attribute( - "md5|input_lines", md5(pot_lines.encode("utf-8")).hexdigest() - ) - self.put_object_from_filelike(StringIO(pot_lines), self.pot_lines_fname) + self.base.attributes.set("md5|input_lines", + md5(pot_lines.encode("utf-8")).hexdigest()) + self.base.repository.put_object_from_filelike(StringIO(pot_lines), + self.pot_lines_fname) # store external files required by the potential external_files = [] for fname, content in external_contents.items(): - self.set_attribute( + self.base.attributes.set( f'md5|{fname.replace(".", "_")}', md5(content.encode("utf-8")).hexdigest(), ) - self.put_object_from_filelike(StringIO(content), fname) + self.base.repository.put_object_from_filelike( + StringIO(content), fname) external_files.append(fname) - self.set_attribute("external_files", sorted(external_files)) + self.base.attributes.set("external_files", sorted(external_files)) # delete any previously stored files that are no longer required - for fname in self.list_object_names(): + for fname in self.base.repository.list_object_names(): if fname not in external_files + [self.pot_lines_fname]: self.delete_object(fname) @property def potential_type(self): """Return lammps atom style.""" - return self.get_attribute("potential_type") + return self.base.attributes.get("potential_type") @property def atom_style(self): """Return lammps atom style.""" - return self.get_attribute("atom_style") + return self.base.attributes.get("atom_style") @property def default_units(self): """Return lammps default units.""" - return self.get_attribute("default_units") + return self.base.attributes.get("default_units") @property def allowed_element_names(self): """Return available atomic symbols.""" - return self.get_attribute("allowed_element_names") + return self.base.attributes.get("allowed_element_names") def get_input_lines(self, kind_symbols=None): """Return the command(s) required to setup the potential. @@ -128,7 +128,8 @@ def get_input_lines(self, kind_symbols=None): pair_coeff * * S Cr """ - content = self.get_object_content(self.pot_lines_fname, "r") + content = self.base.repository.get_object_content( + self.pot_lines_fname, "r") if kind_symbols: content = content.replace("{kind_symbols}", " ".join(kind_symbols)) return content @@ -136,6 +137,6 @@ def get_input_lines(self, kind_symbols=None): def get_external_files(self): """Return the mapping of external filenames to content.""" fmap = {} - for fname in self.get_attribute("external_files"): - fmap[fname] = self.get_object_content(fname, "r") + for fname in self.base.attributes.get("external_files"): + fmap[fname] = self.base.repository.get_object_content(fname, "r") return fmap diff --git a/aiida_lammps/data/trajectory.py b/aiida_lammps/data/trajectory.py index a17cb0c..380b8ec 100644 --- a/aiida_lammps/data/trajectory.py +++ b/aiida_lammps/data/trajectory.py @@ -6,7 +6,6 @@ """ # pylint: disable=too-many-ancestors import io -import pathlib import tempfile from zipfile import ZIP_DEFLATED, ZipFile @@ -56,7 +55,7 @@ def _validate(self): """Validate that a trajectory has been set, before storing.""" super()._validate() - if self.get_attribute("number_steps", None) is None: + if self.base.attributes.get("number_steps", None) is None: raise ValidationError("trajectory has not yet been set") def set_from_fileobj(self, fileobj, aliases=None): @@ -78,7 +77,7 @@ def set_from_fileobj(self, fileobj, aliases=None): field_names = None number_atoms = None - self.reset_attributes({}) + self.base.attributes.reset({}) if not (aliases is None or isinstance(aliases, dict)): raise ValueError("aliases must be None or dict") @@ -124,38 +123,26 @@ def set_from_fileobj(self, fileobj, aliases=None): temp_handle.flush() temp_handle.seek(0) - if isinstance(temp_handle, (str, pathlib.Path)): - is_filelike = False - else: - is_filelike = True - - if is_filelike: - self.put_object_from_filelike( - temp_handle, - self._trajectory_filename, - mode="wb", - encoding=None, - ) - else: - self.put_object_from_filelike( - temp_handle, - self._trajectory_filename, - ) + self.base.repository.put_object_from_filelike( + temp_handle, + self._trajectory_filename, + ) - self.put_object_from_filelike( + self.base.repository.put_object_from_filelike( io.StringIO(" ".join([str(entry) for entry in time_steps])), self._timestep_filename, ) - self.set_attribute("number_steps", len(time_steps)) - self.set_attribute("number_atoms", number_atoms) - self.set_attribute("field_names", list(sorted(field_names))) - self.set_attribute("trajectory_filename", self._trajectory_filename) - self.set_attribute("timestep_filename", self._timestep_filename) - self.set_attribute("zip_prefix", self._zip_prefix) - self.set_attribute("compression_method", self._compression_method) - self.set_attribute("aliases", aliases) - self.set_attribute("elements", list(sorted(elements))) + self.base.attributes.set("number_steps", len(time_steps)) + self.base.attributes.set("number_atoms", number_atoms) + self.base.attributes.set("field_names", list(sorted(field_names))) + self.base.attributes.set("trajectory_filename", self._trajectory_filename) + self.base.attributes.set("timestep_filename", self._timestep_filename) + self.base.attributes.set("zip_prefix", self._zip_prefix) + self.base.attributes.set("compression_method", + self._compression_method) + self.base.attributes.set("aliases", aliases) + self.base.attributes.set("elements", list(sorted(elements))) @property def number_steps(self): @@ -164,7 +151,7 @@ def number_steps(self): :return: number of steps stored in the data :rtype: int """ - return self.get_attribute("number_steps") + return self.base.attributes.get("number_steps") @property def time_steps(self): @@ -173,7 +160,8 @@ def time_steps(self): :return: time steps stored in the data. :rtype: list """ - with self.open(self.get_attribute("timestep_filename"), "r") as handle: + with self.base.repository.open( + self.base.attributes.get("timestep_filename"), "r") as handle: output = [int(i) for i in handle.readline().split()] return output @@ -184,7 +172,7 @@ def number_atoms(self): :return: number of atoms in the simulation box :rtype: int """ - return self.get_attribute("number_atoms") + return self.base.attributes.get("number_atoms") @property def field_names(self): @@ -193,7 +181,7 @@ def field_names(self): :return: list of field names as written to file. :rtype: list """ - return self.get_attribute("field_names") + return self.base.attributes.get("field_names") @property def aliases(self): @@ -202,20 +190,20 @@ def aliases(self): :return: mapping of one or more lammps variables. :rtype: list """ - return self.get_attribute("aliases") + return self.base.attributes.get("aliases") def get_step_string(self, step_idx): """Return the content string, for a specific trajectory step.""" step_idx = list(range(self.number_steps))[step_idx] - zip_name = f'{self.get_attribute("zip_prefix")}{step_idx}' - with self.open( - self.get_attribute("trajectory_filename"), - mode="rb", + zip_name = f'{self.base.attributes.get("zip_prefix")}{step_idx}' + with self.base.repository.open( + self.base.attributes.get("trajectory_filename"), + mode="rb", ) as handle: with ZipFile( - handle, - "r", - self.get_attribute("compression_method"), + handle, + "r", + self.base.attributes.get("compression_method"), ) as zip_file: with zip_file.open(zip_name, "r") as step_file: content = step_file.read() @@ -233,17 +221,17 @@ def iter_step_strings(self, steps=None): elif isinstance(steps, int): steps = range(0, self.number_steps, steps) - with self.open( - self.get_attribute("trajectory_filename"), - mode="rb", + with self.base.repository.open( + self.base.attributes.get("trajectory_filename"), + mode="rb", ) as handle: with ZipFile( - handle, - "r", - self.get_attribute("compression_method"), + handle, + "r", + self.base.attributes.get("compression_method"), ) as zip_file: for step_idx in steps: - zip_name = f'{self.get_attribute("zip_prefix")}{step_idx}' + zip_name = f'{self.base.attributes.get("zip_prefix")}{step_idx}' with zip_file.open(zip_name) as step_file: content = step_file.read() yield content diff --git a/aiida_lammps/parsers/lammps/base.py b/aiida_lammps/parsers/lammps/base.py index 0e2afc6..4019021 100644 --- a/aiida_lammps/parsers/lammps/base.py +++ b/aiida_lammps/parsers/lammps/base.py @@ -50,7 +50,7 @@ def get_parsing_resources( list_of_temp_files = os.listdir(temporary_folder) # check what is inside the folder - list_of_files = out_folder.list_object_names() + list_of_files = out_folder.base.repository.list_object_names() # check log file if self.node.get_option("output_filename") not in list_of_files: @@ -108,7 +108,8 @@ def get_parsing_resources( def parse_log_file(self, compute_stress=False): """Parse the log file.""" output_filename = self.node.get_option("output_filename") - output_txt = self.retrieved.get_object_content(output_filename) + output_txt = self.retrieved.base.repository.get_object_content( + output_filename) try: output_data = read_log_file( output_txt, @@ -122,15 +123,11 @@ def parse_log_file(self, compute_stress=False): def add_warnings_and_errors(self, output_data): """Add warning and errors to the output data.""" # add the dictionary with warnings and errors - warnings = ( - self.retrieved.get_object_content(self.node.get_option("scheduler_stderr")) - .strip() - .splitlines() - ) + warnings = (self.retrieved.base.repository.get_object_content( + self.node.get_option("scheduler_stderr")).strip().splitlines()) # for some reason, errors may be in the stdout, but not the log.lammps - stdout = self.retrieved.get_object_content( - self.node.get_option("scheduler_stdout") - ) + stdout = self.retrieved.base.repository.get_object_content( + self.node.get_option("scheduler_stdout")) errors = [line for line in stdout.splitlines() if line.startswith("ERROR")] warnings.extend( [line for line in stdout.splitlines() if line.startswith("WARNING")] diff --git a/aiida_lammps/parsers/lammps/lammps_parser.py b/aiida_lammps/parsers/lammps/lammps_parser.py index 80ee132..0eedeaf 100644 --- a/aiida_lammps/parsers/lammps/lammps_parser.py +++ b/aiida_lammps/parsers/lammps/lammps_parser.py @@ -42,15 +42,15 @@ def parse(self, **kwargs): except exceptions.NotExistent: return self.exit_codes.ERROR_NO_RETRIEVED_FOLDER - list_of_files = out_folder.list_object_names() + list_of_files = out_folder.base.repository.list_object_names() # check log file if self.node.get_option("logfile_filename") not in list_of_files: return self.exit_codes.ERROR_LOG_FILE_MISSING filename = self.node.get_option("logfile_filename") parsed_data = parse_logfile( - file_contents=self.node.outputs.retrieved.get_object_content(filename) - ) + file_contents=self.node.outputs.retrieved.base.repository. + get_object_content(filename)) if parsed_data is None: return self.exit_codes.ERROR_PARSING_LOGFILE global_data = parsed_data["global"] @@ -62,8 +62,8 @@ def parse(self, **kwargs): filename = self.node.get_option("variables_filename") final_variables = parse_final_data( - file_contents=self.node.outputs.retrieved.get_object_content(filename) - ) + file_contents=self.node.outputs.retrieved.base.repository. + get_object_content(filename)) if final_variables is None: return self.exit_codes.ERROR_PARSING_FINAL_VARIABLES diff --git a/aiida_lammps/parsers/lammps/md.py b/aiida_lammps/parsers/lammps/md.py index 67e00bf..668fef0 100644 --- a/aiida_lammps/parsers/lammps/md.py +++ b/aiida_lammps/parsers/lammps/md.py @@ -78,7 +78,8 @@ def parse(self, **kwargs): except Exception: # pylint: disable=broad-except traceback.print_exc() sys_data_error = self.exit_codes.ERROR_INFO_PARSING - sys_data.set_attribute("units_style", output_data.get("units_style", None)) + sys_data.base.attributes.set("units_style", + output_data.get("units_style", None)) self.out("system_data", sys_data) if output_data["errors"]: diff --git a/aiida_lammps/parsers/lammps/md_multi.py b/aiida_lammps/parsers/lammps/md_multi.py index d11e93a..a1078c9 100644 --- a/aiida_lammps/parsers/lammps/md_multi.py +++ b/aiida_lammps/parsers/lammps/md_multi.py @@ -80,7 +80,8 @@ def parse(self, **kwargs): for sys_path in resources.sys_paths: stage_name = os.path.basename(sys_path).split("-")[0] sys_data = ArrayData() - sys_data.set_attribute("units_style", output_data.get("units_style", None)) + sys_data.base.attributes.set("units_style", + output_data.get("units_style", None)) try: with open(sys_path) as handle: names = handle.readline().strip().split() @@ -107,9 +108,8 @@ def parse(self, **kwargs): for stage, (step, rpath) in restart_map.items(): with open(rpath, "rb") as handle: - self.retrieved.put_object_from_filelike( - handle, os.path.basename(rpath), "wb", force=True - ) + self.retrieved.base.repository.put_object_from_filelike( + handle, os.path.basename(rpath), "wb", force=True) if output_data["errors"]: return self.exit_codes.ERROR_LAMMPS_RUN diff --git a/aiida_lammps/validation/utils.py b/aiida_lammps/validation/utils.py index 04ba1bd..a2c6b79 100644 --- a/aiida_lammps/validation/utils.py +++ b/aiida_lammps/validation/utils.py @@ -23,7 +23,7 @@ def load_schema(name): with open(name) as jfile: schema = json.load(jfile) else: - schema = json.loads(importlib_resources.read_text(schemas, name)) + schema = json.loads(importlib_resources.files(schemas).joinpath(name).read_text()) return schema diff --git a/conftest.py b/conftest.py index dc16623..96b96ad 100644 --- a/conftest.py +++ b/conftest.py @@ -73,7 +73,7 @@ def db_test_app(aiida_profile, pytestconfig): work_directory = tempfile.mkdtemp() yield AiidaTestApp(work_directory, executables, environment=aiida_profile) - aiida_profile.reset_db() + aiida_profile.clear_profile() if not test_workdir: shutil.rmtree(work_directory) diff --git a/examples/launch_lammps_base.py b/examples/launch_lammps_base.py index c76bb2b..56ed468 100644 --- a/examples/launch_lammps_base.py +++ b/examples/launch_lammps_base.py @@ -149,19 +149,19 @@ def main( STRUCTURE = generate_structure() POTENTIAL = generate_potential() - CODE = orm.load_code("my_lammps_code") + CODE = orm.load_code("lammps@localhost") OPTIONS = AttributeDict() OPTIONS.resources = AttributeDict() # Total number of mpi processes OPTIONS.resources.tot_num_mpiprocs = 2 # Name of the parallel environment - OPTIONS.resources.parallel_env = "mpi" + # OPTIONS.resources.parallel_env = "mpi" # Maximum allowed execution time in seconds - OPTIONS.max_wallclock_seconds = 18000 + # OPTIONS.max_wallclock_seconds = 18000 # Whether to run in parallel - OPTIONS.withmpi = True + # OPTIONS.withmpi = True # Set the slot type for the calculation - OPTIONS.custom_scheduler_commands = "#$ -l slot_type=execute\n#$ -l exclusive=true" + # OPTIONS.custom_scheduler_commands = "#$ -l slot_type=execute\n#$ -l exclusive=true" _parameters = AttributeDict() _parameters.control = AttributeDict() diff --git a/tests/test_calculations.py b/tests/test_calculations.py index 366e169..4438a4c 100644 --- a/tests/test_calculations.py +++ b/tests/test_calculations.py @@ -347,9 +347,9 @@ def test_force_process( output = run_get_node(builder) calc_node = output.node - # raise ValueError(calc_node.get_object_content('input.in')) - # raise ValueError(calc_node.outputs.retrieved.get_object_content('_scheduler-stdout.txt')) - # raise ValueError(calc_node.outputs.retrieved.get_object_content('trajectory.lammpstrj')) + # raise ValueError(calc_node.base.repository.get_object_content('input.in')) + # raise ValueError(calc_node.outputs.retrieved.base.repository.get_object_content('_scheduler-stdout.txt')) + # raise ValueError(calc_node.outputs.retrieved.base.repository.get_object_content('trajectory.lammpstrj')) if not calc_node.is_finished_ok: print(calc_node.attributes) @@ -547,15 +547,17 @@ def test_md_multi_process( ] ) - data_regression.check( - { - "retrieved": calc_node.outputs.retrieved.list_object_names(), - "results": sanitize_results( - calc_node.outputs.results.get_dict(), round_energy=1 - ), - "system__thermalise": calc_node.outputs.system__thermalise.attributes, - "system__equilibrate": calc_node.outputs.system__equilibrate.attributes, - "trajectory__thermalise": calc_node.outputs.trajectory__thermalise.attributes, - "trajectory__equilibrate": calc_node.outputs.trajectory__equilibrate.attributes, - } - ) + data_regression.check({ + "retrieved": + calc_node.outputs.retrieved.base.repository.list_object_names(), + "results": + sanitize_results(calc_node.outputs.results.get_dict(), round_energy=1), + "system__thermalise": + calc_node.outputs.system__thermalise.attributes, + "system__equilibrate": + calc_node.outputs.system__equilibrate.attributes, + "trajectory__thermalise": + calc_node.outputs.trajectory__thermalise.attributes, + "trajectory__equilibrate": + calc_node.outputs.trajectory__equilibrate.attributes, + }) diff --git a/tests/test_parsers.py b/tests/test_parsers.py index 913617b..9335e53 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -82,9 +82,11 @@ def test_missing_log(db_test_app, plugin_name): def test_missing_traj(db_test_app, plugin_name): """Check if the trajectory file is produced during calculation.""" retrieved = FolderData() - retrieved.put_object_from_filelike(io.StringIO(get_log()), "log.lammps") - retrieved.put_object_from_filelike(io.StringIO(""), "_scheduler-stdout.txt") - retrieved.put_object_from_filelike(io.StringIO(""), "_scheduler-stderr.txt") + retrieved.base.repository.put_object_from_filelike(io.StringIO(get_log()), "log.lammps") + retrieved.base.repository.put_object_from_filelike( + io.StringIO(""), "_scheduler-stdout.txt") + retrieved.base.repository.put_object_from_filelike( + io.StringIO(""), "_scheduler-stderr.txt") calc_node = db_test_app.generate_calcjob_node(plugin_name, retrieved) parser = ParserFactory(plugin_name) @@ -117,7 +119,8 @@ def test_empty_log(db_test_app, plugin_name): "_scheduler-stdout.txt", "_scheduler-stderr.txt", ]: - retrieved.put_object_from_filelike(io.StringIO(""), filename) + retrieved.base.repository.put_object_from_filelike( + io.StringIO(""), filename) calc_node = db_test_app.generate_calcjob_node(plugin_name, retrieved) parser = ParserFactory(plugin_name) @@ -147,13 +150,15 @@ def test_empty_log(db_test_app, plugin_name): def test_empty_traj(db_test_app, plugin_name): """Check if the lammps trajectory file is empty.""" retrieved = FolderData() - retrieved.put_object_from_filelike(io.StringIO(get_log()), "log.lammps") + retrieved.base.repository.put_object_from_filelike(io.StringIO(get_log()), + "log.lammps") for filename in [ "trajectory.lammpstrj", "_scheduler-stdout.txt", "_scheduler-stderr.txt", ]: - retrieved.put_object_from_filelike(io.StringIO(""), filename) + retrieved.base.repository.put_object_from_filelike( + io.StringIO(""), filename) calc_node = db_test_app.generate_calcjob_node(plugin_name, retrieved) parser = ParserFactory(plugin_name) @@ -182,19 +187,19 @@ def test_empty_traj(db_test_app, plugin_name): def test_run_error(db_test_app, plugin_name): """Check if the parser runs without producing errors.""" retrieved = FolderData() - retrieved.put_object_from_filelike( + retrieved.base.repository.put_object_from_filelike( io.StringIO(get_log()), "log.lammps", ) - retrieved.put_object_from_filelike( + retrieved.base.repository.put_object_from_filelike( io.StringIO(get_traj_force()), "x-trajectory.lammpstrj", ) - retrieved.put_object_from_filelike( + retrieved.base.repository.put_object_from_filelike( io.StringIO("ERROR description"), "_scheduler-stdout.txt", ) - retrieved.put_object_from_filelike( + retrieved.base.repository.put_object_from_filelike( io.StringIO(""), "_scheduler-stderr.txt", ) diff --git a/tests/test_potential_data.py b/tests/test_potential_data.py index 171ebd2..fd9979a 100644 --- a/tests/test_potential_data.py +++ b/tests/test_potential_data.py @@ -38,7 +38,7 @@ def test_init( potential_type=potential.type, data=potential.data, ) - data_regression.check(node.attributes) + data_regression.check(node.base.attributes.all) @pytest.mark.parametrize("potential_type", ["tersoff"]) @@ -54,7 +54,8 @@ def test_potential_files( potential_type=potential.type, data=potential.data, ) - file_regression.check(node.get_object_content("potential.pot", "r")) + file_regression.check( + node.base.repository.get_object_content("potential.pot", "r")) @pytest.mark.parametrize( @@ -107,7 +108,7 @@ def test_lammps_potentials_init( for _attribute in _attributes: _msg = f'attribute "{_attribute}" does not match between reference and current value' - assert reference_values[_attribute] == node.get_attribute(_attribute), _msg + assert reference_values[_attribute] == node.base.attributes.get(_attribute), _msg @pytest.mark.parametrize( diff --git a/tests/test_trajectory.py b/tests/test_trajectory.py index 80c8159..1581480 100644 --- a/tests/test_trajectory.py +++ b/tests/test_trajectory.py @@ -28,7 +28,8 @@ def test_create_structure( traj_block = next(iter_trajectories(handle)) structure = create_structure(traj_block) - data_regression.check(recursive_round(structure.attributes, 2, apply_lists=True)) + data_regression.check( + recursive_round(structure.base.attributes.all, 2, apply_lists=True)) def test_lammps_trajectory_data( @@ -37,7 +38,7 @@ def test_lammps_trajectory_data( """Test that one can generate a trajectory from a file""" path = os.path.join(TEST_DIR, "input_files", "trajectory.lammpstrj") data = LammpsTrajectory(path) - data_regression.check(data.attributes) + data_regression.check(data.base.attributes.all) def test_lammpstraj_get_step_string( @@ -56,8 +57,9 @@ def test_lammpstraj_get_step_struct( path = os.path.join(TEST_DIR, "input_files", "trajectory.lammpstrj") data = LammpsTrajectory(path) data_regression.check( - recursive_round(data.get_step_structure(-1).attributes, 2, apply_lists=True) - ) + recursive_round(data.get_step_structure(-1).base.attributes.all, + 2, + apply_lists=True)) def test_lammpstraj_timesteps(db_test_app): # pylint: disable=unused-argument diff --git a/tests/utils.py b/tests/utils.py index ee576f7..e82e29a 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -76,7 +76,7 @@ def get_or_create_local_computer(work_directory, name="localhost"): """ try: - computer = Computer.objects.get(label=name) + computer = Computer.collection.get(label=name) except NotExistent: computer = Computer( label=name, @@ -96,10 +96,10 @@ def get_or_create_code(entry_point, computer, executable, exec_path=None): """Setup code on localhost computer""" if isinstance(computer, str): - computer = Computer.objects.get(label=computer) + computer = Computer.collection.get(label=computer) try: - code = Code.objects.get( # pylint: disable=no-member + code = Code.collection.get( # pylint: disable=no-member label=f"{entry_point}-{executable}-{computer.label}" ) except NotExistent: @@ -281,7 +281,7 @@ def generate_calcjob_node( node.set_option("max_wallclock_seconds", 1800) if attributes: - node.set_attributes(attributes) # pylint: disable=no-member + node.base.attributes.set(attributes) # pylint: disable=no-member node.store() From 1310636972634ad45dc80ce9b26f1a47a736269c Mon Sep 17 00:00:00 2001 From: Jonathan Chico Date: Fri, 5 Aug 2022 13:32:58 +0200 Subject: [PATCH 2/4] Updating the CI to make sure that the tests are run in the workchains branch. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adba8bd..965164a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [master, develop] + branches: [master, develop, workchains] pull_request: jobs: From a53d97490d5bf9c812fa8d70d4da49a06f4bbfd8 Mon Sep 17 00:00:00 2001 From: Jonathan Chico Date: Fri, 5 Aug 2022 13:37:21 +0200 Subject: [PATCH 3/4] Bump the aiida-core version to 2.x Removing the reentry command from the tests as it is not needed for aiida-2.x Removing the md_multi capability of reading the restart for each stage, as it is incompatible with aiida-2.x Fixing the last of the tests that was blocking the aiida-2.x adoption. Removing unnecessary tests and adding an older version of lammps for testing. Fixing an issue in which the lammps version could not be parsed properly when it was not only a datetime. --- .github/workflows/cd.yml | 1 - .github/workflows/ci.yml | 11 ++--- README.md | 3 +- aiida_lammps/calculations/lammps/__init__.py | 12 +++--- aiida_lammps/calculations/lammps/force.py | 8 ++-- aiida_lammps/calculations/lammps/md.py | 7 ++-- aiida_lammps/calculations/lammps/md_multi.py | 7 ++-- aiida_lammps/calculations/lammps/optimize.py | 10 +++-- aiida_lammps/common/utils.py | 1 + aiida_lammps/data/potential.py | 19 +++++---- aiida_lammps/data/trajectory.py | 26 ++++++------ aiida_lammps/parsers/lammps/base.py | 15 ++++--- aiida_lammps/parsers/lammps/force.py | 2 +- aiida_lammps/parsers/lammps/lammps_parser.py | 12 ++++-- aiida_lammps/parsers/lammps/md.py | 7 ++-- aiida_lammps/parsers/lammps/md_multi.py | 36 ++++++++-------- aiida_lammps/validation/utils.py | 4 +- docs/source/developers/intro.md | 3 +- examples/launch_lammps_force_gan.py | 6 +-- examples/launch_lammps_md_si.py | 9 ++-- examples/launch_lammps_optimization_fe.py | 8 ++-- examples/launch_lammps_optimization_gan.py | 8 ++-- examples/launch_lammps_optimization_lj.py | 8 ++-- pyproject.toml | 2 +- tests/test_calculations.py | 42 +++++++++---------- .../test_md_multi_process_eam_.yml | 1 - .../test_md_multi_process_lennard_jones_.yml | 1 - .../test_md_multi_process_reaxff_.yml | 1 - .../test_md_multi_process_tersoff_.yml | 1 - tests/test_parsers.py | 21 ++++++---- tests/test_potential_data.py | 7 ++-- tests/test_trajectory.py | 10 +++-- tests/utils.py | 22 +++++----- tox.ini | 2 - 34 files changed, 171 insertions(+), 162 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index b7847cc..b4e8bee 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -86,7 +86,6 @@ jobs: - name: Installation run: | pip install -e .[testing,pre-commit] - reentry scan - name: Run pytest run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 965164a..de9c116 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,17 +32,15 @@ jobs: matrix: include: - python-version: "3.8" - lammps-version: "2020.12.24" - backend: django + lammps-version: "2020.03.03" - python-version: "3.8" lammps-version: "2020.12.24" - backend: sqlalchemy - python-version: "3.9" lammps-version: "2020.12.24" - backend: django + - python-version: "3.9" + lammps-version: "2020.03.03" - python-version: "3.10" lammps-version: "2021.09.29" - backend: django runs-on: ubuntu-latest @@ -50,7 +48,7 @@ jobs: postgres: image: postgres:10 env: - POSTGRES_DB: test_${{ matrix.backend }} + POSTGRES_DB: test_lammps POSTGRES_PASSWORD: '' POSTGRES_HOST_AUTH_METHOD: trust options: >- @@ -86,7 +84,6 @@ jobs: - name: Installation run: | pip install -e .[testing,pre-commit] - reentry scan - name: Run pytest run: | diff --git a/README.md b/README.md index 0ad3c67..a38045d 100644 --- a/README.md +++ b/README.md @@ -447,8 +447,7 @@ the test suite can be run in an isolated, virtual environment using `tox` (see ` or directly: ```shell ->> pip install -e .[testing] ->> reentry scan -r aiida +>> pip install .[testing] >> pytest -v ``` diff --git a/aiida_lammps/calculations/lammps/__init__.py b/aiida_lammps/calculations/lammps/__init__.py index f575870..81afa49 100644 --- a/aiida_lammps/calculations/lammps/__init__.py +++ b/aiida_lammps/calculations/lammps/__init__.py @@ -6,8 +6,6 @@ from aiida.common import CalcInfo, CodeInfo from aiida.common.exceptions import ValidationError from aiida.engine import CalcJob -from aiida.orm import Dict, StructureData -from aiida.plugins import DataFactory import numpy as np from aiida_lammps.common.generate_structure import generate_lammps_structure @@ -34,7 +32,7 @@ def get_supercell( supercell_array = np.dot(cell, np.diag(supercell_shape)) - supercell = StructureData(cell=supercell_array) + supercell = orm.StructureData(cell=supercell_array) for k in range(positions.shape[0]): for entry in itertools.product(*[range(i) for i in supercell_shape[::-1]]): position = positions[k, :] + np.dot(np.array(entry[::-1]), cell) @@ -118,7 +116,7 @@ def define(cls, spec): super().define(spec) spec.input( "structure", - valid_type=StructureData, + valid_type=orm.StructureData, help="the structure", ) spec.input( @@ -128,7 +126,7 @@ def define(cls, spec): ) spec.input( "parameters", - valid_type=Dict, + valid_type=orm.Dict, help="the parameters", required=False, ) @@ -160,7 +158,7 @@ def define(cls, spec): spec.output( "results", - valid_type=DataFactory("dict"), + valid_type=orm.Dict, required=True, help="the data extracted from the main output file", ) @@ -331,7 +329,7 @@ def prepare_for_submission(self, tempfolder): # pylint: disable=arguments-diffe if "parameters" in self.inputs: parameters = self.inputs.parameters else: - parameters = Dict() + parameters = orm.Dict() # Setup input parameters input_txt = self.create_main_input_content( diff --git a/aiida_lammps/calculations/lammps/force.py b/aiida_lammps/calculations/lammps/force.py index 8950525..9a2b784 100644 --- a/aiida_lammps/calculations/lammps/force.py +++ b/aiida_lammps/calculations/lammps/force.py @@ -1,6 +1,6 @@ """Single point calculation of the energy in LAMMPS.""" # pylint: disable=fixme, duplicate-code, useless-super-delegation -from aiida.plugins import DataFactory +from aiida import orm from aiida_lammps.calculations.lammps import BaseLammpsCalculation from aiida_lammps.common.utils import convert_date_string @@ -22,7 +22,7 @@ def define(cls, spec): spec.output( "arrays", - valid_type=DataFactory("array"), + valid_type=orm.ArrayData, required=True, help="force data per atom", ) @@ -39,8 +39,8 @@ def create_main_input_content( ): # pylint: disable=too-many-arguments, too-many-locals version_date = convert_date_string( - parameter_data.base.attributes.get("lammps_version", - "11 Aug 2017")) + parameter_data.base.attributes.get("lammps_version", "11 Aug 2017") + ) lammps_input_file = f"units {potential_data.default_units}\n" lammps_input_file += "boundary p p p\n" diff --git a/aiida_lammps/calculations/lammps/md.py b/aiida_lammps/calculations/lammps/md.py index ff19f69..d58ef59 100644 --- a/aiida_lammps/calculations/lammps/md.py +++ b/aiida_lammps/calculations/lammps/md.py @@ -1,11 +1,12 @@ """Single stage MD calculation in LAMMPS.""" # pylint: disable=fixme, useless-super-delegation, duplicate-code +from aiida import orm from aiida.common.exceptions import InputValidationError -from aiida.plugins import DataFactory import numpy as np from aiida_lammps.calculations.lammps import BaseLammpsCalculation from aiida_lammps.common.utils import convert_date_string, get_path, join_keywords +from aiida_lammps.data.trajectory import LammpsTrajectory from aiida_lammps.validation import validate_against_schema @@ -25,13 +26,13 @@ def define(cls, spec): spec.output( "trajectory_data", - valid_type=DataFactory("lammps.trajectory"), + valid_type=LammpsTrajectory, required=True, help="atomic configuration data per dump step", ) spec.output( "system_data", - valid_type=DataFactory("array"), + valid_type=orm.ArrayData, required=False, help="selected system data per dump step", ) diff --git a/aiida_lammps/calculations/lammps/md_multi.py b/aiida_lammps/calculations/lammps/md_multi.py index 1f4615a..af93b4d 100644 --- a/aiida_lammps/calculations/lammps/md_multi.py +++ b/aiida_lammps/calculations/lammps/md_multi.py @@ -1,10 +1,11 @@ """Run a multi-stage molecular dynamic simulation.""" # pylint: disable=fixme +from aiida import orm from aiida.common.exceptions import InputValidationError -from aiida.plugins import DataFactory from aiida_lammps.calculations.lammps import BaseLammpsCalculation from aiida_lammps.common.utils import convert_date_string, get_path, join_keywords +from aiida_lammps.data.trajectory import LammpsTrajectory from aiida_lammps.validation import validate_against_schema @@ -25,14 +26,14 @@ def define(cls, spec): spec.output_namespace( "system", dynamic=True, - valid_type=DataFactory("array"), + valid_type=orm.ArrayData, help="selected system data per dump step of a stage", ) spec.output_namespace( "trajectory", dynamic=True, - valid_type=DataFactory("lammps.trajectory"), + valid_type=LammpsTrajectory, help="atomic configuration data per dump step of a stage", ) diff --git a/aiida_lammps/calculations/lammps/optimize.py b/aiida_lammps/calculations/lammps/optimize.py index c1a821e..7544d2c 100644 --- a/aiida_lammps/calculations/lammps/optimize.py +++ b/aiida_lammps/calculations/lammps/optimize.py @@ -1,12 +1,14 @@ """Class describing the calculation of the optimization of a structure using LAMMPS (minimize method). """ +from aiida import orm + # pylint: disable=fixme, duplicate-code, useless-super-delegation from aiida.common.exceptions import InputValidationError -from aiida.plugins import DataFactory from aiida_lammps.calculations.lammps import BaseLammpsCalculation from aiida_lammps.common.utils import convert_date_string, join_keywords +from aiida_lammps.data.trajectory import LammpsTrajectory from aiida_lammps.validation import validate_against_schema @@ -25,13 +27,13 @@ def define(cls, spec): spec.output( "structure", - valid_type=DataFactory("structure"), + valid_type=orm.StructureData, required=True, help="the structure output from the calculation", ) spec.output( "trajectory_data", - valid_type=DataFactory("lammps.trajectory"), + valid_type=LammpsTrajectory, required=True, help="forces, stresses and positions data per step", ) @@ -160,7 +162,7 @@ def validate_parameters(param_data, potential_object) -> bool: raise InputValidationError("parameter data not set") validate_against_schema(param_data.get_dict(), "optimize.schema.json") - # ensure the potential and paramters are in the same unit systems + # ensure the potential and parameters are in the same unit systems # TODO convert between unit systems (e.g. using https://pint.readthedocs.io) if "units" in param_data.get_dict(): punits = param_data.get_dict()["units"] diff --git a/aiida_lammps/common/utils.py b/aiida_lammps/common/utils.py index e7332ea..d907c39 100644 --- a/aiida_lammps/common/utils.py +++ b/aiida_lammps/common/utils.py @@ -36,6 +36,7 @@ def convert_date_string(string): """converts date string e.g. '10 Nov 2017' to datetime object if None, return todays date '""" + if string is None: date = datetime.today() else: diff --git a/aiida_lammps/data/potential.py b/aiida_lammps/data/potential.py index a38274a..9d73c24 100644 --- a/aiida_lammps/data/potential.py +++ b/aiida_lammps/data/potential.py @@ -65,14 +65,17 @@ def set_data(self, potential_type, data=None): self.base.attributes.set( "allowed_element_names", sorted(allowed_element_names) - if allowed_element_names else allowed_element_names, + if allowed_element_names + else allowed_element_names, ) # store potential section of main input file - self.base.attributes.set("md5|input_lines", - md5(pot_lines.encode("utf-8")).hexdigest()) - self.base.repository.put_object_from_filelike(StringIO(pot_lines), - self.pot_lines_fname) + self.base.attributes.set( + "md5|input_lines", md5(pot_lines.encode("utf-8")).hexdigest() + ) + self.base.repository.put_object_from_filelike( + StringIO(pot_lines), self.pot_lines_fname + ) # store external files required by the potential external_files = [] @@ -81,8 +84,7 @@ def set_data(self, potential_type, data=None): f'md5|{fname.replace(".", "_")}', md5(content.encode("utf-8")).hexdigest(), ) - self.base.repository.put_object_from_filelike( - StringIO(content), fname) + self.base.repository.put_object_from_filelike(StringIO(content), fname) external_files.append(fname) self.base.attributes.set("external_files", sorted(external_files)) @@ -128,8 +130,7 @@ def get_input_lines(self, kind_symbols=None): pair_coeff * * S Cr """ - content = self.base.repository.get_object_content( - self.pot_lines_fname, "r") + content = self.base.repository.get_object_content(self.pot_lines_fname, "r") if kind_symbols: content = content.replace("{kind_symbols}", " ".join(kind_symbols)) return content diff --git a/aiida_lammps/data/trajectory.py b/aiida_lammps/data/trajectory.py index 380b8ec..4c44800 100644 --- a/aiida_lammps/data/trajectory.py +++ b/aiida_lammps/data/trajectory.py @@ -139,8 +139,7 @@ def set_from_fileobj(self, fileobj, aliases=None): self.base.attributes.set("trajectory_filename", self._trajectory_filename) self.base.attributes.set("timestep_filename", self._timestep_filename) self.base.attributes.set("zip_prefix", self._zip_prefix) - self.base.attributes.set("compression_method", - self._compression_method) + self.base.attributes.set("compression_method", self._compression_method) self.base.attributes.set("aliases", aliases) self.base.attributes.set("elements", list(sorted(elements))) @@ -161,7 +160,8 @@ def time_steps(self): :rtype: list """ with self.base.repository.open( - self.base.attributes.get("timestep_filename"), "r") as handle: + self.base.attributes.get("timestep_filename"), "r" + ) as handle: output = [int(i) for i in handle.readline().split()] return output @@ -197,13 +197,13 @@ def get_step_string(self, step_idx): step_idx = list(range(self.number_steps))[step_idx] zip_name = f'{self.base.attributes.get("zip_prefix")}{step_idx}' with self.base.repository.open( - self.base.attributes.get("trajectory_filename"), - mode="rb", + self.base.attributes.get("trajectory_filename"), + mode="rb", ) as handle: with ZipFile( - handle, - "r", - self.base.attributes.get("compression_method"), + handle, + "r", + self.base.attributes.get("compression_method"), ) as zip_file: with zip_file.open(zip_name, "r") as step_file: content = step_file.read() @@ -222,13 +222,13 @@ def iter_step_strings(self, steps=None): steps = range(0, self.number_steps, steps) with self.base.repository.open( - self.base.attributes.get("trajectory_filename"), - mode="rb", + self.base.attributes.get("trajectory_filename"), + mode="rb", ) as handle: with ZipFile( - handle, - "r", - self.base.attributes.get("compression_method"), + handle, + "r", + self.base.attributes.get("compression_method"), ) as zip_file: for step_idx in steps: zip_name = f'{self.base.attributes.get("zip_prefix")}{step_idx}' diff --git a/aiida_lammps/parsers/lammps/base.py b/aiida_lammps/parsers/lammps/base.py index 4019021..1ac69ce 100644 --- a/aiida_lammps/parsers/lammps/base.py +++ b/aiida_lammps/parsers/lammps/base.py @@ -108,8 +108,7 @@ def get_parsing_resources( def parse_log_file(self, compute_stress=False): """Parse the log file.""" output_filename = self.node.get_option("output_filename") - output_txt = self.retrieved.base.repository.get_object_content( - output_filename) + output_txt = self.retrieved.base.repository.get_object_content(output_filename) try: output_data = read_log_file( output_txt, @@ -123,11 +122,17 @@ def parse_log_file(self, compute_stress=False): def add_warnings_and_errors(self, output_data): """Add warning and errors to the output data.""" # add the dictionary with warnings and errors - warnings = (self.retrieved.base.repository.get_object_content( - self.node.get_option("scheduler_stderr")).strip().splitlines()) + warnings = ( + self.retrieved.base.repository.get_object_content( + self.node.get_option("scheduler_stderr") + ) + .strip() + .splitlines() + ) # for some reason, errors may be in the stdout, but not the log.lammps stdout = self.retrieved.base.repository.get_object_content( - self.node.get_option("scheduler_stdout")) + self.node.get_option("scheduler_stdout") + ) errors = [line for line in stdout.splitlines() if line.startswith("ERROR")] warnings.extend( [line for line in stdout.splitlines() if line.startswith("WARNING")] diff --git a/aiida_lammps/parsers/lammps/force.py b/aiida_lammps/parsers/lammps/force.py index fc5509a..fc3a087 100644 --- a/aiida_lammps/parsers/lammps/force.py +++ b/aiida_lammps/parsers/lammps/force.py @@ -74,7 +74,7 @@ def parse_traj_file(self, trajectory_filename: str) -> ArrayData: :return: array with the forces and charges (if present) for the calculation :rtype: orm.ArrayData """ - with self.retrieved.open(trajectory_filename, "r") as handle: + with self.retrieved.base.repository.open(trajectory_filename, "r") as handle: traj_steps = list(iter_trajectories(handle)) if not traj_steps: raise OSError("trajectory file empty") diff --git a/aiida_lammps/parsers/lammps/lammps_parser.py b/aiida_lammps/parsers/lammps/lammps_parser.py index 0eedeaf..1833d4c 100644 --- a/aiida_lammps/parsers/lammps/lammps_parser.py +++ b/aiida_lammps/parsers/lammps/lammps_parser.py @@ -49,8 +49,10 @@ def parse(self, **kwargs): return self.exit_codes.ERROR_LOG_FILE_MISSING filename = self.node.get_option("logfile_filename") parsed_data = parse_logfile( - file_contents=self.node.outputs.retrieved.base.repository. - get_object_content(filename)) + file_contents=self.node.outputs.retrieved.base.repository.get_object_content( + filename + ) + ) if parsed_data is None: return self.exit_codes.ERROR_PARSING_LOGFILE global_data = parsed_data["global"] @@ -62,8 +64,10 @@ def parse(self, **kwargs): filename = self.node.get_option("variables_filename") final_variables = parse_final_data( - file_contents=self.node.outputs.retrieved.base.repository. - get_object_content(filename)) + file_contents=self.node.outputs.retrieved.base.repository.get_object_content( + filename + ) + ) if final_variables is None: return self.exit_codes.ERROR_PARSING_FINAL_VARIABLES diff --git a/aiida_lammps/parsers/lammps/md.py b/aiida_lammps/parsers/lammps/md.py index 668fef0..ae754e5 100644 --- a/aiida_lammps/parsers/lammps/md.py +++ b/aiida_lammps/parsers/lammps/md.py @@ -54,7 +54,7 @@ def parse(self, **kwargs): self.logger.warning("units missing in log") self.add_warnings_and_errors(output_data) self.add_standard_info(output_data) - if "parameters" in self.node.get_incoming().all_link_labels(): + if "parameters" in self.node.base.links.get_incoming().all_link_labels(): output_data["timestep_picoseconds"] = convert_units( self.node.inputs.parameters.dict.timestep, output_data["units_style"], @@ -78,8 +78,9 @@ def parse(self, **kwargs): except Exception: # pylint: disable=broad-except traceback.print_exc() sys_data_error = self.exit_codes.ERROR_INFO_PARSING - sys_data.base.attributes.set("units_style", - output_data.get("units_style", None)) + sys_data.base.attributes.set( + "units_style", output_data.get("units_style", None) + ) self.out("system_data", sys_data) if output_data["errors"]: diff --git a/aiida_lammps/parsers/lammps/md_multi.py b/aiida_lammps/parsers/lammps/md_multi.py index a1078c9..11266cb 100644 --- a/aiida_lammps/parsers/lammps/md_multi.py +++ b/aiida_lammps/parsers/lammps/md_multi.py @@ -1,6 +1,5 @@ """Parser for LAMMPS MDMulti calculations.""" import os -import re import traceback from aiida.orm import ArrayData, Dict @@ -61,7 +60,7 @@ def parse(self, **kwargs): self.logger.warning("units missing in log") self.add_warnings_and_errors(output_data) self.add_standard_info(output_data) - if "parameters" in self.node.get_incoming().all_link_labels(): + if "parameters" in self.node.base.links.get_incoming().all_link_labels(): output_data["timestep_picoseconds"] = convert_units( self.node.inputs.parameters.dict.timestep, output_data["units_style"], @@ -80,8 +79,9 @@ def parse(self, **kwargs): for sys_path in resources.sys_paths: stage_name = os.path.basename(sys_path).split("-")[0] sys_data = ArrayData() - sys_data.base.attributes.set("units_style", - output_data.get("units_style", None)) + sys_data.base.attributes.set( + "units_style", output_data.get("units_style", None) + ) try: with open(sys_path) as handle: names = handle.readline().strip().split() @@ -96,20 +96,22 @@ def parse(self, **kwargs): if arrays: self.out("system", arrays) + # @TODO Re-add this functionality for aiida-core 2.x if possible # retrieve the last restart file, per stage - restart_map = {} - for rpath in resources.restart_paths: - rpath_base = os.path.basename(rpath) - match = re.match(r"([^\-]*)\-.*\.([\d]+)", rpath_base) - if match: - stage, step = match.groups() - if int(step) > restart_map.get(stage, (-1, None))[0]: - restart_map[stage] = (int(step), rpath) - - for stage, (step, rpath) in restart_map.items(): - with open(rpath, "rb") as handle: - self.retrieved.base.repository.put_object_from_filelike( - handle, os.path.basename(rpath), "wb", force=True) + # restart_map = {} + # for rpath in resources.restart_paths: + # rpath_base = os.path.basename(rpath) + # match = re.match(r"([^\-]*)\-.*\.([\d]+)", rpath_base) + # if match: + # stage, step = match.groups() + # if int(step) > restart_map.get(stage, (-1, None))[0]: + # restart_map[stage] = (int(step), rpath) + + # for stage, (step, rpath) in restart_map.items(): + # with open(rpath, "rb") as handle: + # self.retrieved.base.repository.put_object_from_filelike( + # handle, os.path.basename(rpath) + # ) if output_data["errors"]: return self.exit_codes.ERROR_LAMMPS_RUN diff --git a/aiida_lammps/validation/utils.py b/aiida_lammps/validation/utils.py index a2c6b79..079a883 100644 --- a/aiida_lammps/validation/utils.py +++ b/aiida_lammps/validation/utils.py @@ -23,7 +23,9 @@ def load_schema(name): with open(name) as jfile: schema = json.load(jfile) else: - schema = json.loads(importlib_resources.files(schemas).joinpath(name).read_text()) + schema = json.loads( + importlib_resources.files(schemas).joinpath(name).read_text() + ) return schema diff --git a/docs/source/developers/intro.md b/docs/source/developers/intro.md index 581d01d..88b3582 100644 --- a/docs/source/developers/intro.md +++ b/docs/source/developers/intro.md @@ -29,8 +29,7 @@ $ tox -e py37 or directly: ```shell -$ pip install -e .[testing] -$ reentry scan -r aiida +$ pip install .[testing] $ pytest -v ``` diff --git a/examples/launch_lammps_force_gan.py b/examples/launch_lammps_force_gan.py index c3bf7cb..7d9b53a 100644 --- a/examples/launch_lammps_force_gan.py +++ b/examples/launch_lammps_force_gan.py @@ -1,6 +1,6 @@ +from aiida import orm from aiida.common.extendeddicts import AttributeDict from aiida.engine import run_get_node -from aiida.orm import Code, StructureData from aiida.plugins import CalculationFactory import numpy as np @@ -34,7 +34,7 @@ symbols = ["Ga", "Ga", "N", "N"] - structure = StructureData(cell=cell) + structure = orm.StructureData(cell=cell) positions = np.dot(scaled_positions, cell) for i, scaled_position in enumerate(scaled_positions): @@ -77,7 +77,7 @@ inputs.metadata.options = options # Setup code - inputs.code = Code.get_from_string(codename) + inputs.code = orm.Code.get_from_string(codename) # setup nodes inputs.structure = structure diff --git a/examples/launch_lammps_md_si.py b/examples/launch_lammps_md_si.py index ea2b1f0..20bbaf0 100644 --- a/examples/launch_lammps_md_si.py +++ b/examples/launch_lammps_md_si.py @@ -1,7 +1,6 @@ -from aiida import load_profile +from aiida import load_profile, orm from aiida.common.extendeddicts import AttributeDict from aiida.engine import run_get_node -from aiida.orm import Code, Dict, StructureData from aiida.plugins import CalculationFactory import numpy as np @@ -32,7 +31,7 @@ (0.625, 0.625, 0.125), ] - structure = StructureData(cell=cell) + structure = orm.StructureData(cell=cell) positions = np.dot(scaled_positions, cell) for i, scaled_position in enumerate(scaled_positions): @@ -80,7 +79,7 @@ inputs.metadata.options = options # Setup code - inputs.code = Code.get_from_string(codename) + inputs.code = orm.Code.get_from_string(codename) # setup nodes inputs.structure = structure @@ -88,7 +87,7 @@ type=potential["pair_style"], data=potential["data"] ) - inputs.parameters = Dict(dict=parameters_md) + inputs.parameters = orm.Dict(dict=parameters_md) # run calculation result, node = run_get_node(LammpsMDCalculation, **inputs) diff --git a/examples/launch_lammps_optimization_fe.py b/examples/launch_lammps_optimization_fe.py index 58cb852..65dccfc 100644 --- a/examples/launch_lammps_optimization_fe.py +++ b/examples/launch_lammps_optimization_fe.py @@ -1,6 +1,6 @@ +from aiida import orm from aiida.common.extendeddicts import AttributeDict from aiida.engine import run_get_node -from aiida.orm import Code, Dict, StructureData from aiida.plugins import CalculationFactory import numpy as np @@ -32,7 +32,7 @@ symbols = ["Fe", "Fe"] - structure = StructureData(cell=cell) + structure = orm.StructureData(cell=cell) positions = np.dot(scaled_positions, cell) for i, scaled_position in enumerate(scaled_positions): @@ -83,7 +83,7 @@ inputs.metadata.options = options # Setup code - inputs.code = Code.get_from_string(codename) + inputs.code = orm.Code.get_from_string(codename) # setup nodes inputs.structure = structure @@ -95,7 +95,7 @@ print(inputs.potential.atom_style) print(inputs.potential.default_units) - inputs.parameters = Dict(dict=parameters_opt) + inputs.parameters = orm.Dict(dict=parameters_opt) # run calculation result, node = run_get_node(LammpsOptimizeCalculation, **inputs) diff --git a/examples/launch_lammps_optimization_gan.py b/examples/launch_lammps_optimization_gan.py index 5805b18..a71752d 100644 --- a/examples/launch_lammps_optimization_gan.py +++ b/examples/launch_lammps_optimization_gan.py @@ -1,6 +1,6 @@ +from aiida import orm from aiida.common.extendeddicts import AttributeDict from aiida.engine import run_get_node -from aiida.orm import Code, Dict, StructureData from aiida.plugins import CalculationFactory import numpy as np @@ -34,7 +34,7 @@ symbols = ["Ga", "Ga", "N", "N"] - structure = StructureData(cell=cell) + structure = orm.StructureData(cell=cell) positions = np.dot(scaled_positions, cell) for i, scaled_position in enumerate(scaled_positions): @@ -97,7 +97,7 @@ inputs.metadata.options = options # Setup code - inputs.code = Code.get_from_string(codename) + inputs.code = orm.Code.get_from_string(codename) # setup nodes inputs.structure = structure @@ -105,7 +105,7 @@ type=potential["pair_style"], data=potential["data"] ) - inputs.parameters = Dict(dict=parameters_opt) + inputs.parameters = orm.Dict(dict=parameters_opt) print(inputs.potential.get_potential_file()) print(inputs.potential.atom_style) diff --git a/examples/launch_lammps_optimization_lj.py b/examples/launch_lammps_optimization_lj.py index 392bb1c..5641a00 100644 --- a/examples/launch_lammps_optimization_lj.py +++ b/examples/launch_lammps_optimization_lj.py @@ -1,6 +1,6 @@ +from aiida import orm from aiida.common.extendeddicts import AttributeDict from aiida.engine import run_get_node -from aiida.orm import Code, Dict, StructureData from aiida.plugins import CalculationFactory import numpy as np @@ -27,7 +27,7 @@ symbols = ["Ar"] * 2 scaled_positions = [(0.33333, 0.66666, 0.25000), (0.66667, 0.33333, 0.75000)] - structure = StructureData(cell=cell) + structure = orm.StructureData(cell=cell) positions = np.dot(scaled_positions, cell) for i, scaled_position in enumerate(scaled_positions): @@ -84,7 +84,7 @@ inputs.metadata.options = options # Setup code - inputs.code = Code.get_from_string(codename) + inputs.code = orm.Code.get_from_string(codename) # setup nodes inputs.structure = structure @@ -92,7 +92,7 @@ type=potential["pair_style"], data=potential["data"] ) - inputs.parameters = Dict(dict=parameters_opt) + inputs.parameters = orm.Dict(dict=parameters_opt) # run calculation result, node = run_get_node(LammpsOptimizeCalculation, **inputs) diff --git a/pyproject.toml b/pyproject.toml index 0c4f13e..9b38ee2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ classifiers = [ keywords = ["aiida", "workflows", "lammps"] requires-python = ">=3.8" dependencies = [ - "aiida-core[atomic-tools]>=1.4.0,<2.0.0", + "aiida-core[atomic-tools]>=2.0.0,<3.0.0", "psycopg2-binary<2.9", "ase>=3.12.0,<4.0.0", "importlib_resources", diff --git a/tests/test_calculations.py b/tests/test_calculations.py index 4438a4c..64534e2 100644 --- a/tests/test_calculations.py +++ b/tests/test_calculations.py @@ -356,13 +356,13 @@ def test_force_process( print(get_calcjob_report(calc_node)) raise Exception(f"finished with exit message: {calc_node.exit_message}") - link_labels = calc_node.get_outgoing().all_link_labels() + link_labels = calc_node.base.links.get_outgoing().all_link_labels() assert set(link_labels).issuperset(["results", "arrays"]) data_regression.check( { "results": sanitize_results(calc_node.outputs.results.get_dict(), 1), - "arrays": calc_node.outputs.arrays.attributes, + "arrays": calc_node.outputs.arrays.base.attributes.all, } ) @@ -411,10 +411,10 @@ def test_optimize_process( print(get_calcjob_report(calc_node)) raise Exception(f"finished with exit message: {calc_node.exit_message}") - link_labels = calc_node.get_outgoing().all_link_labels() + link_labels = calc_node.base.links.get_outgoing().all_link_labels() assert set(link_labels).issuperset(["results", "trajectory_data", "structure"]) - trajectory_data = calc_node.outputs.trajectory_data.attributes + trajectory_data = calc_node.outputs.trajectory_data.base.attributes.all # optimization steps may differ between lammps versions trajectory_data = {k: v for k, v in trajectory_data.items() if k != "number_steps"} data_regression.check( @@ -475,7 +475,7 @@ def test_md_process( print(get_calcjob_report(calc_node)) raise Exception(f"finished with exit message: {calc_node.exit_message}") - link_labels = calc_node.get_outgoing().all_link_labels() + link_labels = calc_node.base.links.get_outgoing().all_link_labels() assert set(link_labels).issuperset(["results", "trajectory_data", "system_data"]) data_regression.check( @@ -484,8 +484,8 @@ def test_md_process( calc_node.outputs.results.get_dict(), round_energy=1, ), - "system_data": calc_node.outputs.system_data.attributes, - "trajectory_data": calc_node.outputs.trajectory_data.attributes, + "system_data": calc_node.outputs.system_data.base.attributes.all, + "trajectory_data": calc_node.outputs.trajectory_data.base.attributes.all, }, basename=f"test_md_process-{potential_type}-{version_year}", ) @@ -535,7 +535,7 @@ def test_md_multi_process( print(get_calcjob_report(calc_node)) raise Exception(f"finished with exit message: {calc_node.exit_message}") - link_labels = calc_node.get_outgoing().all_link_labels() + link_labels = calc_node.base.links.get_outgoing().all_link_labels() assert set(link_labels).issuperset( [ "results", @@ -547,17 +547,15 @@ def test_md_multi_process( ] ) - data_regression.check({ - "retrieved": - calc_node.outputs.retrieved.base.repository.list_object_names(), - "results": - sanitize_results(calc_node.outputs.results.get_dict(), round_energy=1), - "system__thermalise": - calc_node.outputs.system__thermalise.attributes, - "system__equilibrate": - calc_node.outputs.system__equilibrate.attributes, - "trajectory__thermalise": - calc_node.outputs.trajectory__thermalise.attributes, - "trajectory__equilibrate": - calc_node.outputs.trajectory__equilibrate.attributes, - }) + data_regression.check( + { + "retrieved": calc_node.outputs.retrieved.base.repository.list_object_names(), + "results": sanitize_results( + calc_node.outputs.results.get_dict(), round_energy=1 + ), + "system__thermalise": calc_node.outputs.system.thermalise.base.attributes.all, + "system__equilibrate": calc_node.outputs.system.equilibrate.base.attributes.all, + "trajectory__thermalise": calc_node.outputs.trajectory.thermalise.base.attributes.all, + "trajectory__equilibrate": calc_node.outputs.trajectory.equilibrate.base.attributes.all, + } + ) diff --git a/tests/test_calculations/test_md_multi_process_eam_.yml b/tests/test_calculations/test_md_multi_process_eam_.yml index 38159fe..57b8c97 100644 --- a/tests/test_calculations/test_md_multi_process_eam_.yml +++ b/tests/test_calculations/test_md_multi_process_eam_.yml @@ -14,7 +14,6 @@ retrieved: - _scheduler-stderr.txt - _scheduler-stdout.txt - cell_transform.npy -- equilibrate-lammps.restart.400 - log.lammps system__equilibrate: array|etotal: diff --git a/tests/test_calculations/test_md_multi_process_lennard_jones_.yml b/tests/test_calculations/test_md_multi_process_lennard_jones_.yml index ec0df94..f2f0de3 100644 --- a/tests/test_calculations/test_md_multi_process_lennard_jones_.yml +++ b/tests/test_calculations/test_md_multi_process_lennard_jones_.yml @@ -14,7 +14,6 @@ retrieved: - _scheduler-stderr.txt - _scheduler-stdout.txt - cell_transform.npy -- equilibrate-lammps.restart.400 - log.lammps system__equilibrate: array|etotal: diff --git a/tests/test_calculations/test_md_multi_process_reaxff_.yml b/tests/test_calculations/test_md_multi_process_reaxff_.yml index e593061..f32913e 100644 --- a/tests/test_calculations/test_md_multi_process_reaxff_.yml +++ b/tests/test_calculations/test_md_multi_process_reaxff_.yml @@ -14,7 +14,6 @@ retrieved: - _scheduler-stderr.txt - _scheduler-stdout.txt - cell_transform.npy -- equilibrate-lammps.restart.400 - log.lammps system__equilibrate: array|c_reax_1_: diff --git a/tests/test_calculations/test_md_multi_process_tersoff_.yml b/tests/test_calculations/test_md_multi_process_tersoff_.yml index 2e6a2bd..26e2c57 100644 --- a/tests/test_calculations/test_md_multi_process_tersoff_.yml +++ b/tests/test_calculations/test_md_multi_process_tersoff_.yml @@ -14,7 +14,6 @@ retrieved: - _scheduler-stderr.txt - _scheduler-stdout.txt - cell_transform.npy -- equilibrate-lammps.restart.400 - log.lammps system__equilibrate: array|etotal: diff --git a/tests/test_parsers.py b/tests/test_parsers.py index 9335e53..bcf473b 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -82,11 +82,15 @@ def test_missing_log(db_test_app, plugin_name): def test_missing_traj(db_test_app, plugin_name): """Check if the trajectory file is produced during calculation.""" retrieved = FolderData() - retrieved.base.repository.put_object_from_filelike(io.StringIO(get_log()), "log.lammps") retrieved.base.repository.put_object_from_filelike( - io.StringIO(""), "_scheduler-stdout.txt") + io.StringIO(get_log()), "log.lammps" + ) + retrieved.base.repository.put_object_from_filelike( + io.StringIO(""), "_scheduler-stdout.txt" + ) retrieved.base.repository.put_object_from_filelike( - io.StringIO(""), "_scheduler-stderr.txt") + io.StringIO(""), "_scheduler-stderr.txt" + ) calc_node = db_test_app.generate_calcjob_node(plugin_name, retrieved) parser = ParserFactory(plugin_name) @@ -119,8 +123,7 @@ def test_empty_log(db_test_app, plugin_name): "_scheduler-stdout.txt", "_scheduler-stderr.txt", ]: - retrieved.base.repository.put_object_from_filelike( - io.StringIO(""), filename) + retrieved.base.repository.put_object_from_filelike(io.StringIO(""), filename) calc_node = db_test_app.generate_calcjob_node(plugin_name, retrieved) parser = ParserFactory(plugin_name) @@ -150,15 +153,15 @@ def test_empty_log(db_test_app, plugin_name): def test_empty_traj(db_test_app, plugin_name): """Check if the lammps trajectory file is empty.""" retrieved = FolderData() - retrieved.base.repository.put_object_from_filelike(io.StringIO(get_log()), - "log.lammps") + retrieved.base.repository.put_object_from_filelike( + io.StringIO(get_log()), "log.lammps" + ) for filename in [ "trajectory.lammpstrj", "_scheduler-stdout.txt", "_scheduler-stderr.txt", ]: - retrieved.base.repository.put_object_from_filelike( - io.StringIO(""), filename) + retrieved.base.repository.put_object_from_filelike(io.StringIO(""), filename) calc_node = db_test_app.generate_calcjob_node(plugin_name, retrieved) parser = ParserFactory(plugin_name) diff --git a/tests/test_potential_data.py b/tests/test_potential_data.py index fd9979a..031875b 100644 --- a/tests/test_potential_data.py +++ b/tests/test_potential_data.py @@ -54,8 +54,7 @@ def test_potential_files( potential_type=potential.type, data=potential.data, ) - file_regression.check( - node.base.repository.get_object_content("potential.pot", "r")) + file_regression.check(node.base.repository.get_object_content("potential.pot", "r")) @pytest.mark.parametrize( @@ -108,7 +107,9 @@ def test_lammps_potentials_init( for _attribute in _attributes: _msg = f'attribute "{_attribute}" does not match between reference and current value' - assert reference_values[_attribute] == node.base.attributes.get(_attribute), _msg + assert reference_values[_attribute] == node.base.attributes.get( + _attribute + ), _msg @pytest.mark.parametrize( diff --git a/tests/test_trajectory.py b/tests/test_trajectory.py index 1581480..67baed2 100644 --- a/tests/test_trajectory.py +++ b/tests/test_trajectory.py @@ -29,7 +29,8 @@ def test_create_structure( structure = create_structure(traj_block) data_regression.check( - recursive_round(structure.base.attributes.all, 2, apply_lists=True)) + recursive_round(structure.base.attributes.all, 2, apply_lists=True) + ) def test_lammps_trajectory_data( @@ -57,9 +58,10 @@ def test_lammpstraj_get_step_struct( path = os.path.join(TEST_DIR, "input_files", "trajectory.lammpstrj") data = LammpsTrajectory(path) data_regression.check( - recursive_round(data.get_step_structure(-1).base.attributes.all, - 2, - apply_lists=True)) + recursive_round( + data.get_step_structure(-1).base.attributes.all, 2, apply_lists=True + ) + ) def test_lammpstraj_timesteps(db_test_app): # pylint: disable=unused-argument diff --git a/tests/utils.py b/tests/utils.py index e82e29a..a4b0e38 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -7,12 +7,12 @@ import subprocess import sys +from aiida import orm from aiida.common import NotExistent from aiida.common.folders import SandboxFolder from aiida.common.links import LinkType from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager -from aiida.orm import CalcJobNode, Code, Computer from aiida.plugins import CalculationFactory, DataFactory, ParserFactory from aiida.plugins.entry_point import format_entry_point_string @@ -35,7 +35,7 @@ def lammps_version(executable="lammps"): ) match = re.search(regex, out_text) if match: - return match.group(1).strip() + return match.group(1).strip().split("-")[0].strip() raise OSError(f"Could not find version from `{executable} -h`") @@ -76,14 +76,14 @@ def get_or_create_local_computer(work_directory, name="localhost"): """ try: - computer = Computer.collection.get(label=name) + computer = orm.Computer.collection.get(label=name) except NotExistent: - computer = Computer( + computer = orm.Computer( label=name, hostname="localhost", description=("localhost computer, " "set up by aiida_lammps tests"), - transport_type="local", - scheduler_type="direct", + transport_type="core.local", + scheduler_type="core.direct", workdir=os.path.abspath(work_directory), ) computer.store() @@ -96,16 +96,16 @@ def get_or_create_code(entry_point, computer, executable, exec_path=None): """Setup code on localhost computer""" if isinstance(computer, str): - computer = Computer.collection.get(label=computer) + computer = orm.Computer.collection.get(label=computer) try: - code = Code.collection.get( # pylint: disable=no-member + code = orm.Code.collection.get( # pylint: disable=no-member label=f"{entry_point}-{executable}-{computer.label}" ) except NotExistent: if exec_path is None: exec_path = get_path_to_executable(executable) - code = Code( + code = orm.Code( input_plugin_name=entry_point, remote_computer_exec=[computer, exec_path] ) code.label = f"{entry_point}-{executable}-{computer.label}" @@ -269,7 +269,7 @@ def generate_calcjob_node( computer = self.get_or_create_computer(computer_name) entry_point = format_entry_point_string("aiida.calculations", entry_point_name) - node = CalcJobNode(computer=computer, process_type=entry_point) + node = orm.CalcJobNode(computer=computer, process_type=entry_point) node.set_options( { k: v.default() if callable(v.default) else v.default @@ -285,7 +285,7 @@ def generate_calcjob_node( node.store() - retrieved.add_incoming( + retrieved.base.links.add_incoming( node, link_type=LinkType.CREATE, link_label="retrieved", diff --git a/tox.ini b/tox.ini index c5b1aa1..f88dc34 100644 --- a/tox.ini +++ b/tox.ini @@ -18,12 +18,10 @@ extras = testing deps = black flake8 -commands_pre = reentry scan commands = pytest --lammps-exec lmp_serial {posargs} [testenv:docs-{clean,update}] extras = docs -commands_pre = reentry scan allowlist_externals = rm echo From 79140492c141ee8227f5fc4a745b947a23ea60d1 Mon Sep 17 00:00:00 2001 From: Jonathan Chico Date: Fri, 19 Aug 2022 16:15:40 +0200 Subject: [PATCH 4/4] Removing the explicit psycopg2-binary dependency. Removing the explicit ase dependency as it is installed via aiida-core[atomic_tools]. --- pyproject.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9b38ee2..a36288f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,9 +23,7 @@ classifiers = [ keywords = ["aiida", "workflows", "lammps"] requires-python = ">=3.8" dependencies = [ - "aiida-core[atomic-tools]>=2.0.0,<3.0.0", - "psycopg2-binary<2.9", - "ase>=3.12.0,<4.0.0", + "aiida-core[atomic_tools]>=2.0.0,<3.0.0", "importlib_resources", "jsonschema", "numpy",