예제 #1
0
def minimize(parm, igb, saltcon, cutoff, tol, maxcyc):
    """ Minimizes a snapshot. Use the existing System if it exists """
    if not HAS_SANDER:
        raise SimulationError('Could not import sander')
    if not HAS_SCIPY:
        raise SimulationError('Could not import scipy')

    if parm.box is None:
        if not igb in (0, 1, 2, 5, 6, 7, 8):
            raise SimulationError('Bad igb value. Must be 0, 1, 2, 5, '
                                  '6, 7, or 8')
        if cutoff is None: cutoff = 999.0
        inp = sander.gas_input(igb)
        inp.saltcon = saltcon
        inp.cut = cutoff
    else:
        if cutoff is None: cutoff = 8.0
        inp = sander.pme_input()
        inp.cut = cutoff

    # Define the objective function to minimize
    def energy_function(xyz):
        sander.set_positions(xyz)
        e, f = sander.energy_forces()
        return e.tot, -np.array(f)
    with sander.setup(parm, parm.coordinates, parm.box, inp):
        options = dict(maxiter=maxcyc, disp=True, gtol=tol)
        results = optimize.minimize(energy_function, parm.coordinates,
                                    method='L-BFGS-B', jac=True,
                                    options=options)
        parm.coordinates = results.x
    if not results.success:
        print('Problem minimizing structure with scipy and sander:',
              file=sys.stderr)
        print('\t' + results.message)
예제 #2
0
def minimize(parm, igb, saltcon, cutoff, tol, maxcyc, disp=True, callback=None):
    """ Minimizes a snapshot. Use the existing System if it exists """
    if not HAS_SANDER:
        raise SimulationError('Could not import sander')
    if not HAS_SCIPY:
        raise SimulationError('Could not import scipy')

    if parm.box is None:
        if not igb in {0, 1, 2, 5, 6, 7, 8}:
            raise SimulationError('Bad igb value. Must be 0, 1, 2, 5, 6, 7, or 8')
        if cutoff is None: cutoff = 999.0
        inp = sander.gas_input(igb)
        inp.saltcon = saltcon
        inp.cut = cutoff
    else:
        if cutoff is None: cutoff = 8.0
        inp = sander.pme_input()
        inp.cut = cutoff

    # Define the objective function to minimize
    def energy_function(xyz):
        sander.set_positions(xyz)
        e, f = sander.energy_forces()
        return e.tot, -np.array(f)
    with sander.setup(parm, parm.coordinates, parm.box, inp):
        options = dict(maxiter=maxcyc, disp=disp, gtol=tol)
        more_options = dict()
        if callable(callback):
            more_options['callback'] = callback
        results = optimize.minimize(energy_function, parm.coordinates, method='L-BFGS-B', jac=True,
                                    options=options, **more_options)
        parm.coordinates = results.x
    if not results.success:
        LOGGER.error(f'Problem minimizing structure with scipy and sander: {results.message}')
예제 #3
0
def main():
    # require 'sanderapi' and 'parmed' packages in AmberTools15
    # http://ambermd.org/#AmberTools
    # more info about `sanderapi` in Amber15 manual
    # http://ambermd.org/doc12/Amber15.pdf (page 341)
    traj = io.iterload("../tests/data/Tc5b.x",
                       "../tests/data/Tc5b.top")
    print(traj)
    edict0 = pyca.energy_decomposition(parm="../tests/data/Tc5b.top",
                                       traj=traj,
                                       igb=8,
                                       input_options=None)
    print(edict0)

    # edict1: use default igb=8
    edict1 = pyca.energy_decomposition(traj=traj)
    print(edict1)

    aa_eq(edict0['tot'], edict1['tot'])

    # update `input` and get minimal output
    import sander
    inp = sander.gas_input(6)
    edict2 = pyca.energy_decomposition(traj, input_options=inp, mode='minimal')
    print(edict2)
