def connect_to_engines(nengines): """ Accept connection(s) from the MDI engine(s) and perform basic validation of the connection. Parameters --------- nengines : int The number of MDI engines to connect to. Returns ------- engine_comm : list a list of MDI_Comm values """ # Confirm that this code is being used as a driver role = mdi.MDI_Get_Role() if not role == mdi.MDI_DRIVER: raise Exception("Must run driver_py.py as a DRIVER") # Connect to the engine engine_comm = [] for iengine in range(nengines): comm = mdi.MDI_Accept_Communicator() engine_comm.append(comm) # Verify the engine names for iengine in range(nengines): comm = engine_comm[iengine] # Determine the name of the engine mdi.MDI_Send_Command("<NAME", comm) name = mdi.MDI_Recv(mdi.MDI_NAME_LENGTH, mdi.MDI_CHAR, comm) print(f"Engine name: {name}") if name[:8] != "NO_EWALD": raise Exception("Unrecognized engine name", name) return engine_comm
def collect_task(comm, snapshot_coords, snap_num, output): mdi.MDI_Recv(3 * npoles * len(probes), mdi.MDI_DOUBLE, comm, buf=dfield) # Get the pairwise UFIELD ufield = np.zeros((len(probes), npoles, 3)) mdi.MDI_Send_Command("<UFIELD", comm) mdi.MDI_Recv(3 * npoles * len(probes), mdi.MDI_DOUBLE, comm, buf=ufield) # Sum the appropriate values columns = ['Probe Atom', 'Probe Coordinates'] columns += [F'{by_type} {x}' for x in from_fragment] dfield_df = pd.DataFrame(columns=columns, index=range(len(probes))) ufield_df = pd.DataFrame(columns=columns, index=range(len(probes))) totfield_df = pd.DataFrame(columns=columns, index=range(len(probes))) # Get sum at each probe from fragment. for i in range(len(probes)): dfield_df.loc[i, 'Probe Atom'] = probes[i] dfield_df.loc[i, 'Probe Coordinates'] = snapshot_coords[probes[i] - 1] ufield_df.loc[i, 'Probe Atom'] = probes[i] ufield_df.loc[i, 'Probe Coordinates'] = snapshot_coords[probes[i] - 1] totfield_df.loc[i, 'Probe Atom'] = probes[i] totfield_df.loc[i, 'Probe Coordinates'] = snapshot_coords[probes[i] - 1] for fragment_index, fragment in enumerate(atoms_pole_numbers): fragment_string = F'{by_type} {from_fragment[fragment_index]}' # This uses a numpy array (fragments) for indexing. The fragments # array lists pole indices in that fragment. We subtract 1 because # python indexes from zero. dfield_df.loc[i, fragment_string] = dfield[i, fragment - 1].sum(axis=0) ufield_df.loc[i, fragment_string] = ufield[i, fragment - 1].sum(axis=0) totfield_df.loc[i, fragment_string] = dfield_df.loc[i, fragment_string] + \ ufield_df.loc[i, fragment_string] # Pairwise probe calculation - Get avg electric field count = 0 for i in range(len(probes)): for j in range(i + 1, len(probes)): avg_field = (totfield_df.iloc[i, 2:] + totfield_df.iloc[j, 2:]) / 2 coord1 = totfield_df.loc[i, 'Probe Coordinates'] coord2 = totfield_df.loc[j, 'Probe Coordinates'] # Unit vector dir_vec = (coord2 - coord1) / np.linalg.norm(coord2 - coord1) #print(avg_field) efield_at_point = [] label = [] for column_name, column_value in avg_field.iteritems(): efield_at_point.append( np.dot(column_value, dir_vec) * conversion_factor) label.append(column_name) count += 1 series = pd.Series(efield_at_point, index=label) output = pd.concat([output, series], axis=1) cols = list(output.columns) cols[-1] = F'{probes[i]} and {probes[j]} - frame {snap_num}' output.columns = cols return output
# Print the probe atoms print(F"Probes: {probes}") elapsed = time.time() - start print(F'Setup:\t {elapsed}') ########################################################################### # # Get Information from Tinker # ########################################################################### # Get the number of atoms mdi.MDI_Send_Command("<NATOMS", engine_comm[0]) natoms_engine = mdi.MDI_Recv(1, mdi.MDI_INT, engine_comm[0]) print(F"natoms: {natoms_engine}") # Get the number of multipole centers mdi.MDI_Send_Command("<NPOLES", engine_comm[0]) npoles = mdi.MDI_Recv(1, mdi.MDI_INT, engine_comm[0]) print("npoles: " + str(npoles)) # Get the indices of the mulitpole centers per atom mdi.MDI_Send_Command("<IPOLES", engine_comm[0]) ipoles = mdi.MDI_Recv(natoms_engine, mdi.MDI_INT, engine_comm[0]) # Get the molecule information mdi.MDI_Send_Command("<MOLECULES", engine_comm[0]) molecules = np.array( mdi.MDI_Recv(natoms_engine, mdi.MDI_INT, engine_comm[0]))
# Print the probe atoms print(F"Probes: {probes}") elapsed = time.time() - start print(F'Setup:\t {elapsed}') ########################################################################### # # Get Information from Tinker # ########################################################################### # Get the number of atoms mdi.MDI_Send_Command("<NATOMS", engine_comm[0]) natoms_engine = mdi.MDI_Recv(1, mdi.MDI_INT, engine_comm[0]) print(F"natoms: {natoms_engine}") # Get the number of multipole centers mdi.MDI_Send_Command("<NPOLES", engine_comm[0]) npoles = mdi.MDI_Recv(1, mdi.MDI_INT, engine_comm[0]) print("npoles: " + str(npoles)) # Get the indices of the mulitpole centers per atom mdi.MDI_Send_Command("<IPOLES", engine_comm[0]) ipoles = mdi.MDI_Recv(natoms_engine, mdi.MDI_INT, engine_comm[0]) # Get the molecule information mdi.MDI_Send_Command("<MOLECULES", engine_comm[0]) molecules = np.array(mdi.MDI_Recv(natoms_engine, mdi.MDI_INT, engine_comm[0]))
def collect_task(comm, npoles, snapshot_coords, snap_num, atoms_pole_numbers, output): """ Receive all data associated with an engine's task. Parameters --------- comm : MDI_Comm The MDI communicator of the engine performing this task. npoles : int Number of poles involved in this calculation snapshot_coords : np.ndarray Nuclear coordinates at the snapshot associated with this task. snap_num : int The snapshot associated with this task. atoms_pole_numbers : list A multidimensional list where each element gives the pole indices in that fragment. output : pd.DataFrame The aggregated data from all tasks. Returns ------- output : pd.DataFrame The aggregated data from all tasks, including the data collected by this function. """ mdi.MDI_Recv(3 * npoles * len(probes), mdi.MDI_DOUBLE, comm, buf=dfield) # Get the pairwise UFIELD ufield = np.zeros((len(probes), npoles, 3)) mdi.MDI_Send_Command("<UFIELD", comm) mdi.MDI_Recv(3 * npoles * len(probes), mdi.MDI_DOUBLE, comm, buf=ufield) # Sum the appropriate values columns = ["Probe Atom", "Probe Coordinates"] columns += [f"{by_type} {x}" for x in from_fragment] dfield_df = pd.DataFrame(columns=columns, index=range(len(probes))) ufield_df = pd.DataFrame(columns=columns, index=range(len(probes))) totfield_df = pd.DataFrame(columns=columns, index=range(len(probes))) # Get sum at each probe from fragment. for i in range(len(probes)): dfield_df.loc[i, "Probe Atom"] = probes[i] dfield_df.loc[i, "Probe Coordinates"] = snapshot_coords[probes[i] - 1] ufield_df.loc[i, "Probe Atom"] = probes[i] ufield_df.loc[i, "Probe Coordinates"] = snapshot_coords[probes[i] - 1] totfield_df.loc[i, "Probe Atom"] = probes[i] totfield_df.loc[i, "Probe Coordinates"] = snapshot_coords[probes[i] - 1] for fragment_index, fragment in enumerate(atoms_pole_numbers): fragment_string = f"{by_type} {from_fragment[fragment_index]}" # This uses a numpy array (fragments) for indexing. The fragments # array lists pole indices in that fragment. We subtract 1 because # python indexes from zero. dfield_df.loc[i, fragment_string] = dfield[i, fragment - 1].sum(axis=0) ufield_df.loc[i, fragment_string] = ufield[i, fragment - 1].sum(axis=0) totfield_df.loc[i, fragment_string] = ( dfield_df.loc[i, fragment_string] + ufield_df.loc[i, fragment_string]) # Pairwise probe calculation - Get avg electric field count = 0 for i in range(len(probes)): for j in range(i + 1, len(probes)): avg_field = (totfield_df.iloc[i, 2:] + totfield_df.iloc[j, 2:]) / 2 coord1 = totfield_df.loc[i, "Probe Coordinates"] coord2 = totfield_df.loc[j, "Probe Coordinates"] # Unit vector dir_vec = (coord2 - coord1) / np.linalg.norm(coord2 - coord1) # print(avg_field) efield_at_point = [] label = [] for column_name, column_value in avg_field.iteritems(): efield_at_point.append( np.dot(column_value, dir_vec) * conversion_factor) label.append(column_name) count += 1 series = pd.Series(efield_at_point, index=label) output = pd.concat([output, series], axis=1) cols = list(output.columns) cols[-1] = f"{probes[i]} and {probes[j]} - frame {snap_num}" output.columns = cols return output
upper_window = 8.0 * angstrom_to_atomic lower_window = 2.4 * angstrom_to_atomic k_restraint = 10 * kcalmol_per_angstrom_to_atomic verbose = False s_of_t = [] # value of collective variable at time t' # Creat a plot of the results my_plot = pl.AnimatedPlot(kcalmol_to_atomic, angstrom_to_atomic) # Connect to the engines comm = mdi.MDI_Accept_Communicator() # Perform the simulation mdi.MDI_Send_Command("<NAME", comm) name = mdi.MDI_Recv(mdi.MDI_NAME_LENGTH, mdi.MDI_CHAR, comm) print("ENGINE NAME: " + str(name)) # Get the number of atoms mdi.MDI_Send_Command("<NATOMS", comm) natoms = mdi.MDI_Recv(1, mdi.MDI_INT, comm) # Get the number of masses mdi.MDI_Send_Command("<MASSES", comm) masses = mdi.MDI_Recv(natoms, mdi.MDI_DOUBLE, comm) # Initialize an MD simulation mdi.MDI_Send_Command("@INIT_MD", comm) print("MD Simulation successfully initialized")