Example #1
0
def cmd_relax(plugin, structure, codes, protocol, relax_type, spin_type,
              threshold_forces, threshold_stress, number_machines,
              wallclock_seconds, daemon, magnetization_per_site,
              previous_workchain, show_engines):
    """Relax a crystal structure using the common relax workflow for one of the existing plugin implementations.

    The codes required for the plugin workflow in order to complete the task can be passed with the option `-X`,
    however, if no code is passed, the command will automatically try to find and load the codes that are required.
    If no code is installed for at least one of the calculation engines, the command will fail.
    Use the `--show-engine` flag to display the required calculation engines for the selected plugin workflow.
    """
    # pylint: disable=too-many-locals
    process_class = load_workflow_entry_point('relax', plugin)
    generator = process_class.get_inputs_generator()

    number_engines = len(generator.get_calc_types())

    if number_machines is None:
        number_machines = [1] * number_engines

    if len(number_machines) != number_engines:
        raise click.BadParameter(
            f'{process_class.__name__} has {number_engines} engine steps, so requires {number_engines} values',
            param_hint='--number-machines')

    if wallclock_seconds is None:
        wallclock_seconds = [1 * 3600] * number_engines

    if len(wallclock_seconds) != number_engines:
        raise click.BadParameter(
            f'{process_class.__name__} has {number_engines} engine steps, so requires {number_engines} values',
            param_hint='--wallclock-seconds')

    if not generator.is_valid_protocol(protocol):
        protocols = generator.get_protocol_names()
        process_class_name = process_class.__name__
        message = f'`{protocol}` is not implemented by `{process_class_name}` workflow: choose one of {protocols}'
        raise click.BadParameter(message, param_hint='protocol')

    if show_engines:
        for engine in generator.get_calc_types():
            schema = generator.get_calc_type_schema(engine)
            click.secho(engine, fg='red', bold=True)
            click.echo('Required code plugin: {}'.format(
                schema['code_plugin']))
            click.echo('Engine description:   {}'.format(
                schema['description']))

        return

    engines = {}

    for index, engine in enumerate(generator.get_calc_types()):
        schema = generator.get_calc_type_schema(engine)
        code_plugin = schema['code_plugin']

        code = utils.get_code_from_list_or_database(codes or [], code_plugin)

        if code is None:
            raise click.UsageError(
                f'could not find a configured code for the plugin `{code_plugin}`. '
                'Either provide it with the -X option or make sure such a code is configured in the DB.'
            )

        engines[engine] = {
            'code': code.full_label,
            'options': {
                'resources': {
                    'num_machines': number_machines[index]
                },
                'max_wallclock_seconds': wallclock_seconds[index],
            }
        }

    builder = generator.get_builder(
        structure,
        engines,
        protocol=protocol,
        relax_type=relax_type,
        threshold_forces=threshold_forces,
        threshold_stress=threshold_stress,
        spin_type=spin_type,
        magnetization_per_site=magnetization_per_site,
        previous_workchain=previous_workchain,
    )
    utils.launch_process(builder, daemon)
Example #2
0
def cmd_relax(
    plugin, structure, protocol, relaxation_type, threshold_forces, threshold_stress, number_machines,
    wallclock_seconds, daemon, show_engines
):
    """Relax a crystal structure using the common relax workflow for one of the existing plugin implementations.

    The command will automatically try to find and load the codes that are required by the plugin workflow. If no code
    is installed for at least one of the calculation engines, the command will fail. Use the `--show-engine` flag to
    display the required calculation engines for the selected plugin workflow.
    """
    # pylint: disable=too-many-locals
    from aiida.orm import QueryBuilder, Code

    process_class = load_workflow_entry_point('relax', plugin)
    generator = process_class.get_inputs_generator()

    number_engines = len(generator.get_calc_types())

    if number_machines is None:
        number_machines = [1] * number_engines

    if len(number_machines) != number_engines:
        raise click.BadParameter(
            f'{process_class.__name__} has {number_engines} engine steps, so requires {number_engines} values',
            param_hint='--number-machines'
        )

    if wallclock_seconds is None:
        wallclock_seconds = [1 * 3600] * number_engines

    if len(wallclock_seconds) != number_engines:
        raise click.BadParameter(
            f'{process_class.__name__} has {number_engines} engine steps, so requires {number_engines} values',
            param_hint='--wallclock-seconds'
        )

    if not generator.is_valid_protocol(protocol):
        protocols = generator.get_protocol_names()
        process_class_name = process_class.__name__
        message = f'`{protocol}` is not implemented by `{process_class_name}` workflow: choose one of {protocols}'
        raise click.BadParameter(message, param_hint='protocol')

    if show_engines:
        for engine in generator.get_calc_types():
            schema = generator.get_calc_type_schema(engine)
            click.secho(engine, fg='red', bold=True)
            click.echo('Required code plugin: {}'.format(schema['code_plugin']))
            click.echo('Engine description:   {}'.format(schema['description']))

        return

    engines = {}

    for index, engine in enumerate(generator.get_calc_types()):
        schema = generator.get_calc_type_schema(engine)
        engines[engine] = {
            'options': {
                'resources': {
                    'num_machines': number_machines[index]
                },
                'max_wallclock_seconds': wallclock_seconds[index],
            }
        }
        code_plugin = schema['code_plugin']
        query = QueryBuilder().append(Code, filters={'attributes.input_plugin': code_plugin})

        code = query.first()

        if code is None:
            raise click.UsageError(f'could not find a configured code for the plugin `{code_plugin}`.')

        engines[engine]['code'] = code[0].full_label

    builder = generator.get_builder(structure, engines, protocol, relaxation_type, threshold_forces, threshold_stress)
    utils.launch_process(builder, daemon)