예제 #4
0
    def test_GB_QMMM(self):
        # compare to saved test: GB + QMMM
        topfile = os.path.join(amberhome, "test/qmmm2/lysine_PM3_qmgb2/prmtop")
        rstfile = os.path.join(amberhome,
                               "test/qmmm2/lysine_PM3_qmgb2/lysine.crd")
        traj = pt.load(rstfile, topfile)

        options = sander.gas_input(1)
        options.cut = 99.0
        options.ifqnt = 1
        qm_options = sander.qm_input()
        qm_options.iqmatoms[:3] = [8, 9, 10]
        qm_options.qm_theory = "PM3"
        qm_options.qmcharge = 0
        qm_options.qmgb = 2
        qm_options.adjust_q = 0

        edict = pt.energy_decomposition(traj=traj,
                                        mm_options=options,
                                        qm_options=qm_options)
        assert_close(edict['bond'][0], 0.0016, tol=3E-4)
        assert_close(edict['vdw'][0], 0.1908, tol=3E-4)
        assert_close(edict['vdw_14'][0], 3.7051, tol=3E-4)
        assert_close(edict['elec'][0], -4.1241, tol=3E-4)
        assert_close(edict['elec_14'][0], 65.9137, tol=3E-4)
        assert_close(edict['gb'][0], -80.1406, tol=3E-4)
        assert_close(edict['scf'][0], -11.9100, tol=3E-4)
예제 #5
0
    def test_GB_QMMM(self):
        # compare to saved test: GB + QMMM
        topfile = os.path.join(amberhome, "test/qmmm2/lysine_PM3_qmgb2/prmtop")
        rstfile = os.path.join(amberhome,
                               "test/qmmm2/lysine_PM3_qmgb2/lysine.crd")
        traj = pt.load(rstfile, topfile)

        options = sander.gas_input(1)
        options.cut = 99.0
        options.ifqnt = 1
        qm_options = sander.qm_input()
        qm_options.iqmatoms[:3] = [8, 9, 10]
        qm_options.qm_theory = "PM3"
        qm_options.qmcharge = 0
        qm_options.qmgb = 2
        qm_options.adjust_q = 0

        edict = pt.energy_decomposition(traj=traj,
                                        mm_options=options,
                                        qm_options=qm_options)
        assert_close(edict['bond'][0], 0.0016, tol=3E-4)
        assert_close(edict['vdw'][0], 0.1908, tol=3E-4)
        assert_close(edict['vdw_14'][0], 3.7051, tol=3E-4)
        assert_close(edict['elec'][0], -4.1241, tol=3E-4)
        assert_close(edict['elec_14'][0], 65.9137, tol=3E-4)
        assert_close(edict['gb'][0], -80.1406, tol=3E-4)
        assert_close(edict['scf'][0], -11.9100, tol=3E-4)
예제 #6
0
    def test_mm_options_as_string(self):
        traj = pt.iterload(fn('tz2.nc'), fn('tz2.parm7'))
        igb = 8
        mm_options = sander.gas_input(igb)
        mm_options_str = 'mm_options = sander.gas_input(8)'

        e0 = pt.energy_decomposition(traj, mm_options=mm_options, dtype='dict')
        e1 = pt.energy_decomposition(traj,
                                     mm_options=mm_options_str,
                                     dtype='dict')
        assert sorted(e0) == sorted(e1)
    def test_update_dihedral_parm(self):
        traj = pt.iterload("./data/Tc5b.crd", fn('Tc5b.top'))
        p = pmd.load_file(traj.top.filename)
        inp = sander.gas_input(8)
        coords = traj[0].xyz

        with pt.utils.context.tempfolder():
            for k in range(20, 100):
                p.bonds[3].type.k = k
                p.remake_parm()
                with sander.setup(p, coords, None, inp):
                    ene, frc = sander.energy_forces()
예제 #8
0
 def test_gbneck2nu(self):
     # compare to saved test: GBneck2nu
     topfile = os.path.join(amberhome, "test/gbneck2nu/1hji/prmtop")
     rstfile = os.path.join(amberhome, "test/gbneck2nu/1hji/min.r")
     traj = pt.load(rstfile, topfile)
     options = sander.gas_input(8)
     options.cut = 9999.0
     edict = pt.esander(traj=traj, mm_options=options, prmtop=topfile)
     assert_close(edict['gb'][0], -2287.6880, tol=3E-4)
     assert_close(edict['gb'][0], -2287.6880, tol=3E-4)
     assert_close(edict['elec'][0], -1659.5740, tol=3E-4)
     assert_close(edict['vdw'][0], 384.2512, tol=3E-4)
예제 #9
0
    def test_update_dihedral_parm(self):
        traj = pt.iterload("./data/Tc5b.crd", "./data/Tc5b.top")
        p = pmd.load_file(traj.top.filename)
        inp = sander.gas_input(8)
        coords = traj[0].xyz

        fname = "tmp.parm7"

        with pt.utils.context.tempfolder():
            for k in range(20, 100):
                p.bonds[3].type.k = k
                p.remake_parm()
                with sander.setup(p, coords, None, inp):
                    ene, frc = sander.energy_forces()
