Source code for aiida_vasp.commands.mock_vasp

# pylint: disable=too-many-function-args
"""
Mock vasp command.

Separate cli interface for commands useful in development and testing.
"""

import os
import pathlib
import shutil
from typing import List

import click

from aiida_vasp.parsers.content_parsers.incar import IncarParser
from aiida_vasp.parsers.content_parsers.kpoints import KpointsParser
from aiida_vasp.parsers.content_parsers.poscar import PoscarParser
from aiida_vasp.utils.mock_code import MockVasp, VaspMockRegistry, data_path


@click.command('mock-vasp-loose')
def mock_vasp_loose() -> None:
    """
    Loose version of mock-vasp that has default test data - only useful for testing and development.
    """
    return _mock_vasp(False)


@click.command('mock-vasp')
def mock_vasp() -> None:
    """
    If `MOCK_VASP_VASP_CMD` is set in the environment, it will use that command to run VASP if needed and add the
    calculation to the registry.
    """
    return _mock_vasp(True)


[docs] def _mock_vasp(strict_match: bool) -> None: # pylint: disable=too-many-statements, too-many-locals, too-many-branches """ Verify input objects are parsable and copy in output objects. """ pwd = pathlib.Path().absolute() vasp_mock_output = [] vasp_output_file = pwd / 'vasp_output' vasp_mock_output.append('MOCK PREPEND: START ----------------------\n') vasp_mock_output.append('MOCK PREPEND: Mock directory: ' + str(pwd) + '\n') incar = pwd / 'INCAR' if not incar.is_file(): vasp_mock_output.append('MOCK PREPEND: INCAR not found.\n') stop_and_return(vasp_mock_output) potcar = pwd / 'POTCAR' if not potcar.is_file(): vasp_mock_output.append('MOCK PREPEND: POTCAR not found.\n') stop_and_return(vasp_mock_output) poscar = pwd / 'POSCAR' if not poscar.is_file(): vasp_mock_output.append('MOCK PREPEND: POSCAR not found.\n') stop_and_return(vasp_mock_output) kpoints = pwd / 'KPOINTS' if not kpoints.is_file(): vasp_mock_output.append('MOCK PREPEND: KPOINTS not found.\n') stop_and_return(vasp_mock_output) # Check that the input files can be parsed (as close to a validity check we can get) incar_parser = False system = '' with open(str(incar), 'r', encoding='utf8') as handler: incar_parser = IncarParser(handler=handler, validate_tags=False) system = incar_parser.incar.get('system', '') if not incar_parser: vasp_mock_output.append('MOCK PREPEND: INCAR could not be parsed.\n') stop_and_return(vasp_mock_output) poscar_parser = False with open(str(poscar), 'r', encoding='utf8') as handler: poscar_parser = PoscarParser(handler=handler) if not poscar_parser: vasp_mock_output.append('MOCK PREPEND: POSCAR could not be parsed.\n') stop_and_return(vasp_mock_output) kpoints_parser = False with open(str(kpoints), 'r', encoding='utf8') as handler: kpoints_parser = KpointsParser(handler=handler) if not kpoints_parser: vasp_mock_output.append('MOCK PREPEND: KPOINTS could not be parsed.\n') stop_and_return(vasp_mock_output) try: test_case = system.strip().split(':')[1].strip() except IndexError: test_case = '' if not test_case: vasp_mock_output.append('MOCK PREPEND: Trying to detect test case using registry or reverting to default.\n') # If no test case is defined, we first try the hash-based mock registry mock_registry_path = os.environ.get('MOCK_VASP_REG_BASE', data_path('.')) mock_registry = VaspMockRegistry(mock_registry_path) vasp_mock_output.append(f'MOCK PREPEND: registry search paths: {mock_registry.search_paths}\n') # Setup the mock code mock = MockVasp(pwd, mock_registry, vasp_cmd=os.environ.get('MOCK_VASP_VASP_CMD')) if mock.is_runnable: mock.run() detected_path = mock.registry.get_path_by_hash(mock_registry.compute_hash(pwd)) vasp_mock_output.append( f'MOCK PREPEND: Using test data in path {detected_path} based detection from inputs.\n' ) else: vasp_mock_output.append( 'MOCK PREPEND: Using default test data in the respective folders named similar to the file name.\n' ) if not strict_match: # Then this is a simple case - assemble the outputs from folders shutil.copy(data_path('outcar', 'OUTCAR'), pwd / 'OUTCAR') shutil.copy(data_path('vasprun', 'vasprun.xml'), pwd / 'vasprun.xml') shutil.copy(data_path('chgcar', 'CHGCAR'), pwd / 'CHGCAR') shutil.copy(data_path('wavecar', 'WAVECAR'), pwd / 'WAVECAR') shutil.copy(data_path('eigenval', 'EIGENVAL'), pwd / 'EIGENVAL') shutil.copy(data_path('doscar', 'DOSCAR'), pwd / 'DOSCAR') shutil.copy(data_path('basic_run', 'vasp_output'), pwd / 'vasp_output') shutil.copy(poscar, pwd / 'CONTCAR') else: vasp_mock_output.append( 'MOCK PREPEND: Caller demanded to only locate test data by input, but no match was found.\n' ) stop_and_return(vasp_mock_output) else: vasp_mock_output.append('MOCK PREPEND: Using test data from folder: ' + test_case + '\n') test_data_path = data_path(test_case, 'out') for out_object in pathlib.Path(test_data_path).iterdir(): shutil.copy(out_object, pwd) # Read original vasp_output as we will append mock messages to it vasp_output_content = [] if vasp_output_file.exists(): with open(vasp_output_file, 'r', encoding='utf8') as handler: vasp_output_content = handler.readlines() vasp_mock_output.append('MOCK PREPEND: Mock folder contains the following files: ' + str(os.listdir(pwd)) + '\n') vasp_mock_output.append('MOCK PREPEND: END ----------------------\n') vasp_mock_output.append('Existing VASP stdout/stderr follows:\n') # Make sure we add the mock details in case we need to inspect later with open(vasp_output_file, 'w', encoding='utf8') as handler: handler.write(''.join(vasp_mock_output + vasp_output_content))
[docs] def stop_and_return(vasp_mock_output: List[str]) -> None: """Halts mock-vasp, rebuilds the vasp_output and returns.""" # Assemble the print(''.join(vasp_mock_output)) raise RuntimeError('The mock-vasp code could not perform a clean run.')