Example #1
0
    def __init__(self, scf_method, **kwargs):
        """ Initialize an MDIEngine object for communication with MDI

        Arguments:
           scf_method: Method used when calculating energies or gradients
        """

        # Method used when the SCF command is received
        self.scf_method = scf_method

        # Additional arguments for energy, gradient, or optimization calculations
        self.kwargs = kwargs

        # Molecule all MDI operations are performed on
        input_molecule = kwargs.pop('molecule',
                                    psi4.core.get_active_molecule())
        self.molecule = input_molecule.clone()
        psi4.core.set_active_molecule(self.molecule)

        # Most recent SCF energy
        self.energy = 0.0

        # Variables used when MDI sets a lattice of point charges
        self.nlattice = 0  # number of lattice point charges
        self.clattice = []  # list of lattice coordinates
        self.lattice = []  # list of lattice charges
        self.lattice_field = psi4.QMMM()  # Psi4 chargefield

        # MPI variables
        self.mpi_world = None
        self.world_rank = 0

        # Flag for if a lattice of point charges has been set
        self.set_lattice = False

        # Get correct intra-code MPI communicator
        if use_mpi4py:
            self.mpi_world = MDI_MPI_get_world_comm()
            self.world_rank = self.mpi_world.Get_rank()

            # Psi4 does not currently support multiple MPI ranks
            if self.mpi_world.Get_size() != 1:
                MPI.COMM_WORLD.Abort()

        # Accept a communicator to the driver code
        self.comm = MDI_Accept_Communicator()

        # Ensure that the molecule is using c1 symmetry
        self.molecule.reset_point_group('c1')
        self.molecule.fix_orientation(True)
        self.molecule.fix_com(True)
        self.molecule.reinterpret_coordentry(False)
        self.molecule.update_geometry()

        # Flag to stop listening for MDI commands
        self.stop_listening = False

        # Dictionary of all supported MDI commands
        self.commands = {
            "<NATOMS": self.send_natoms,
            "<COORDS": self.send_coords,
            "<CHARGES": self.send_charges,
            "<ELEMENTS": self.send_elements,
            "<MASSES": self.send_masses,
            "<ENERGY": self.send_energy,
            "<FORCES": self.send_forces,
            ">COORDS": self.recv_coords,
            ">NLATTICE": self.recv_nlattice,
            ">CLATTICE": self.recv_clattice,
            ">LATTICE": self.recv_lattice,
            ">MASSES": self.recv_masses,
            "SCF": self.run_scf,
            "<DIMENSIONS": self.send_dimensions,
            "<TOTCHARGE": self.send_total_charge,
            ">TOTCHARGE": self.recv_total_charge,
            "<ELEC_MULT": self.send_multiplicity,
            ">ELEC_MULT": self.recv_multiplicity,
            "EXIT": self.exit
        }

        # Register all the supported commands
        MDI_Register_Node("@DEFAULT")
        for command in self.commands.keys():
            MDI_Register_Command("@DEFAULT", command)
Example #2
0
    def __init__(
        self,
        mdi_options: str,
        program: str,
        molecule,
        model,
        keywords,
        raise_error: bool = False,
        local_options: Optional[Dict[str, Any]] = None,
    ):
        """Initialize an MDIServer object for communication with MDI

        Parameters
        ----------
        mdi_options: str
            Options used during MDI initialization.
        program : str
            The program to execute the input with.
        molecule
            The initial state of the molecule.
        model
            The simulation model to use.
        keywords
            Program-specific keywords.
        raise_error : bool, optional
            Determines if compute should raise an error or not.
        local_options : Optional[Dict[str, Any]], optional
            A dictionary of local configuration options
        """

        if not use_mdi:
            raise Exception(
                "Trying to run as an MDI engine, but the MDI Library was not found"
            )

        if MDI_MAJOR_VERSION < 1:
            raise Exception(
                "QCEngine requires version 1.0.0 or higher of the MDI Library")

        # Confirm that the MDI library has been located
        which_import(
            "mdi",
            raise_error=True,
            raise_msg="Please install via 'conda install pymdi -c conda-forge'"
        )

        # Initialize MDI
        MDI_Init(mdi_options)

        # Input variables
        self.molecule = molecule
        self.model = model
        self.keywords = keywords
        self.program = program
        self.raise_error = raise_error
        self.local_options = local_options

        # The MDI interface does not currently support multiple fragments
        if len(self.molecule.fragments) != 1:
            raise Exception(
                "The MDI interface does not support multiple fragments")

        # Molecule charge and multiplicity
        self.total_charge = self.molecule.molecular_charge
        self.multiplicity = self.molecule.molecular_multiplicity

        # Flag to track whether the latest molecule specification has been validated
        self.molecule_validated = True

        # Output of most recent compute call
        self.compute_return = None

        # MPI variables
        self.mpi_world = None
        self.world_rank = 0

        # Get correct intra-code MPI communicator
        if use_mpi4py:
            self.mpi_world = MDI_MPI_get_world_comm()
            self.world_rank = self.mpi_world.Get_rank()

            # QCEngine does not currently support multiple MPI ranks
            if self.mpi_world.Get_size() != 1:
                MPI.COMM_WORLD.Abort()

        # Flag to stop listening for MDI commands
        self.stop_listening = False

        # Dictionary of all supported MDI commands
        self.commands = {
            "<@": self.send_node,
            "<NATOMS": self.send_natoms,
            "<COORDS": self.send_coords,
            "<ENERGY": self.send_energy,
            "<FORCES": self.send_forces,
            ">COORDS": self.recv_coords,
            "SCF": self.run_energy,
            "<ELEMENTS": self.send_elements,
            ">ELEMENTS": self.recv_elements,
            "<MASSES": self.send_masses,
            ">MASSES": self.recv_masses,
            "<TOTCHARGE": self.send_total_charge,
            ">TOTCHARGE": self.recv_total_charge,
            "<ELEC_MULT": self.send_multiplicity,
            ">ELEC_MULT": self.recv_multiplicity,
            "EXIT": self.stop,
        }

        # Register the @DEFAULT node
        MDI_Register_Node("@DEFAULT")

        # Register all supported commands
        for c in self.commands.keys():
            MDI_Register_Command("@DEFAULT", c)

        # Set the current node
        self.current_node = "@DEFAULT"

        # Accept a communicator to the driver code
        self.comm = MDI_Accept_Communicator()