예제 #10
0
 def test_gbneck2nu(self):
     # compare to saved test: GBneck2nu
     topfile = os.path.join(amberhome, "test/gbneck2nu/1hji/prmtop")
     rstfile = os.path.join(amberhome, "test/gbneck2nu/1hji/min.r")
     traj = pt.load(rstfile, topfile)
     options = sander.gas_input(8)
     options.cut = 9999.0
     edict = pt.energy_decomposition(traj=traj,
                                     mm_options=options,
                                     prmtop=topfile)
     assert_close(edict['gb'][0], -2287.6880, tol=3E-4)
     assert_close(edict['gb'][0], -2287.6880, tol=3E-4)
     assert_close(edict['elec'][0], -1659.5740, tol=3E-4)
     assert_close(edict['vdw'][0], 384.2512, tol=3E-4)
예제 #11
0
    def test_GB(self):
        # compare to saved test: GB
        topfile = os.path.join(amberhome, "test/gb7_trx/prmtop_an")
        rstfile = os.path.join(amberhome, "test/gb7_trx/trxox.2.4ns.x")
        traj = pt.load(rstfile, topfile)
        options = sander.gas_input(7)
        options.cut = 9999.0
        options.saltcon = 0.2
        options.gbsa = 1
        edict = pt.energy_decomposition(traj=traj,
                                        mm_options=options,
                                        prmtop=topfile)
        assert_close(edict['bond'][0], 631.8993, tol=3E-4)
        assert_close(edict['angle'][0], 898.2543, tol=3E-4)
        assert_close(edict['surf'][0], 33.8338, tol=3E-4)
        assert_close(edict['gb'][0], -1943.0838, tol=3E-4)

        # dummy test to make sure `energy_decomposition` can work with list
        edict2 = pt.energy_decomposition(traj=[
            traj,
        ],
                                         mm_options=options,
                                         prmtop=topfile,
                                         top=traj.top)
        edict3 = pt.energy_decomposition(traj=traj(),
                                         mm_options=options,
                                         prmtop=topfile,
                                         top=traj.top)
        edict4 = pt.energy_decomposition(traj=[traj[:5], traj[5:]],
                                         mm_options=options,
                                         prmtop=topfile,
                                         top=traj.top)
        edict5 = pt.energy_decomposition(traj=[traj[:5],
                                               traj(start=5)],
                                         mm_options=options,
                                         prmtop=topfile,
                                         top=traj.top)
        # test dtype
        dslist = pt.energy_decomposition(traj=[
            traj,
        ],
                                         mm_options=options,
                                         prmtop=topfile,
                                         top=traj.top,
                                         dtype='dataset')
        assert edict == edict2
        assert edict == edict3
        assert edict == edict4
        assert sorted(dslist.to_dict()) == sorted(edict)
예제 #12
0
def get_total_energy(agls):
    # get the coor from pyrosetta
    inp_coor=generate_coord(agls)
    # initialize the object topology with coordinates
    parm=AmberParm("tpp-1.prmtop",inp_coor)
    # set up the input options
    inp=sander.gas_input() 
    sander.setup (parm, parm.coordinates, None, inp)

    # compute the energy and force
    eney, frc=sander.energy_forces()
    # print('sander',eney.tot,eney.gb,eney.vdw, eney.elec, eney.dihedral,eney.angle, eney.bond)

    # clean and finish
    sander.cleanup()
    return eney.tot
예제 #13
0
    def test_GB(self):
        # compare to saved test: GB
        topfile = os.path.join(amberhome, "test/gb7_trx/prmtop_an")
        rstfile = os.path.join(amberhome, "test/gb7_trx/trxox.2.4ns.x")
        traj = pt.load(rstfile, topfile)
        options = sander.gas_input(7)
        options.cut = 9999.0
        options.saltcon = 0.2
        options.gbsa = 1
        edict = pt.energy_decomposition(traj=traj,
                                        mm_options=options,
                                        prmtop=topfile)
        assert_close(edict['bond'][0], 631.8993, tol=3E-4)
        assert_close(edict['angle'][0], 898.2543, tol=3E-4)
        assert_close(edict['surf'][0], 33.8338, tol=3E-4)
        assert_close(edict['gb'][0], -1943.0838, tol=3E-4)

        # dummy test to make sure `energy_decomposition` can work with list
        edict2 = pt.energy_decomposition(traj=[traj, ],
                                         mm_options=options,
                                         prmtop=topfile,
                                         top=traj.top)
        edict3 = pt.energy_decomposition(traj=traj(),
                                         mm_options=options,
                                         prmtop=topfile,
                                         top=traj.top)
        edict4 = pt.energy_decomposition(traj=[traj[:5], traj[5:]],
                                         mm_options=options,
                                         prmtop=topfile,
                                         top=traj.top)
        edict5 = pt.energy_decomposition(traj=[traj[:5], traj(start=5)],
                                         mm_options=options,
                                         prmtop=topfile,
                                         top=traj.top)
        # test dtype
        dslist = pt.energy_decomposition(traj=[traj, ],
                                         mm_options=options,
                                         prmtop=topfile,
                                         top=traj.top,
                                         dtype='dataset')
        assert edict == edict2
        assert edict == edict3
        assert edict == edict4
        assert sorted(dslist.to_dict()) == sorted(edict)