Example #3
0
def cmd_dissociation_curve(plugin, structure, codes, protocol, spin_type,
                           number_machines, wallclock_seconds, daemon,
                           magnetization_per_site, show_engines):
    """Compute the dissociation curve of a diatomic molecule using the common relax workflow.

    The relaxation type is constrained to be `RelaxType.NONE`, meaning a single point calculation.
    It does not make sense to have any other type of relaxation for this task.

    The codes required for the plugin workflow in order to complete the task can be passed with the option `-X`,
    however, if no code is passed, the command will automatically try to find and load the codes that are required.
    If no code is installed for at least one of the calculation engines, the command will fail.
    Use the `--show-engine` flag to display the required calculation engines for the selected plugin workflow.
    """
    # pylint: disable=too-many-locals
    from aiida_common_workflows.plugins import get_entry_point_name_from_class
    from aiida_common_workflows.workflows.dissociation import DissociationCurveWorkChain
    from aiida_common_workflows.workflows.relax.generator import RelaxType

    process_class = load_workflow_entry_point('relax', plugin)
    generator = process_class.get_inputs_generator()

    number_engines = len(generator.get_calc_types())

    if number_machines is None:
        number_machines = [1] * number_engines

    if len(number_machines) != number_engines:
        raise click.BadParameter(
            f'{process_class.__name__} has {number_engines} engine steps, so requires {number_engines} values',
            param_hint='--number-machines')

    if wallclock_seconds is None:
        wallclock_seconds = [1 * 3600] * number_engines

    if len(wallclock_seconds) != number_engines:
        raise click.BadParameter(
            f'{process_class.__name__} has {number_engines} engine steps, so requires {number_engines} values',
            param_hint='--wallclock-seconds')

    if not generator.is_valid_protocol(protocol):
        protocols = generator.get_protocol_names()
        process_class_name = process_class.__name__
        message = f'`{protocol}` is not implemented by `{process_class_name}` workflow: choose one of {protocols}'
        raise click.BadParameter(message, param_hint='protocol')

    if show_engines:
        for engine in generator.get_calc_types():
            schema = generator.get_calc_type_schema(engine)
            click.secho(engine, fg='red', bold=True)
            click.echo('Required code plugin: {}'.format(
                schema['code_plugin']))
            click.echo('Engine description:   {}'.format(
                schema['description']))

        return

    engines = {}

    for index, engine in enumerate(generator.get_calc_types()):
        schema = generator.get_calc_type_schema(engine)
        code_plugin = schema['code_plugin']

        code = utils.get_code_from_list_or_database(codes or [], code_plugin)

        if code is None:
            raise click.UsageError(
                f'could not find a configured code for the plugin `{code_plugin}`. '
                'Either provide it with the -X option or make sure such a code is configured in the DB.'
            )

        engines[engine] = {
            'code': code.full_label,
            'options': {
                'resources': {
                    'num_machines': number_machines[index]
                },
                'max_wallclock_seconds': wallclock_seconds[index],
            }
        }

    inputs = {
        'molecule': structure,
        'generator_inputs': {
            'calc_engines': engines,
            'protocol': protocol,
            'relax_type': RelaxType.NONE,
            'spin_type': spin_type,
        },
        'sub_process_class':
        get_entry_point_name_from_class(process_class).name,
    }

    if magnetization_per_site is not None:
        inputs['generator_inputs'][
            'magnetization_per_site'] = magnetization_per_site

    utils.launch_process(DissociationCurveWorkChain, daemon, **inputs)
