コード例 #1
0
    def build_input(
        self,
        input_model: AtomicInput,
        config: "TaskConfig",
        template: Optional[str] = None,
    ) -> Dict[str, Any]:
        """
        Use the template files stored in QUBEKit to build a gaussian input file for the given driver.
        """
        import os

        from jinja2 import Template

        template_file = get_data(os.path.join("templates", "gaussian.com"))
        with open(template_file) as file:
            template = Template(file.read())

        template_data = {
            "memory": int(config.memory),
            "threads": config.ncores,
            "driver": self.driver_conversion(driver=input_model.driver),
            "title": "gaussian job",
        }
        molecule = input_model.molecule
        spec = input_model.model
        theory = self.functional_converter(method=spec.method)
        template_data["theory"] = theory
        template_data["basis"] = spec.basis
        template_data["charge"] = int(molecule.molecular_charge)
        template_data["multiplicity"] = molecule.molecular_multiplicity
        template_data["scf_maxiter"] = input_model.extras.get("maxiter", 300)
        # work around for extra cmdline args
        template_data["cmdline_extra"] = input_model.keywords.get(
            "cmdline_extra", [])
        # work around for extra trailing input
        template_data["add_input"] = input_model.keywords.get("add_input", [])
        template_data.update(input_model.keywords)
        # now we need to build the coords data
        data = []
        for i, symbol in enumerate(molecule.symbols):
            # we must convert the atomic input back to angstroms
            data.append(
                (symbol, molecule.geometry[i] * constants.BOHR_TO_ANGS))
        template_data["data"] = data

        rendered_template = template.render(**template_data)
        return {
            "infiles": {
                "gaussian.com": rendered_template
            },
            "scratch_directory": config.scratch_directory,
            "input_result": input_model.copy(deep=True),
        }
コード例 #2
0
def atomic_input_to_job_input(atomic_input: AtomicInput) -> pb.JobInput:
    """Convert AtomicInput to JobInput"""
    # Don't mutate original atomic_input object
    ai_copy = atomic_input.copy(deep=True)

    # Create Mol instance
    mol_msg = pb.Mol()
    mol_msg.atoms.extend(ai_copy.molecule.symbols)
    mol_msg.xyz.extend(ai_copy.molecule.geometry.flatten())
    mol_msg.units = pb.Mol.UnitType.BOHR  # Molecule always in bohr
    mol_msg.charge = int(ai_copy.molecule.molecular_charge)
    mol_msg.multiplicity = ai_copy.molecule.molecular_multiplicity
    mol_msg.closed = ai_copy.keywords.pop("closed_shell", True)
    mol_msg.restricted = ai_copy.keywords.pop("restricted", True)
    # Drop keyword terms already applied from Molecule object
    ai_copy.keywords.pop("charge", None)  # mol_msg.charge
    ai_copy.keywords.pop("spinmult", None)  # mol_msg.multiplicity

    # Create JobInput message
    ji = pb.JobInput(mol=mol_msg)
    # Set driver
    driver = ai_copy.driver.upper()
    if driver not in SUPPORTED_DRIVERS:
        # Only support QCEngine supported drivers; energy, gradient, hessian, properties
        raise ValueError(
            f"Driver '{driver}' not supported, please select from {SUPPORTED_DRIVERS}"
        )
    ji.run = pb.JobInput.RunType.Value(driver)
    # Set Method
    ji.method = pb.JobInput.MethodType.Value(ai_copy.model.method.upper())
    # Set Basis
    ji.basis = ai_copy.model.basis

    # Get keywords that have specific protobuf fields
    ji.return_bond_order = ai_copy.keywords.pop("bond_order", False)
    # Request AO and MO information
    if ai_copy.keywords.pop("mo_output", False):
        ji.imd_orbital_type = pb.JobInput.ImdOrbitalType.WHOLE_C

    # Set all other keywords under the "user_options" catch all
    for key, value in ai_copy.keywords.items():
        ji.user_options.extend([key, str(value)])

    return ji