예제 #14
0
    def test_sander_pmap_with_options(self):
        '''need to write mm_options as text
        '''
        code_local = '''
        mm_options = sander.gas_input(8)
        '''

        traj = pt.iterload(fn('Tc5b.x'), fn('Tc5b.top'))

        for code in [code_global, code_local]:
            data_parallel = pt.pmap(pt.energy_decomposition,
                                    traj,
                                    mm_options=code,
                                    n_cores=3,
                                    dtype='dict')

            mm_options = sander.gas_input(8)
            data_serial = pt.energy_decomposition(traj,
                                                  mm_options=mm_options,
                                                  dtype='dict')
            aa_eq(pt.tools.dict_to_ndarray(data_parallel),
                  pt.tools.dict_to_ndarray(data_serial))
예제 #15
0
    def test_sander_pmap_with_options(self):
        '''need to write mm_options as text
        '''
        code_local = '''
        mm_options = sander.gas_input(8)
        '''

        traj = pt.iterload('./data/Tc5b.x', './data/Tc5b.top')

        for code in [code_global, code_local]:
            data_parallel = pt.pmap(pt.energy_decomposition,
                                    traj,
                                    mm_options=code,
                                    n_cores=3,
                                    dtype='dict')

            mm_options = sander.gas_input(8)
            data_serial = pt.energy_decomposition(traj,
                                                  mm_options=mm_options,
                                                  dtype='dict')
            aa_eq(
                pt.tools.dict_to_ndarray(data_parallel),
                pt.tools.dict_to_ndarray(data_serial))
예제 #16
0
   def sanderforce(self,parmstr,atmlst,boxflag=False,pmeflag=False):
      """Calculates energy and forces for a provided
         Amber parm string and set of coordinates using the Sander
         API. Also takes box dimensions and a flag for use of PME.
         Currently uses standard simulation options for gas phase or pme
         based on pmeflag.
         Only returns forces on first 2 atoms in atmlst
         Returns a sander energy object and a 3 x 2 x traj length array
         of forces with units"""

      self.forces=[]
      self.energies=[]
#      sander.APPLY_UNITS = True # More bugs/inconsistencies in pysander in amber15, may be fixed later
      indices = [a.idx for a in atmlst[:2]]
      if pmeflag is True:
#        These default options will be suitable in most cases
#        PME,cut=8.0,ntb=1,ntf=1,ntc=1
#        Should be adapted if shake is required (not important here for ele)
         inp = sander.pme_input()
      else:
         inp = sander.gas_input()
      for i in range(0,self.traj.frame):
         coord = self.traj.coordinates[i]
         if boxflag is True:
            box = self.traj.box[i]
#           print box
         else:
            box = None
         with sander.setup(parmstr,coord,box=box,mm_options=inp): #Pass a string, else a temp parmfile is created that fills up tmp directory!
            ene,frc = sander.energy_forces(as_numpy=False) # pysander __init__ bug/inconsistency, can't use as_numpy!
         frc = np.asarray(frc)
         frc = np.reshape(frc,((len(frc)/3.),3))
         frcslice = frc[indices]
         # Add units for forces: kcal mol-1 A-1
         frcslice = frcslice * u.kilocalorie / (u.mole * u.angstroms)
         self.forces.append(frcslice)
         self.energies.append(ene)
예제 #17
0
import numpy as np
import pytraj as pt
import sander

traj = pt.datafiles.load_tz2()

inp = sander.gas_input(8)

frcs = []

with sander.setup(traj.top.filename, traj[0].xyz, traj.top.box, inp):
    for frame in traj:
        sander.set_box(*frame.box.tolist())
        sander.set_positions(frame.xyz)
        ene, frc = sander.energy_forces()
        frcs.append(np.array(frc).reshape(traj.n_atoms, 3))


