def mdi_checks(mdi_engine, nengines): """ Perform checks on the MDI driver we have accepted to make sure it fits this analysis. """ # Confirm that this code is being used as a driver role = mdi_engine.MDI_Get_Role() if not role == mdi_engine.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_engine.MDI_Send_Command("<NAME", comm) name = mdi_engine.MDI_Recv(mdi.MDI_NAME_LENGTH, mdi.MDI_CHAR, comm) print(F"Engine name: {name}") if name != "NO_EWALD": raise Exception("Unrecognized engine name", name) return engine_comm
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
########################################################################### # # Handle user arguments # ########################################################################### start = time.time() parser = create_parser() args = parser.parse_args() nengines = args.nengines equil = args.equil stride = args.stride # Process args for MDI mdi.MDI_Init(args.mdi, mpi_world) if use_mpi4py: mpi_world = mdi.MDI_Get_Intra_Code_MPI_Comm() world_rank = mpi_world.Get_rank() snapshot_filename = args.snap probes = [int(x) for x in args.probes.split()] if args.byres and args.bymol: parser.error( "--byres and --bymol cannot be used together. Please only use one." ) if args.byres: residues = process_pdb(args.byres)[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
arg = sys.argv[iarg] if arg == "-mdi": mdi_options = sys.argv[iarg + 1] iarg += 1 else: raise Exception("Unrecognized command-line option") iarg += 1 # Confirm that the MDI options were provided if mdi_options is None: raise Exception("-mdi command-line option was not provided") # Initialize the MDI Library mdi.MDI_Init(mdi_options, mpi_comm_world) # Get unit conversions colvar = distance.Distance(319, 320) kcalmol_to_atomic = mdi.MDI_Conversion_Factor("kilocalorie_per_mol", "atomic_unit_of_energy") angstrom_to_atomic = mdi.MDI_Conversion_Factor("angstrom", "atomic_unit_of_length") kcalmol_per_angstrom_to_atomic = kcalmol_to_atomic / angstrom_to_atomic # Input parameters width = 0.2 * angstrom_to_atomic # Gaussian width of first collective variable height = 0.1 * kcalmol_to_atomic # Gaussian height of first collective variable total_steps = 8000 # Number of MD iterations. Note timestep = 2fs tau_gaussian = 400 # Frequency of addition of Gaussians upper_restraint = 14.0 * angstrom_to_atomic