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)
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()