def get_frame_with_force(traj, forces=frcs):
    frame0 = pt.Frame()
    crdinfo = dict(has_force=True)

    frame0._allocate_force_and_velocity(traj.top, crdinfo)

    for frame, frc in zip(traj, frcs):
        frame0.xyz[:] = frame.xyz
        frame0.force[:] = frc
        yield frame0


pt.write_traj('traj.nc',
예제 #18
0
                   help='''Cutoff for nonbonded forces in Angstroms. Cutoff is
                   always infinite for non-periodic systems''')
group.add_argument('--platform',
                   dest='platform',
                   default='Reference',
                   help='OpenMM platform to use. Default is %(default)s')

args = parser.parse_args()

# Get the Amber forces and energies
if args.pbc:
    inp = sander.pme_input()
    inp.cut = args.cutoff
    inp.ntc = inp.ntf = 1
else:
    inp = sander.gas_input(args.igb)
    inp.cut = 1000
    inp.rgbmax = 1000

with sander.setup(args.prmtop, args.inpcrd, None, inp) as context:
    e, f = sander.energy_forces()
    f = np.array(f).reshape((context.natom, 3))

# Get the OpenMM forces and energies
parm = app.AmberPrmtopFile(args.prmtop)
inpcrd = app.AmberInpcrdFile(args.inpcrd)

gbmap = collections.defaultdict(lambda: None)
gbmap[1] = app.HCT
gbmap[2] = app.OBC1
gbmap[5] = app.OBC2
예제 #19
0
                   help='''GB model to use (see Amber manual). Default is
                   %(default)s''')
group.add_argument('--cutoff', dest='cutoff', type=float, default=8,
                   help='''Cutoff for nonbonded forces in Angstroms. Cutoff is
                   always infinite for non-periodic systems''')
group.add_argument('--platform', dest='platform', default='Reference',
                   help='OpenMM platform to use. Default is %(default)s')

args = parser.parse_args()

# Get the Amber forces and energies
if args.pbc:
    inp = sander.pme_input()
    inp.cut = args.cutoff
else:
    inp = sander.gas_input(args.igb)
    inp.cut = 1000

with sander.setup(args.prmtop, args.inpcrd, None, inp) as context:
    e, f = sander.energy_forces()
    f = np.array(f).reshape((context.natom, 3))

# Get the OpenMM forces and energies
parm = app.AmberPrmtopFile(args.prmtop)
inpcrd = app.AmberInpcrdFile(args.inpcrd)