Example #4
0
def cmd_relax(  # pylint: disable=too-many-branches
        plugin, structure, codes, protocol, relax_type, electronic_type,
        spin_type, threshold_forces, threshold_stress, number_machines,
        number_mpi_procs_per_machine, number_cores_per_mpiproc,
        wallclock_seconds, daemon, magnetization_per_site, reference_workchain,
        engine_options, show_engines):
    """Relax a crystal structure using the common relax workflow for one of the existing plugin implementations.

    The codes required for the plugin workflow in order to complete the task can be passed with the option `-X`,
    however, if no code is passed, the command will automatically try to find and load the codes that are required.
    If no code is installed for at least one of the calculation engines, the command will fail.
    Use the `--show-engine` flag to display the required calculation engines for the selected plugin workflow.
    """
    # pylint: disable=too-many-locals,too-many-statements
    process_class = load_workflow_entry_point('relax', plugin)
    generator = process_class.get_input_generator()

    number_engines = len(generator.spec().inputs['engines'])

    if number_machines is None:
        number_machines = [1] * number_engines

    if len(number_machines) != number_engines:
        raise click.BadParameter(
            f'{process_class.__name__} has {number_engines} engine steps, so requires {number_engines} values',
            param_hint='--number-machines')

    if number_mpi_procs_per_machine is not None and len(
            number_mpi_procs_per_machine) != number_engines:
        raise click.BadParameter(
            f'{process_class.__name__} has {number_engines} engine steps, so requires {number_engines} values',
            param_hint='--number-mpi-procs-per-machine')

    if number_cores_per_mpiproc is not None and len(
            number_cores_per_mpiproc) != number_engines:
        raise click.BadParameter(
            f'{process_class.__name__} has {number_engines} engine steps, so requires {number_engines} values',
            param_hint='--number-cores-per-mpiproc')

    if wallclock_seconds is None:
        wallclock_seconds = [1 * 3600] * number_engines

    if len(wallclock_seconds) != number_engines:
        raise click.BadParameter(
            f'{process_class.__name__} has {number_engines} engine steps, so requires {number_engines} values',
            param_hint='--wallclock-seconds')

    if not generator.is_valid_protocol(protocol):
        protocols = generator.get_protocol_names()
        process_class_name = process_class.__name__
        message = f'`{protocol}` is not implemented by `{process_class_name}` workflow: choose one of {protocols}'
        raise click.BadParameter(message, param_hint='protocol')

    if show_engines:
        for engine, port in generator.spec().inputs['engines'].items():
            click.secho(engine, fg='red', bold=True)
            click.echo(f'Required code plugin: {port["code"].entry_point}')
            click.echo(f'Engine description:   {port.help}')

        return

    validate_engine_options(engine_options, generator.spec().inputs['engines'])

    engines = {}

    for index, engine in enumerate(generator.spec().inputs['engines']):
        port = generator.spec().inputs['engines'][engine]
        entry_point = port['code'].code_entry_point
        code = utils.get_code_from_list_or_database(codes or [], entry_point)

        if code is None:
            raise click.UsageError(
                f'could not find a configured code for the plugin `{entry_point}`. '
                'Either provide it with the -X option or make sure such a code is configured in the DB.'
            )

        all_options = {
            'resources': {
                'num_machines': number_machines[index],
            },
            'max_wallclock_seconds': wallclock_seconds[index],
        }
        all_options.update(engine_options.get(engine, {}))

        engines[engine] = {'code': code.full_label, 'options': all_options}

        if number_mpi_procs_per_machine is not None:
            engines[engine]['options']['resources'][
                'num_mpiprocs_per_machine'] = number_mpi_procs_per_machine[
                    index]
            if number_mpi_procs_per_machine[index] > 1:
                engines[engine]['options']['withmpi'] = True

        if number_cores_per_mpiproc is not None:
            engines[engine]['options']['resources'][
                'num_cores_per_mpiproc'] = number_cores_per_mpiproc[index]

    inputs = {
        'structure': structure,
        'engines': engines,
        'protocol': protocol,
        'spin_type': spin_type,
        'relax_type': relax_type,
        'electronic_type': electronic_type,
    }

    if threshold_forces is not None:
        inputs['threshold_forces'] = threshold_forces

    if threshold_stress is not None:
        inputs['threshold_stress'] = threshold_stress

    if magnetization_per_site is not None:
        inputs['magnetization_per_site'] = magnetization_per_site

    if reference_workchain is not None:
        inputs['reference_workchain'] = reference_workchain

    builder = generator.get_builder(**inputs)
    utils.launch_process(builder, daemon)