Пример #1
0
def perform_aimd(world, mm_comm, qm_comm):

    me = world.Get_rank()

    # receive number of atoms from the MM engine

    mdi.MDI_Send_command("<NATOMS", mm_comm)
    natoms = mdi.MDI_Recv(1, mdi.MDI_INT, mm_comm)
    natoms = world.bcast(natoms, root=0)

    # allocate arrays for coordinates and forces

    coords = np.zeros(3 * natoms, dtype=np.float64)
    forces = np.zeros(3 * natoms, dtype=np.float64)

    # MM engine initializes a new MD simulation

    mdi.MDI_Send_command("@INIT_MD", mm_comm)

    # -----------------
    # compute initial forces for Verlet timestepping
    #   and initial energy for output on step 0
    # -----------------

    # MM engine proceeds to @FORCES node in setup()

    mdi.MDI_Send_command("@FORCES", mm_comm)

    # get coords from MM engine

    mdi.MDI_Send_command("<COORDS", mm_comm)
    mdi.MDI_Recv(3 * natoms, mdi.MDI_DOUBLE, mm_comm, buf=coords)
    world.Bcast(coords, root=0)

    # send coords to QM engine

    mdi.MDI_Send_command(">COORDS", qm_comm)
    mdi.MDI_Send(coords, 3 * natoms, mdi.MDI_DOUBLE, qm_comm)

    # get QM potential energy

    mdi.MDI_Send_command("<PE", qm_comm)
    qm_pe = mdi.MDI_Recv(1, mdi.MDI_DOUBLE, qm_comm)
    qm_pe = world.bcast(qm_pe, root=0)

    # get forces from QM engine

    mdi.MDI_Send_command("<FORCES", qm_comm)
    mdi.MDI_Recv(3 * natoms, mdi.MDI_DOUBLE, qm_comm, buf=forces)
    world.Bcast(forces, root=0)

    # send forces to MM engine

    mdi.MDI_Send_command(">FORCES", mm_comm)
    mdi.MDI_Send(forces, 3 * natoms, mdi.MDI_DOUBLE, mm_comm)

    # get MM kinetic energy

    mdi.MDI_Send_command("<KE", mm_comm)
    mm_ke = mdi.MDI_Recv(1, mdi.MDI_DOUBLE, mm_comm)
    mm_ke = world.bcast(mm_ke, root=0)

    # output by driver
    # normalize energies by atom count

    if me == 0:
        print("Step %d: MM energy %g, QM energy %g, Total energy %g" % \
              (0,mm_ke/natoms,qm_pe/natoms,(mm_ke+qm_pe)/natoms))

    # -----------------
    # timestepping loop
    # -----------------

    for istep in range(nsteps):

        # MM engine proceeds to @FORCES node

        mdi.MDI_Send_command("@FORCES", mm_comm)

        # get coords from MM engine

        mdi.MDI_Send_command("<COORDS", mm_comm)
        mdi.MDI_Recv(3 * natoms, mdi.MDI_DOUBLE, mm_comm, buf=coords)
        world.Bcast(coords, root=0)

        # send coords to QM engine

        mdi.MDI_Send_command(">COORDS", qm_comm)
        mdi.MDI_Send(coords, 3 * natoms, mdi.MDI_DOUBLE, qm_comm)

        # get QM potential energy

        mdi.MDI_Send_command("<PE", qm_comm)
        qm_pe = mdi.MDI_Recv(1, mdi.MDI_DOUBLE, qm_comm)
        qm_pe = world.bcast(qm_pe, root=0)

        # get forces from QM engine

        mdi.MDI_Send_command("<FORCES", qm_comm)
        mdi.MDI_Recv(3 * natoms, mdi.MDI_DOUBLE, qm_comm, buf=forces)
        world.Bcast(forces, root=0)

        # send forces to MM engine

        mdi.MDI_Send_command(">FORCES", mm_comm)
        mdi.MDI_Send(forces, 3 * natoms, mdi.MDI_DOUBLE, mm_comm)

        # MM engine proceeds to @ENDSTEP node
        # so that KE will be for fully updated velocity

        mdi.MDI_Send_command("@ENDSTEP", mm_comm)

        # get MM kinetic energy

        mdi.MDI_Send_command("<KE", mm_comm)
        mm_ke = mdi.MDI_Recv(1, mdi.MDI_DOUBLE, mm_comm)
        mm_ke = world.bcast(mm_ke, root=0)

        # output by driver
        # normalize energies by atom count

        if me == 0:
            print("Step %d: MM energy %g, QM energy %g, Total energy %g" % \
                  (istep+1,mm_ke/natoms,qm_pe/natoms,(mm_ke+qm_pe)/natoms))

    #  send EXIT to each engine

    mdi.MDI_Send_command("EXIT", mm_comm)
    mdi.MDI_Send_command("EXIT", qm_comm)