gbmap = collections.defaultdict(lambda: None)
gbmap[1] = app.HCT
gbmap[2] = app.OBC1
gbmap[5] = app.OBC2
gbmap[7] = app.GBn
예제 #20
0
def energy(parm, args, output=sys.stdout):
    """
    Compute a single-point energy using sander and print the result to the
    desired output

    Parameters
    ----------
    parm : Structure
    args : ArgumentList
    output : file handler, default sys.stdout
    """
    global HAS_SANDER
    if not HAS_SANDER:
        raise SimulationError('Could not import sander')

    cutoff = args.get_key_float('cutoff', None)
    igb = args.get_key_int('igb', 5)
    saltcon = args.get_key_float('saltcon', 0.0)
    do_ewald = args.has_key('Ewald')
    vdw_longrange = not args.has_key('nodisper')
    has_1264 = 'LENNARD_JONES_CCOEF' in parm.parm_data

    # Get any unmarked arguments
    unmarked_cmds = args.unmarked()
    if len(unmarked_cmds) > 0:
        warnings.warn("Un-handled arguments: " + ' '.join(unmarked_cmds),
                      UnhandledArgumentWarning)

    if parm.ptr('ifbox') == 0:
        if not igb in (0, 1, 2, 5, 6, 7, 8):
            raise SimulationError('Bad igb value. Must be 0, 1, 2, 5, '
                                  '6, 7, or 8')
        # Force vacuum electrostatics down the GB code path
        if igb == 0:
            igb = 6
        inp = sander.gas_input(igb)
        if cutoff is None:
            cutoff = 1000.0
        if cutoff <= 0:
            raise SimulationError('cutoff must be > 0')
        inp.cut = cutoff
        if saltcon < 0:
            raise SimulationError('salt concentration must be >= 0')
        inp.saltcon = saltcon
    elif parm.ptr('ifbox') > 0:
        inp = sander.pme_input()
        if cutoff is None:
            cutoff = 8.0
        elif cutoff <= 0:
            raise SimulationError('cutoff must be > 0')
        inp.cut = cutoff
        inp.ew_type = int(do_ewald)
        inp.vdwmeth = int(vdw_longrange)
        inp.lj1264 = int(has_1264)

    if parm.coordinates is None:
        raise SimulationError('No coordinates are loaded')
    # Time to set up sander
    with sander.setup(parm, parm.coordinates, parm.box, inp):
        e, f = sander.energy_forces()

    if parm.chamber:
        output.write('Bond          = %20.7f     Angle         = %20.7f\n'
                     'Dihedral      = %20.7f     Urey-Bradley  = %20.7f\n'
                     'Improper      = %20.7f     ' %
                     (e.bond, e.angle, e.dihedral, e.angle_ub, e.imp))
        if parm.has_cmap:
            output.write('CMAP         = %20.7f\n' % e.cmap)
        output.write('1-4 vdW       = %20.7f     1-4 Elec.     = %20.7f\n'
                     'Lennard-Jones = %20.7f     Electrostatic = %20.7f\n'
                     'TOTAL         = %20.7f\n' %
                     (e.vdw_14, e.elec_14, e.vdw, e.elec, e.tot))
    else:
        output.write(
            'Bond     = %20.7f     Angle    = %20.7f\n'
            'Dihedral = %20.7f     1-4 vdW  = %20.7f\n'
            '1-4 Elec = %20.7f     vdWaals  = %20.7f\n'
            'Elec.    = %20.7f' %
            (e.bond, e.angle, e.dihedral, e.vdw_14, e.elec_14, e.vdw, e.elec))
        if igb != 0 and inp.ntb == 0:
            output.write('     Egb      = %20.7f' % e.gb)
        elif e.hbond != 0:
            output.write('     EHbond   = %20.7f' % e.hbond)
        output.write('\nTOTAL    = %20.7f\n' % e.tot)
예제 #21
0
def energy_decomposition(traj=None,
                         prmtop=None,
                         igb=8,
                         mm_options=None,
                         qm_options=None,
                         mode=None,
                         dtype='dict',
                         frame_indices=None,
                         top=None):
    """energy decomposition by calling `libsander`

    Parameters
    ----------
    traj : Trajectory-like or iterables that produce Frame
        if `traj` does not hold Topology information, `top` must be provided
    prmtop : str or Structure from ParmEd, default=None, optional
        To avoid any unexpected error, you should always provide original topology
        filename. If prmtop is None, pytraj will load Topology from traj.top.filename.

        - why do you need to load additional topology filename? Because cpptraj and sander
          use different Topology object, can not convert from one to another.
    igb : GB model, default=8 (GB-Neck2)
        If specify `mm_options`, this `igb` input will be ignored
    mm_options : InputOptions from `sander`, default=None, optional
        if `mm_options` is None, use `gas_input` with given igb.
        If `mm_options` is not None, use this
    qm_options : InputOptions from `sander` for QMMM, optional
    mode : str, default=None, optional
        if mode='minimal', get only 'bond', 'angle', 'dihedral' and 'total' energies
    top : pytraj.Topology or str, default=None, optional
        only need to specify this ``top`` if ``traj`` does not hold Topology
    dtype : str, {'dict', 'dataset', 'ndarray', 'dataframe'}, default='dict'
        return data type
    frame_indices : None or 1D array-like, default None
        if not None, only perform calculation for given frames

    Returns
    -------
    Dict of energies (to be used with DataFrame) or DatasetList

    Examples
    --------
    Examples are adapted from $AMBERHOME/test/sanderapi

    >>> import pytraj as pt
    >>> # GB energy
    >>> traj = pt.datafiles.load_ala3()
    >>> traj.n_frames
    1
    >>> data = pt.energy_decomposition(traj, igb=8)
    >>> data['gb']
    array([-92.88577683])
    >>> data['bond']
    array([ 5.59350521])

    >>> # PME
    >>> import os
    >>> from pytraj.testing import amberhome
    >>> import sander
    >>> topfile = os.path.join(amberhome, "test/4096wat/prmtop")
    >>> rstfile = os.path.join(amberhome, "test/4096wat/eq1.x")
    >>> traj = pt.iterload(rstfile, topfile)
    >>> options = sander.pme_input()
    >>> options.cut = 8.0
    >>> edict = pt.energy_decomposition(traj=traj, mm_options=options)
    >>> edict['vdw']
    array([ 6028.95167558])

    >>> # GB + QMMM
    >>> topfile = os.path.join(amberhome, "test/qmmm2/lysine_PM3_qmgb2/prmtop")
    >>> rstfile = os.path.join(amberhome, "test/qmmm2/lysine_PM3_qmgb2/lysine.crd")
    >>> traj = pt.iterload(rstfile, topfile)

    >>> options = sander.gas_input(8)
    >>> options.cut = 99.0
    >>> options.ifqnt = 1
    >>> qm_options = sander.qm_input()
    >>> qm_options.iqmatoms[:3] = [8, 9, 10]
    >>> qm_options.qm_theory = "PM3"
    >>> qm_options.qmcharge = 0
    >>> qm_options.qmgb = 2
    >>> qm_options.adjust_q = 0

    >>> edict = pt.energy_decomposition(traj=traj, mm_options=options, qm_options=qm_options)
    >>> edict['bond']
    array([ 0.00160733])
    >>> edict['scf']
    array([-11.92177575])

    Notes
    -----
    This method does not work with `pytraj.pmap` when you specify mm_options and
    qm_options. Use `pytraj.pmap_mpi` with MPI instead.

    Work with ``pytraj.pmap``::

        pt.pmap(pt.energy_decomposition, traj, igb=8, dtype='dict')

    Will NOT work with ``pytraj.pmap``::

        import sander
        inp = sander.gas_input(8)
        pt.pmap(pt.energy_decomposition, traj, mm_options=inp, dtype='dict')

    Why? Because Python need to pickle each object to send to different cores and Python
    does not know how to pickle mm_options from sander.gas_input(8).

    This works with ``pytraj.pmap_mpi`` because pytraj explicitly create ``mm_options``
    in each core without pickling.
    """
    from collections import defaultdict, OrderedDict
    from pytraj.misc import get_atts
    import numpy as np

    try:
        import sander
    except ImportError:
        raise ImportError("need both `pysander` installed. Check Ambertools15")

    ddict = defaultdict(_default_func)

    if mm_options is None:
        inp = sander.gas_input(igb)
    elif igb is not None:
        inp = mm_options

    if isinstance(inp, string_types):
        # dangerous
        local_dict = {'sander': sander}
        exec(inp.lstrip(), local_dict)
        inp = local_dict['mm_options']

    if isinstance(qm_options, string_types):
        # dangerous
        local_dict = {'sander': sander}
        exec(qm_options.lstrip(), local_dict)
        qm_options = local_dict['qm_options']

    if prmtop is None:
        try:
            # try to load from file by taking top.filename
            prmtop_ = top.filename
        except AttributeError:
            raise ValueError("prmtop must be AmberParm object in ParmEd")
    else:
        # Structure, string
        prmtop_ = prmtop

    if not hasattr(prmtop_, 'coordinates') or prmtop_.coordinates is None:
        try:
            # if `traj` is Trajectory-like (not frame_iter), try to take 1st
            # coords
            coords = traj[0].xyz
        except (TypeError, AttributeError):
            # create fake list
            coords = [0. for _ in range(top.n_atoms * 3)]
    else:
        # use default coords in `AmberParm`
        coords = prmtop_.coordinates

    if top.has_box():
        box = top.box.tolist()
        has_box = True
    else:
        box = None
        has_box = False

    with sander.setup(prmtop_, coords, box, inp, qm_options):
        for frame in iterframe_master(traj):
            if has_box:
                sander.set_box(*frame.box.tolist())
            sander.set_positions(frame.xyz)
            ene, frc = sander.energy_forces()

            # potentially slow
            ene_atts = get_atts(ene)
            for att in ene_atts:
                ddict[att].append(getattr(ene, att))

    new_dict = None
    if mode == 'minimal':
        new_dict = {}
        for key in ['bond', 'angle', 'dihedral', 'tot']:
            new_dict[key] = ddict[key]
    else:
        new_dict = ddict

    for key in new_dict.keys():
        new_dict[key] = np.asarray(new_dict[key])

    if dtype == 'dict':
        return OrderedDict(new_dict)
    else:
        from pytraj.datasets.c_datasetlist import DatasetList

        dslist = DatasetList()
        size = new_dict['tot'].__len__()
        for key in new_dict.keys():
            dslist.add('double')
            dslist[-1].key = key
            dslist[-1].resize(size)
            dslist[-1].data[:] = new_dict[key]
        return get_data_from_dtype(dslist, dtype)