Пример #2
0
def perform_tasks(world, mdicomm, dummy):

    me = world.Get_rank()
    nprocs = world.Get_size()

    # allocate vectors for per-atom types, coords, vels, forces

    natoms = nx * ny * nz
    atypes = np.zeros(natoms, dtype=np.int)
    coords = np.zeros(3 * natoms, dtype=np.float64)
    vels = np.zeros(3 * natoms, dtype=np.float64)
    forces = np.zeros(3 * natoms, dtype=np.float64)

    atypes[:] = 1

    # initialize RN generator

    random.seed(seed)

    # loop over sequence of calculations

    for icalc in range(ncalc):

        # define simulation box

        onerho = rho + (random.random() - 0.5) * rhodelta
        sigma = pow(1.0 / onerho, 1.0 / 3.0)

        xlo = ylo = zlo = 0.0
        xhi = nx * sigma
        yhi = ny * sigma
        zhi = nz * sigma

        # send simulation box to engine

        vec = [xhi - xlo, 0.0, 0.0] + [0.0, yhi - ylo, 0.0
                                       ] + [0.0, 0.0, zhi - zlo]
        mdi.MDI_Send_command(">CELL", mdicomm)
        mdi.MDI_Send(vec, 9, mdi.MDI_DOUBLE, mdicomm)

        # create atoms on perfect lattice

        m = 0
        for k in range(nz):
            for j in range(ny):
                for i in range(nx):
                    coords[m] = i * sigma
                    coords[m + 1] = j * sigma
                    coords[m + 2] = k * sigma
                    m += 3

        # perturb lattice

        for m in range(3 * natoms):
            coords[m] += 2.0 * random.random() * delta - delta

        # define initial velocities

        for m in range(3 * natoms):
            vels[m] = random.random() - 0.5

        tcurrent = 0.0
        for m in range(3 * natoms):
            tcurrent += vels[m] * vels[m]
        tcurrent /= 3 * (natoms - 1)

        factor = math.sqrt(tinitial / tcurrent)

        for m in range(3 * natoms):
            vels[m] *= factor

        # send atoms and their properties to engine

        mdi.MDI_Send_command(">NATOMS", mdicomm)
        mdi.MDI_Send(natoms, 1, mdi.MDI_INT, mdicomm)
        mdi.MDI_Send_command(">TYPES", mdicomm)
        mdi.MDI_Send(atypes, natoms, mdi.MDI_INT, mdicomm)
        mdi.MDI_Send_command(">COORDS", mdicomm)
        mdi.MDI_Send(coords, 3 * natoms, mdi.MDI_DOUBLE, mdicomm)
        mdi.MDI_Send_command(">VELOCITIES", mdicomm)
        mdi.MDI_Send(vels, 3 * natoms, mdi.MDI_DOUBLE, mdicomm)

        # eval or run or minimize

        if mode == "eval":
            pass
        elif mode == "run":
            mdi.MDI_Send_command(">NSTEPS", mdicomm)
            mdi.MDI_Send(nsteps, 1, mdi.MDI_INT, mdicomm)
            mdi.MDI_Send_command("MD", mdicomm)
        elif mode == "min":
            mdi.MDI_Send_command(">TOLERANCE", mdicomm)
            params = [tol, tol, 1000.0, 1000.0]
            mdi.MDI_Send(params, 4, mdi.MDI_DOUBLE, mdicomm)
            mdi.MDI_Send_command("OPTG", mdicomm)

        # request potential energy

        mdi.MDI_Send_command("<PE", mdicomm)
        pe = mdi.MDI_Recv(1, mdi.MDI_DOUBLE, mdicomm)
        pe = world.bcast(pe, root=0)

        # request virial tensor

        mdi.MDI_Send_command("<STRESS", mdicomm)
        virial = mdi.MDI_Recv(9, mdi.MDI_DOUBLE, mdicomm)
        virial = world.bcast(virial, root=0)

        # request forces

        mdi.MDI_Send_command("<FORCES", mdicomm)
        mdi.MDI_Recv(3 * natoms, mdi.MDI_DOUBLE, mdicomm, buf=forces)
        world.Bcast(forces, root=0)

        # final output from each calculation
        # pressure = trace of virial tensor, no kinetic component

        aveeng = pe / natoms
        pressure = (virial[0] + virial[4] + virial[8]) / 3.0

        m = 0
        fx = fy = fz = 0.0
        for i in range(natoms):
            fx += forces[m]
            fy += forces[m + 1]
            fz += forces[m + 2]
            m += 3

        fx /= natoms
        fy /= natoms
        fz /= natoms

        line = "Calc %d: eng %7.5g pressure %7.5g aveForce %7.5g %7.5g %7.5g" % \
               (icalc+1,aveeng,pressure,fx,fy,fz)
        if me == 0: print(line)

    # send EXIT command to engine
    # in plugin mode, removes the plugin library

    mdi.MDI_Send_command("EXIT", mdicomm)

    # return needed for plugin mode

    return 0
Пример #3
0
if not mdiarg: error()

# LAMMPS engines are stand-alone codes
# world = MPI communicator for just this driver
# invoke perform_tasks() directly

if not plugin:
    mdi.MDI_Init(mdiarg)
    world = mdi.MDI_MPI_get_world_comm()

    # connect to 2 engines, determine which is MM vs QM

    mdicomm1 = mdi.MDI_Accept_Communicator()
    mdicomm2 = mdi.MDI_Accept_Communicator()

    mdi.MDI_Send_command("<NAME", mdicomm1)
    name1 = mdi.MDI_Recv(mdi.MDI_NAME_LENGTH, mdi.MDI_CHAR, mdicomm1)
    name1 = world.bcast(name1, root=0)
    mdi.MDI_Send_command("<NAME", mdicomm2)
    name2 = mdi.MDI_Recv(mdi.MDI_NAME_LENGTH, mdi.MDI_CHAR, mdicomm2)
    name2 = world.bcast(name2, root=0)

    if name1 == "MM" and name2 == "QM":
        mm_comm = mdicomm1
        qm_comm = mdicomm2
    elif name1 == "QM" and name2 == "MM":
        mm_comm = mdicomm2
        qm_comm = mdicomm1
    else:
        error("Two engines have invalid names")