예제 #22
0
def energy(parm, args, output=sys.stdout):
    """
    Compute a single-point energy using sander and print the result to the
    desired output
    """
    global HAS_SANDER
    if not HAS_SANDER:
        raise SimulationError('Could not import sander')

    cutoff = args.get_key_float('cutoff', None)
    igb = args.get_key_int('igb', 5)
    saltcon = args.get_key_float('saltcon', 0.0)
    do_ewald = args.has_key('Ewald')
    vdw_longrange = not args.has_key('nodisper')
    has_1264 = 'LENNARD_JONES_CCOEF' in parm.parm_data

    # Get any unmarked arguments
    unmarked_cmds = args.unmarked()
    if len(unmarked_cmds) > 0:
        warnings.warn("Un-handled arguments: " + ' '.join(unmarked_cmds),
                      UnhandledArgumentWarning)

    if parm.ptr('ifbox') == 0:
        if not igb in (0, 1, 2, 5, 6, 7, 8):
            raise SimulationError('Bad igb value. Must be 0, 1, 2, 5, '
                                  '6, 7, or 8')
        # Force vacuum electrostatics down the GB code path
        if igb == 0:
            igb = 6
        inp = sander.gas_input(igb)
        if cutoff is None:
            cutoff = 1000.0
        if cutoff <= 0:
            raise SimulationError('cutoff must be > 0')
        inp.cut = cutoff
        if saltcon < 0:
            raise SimulationError('salt concentration must be >= 0')
        inp.saltcon = saltcon
    elif parm.ptr('ifbox') > 0:
        inp = sander.pme_input()
        if cutoff is None:
            cutoff = 8.0
        elif cutoff <= 0:
            raise SimulationError('cutoff must be > 0')
        inp.cut = cutoff
        inp.ew_type = int(do_ewald)
        inp.vdwmeth = int(vdw_longrange)
        inp.lj1264 = int(has_1264)

    if parm.coordinates is None:
        raise SimulationError('No coordinates are loaded')
    # Time to set up sander
    with sander.setup(parm, parm.coordinates, parm.box, inp):
        e, f = sander.energy_forces()

    if parm.chamber:
        output.write('Bond          = %20.7f     Angle         = %20.7f\n'
                     'Dihedral      = %20.7f     Urey-Bradley  = %20.7f\n'
                     'Improper      = %20.7f     ' % (e.bond, e.angle,
                     e.dihedral, e.angle_ub, e.imp))
        if parm.has_cmap:
            output.write('CMAP         = %20.7f\n' % e.cmap)
        output.write('1-4 vdW       = %20.7f     1-4 Elec.     = %20.7f\n'
                     'Lennard-Jones = %20.7f     Electrostatic = %20.7f\n'
                     'TOTAL         = %20.7f\n' % (e.vdw_14, e.elec_14,
                     e.vdw, e.elec, e.tot))
    else:
        output.write('Bond     = %20.7f     Angle    = %20.7f\n'
                     'Dihedral = %20.7f     1-4 vdW  = %20.7f\n'
                     '1-4 Elec = %20.7f     vdWaals  = %20.7f\n'
                     'Elec.    = %20.7f' % (e.bond, e.angle, e.dihedral,
                      e.vdw_14, e.elec_14, e.vdw, e.elec))
        if igb != 0 and inp.ntb == 0:
            output.write('     Egb      = %20.7f' % e.gb)
        elif e.hbond != 0:
            output.write('     EHbond   = %20.7f' % e.hbond)
        output.write('\nTOTAL    = %20.7f\n' % e.tot)
예제 #23
0
# import MPI to get rank
from mpi4py import MPI
import pytraj as pt
from pytraj.testing import aa_eq

try:
    import sander
    comm = MPI.COMM_WORLD
    # end. you are free to update anything below here

    # split remd.x.000 to N cores and do calc_surf in parallel
    root_dir = "../../tests/data/"
    traj_name = root_dir + "tz2.nc"
    parm_name = root_dir + "tz2.parm7"

    # load to TrajectoryIterator
    traj = pt.iterload(traj_name, parm_name)
    inp = sander.gas_input(8)

    # gather the data
    # if rank != 0: data is None
    data = pt.pmap_mpi(pt.energy_decomposition, traj, mm_options=inp)

    if comm.rank == 0:
        # make sure to reproduce serial output
        serial_data = pt.energy_decomposition(traj, mm_options=inp)
        aa_eq(pt.tools.dict_to_ndarray(data), pt.tools.dict_to_ndarray(serial_data))
except ImportError:
    print('does not have sander. skip this example')