Exemple #1
0
def energy_derivatives(mvals,h,FF,xyz,tky,AGrad=True):

    """
    Compute the first and second derivatives of a set of snapshot
    energies with respect to the force field parameters.

    This basically calls the finite difference subroutine on the
    energy_driver subroutine also in this script.

    @todo This is a sufficiently general function to be merged into openmmio.py?
    @param[in] mvals Mathematical parameter values
    @param[in] pdb OpenMM PDB object
    @param[in] FF ForceBalance force field object
    @param[in] xyzs List of OpenMM positions
    @param[in] settings OpenMM settings for creating the System
    @param[in] boxes Periodic box vectors
    @return G First derivative of the energies in a N_param x N_coord array

    """
    E0       = energy_driver(mvals, FF, xyz, tky)
    ns       = len(E0)
    G        = np.zeros((FF.np,ns))
    if not AGrad:
        return G
    CheckFDPts = False
    for i in range(FF.np):
        G[i,:], _ = f12d3p(fdwrap(energy_driver,mvals,i,FF=FF,xyz=xyz,tky=tky),h,f0=E0)
        if CheckFDPts:
            # Check whether the number of finite difference points is sufficient.  Forward difference still gives residual error of a few percent.
            G1 = f1d7p(fdwrap(energy_driver,mvals,i,FF=FF,xyz=xyz,tky=tky),h)
            dG = G1 - G[i,:]
            dGfrac = (G1 - G[i,:]) / G[i,:]
            print "Parameter %3i 7-pt vs. central derivative : RMS, Max error (fractional) = % .4e % .4e (% .4e % .4e)" % (i, np.sqrt(np.mean(dG**2)), max(np.abs(dG)), np.sqrt(np.mean(dGfrac**2)), max(np.abs(dGfrac)))
    return G
Exemple #2
0
def property_derivatives(mvals,h,FF,xyz,tky,kT,property_driver,property_kwargs,AGrad=True):
    G        = np.zeros(FF.np)
    if not AGrad:
        return G
    ED0      = energy_driver(mvals, FF, xyz=xyz, tky=tky, dipole=True)
    E0       = ED0[:,0]
    D0       = ED0[:,1:]
    P0       = property_driver(b=None, **property_kwargs)
    if 'h_' in property_kwargs:
        H0 = property_kwargs['h_'].copy()

    for i in range(FF.np):
        ED1 = fdwrap(energy_driver,mvals,i,FF=FF,xyz=xyz,tky=tky,dipole=True)(h)
        E1       = ED1[:,0]
        D1       = ED1[:,1:]
        b = np.exp(-(E1-E0)/kT)
        b /= np.sum(b)
        if 'h_' in property_kwargs:
            property_kwargs['h_'] = H0.copy() + (E1-E0)
        if 'd_' in property_kwargs:
            property_kwargs['d_'] = D1.copy()
        S = -1*np.dot(b,np.log(b))
        InfoContent = np.exp(S)
        if InfoContent / len(E0) < 0.1:
            print "Warning: Effective number of snapshots: % .1f (out of %i)" % (InfoContent, len(E0))
        P1 = property_driver(b, **property_kwargs)

        EDM1 = fdwrap(energy_driver,mvals,i,FF=FF,xyz=xyz,tky=tky,dipole=True)(-h)
        EM1       = EDM1[:,0]
        DM1       = EDM1[:,1:]
        b = np.exp(-(EM1-E0)/kT)
        b /= np.sum(b)
        if 'h_' in property_kwargs:
            property_kwargs['h_'] = H0.copy() + (EM1-E0)
        if 'd_' in property_kwargs:
            property_kwargs['d_'] = DM1.copy()
        S = -1*np.dot(b,np.log(b))
        InfoContent = np.exp(S)
        if InfoContent / len(E0) < 0.1:
            print "Warning: Effective number of snapshots: % .1f (out of %i)" % (InfoContent, len(E0))
        PM1 = property_driver(b, **property_kwargs)

        G[i] = (P1-PM1)/(2*h)

    if 'h_' in property_kwargs:
        property_kwargs['h_'] = H0.copy()
    if 'd_' in property_kwargs:
        property_kwargs['d_'] = D0.copy()

    return G
Exemple #3
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}

        if not hasattr(self, 'ref_eigvecs_nrm'):
            self.ref_eigvecs_nrm, self.ref_eigvecs_nrm_mw = self.process_vectors(self.ref_eigvecs)
        
        def get_eigvals(mvals_):
            self.FF.make(mvals_)
            eigvals, eigvecs = self.vibration_driver()
            eigvecs_nrm, eigvecs_nrm_mw = self.process_vectors(eigvecs)
            # The overlap metric may take into account some frequency differences
            dev = np.array([[(np.abs(i-j)/1000)/(1.0+np.abs(i-j)/1000) for j in self.ref_eigvals] for i in eigvals])
            for i in range(dev.shape[0]):
                dev[i, :] /= max(dev[i, :])

            if self.reassign in ['permute', 'overlap']:
                # In the matrix that we constructed, these are the column numbers (reference mode numbers) 
                # that are mapped to the row numbers (calculated mode numbers)
                if self.reassign == 'permute':
                    a = np.array([[int(1e6*(1.0-np.dot(v1.flatten(),v2.flatten())**2)) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw])
                    row, c2r = optimize.linear_sum_assignment(a)
                    # Commented out dependency on assignment code
                    # c2r = Assign(a)
                    eigvals = eigvals[c2r]
                elif self.reassign == 'overlap':
                    a = np.array([[(1.0-np.dot(v1.flatten(),v2.flatten())**2) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw])
                    a += dev
                    c2r = np.argmin(a, axis=0)
                    eigvals_p = []
                    for j in c2r:
                        eigvals_p.append(eigvals[j])
                    eigvals = np.array(eigvals_p)
            if not in_fd():
                if self.reassign == 'permute':
                    eigvecs_nrm_mw = eigvecs_nrm_mw[c2r]
                elif self.reassign == 'overlap':
                    self.c2r = c2r
                    eigvecs_nrm_mw_p = []
                    for j in c2r:
                        eigvecs_nrm_mw_p.append(eigvecs_nrm_mw[j])
                    eigvecs_nrm_mw = np.array(eigvecs_nrm_mw_p)
                self.overlaps = np.array([np.abs(np.dot(v1.flatten(),v2.flatten())) for v1, v2 in zip(self.ref_eigvecs_nrm, eigvecs_nrm_mw)])
            return eigvals

        calc_eigvals = get_eigvals(mvals)
        D = calc_eigvals - self.ref_eigvals
        dV = np.zeros((self.FF.np,len(calc_eigvals)))
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p,:], _ = f12d3p(fdwrap(get_eigvals, mvals, p), h = self.h, f0 = calc_eigvals)
        Answer['X'] = np.dot(D,D) / self.denom**2 / (len(D) if self.normalize else 1)
        for p in self.pgrad:
            Answer['G'][p] = 2*np.dot(D, dV[p,:]) / self.denom**2 / (len(D) if self.normalize else 1)
            for q in self.pgrad:
                Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) / self.denom**2 / (len(D) if self.normalize else 1)
        if not in_fd():
            self.calc_eigvals = calc_eigvals
            self.objective = Answer['X']
        return Answer
Exemple #4
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}
        def get_momvals(mvals_):
            self.FF.make(mvals_)
            moments = self.engine.multipole_moments(polarizability='polarizability' in self.ref_moments, optimize=self.optimize_geometry)
            # Unpack from dictionary.
            return self.unpack_moments(moments)

        self.FF.make(mvals)
        ref_momvals = self.unpack_moments(self.ref_moments)
        calc_moments = self.engine.multipole_moments(polarizability='polarizability' in self.ref_moments, optimize=self.optimize_geometry)
        calc_momvals = self.unpack_moments(calc_moments)

        D = calc_momvals - ref_momvals
        dV = np.zeros((self.FF.np,len(calc_momvals)))

        if AGrad or AHess:
            for p in range(self.FF.np):
                dV[p,:], _ = f12d3p(fdwrap(get_momvals, mvals, p), h = self.h, f0 = calc_momvals)
                
        Answer['X'] = np.dot(D,D)
        for p in range(self.FF.np):
            Answer['G'][p] = 2*np.dot(D, dV[p,:])
            for q in range(self.FF.np):
                Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:])

        if not in_fd():
            self.calc_moments = calc_moments
            self.objective = Answer['X']

        return Answer
Exemple #5
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':zeros(self.FF.np, dtype=float), 'H':zeros((self.FF.np, self.FF.np), dtype=float)}
        def get_momvals(mvals_):
            self.FF.make(mvals_)
            moments = self.moments_driver()
            # Unpack from dictionary.
            return self.unpack_moments(moments)

        self.FF.make(mvals)
        ref_momvals = self.unpack_moments(self.ref_moments)
        calc_moments = self.moments_driver()
        calc_momvals = self.unpack_moments(calc_moments)

        D = calc_momvals - ref_momvals
        dV = zeros((self.FF.np,len(calc_momvals)),dtype=float)

        if AGrad or AHess:
            for p in range(self.FF.np):
                dV[p,:], _ = f12d3p(fdwrap(get_momvals, mvals, p), h = self.h, f0 = calc_momvals)
                
        Answer['X'] = dot(D,D)
        for p in range(self.FF.np):
            Answer['G'][p] = 2*dot(D, dV[p,:])
            for q in range(self.FF.np):
                Answer['H'][p,q] = 2*dot(dV[p,:], dV[q,:])

        if not in_fd():
            self.FF.make(mvals)
            self.calc_moments = calc_moments
            self.objective = Answer['X']

        return Answer
Exemple #6
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':zeros(self.FF.np, dtype=float), 'H':zeros((self.FF.np, self.FF.np), dtype=float)}
        def get_eigvals(mvals_):
            self.FF.make(mvals_)
            eigvals, eigvecs = self.vibration_driver()
            # Put reference eigenvectors in the rows and calculated eigenvectors in the columns.
            # Square the dot product (pointing in opposite direction is still the same eigenvector)
            # Convert to integer for the "Assign" subroutine, subtract from a million.
            a = array([[int(1e6*(1.0-min(1.0,dot(v1.flatten(),v2.flatten())**2))) for v2 in self.ref_eigvecs] for v1 in eigvecs])
            # In the matrix that we constructed, these are the column numbers (reference mode numbers) 
            # that are mapped to the row numbers (calculated mode numbers)
            c2r = Assign(a)
            return eigvals[c2r]

        calc_eigvals = get_eigvals(mvals)
        D = calc_eigvals - self.ref_eigvals
        dV = zeros((self.FF.np,len(calc_eigvals)),dtype=float)

        if AGrad or AHess:
            for p in range(self.FF.np):
                dV[p,:], _ = f12d3p(fdwrap(get_eigvals, mvals, p), h = self.h, f0 = calc_eigvals)
                
        Answer['X'] = dot(D,D) / self.denom**2
        for p in range(self.FF.np):
            Answer['G'][p] = 2*dot(D, dV[p,:]) / self.denom**2
            for q in range(self.FF.np):
                Answer['H'][p,q] = 2*dot(dV[p,:], dV[q,:]) / self.denom**2

        if not in_fd():
            self.calc_eigvals = calc_eigvals
            self.objective = Answer['X']

        return Answer
Exemple #7
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}
        def get_momvals(mvals_):
            self.FF.make(mvals_)
            moments = self.engine.multipole_moments(polarizability='polarizability' in self.ref_moments, optimize=self.optimize_geometry)
            # Unpack from dictionary.
            return self.unpack_moments(moments)

        self.FF.make(mvals)
        ref_momvals = self.unpack_moments(self.ref_moments)
        calc_moments = self.engine.multipole_moments(polarizability='polarizability' in self.ref_moments, optimize=self.optimize_geometry)
        calc_momvals = self.unpack_moments(calc_moments)

        D = calc_momvals - ref_momvals
        dV = np.zeros((self.FF.np,len(calc_momvals)))

        if AGrad or AHess:
            for p in self.pgrad:
                dV[p,:], _ = f12d3p(fdwrap(get_momvals, mvals, p), h = self.h, f0 = calc_momvals)
                
        Answer['X'] = np.dot(D,D)
        for p in self.pgrad:
            Answer['G'][p] = 2*np.dot(D, dV[p,:])
            for q in self.pgrad:
                Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:])

        if not in_fd():
            self.calc_moments = calc_moments
            self.objective = Answer['X']

        return Answer
Exemple #8
0
def energy_dipole_derivatives(mvals,h,FF,xyz,tky,AGrad=True):

    """
    Compute the first and second derivatives of a set of snapshot
    energies with respect to the force field parameters.

    This basically calls the finite difference subroutine on the
    energy_driver subroutine also in this script.

    @todo This is a sufficiently general function to be merged into openmmio.py?
    @param[in] mvals Mathematical parameter values
    @param[in] pdb OpenMM PDB object
    @param[in] FF ForceBalance force field object
    @param[in] xyzs List of OpenMM positions
    @param[in] settings OpenMM settings for creating the System
    @param[in] boxes Periodic box vectors
    @return G First derivative of the energies in a N_param x N_coord array

    """
    ED0      = energy_driver(mvals, FF, xyz=xyz, tky=tky, dipole=True)
    ns       = ED0.shape[0]
    G        = np.zeros((FF.np,ns))
    GDx      = np.zeros((FF.np,ns))
    GDy      = np.zeros((FF.np,ns))
    GDz      = np.zeros((FF.np,ns))
    if not AGrad:
        return G, GDx, GDy, GDz
    CheckFDPts = False
    for i in range(FF.np):
        EDG, _   = f12d3p(fdwrap(energy_driver,mvals,i,FF=FF,xyz=xyz,tky=tky,dipole=True),h,f0=ED0)
        G[i,:]   = EDG[:,0]
        GDx[i,:] = EDG[:,1]
        GDy[i,:] = EDG[:,2]
        GDz[i,:] = EDG[:,3]
    return G, GDx, GDy, GDz
Exemple #9
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}

        if not hasattr(self, 'ref_eigvecs_nrm'):
            self.ref_eigvecs_nrm, self.ref_eigvecs_nrm_mw = self.process_vectors(self.ref_eigvecs)
        
        def get_eigvals(mvals_):
            self.FF.make(mvals_)
            eigvals, eigvecs = self.vibration_driver()
            eigvecs_nrm, eigvecs_nrm_mw = self.process_vectors(eigvecs)
            # The overlap metric may take into account some frequency differences
            dev = np.array([[(np.abs(i-j)/1000)/(1.0+np.abs(i-j)/1000) for j in self.ref_eigvals] for i in eigvals])
            for i in range(dev.shape[0]):
                dev[i, :] /= max(dev[i, :])

            if self.reassign in ['permute', 'overlap']:
                # In the matrix that we constructed, these are the column numbers (reference mode numbers) 
                # that are mapped to the row numbers (calculated mode numbers)
                if self.reassign == 'permute':
                    a = np.array([[int(1e6*(1.0-np.dot(v1.flatten(),v2.flatten())**2)) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw])
                    c2r = Assign(a)
                    eigvals = eigvals[c2r]
                elif self.reassign == 'overlap':
                    a = np.array([[(1.0-np.dot(v1.flatten(),v2.flatten())**2) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw])
                    a += dev
                    c2r = np.argmin(a, axis=0)
                    eigvals_p = []
                    for j in c2r:
                        eigvals_p.append(eigvals[j])
                    eigvals = np.array(eigvals_p)
            if not in_fd():
                if self.reassign == 'permute':
                    eigvecs_nrm_mw = eigvecs_nrm_mw[c2r]
                elif self.reassign == 'overlap':
                    self.c2r = c2r
                    eigvecs_nrm_mw_p = []
                    for j in c2r:
                        eigvecs_nrm_mw_p.append(eigvecs_nrm_mw[j])
                    eigvecs_nrm_mw = np.array(eigvecs_nrm_mw_p)
                self.overlaps = np.array([np.abs(np.dot(v1.flatten(),v2.flatten())) for v1, v2 in zip(self.ref_eigvecs_nrm, eigvecs_nrm_mw)])
            return eigvals

        calc_eigvals = get_eigvals(mvals)
        D = calc_eigvals - self.ref_eigvals
        dV = np.zeros((self.FF.np,len(calc_eigvals)))
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p,:], _ = f12d3p(fdwrap(get_eigvals, mvals, p), h = self.h, f0 = calc_eigvals)
        Answer['X'] = np.dot(D,D) / self.denom**2 / (len(D) if self.normalize else 1)
        for p in self.pgrad:
            Answer['G'][p] = 2*np.dot(D, dV[p,:]) / self.denom**2 / (len(D) if self.normalize else 1)
            for q in self.pgrad:
                Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) / self.denom**2 / (len(D) if self.normalize else 1)
        if not in_fd():
            self.calc_eigvals = calc_eigvals
            self.objective = Answer['X']
        return Answer
Exemple #10
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}

        def get_eigvals(mvals_):
            self.FF.make(mvals_)
            eigvals, eigvecs = self.vibration_driver()
            # The overlap metric may take into account some frequency differences.
            # Here, an element of dev is equal to 2/3 if (for example) the frequencies differ by 1000.
            dev = np.array([[(np.abs(i-j)/1000)/(1.0+np.abs(i-j)/1000) for j in eigvals] for i in self.ref_eigvals])
            for i in range(dev.shape[0]):
                dev[i, :] /= max(dev[i, :])

            if self.reassign in ['permute', 'overlap']:
                # The elements of "a" matrix are the column numbers (reference mode numbers) 
                # that are mapped to the row numbers (calculated mode numbers).
                # Highly similar eigenvectors are assigned small values because
                # the assignment problem is a cost minimization problem.
                a = np.array([[(1.0-vib_overlap(self.engine, v1, v2)) for v2 in eigvecs] for v1 in self.ref_eigvecs])
                a += dev
                if self.reassign == 'permute':
                    row, c2r = optimize.linear_sum_assignment(a)
                    eigvals = eigvals[c2r]
                elif self.reassign == 'overlap':
                    c2r = np.argmin(a, axis=0)
                    eigvals_p = []
                    for j in c2r:
                        eigvals_p.append(eigvals[j])
                    eigvals = np.array(eigvals_p)
            if not in_fd():
                if self.reassign == 'permute':
                    eigvecs = eigvecs[c2r]
                elif self.reassign == 'overlap':
                    self.c2r = c2r
                    eigvecs_p = []
                    for j in c2r:
                        eigvecs_p.append(eigvecs[j])
                    eigvecs = np.array(eigvecs_p)
                self.overlaps = np.array([vib_overlap(self.engine, v1, v2) for v1, v2 in zip(self.ref_eigvecs, eigvecs)])
            return eigvals

        calc_eigvals = get_eigvals(mvals)
        D = calc_eigvals - self.ref_eigvals
        dV = np.zeros((self.FF.np,len(calc_eigvals)))
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p,:], _ = f12d3p(fdwrap(get_eigvals, mvals, p), h = self.h, f0 = calc_eigvals)
        Answer['X'] = np.dot(D,D) / self.denom**2 / (len(D) if self.normalize else 1)
        for p in self.pgrad:
            Answer['G'][p] = 2*np.dot(D, dV[p,:]) / self.denom**2 / (len(D) if self.normalize else 1)
            for q in self.pgrad:
                Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) / self.denom**2 / (len(D) if self.normalize else 1)
        if not in_fd():
            self.calc_eigvals = calc_eigvals
            self.objective = Answer['X']
        return Answer
Exemple #11
0
def energy_derivatives(engine,
                       FF,
                       mvals,
                       h,
                       pgrad,
                       length,
                       AGrad=True,
                       dipole=False):
    """
    Compute the first and second derivatives of a set of snapshot
    energies with respect to the force field parameters.

    This basically calls the finite difference subroutine on the
    energy_driver subroutine also in this script.

    @param[in] mvals Mathematical parameter values
    @param[in] h Finite difference step size
    @param[in] phase The phase (liquid, gas) to perform the calculation on
    @param[in] AGrad Switch to turn derivatives on or off; if off, return all zeros
    @param[in] dipole Switch for dipole derivatives.
    @return G First derivative of the energies in a N_param x N_coord array
    @return GDx First derivative of the box dipole moment x-component in a N_param x N_coord array
    @return GDy First derivative of the box dipole moment y-component in a N_param x N_coord array
    @return GDz First derivative of the box dipole moment z-component in a N_param x N_coord array

    """
    G = np.zeros((FF.np, length))
    GDx = np.zeros((FF.np, length))
    GDy = np.zeros((FF.np, length))
    GDz = np.zeros((FF.np, length))
    if not AGrad:
        return G, GDx, GDy, GDz

    def energy_driver(mvals_):
        FF.make(mvals_)
        if dipole:
            return engine.energy_dipole()
        else:
            return engine.energy()

    ED0 = energy_driver(mvals)
    for i in pgrad:
        logger.info("%i %s\r" % (i, (FF.plist[i] + " " * 30)))
        EDG, _ = f12d3p(fdwrap(energy_driver, mvals, i), h, f0=ED0)
        if dipole:
            G[i, :] = EDG[:, 0]
            GDx[i, :] = EDG[:, 1]
            GDy[i, :] = EDG[:, 2]
            GDz[i, :] = EDG[:, 3]
        else:
            G[i, :] = EDG[:]
    #reset FF parameters
    FF.make(mvals)
    return G, GDx, GDy, GDz
Exemple #12
0
 def get_sp(self, mvals, AGrad=False, AHess=False):
     """ Get the hydration free energy and first parameteric derivatives using single point energy evaluations. """
     def get_hfe(mvals_):
         self.FF.make(mvals_)
         self.hfe_dict = self.hydration_driver_sp()
         return np.array(list(self.hfe_dict.values()))
     calc_hfe = get_hfe(mvals)
     D = calc_hfe - np.array(list(self.expval.values()))
     dD = np.zeros((self.FF.np,len(self.IDs)))
     if AGrad or AHess:
         for p in self.pgrad:
             dD[p,:], _ = f12d3p(fdwrap(get_hfe, mvals, p), h = self.h, f0 = calc_hfe)
     return D, dD
Exemple #13
0
 def get_sp(self, mvals, AGrad=False, AHess=False):
     """ Get the hydration free energy and first parameteric derivatives using single point energy evaluations. """
     def get_hfe(mvals_):
         self.FF.make(mvals_)
         self.hfe_dict = self.hydration_driver_sp()
         return np.array(self.hfe_dict.values())
     calc_hfe = get_hfe(mvals)
     D = calc_hfe - np.array(self.expval.values())
     dD = np.zeros((self.FF.np,len(self.IDs)))
     if AGrad or AHess:
         for p in self.pgrad:
             dD[p,:], _ = f12d3p(fdwrap(get_hfe, mvals, p), h = self.h, f0 = calc_hfe)
     return D, dD
Exemple #14
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}

        if not hasattr(self, 'ref_eigvecs_nrm'):
            self.ref_eigvecs_nrm, self.ref_eigvecs_nrm_mw = self.process_vectors(self.ref_eigvecs)
        
        def get_eigvals(mvals_):
            self.FF.make(mvals_)
            eigvals, eigvecs = self.vibration_driver()
            eigvecs_nrm, eigvecs_nrm_mw = self.process_vectors(eigvecs)
            if self.reassign in ['permute', 'overlap']:
                a = np.array([[int(1e6*(1.0-np.dot(v1.flatten(),v2.flatten())**2)) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw])
                # In the matrix that we constructed, these are the column numbers (reference mode numbers) 
                # that are mapped to the row numbers (calculated mode numbers)
                if self.reassign == 'permute':
                    c2r = Assign(a)
                    eigvals = eigvals[c2r]
                elif self.reassign == 'overlap':
                    c2r = np.argmin(a, axis=0)
                    eigvals_p = []
                    for j in c2r:
                        eigvals_p.append(eigvals[j])
                    eigvals = np.array(eigvals_p)
            if not in_fd():
                if self.reassign == 'permute':
                    eigvecs_nrm_mw = eigvecs_nrm_mw[c2r]
                elif self.reassign == 'overlap':
                    self.c2r = c2r
                    eigvecs_nrm_mw_p = []
                    for j in c2r:
                        eigvecs_nrm_mw_p.append(eigvecs_nrm_mw[j])
                    eigvecs_nrm_mw = np.array(eigvecs_nrm_mw_p)
                self.overlaps = np.array([np.abs(np.dot(v1.flatten(),v2.flatten())) for v1, v2 in zip(self.ref_eigvecs_nrm, eigvecs_nrm_mw)])
            return eigvals

        calc_eigvals = get_eigvals(mvals)
        D = calc_eigvals - self.ref_eigvals
        dV = np.zeros((self.FF.np,len(calc_eigvals)))
        if AGrad or AHess:
            for p in range(self.FF.np):
                dV[p,:], _ = f12d3p(fdwrap(get_eigvals, mvals, p), h = self.h, f0 = calc_eigvals)
        Answer['X'] = np.dot(D,D) / self.denom**2
        for p in range(self.FF.np):
            Answer['G'][p] = 2*np.dot(D, dV[p,:]) / self.denom**2
            for q in range(self.FF.np):
                Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) / self.denom**2
        if not in_fd():
            self.calc_eigvals = calc_eigvals
            self.objective = Answer['X']
        return Answer
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}

        # If the weight is zero, turn all derivatives off.
        if (self.weight == 0.0):
            AGrad = False
            AHess = False

        def callM(mvals_, dielectric=False):
            logger.info("\r")
            pvals = self.FF.make(mvals_)
            return self.engine.interaction_energy(self.select1, self.select2)

        logger.info("Executing\r")
        emm = callM(mvals)

        D = emm - self.eqm
        dV = np.zeros((self.FF.np,len(emm)))

        # Dump interaction energies to disk.
        np.savetxt('M.txt',emm)
        np.savetxt('Q.txt',self.eqm)

        # Do the finite difference derivative.
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p,:], _ = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = emm)
            # Create the force field one last time.
            pvals  = self.FF.make(mvals)

        Answer['X'] = np.dot(self.prefactor*D/self.divisor,D/self.divisor)
        for p in self.pgrad:
            Answer['G'][p] = 2*np.dot(self.prefactor*D/self.divisor, dV[p,:]/self.divisor)
            for q in self.pgrad:
                Answer['H'][p,q] = 2*np.dot(self.prefactor*dV[p,:]/self.divisor, dV[q,:]/self.divisor)

        if not in_fd():
            self.emm = emm
            self.objective = Answer['X']

        ## QYD: try to clean up OpenMM engine.simulation objects to free up GPU memory
        try:
            if self.engine.name == 'openmm':
                if hasattr(self.engine, 'simulation'): del self.engine.simulation
                if hasattr(self.engine, 'A'): del self.engine.A
                if hasattr(self.engine, 'B'): del self.engine.B
        except:
            pass

        return Answer
Exemple #16
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}

        # If the weight is zero, turn all derivatives off.
        if (self.weight == 0.0):
            AGrad = False
            AHess = False

        def callM(mvals_, dielectric=False):
            logger.info("\r")
            pvals = self.FF.make(mvals_)
            return self.engine.interaction_energy(self.select1, self.select2)

        logger.info("Executing\r")
        emm = callM(mvals)

        D = emm - self.eqm
        dV = np.zeros((self.FF.np,len(emm)))

        # Dump interaction energies to disk.
        np.savetxt('M.txt',emm)
        np.savetxt('Q.txt',self.eqm)

        # Do the finite difference derivative.
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p,:], _ = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = emm)
            # Create the force field one last time.
            pvals  = self.FF.make(mvals)

        Answer['X'] = np.dot(self.prefactor*D/self.divisor,D/self.divisor)
        for p in self.pgrad:
            Answer['G'][p] = 2*np.dot(self.prefactor*D/self.divisor, dV[p,:]/self.divisor)
            for q in self.pgrad:
                Answer['H'][p,q] = 2*np.dot(self.prefactor*dV[p,:]/self.divisor, dV[q,:]/self.divisor)

        if not in_fd():
            self.emm = emm
            self.objective = Answer['X']

        ## QYD: try to clean up OpenMM engine.simulation objects to free up GPU memory
        try:
            if self.engine.name == 'openmm':
                if hasattr(self.engine, 'simulation'): del self.engine.simulation
                if hasattr(self.engine, 'A'): del self.engine.A
                if hasattr(self.engine, 'B'): del self.engine.B
        except:
            pass

        return Answer
Exemple #17
0
def energy_derivatives(engine, FF, mvals, h, pgrad, length, AGrad=True, dipole=False):

    """
    Compute the first and second derivatives of a set of snapshot
    energies with respect to the force field parameters.

    This basically calls the finite difference subroutine on the
    energy_driver subroutine also in this script.

    @param[in] mvals Mathematical parameter values
    @param[in] h Finite difference step size
    @param[in] phase The phase (liquid, gas) to perform the calculation on
    @param[in] AGrad Switch to turn derivatives on or off; if off, return all zeros
    @param[in] dipole Switch for dipole derivatives.
    @return G First derivative of the energies in a N_param x N_coord array
    @return GDx First derivative of the box dipole moment x-component in a N_param x N_coord array
    @return GDy First derivative of the box dipole moment y-component in a N_param x N_coord array
    @return GDz First derivative of the box dipole moment z-component in a N_param x N_coord array

    """
    G        = np.zeros((FF.np,length))
    GDx      = np.zeros((FF.np,length))
    GDy      = np.zeros((FF.np,length))
    GDz      = np.zeros((FF.np,length))
    if not AGrad:
        return G, GDx, GDy, GDz
    def energy_driver(mvals_):
        FF.make(mvals_)
        if dipole:
            return engine.energy_dipole()
        else:
            return engine.energy()

    ED0      = energy_driver(mvals)
    for i in pgrad:
        logger.info("%i %s\r" % (i, (FF.plist[i] + " "*30)))
        EDG, _   = f12d3p(fdwrap(energy_driver,mvals,i),h,f0=ED0)
        if dipole:
            G[i,:]   = EDG[:,0]
            GDx[i,:] = EDG[:,1]
            GDy[i,:] = EDG[:,2]
            GDz[i,:] = EDG[:,3]
        else:
            G[i,:]   = EDG[:]
    #reset FF parameters
    FF.make(mvals)
    return G, GDx, GDy, GDz
Exemple #18
0
def energy_derivatives(engine, FF, mvals, h, pgrad, dipole=False):

    """
    Compute the first and second derivatives of a set of snapshot
    energies with respect to the force field parameters.

    This basically calls the finite difference subroutine on the
    energy_driver subroutine also in this script.

    In the future we may need to be more sophisticated with
    controlling the quantities which are differentiated, but for
    now this is okay..

    @param[in] engine Engine object for calculating energies
    @param[in] FF Force field object
    @param[in] mvals Mathematical parameter values
    @param[in] h Finite difference step size
    @param[in] pgrad List of active parameters for differentiation
    @param[in] dipole Switch for dipole derivatives.
    @return G First derivative of the energies in a N_param x N_coord array
    @return GDx First derivative of the box dipole moment x-component in a N_param x N_coord array
    @return GDy First derivative of the box dipole moment y-component in a N_param x N_coord array
    @return GDz First derivative of the box dipole moment z-component in a N_param x N_coord array

    """
    def single_point(mvals_):
        FF.make(mvals_)
        if dipole:
            return engine.energy_dipole()
        else:
            return engine.energy()

    ED0 = single_point(mvals)
    G   = OrderedDict()
    G['potential'] = np.zeros((FF.np, ED0.shape[0]))
    if dipole:
        G['dipole'] = np.zeros((FF.np, ED0.shape[0], 3))
    for i in pgrad:
        logger.info("%i %s\r" % (i, (FF.plist[i] + " "*30)))
        edg, _ = f12d3p(fdwrap(single_point,mvals,i),h,f0=ED0)
        if dipole:
            G['potential'][i] = edg[:,0]
            G['dipole'][i]    = edg[:,1:]
        else:
            G['potential'][i] = edg[:]
    return G
Exemple #19
0
def energy_derivatives(engine, FF, mvals, h, pgrad, length, AGrad=True):
    """Compute the first derivatives of a set of snapshot energies with respect
    to the force field parameters. The function calls the finite
    difference subroutine on the energy_driver subroutine also in this
    script.

    Parameters
    ----------
    engine : Engine
        Use this Engine (`GMX`,`TINKER`,`OPENMM` etc.) object to get the energy
        snapshots.
    FF : FF
       Force field object.
    mvals : list
        Mathematical parameter values.
    h : float
        Finite difference step size.
    length : int
        Number of snapshots (length of energy trajectory).
    AGrad : Boolean
        Switch that turns derivatives on or off; if off, return all zeros.

    Returns
    -------
    G : np.array
        Derivative of the energy in a FF.np x length array.
    
    """
    G = np.zeros((FF.np, length))

    if not AGrad:
        return G

    def energy_driver(mvals_):
        FF.make(mvals_)
        return engine.energy()

    ED0 = energy_driver(mvals)

    for i in pgrad:
        logger.info("%i %s\r" % (i, (FF.plist[i] + " " * 30)))
        EDG, _ = f12d3p(fdwrap(energy_driver, mvals, i), h, f0=ED0)

        G[i, :] = EDG[:]
    return G
Exemple #20
0
def energy_derivatives(engine, FF, mvals, h, pgrad, length, AGrad=True):
    """Compute the first derivatives of a set of snapshot energies with respect
    to the force field parameters. The function calls the finite
    difference subroutine on the energy_driver subroutine also in this
    script.

    Parameters
    ----------
    engine : Engine
        Use this Engine (`GMX`,`TINKER`,`OPENMM` etc.) object to get the energy
        snapshots.
    FF : FF
       Force field object.
    mvals : list
        Mathematical parameter values.
    h : float
        Finite difference step size.
    length : int
        Number of snapshots (length of energy trajectory).
    AGrad : Boolean
        Switch that turns derivatives on or off; if off, return all zeros.

    Returns
    -------
    G : np.array
        Derivative of the energy in a FF.np x length array.
    
    """
    G = np.zeros((FF.np, length))
    
    if not AGrad:
        return G
    def energy_driver(mvals_):
        FF.make(mvals_)
        return engine.energy()

    ED0 = energy_driver(mvals)
        
    for i in pgrad:
        logger.info("%i %s\r" % (i, (FF.plist[i] + " "*30)))
        EDG, _   = f12d3p(fdwrap(energy_driver, mvals, i), h, f0=ED0)

        G[i,:]   = EDG[:]
    return G
Exemple #21
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':zeros(self.FF.np, dtype=float), 'H':zeros((self.FF.np, self.FF.np), dtype=float)}
        
        # If the weight is zero, turn all derivatives off.
        if (self.weight == 0.0):
            AGrad = False
            AHess = False

        def callM(mvals_, dielectric=False):
            logger.info("\r")
            pvals = self.FF.make(mvals_)
            return self.interaction_driver_all(dielectric)

        logger.info("Executing\r")
        emm = callM(mvals)

        D = emm - self.eqm
        dV = zeros((self.FF.np,len(emm)),dtype=float)

        # Dump interaction energies to disk.
        savetxt('M.txt',emm)
        savetxt('Q.txt',self.eqm)

        # Do the finite difference derivative.
        if AGrad or AHess:
            for p in range(self.FF.np):
                dV[p,:], _ = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = emm)
            # Create the force field one last time.
            pvals  = self.FF.make(mvals)
                
        Answer['X'] = dot(self.prefactor*D/self.divisor,D/self.divisor)
        for p in range(self.FF.np):
            Answer['G'][p] = 2*dot(self.prefactor*D/self.divisor, dV[p,:]/self.divisor)
            for q in range(self.FF.np):
                Answer['H'][p,q] = 2*dot(self.prefactor*dV[p,:]/self.divisor, dV[q,:]/self.divisor)

        if not in_fd():
            self.emm = emm
            self.objective = Answer['X']

        return Answer
Exemple #22
0
def rpmd_energy_derivatives(engine, FF, mvals, h, pgrad, length, AGrad=True, dipole=False):
    """
    Compute the first and second derivatives of a set of snapshot
    energies with respect to the force field parameters.
 
    This is analagous to the energy_derivatives function above, but is 
    specific for calculating derivatives for rpmd, which has 
    an additional term due to the force term in the centroid virial
    estimator.
    """
    G              = np.zeros((FF.np,length))
    GDx            = np.zeros((FF.np,length))
    GDy            = np.zeros((FF.np,length))
    GDz            = np.zeros((FF.np,length))
    RPMDG          = np.zeros((FF.np,length))
    RPMDG_frc_term = np.zeros((FF.np,length))  
    if not AGrad:
        return G, GDx, GDy, GDz, RPMDG, RPMDG_frc_term
    def rpmd_energy_driver(mvals_):
        FF.make(mvals_)
        if dipole:
            return engine.energy_dipole_rpmd()
        else:
            return engine.energy_rpmd()

    ED0 = rpmd_energy_driver(mvals)
    for i in pgrad:
        logger.info("%i %s\r" % (i, (FF.plist[i] + " "*30)))
        ERPMDG, _   = f12d3p(fdwrap(rpmd_energy_driver,mvals,i),h,f0=ED0)
        if dipole:
            G[i,:]              = ERPMDG[:,0] 
            GDx[i,:]            = ERPMDG[:,1] 
            GDy[i,:]            = ERPMDG[:,2]
            GDz[i,:]            = ERPMDG[:,3]
            RPMDG[i,:]          = ERPMDG[:,4]    
            RPMDG_frc_term[i,:] = ERPMDG[:,5]
        else:
            G[i,:]              = ERPMDG[:,0]
            RPMDG[i,:]          = ERPMDG[:,1]
            RPMDG_frc_term[i,:] = ERPMDG[:,2]
    return G, GDx, GDy, GDz, RPMDG, RPMDG_frc_term
Exemple #23
0
    def FDCheckG(self):
        """ Finite-difference checker for the objective function gradient.

        For each element in the gradient, use a five-point finite difference
        stencil to compute a finite-difference derivative, and compare it to
        the analytic result.

        """

        Adata        = self.Objective.Full(self.mvals0,Order=1)['G']
        Fdata        = np.zeros(self.FF.np,dtype=float)
        printcool("Checking first derivatives by finite difference!\n%-8s%-20s%13s%13s%13s%13s" \
                  % ("Index", "Parameter ID","Analytic","Numerical","Difference","Fractional"),bold=1,color=5)
        for i in range(self.FF.np):
            Fdata[i] = f1d7p(fdwrap(self.Objective.Full,self.mvals0,i,'X',Order=0),self.h)
            Denom = max(abs(Adata[i]),abs(Fdata[i]))
            Denom = Denom > 1e-8 and Denom or 1e-8
            D = Adata[i] - Fdata[i]
            Q = (Adata[i] - Fdata[i])/Denom
            cD = abs(D) > 0.5 and "\x1b[1;91m" or (abs(D) > 1e-2 and "\x1b[91m" or (abs(D) > 1e-5 and "\x1b[93m" or "\x1b[92m"))
            cQ = abs(Q) > 0.5 and "\x1b[1;91m" or (abs(Q) > 1e-2 and "\x1b[91m" or (abs(Q) > 1e-5 and "\x1b[93m" or "\x1b[92m"))
            logger.info("\r    %-8i%-20s% 13.4e% 13.4e%s% 13.4e%s% 13.4e\x1b[0m\n" \
                  % (i, self.FF.plist[i][:20], Adata[i], Fdata[i], cD, D, cQ, Q))
Exemple #24
0
    def get(self, mvals, AGrad=False, AHess=False):
	"""
        LPW 04-17-2013
        
        This subroutine builds the objective function from Psi4.

        @param[in] mvals Mathematical parameter values
        @param[in] AGrad Switch to turn on analytic gradient
        @param[in] AHess Switch to turn on analytic Hessian
        @return Answer Contribution to the objective function
        """
        Answer = {}
        Fac = 1000000
        n = len(mvals)
        X = 0.0
        G = np.zeros(n,dtype=float)
        H = np.zeros((n,n),dtype=float)
        pvals = self.FF.make(mvals)
        self.tdir = os.getcwd()
        self.objd = OrderedDict()
        self.gradd = OrderedDict()
        self.hdiagd = OrderedDict()
        bidirect = False

        def fdwrap2(func,mvals0,pidx,qidx,key=None,**kwargs):
            def func2(arg1,arg2):
                mvals = list(mvals0)
                mvals[pidx] += arg1
                mvals[qidx] += arg2
                print "\rfdwrap2:", func.__name__, "[%i] = % .1e , [%i] = % .1e" % (pidx, arg1, qidx, arg2), ' '*50,
                if key != None:
                    return func(mvals,**kwargs)[key]
                else:
                    return func(mvals,**kwargs)
            return func2

        def f2d5p(f, h):
            fpp, fpm, fmp, fmm = [f(i*h,j*h) for i,j in [(1,1),(1,-1),(-1,1),(-1,-1)]]
            fpp = (fpp-fpm-fmp+fmm)/(4*h*h)
            return fpp

        def f2d4p(f, h, f0 = None):
            if f0 == None:
                fpp, fp0, f0p, f0 = [f(i*h,j*h) for i,j in [(1,1),(1,0),(0,1),(0,0)]]
            else:
                fpp, fp0, f0p = [f(i*h,j*h) for i,j in [(1,1),(1,0),(0,1)]]
            fpp = (fpp-fp0-f0p+f0)/(h*h)
            return fpp

        for d in self.objfiles:
            print "\rNow working on", d, 50*' ','\r',
            x = self.driver(mvals, d)
            grad  = np.zeros(n,dtype=float)
            hdiag = np.zeros(n,dtype=float)
            hess  = np.zeros((n,n),dtype=float)
            for p in range(self.FF.np):
                if self.callderivs[d][p]:
                    if AHess:
                        grad[p], hdiag[p] = f12d3p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x)
                        hess[p,p] = hdiag[p]
                        # for q in range(p):
                        #     if self.callderivs[d][q]:
                        #         if bidirect:
                        #             hessentry = f2d5p(fdwrap2(self.driver, mvals, p, q, d=d), h = self.h)
                        #         else:
                        #             hessentry = f2d4p(fdwrap2(self.driver, mvals, p, q, d=d), h = self.h, f0 = x)
                        #         hess[p,q] = hessentry
                        #         hess[q,p] = hessentry
                    elif AGrad:
                        if bidirect:
                            grad[p], _ = f12d3p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x)
                        else:
                            grad[p] = f1d2p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x)
                            
            self.objd[d] = x
            self.gradd[d] = grad
            self.hdiagd[d] = hdiag
            X += x
            G += grad
            #H += np.diag(hdiag)
            H += hess
        if not in_fd():
            self.objective = X
            self.objvals = self.objd
        # print self.objd
        # print self.gradd
        # print self.hdiagd
                    
        if float('Inf') in pvals:
            return {'X' : 1e10, 'G' : G, 'H' : H}
        return {'X' : X, 'G' : G, 'H' : H}
Exemple #25
0
    def submit_jobs(self, mvals, AGrad=True, AHess=True):
        # This routine is called by Objective.stage() will run before "get".
        # It submits the jobs to the Work Queue and the stage() function will wait for jobs to complete.
        #
        self.tdir = os.getcwd()
        wq = getWorkQueue()
        if wq is None:
            return

        def submit_psi(this_apath, dname, these_mvals):
            """ Create a grid file and a psi4 input file in the absolute path and submit it to the work queue. """
            cwd = os.getcwd()
            if not os.path.exists(this_apath): os.makedirs(this_apath)
            os.chdir(this_apath)
            self.FF.make(these_mvals)
            o = wopen('objective.dat')
            for line in self.objfiles[d]:
                s = line.split()
                if len(s) > 2 and s[0] == 'path' and s[1] == '=':
                    print("path = '%s'" % os.getcwd(), file=o)
                elif len(s) > 2 and s[0] == 'set' and s[1] == 'objective_path':
                    print("opath = '%s'" % os.getcwd(), file=o)
                    print("set objective_path $opath", file=o)
                else:
                    print(line, end=' ', file=o)
            o.close()
            os.system("rm -f objective.out")
            if wq is None:
                logger.info("There is no Work Queue!!!\n")
                sys.exit()
            else:
                input_files = [(os.path.join(this_apath, i), i)
                               for i in glob.glob("*")]
                input_files += [(os.path.join(self.root, self.tgtdir, dname,
                                              "build.dat"), "build.dat")]
                input_files += [(os.path.join(
                    os.path.split(__file__)[0], "data",
                    "run_psi_rdvr3_objective.sh"),
                                 "run_psi_rdvr3_objective.sh")]
                logger.info("\r")
                queue_up_src_dest(
                    wq,
                    "sh run_psi_rdvr3_objective.sh -c %s &> run_psi_rdvr3_objective.log"
                    % os.path.join(self.root, self.tgtdir, dname),
                    input_files=input_files,
                    output_files=[
                        (os.path.join(this_apath, i), i)
                        for i in ["run_psi_rdvr3_objective.log", "output.dat"]
                    ],
                    verbose=False)
            os.chdir(cwd)

        for d in self.objfiles:
            logger.info("\rNow working on" + str(d) + 50 * ' ' + '\r')
            odir = os.path.join(os.getcwd(), d)
            #if os.path.exists(odir):
            #    shutil.rmtree(odir)
            if not os.path.exists(odir): os.makedirs(odir)
            apath = os.path.join(odir, "current")
            submit_psi(apath, d, mvals)
            for p in range(self.FF.np):

                def subjob(mvals_, h):
                    apath = os.path.join(odir, str(p), str(h))
                    submit_psi(apath, d, mvals_)
                    #logger.info("Will set up a job for %s, parameter %i\n" % (d, p))
                    return 0.0

                if self.callderivs[d][p]:
                    if AHess:
                        f12d3p(fdwrap(subjob, mvals, p, h=self.h),
                               h=self.h,
                               f0=0.0)
                    elif AGrad:
                        if self.bidirect:
                            f12d3p(fdwrap(subjob, mvals, p, h=self.h),
                                   h=self.h,
                                   f0=0.0)
                        else:
                            f1d2p(fdwrap(subjob, mvals, p, h=self.h),
                                  h=self.h,
                                  f0=0.0)
Exemple #26
0
    def get(self, mvals, AGrad=False, AHess=False):
        """
        LPW 04-17-2013
        
        This subroutine builds the objective function from Psi4.

        @param[in] mvals Mathematical parameter values
        @param[in] AGrad Switch to turn on analytic gradient
        @param[in] AHess Switch to turn on analytic Hessian
        @return Answer Contribution to the objective function
        """
        Answer = {}
        Fac = 1000000
        n = len(mvals)
        X = 0.0
        G = np.zeros(n)
        H = np.zeros((n, n))
        pvals = self.FF.make(mvals)
        self.tdir = os.getcwd()
        self.objd = OrderedDict()
        self.gradd = OrderedDict()
        self.hdiagd = OrderedDict()
        wq = getWorkQueue()

        def fdwrap2(func, mvals0, pidx, qidx, key=None, **kwargs):
            def func2(arg1, arg2):
                mvals = list(mvals0)
                mvals[pidx] += arg1
                mvals[qidx] += arg2
                logger.info("\rfdwrap2:" + func.__name__ +
                            "[%i] = % .1e , [%i] = % .1e" %
                            (pidx, arg1, qidx, arg2) + ' ' * 50)
                if key is not None:
                    return func(mvals, **kwargs)[key]
                else:
                    return func(mvals, **kwargs)

            return func2

        def f2d5p(f, h):
            fpp, fpm, fmp, fmm = [
                f(i * h, j * h)
                for i, j in [(1, 1), (1, -1), (-1, 1), (-1, -1)]
            ]
            fpp = (fpp - fpm - fmp + fmm) / (4 * h * h)
            return fpp

        def f2d4p(f, h, f0=None):
            if f0 is None:
                fpp, fp0, f0p, f0 = [
                    f(i * h, j * h)
                    for i, j in [(1, 1), (1, 0), (0, 1), (0, 0)]
                ]
            else:
                fpp, fp0, f0p = [
                    f(i * h, j * h) for i, j in [(1, 1), (1, 0), (0, 1)]
                ]
            fpp = (fpp - fp0 - f0p + f0) / (h * h)
            return fpp

        for d in self.objfiles:
            logger.info("\rNow working on" + str(d) + 50 * ' ' + '\r')
            if wq is None:
                x = self.driver(mvals, d)
            grad = np.zeros(n)
            hdiag = np.zeros(n)
            hess = np.zeros((n, n))
            apath = os.path.join(self.tdir, d, "current")
            x = float(
                open(os.path.join(
                    apath,
                    'objective.out')).readlines()[0].split()[1]) * self.factor
            for p in range(self.FF.np):
                if self.callderivs[d][p]:

                    def reader(mvals_, h):
                        apath = os.path.join(self.tdir, d, str(p), str(h))
                        answer = float(
                            open(os.path.join(apath, 'objective.out')).
                            readlines()[0].split()[1]) * self.factor
                        return answer

                    if AHess:
                        if wq is not None:
                            apath = os.path.join(self.tdir, d, "current")
                            x = float(
                                open(os.path.join(apath, 'objective.out')).
                                readlines()[0].split()[1]) * self.factor
                            grad[p], hdiag[p] = f12d3p(fdwrap(reader,
                                                              mvals,
                                                              p,
                                                              h=self.h),
                                                       h=self.h,
                                                       f0=x)
                        else:
                            grad[p], hdiag[p] = f12d3p(fdwrap(self.driver,
                                                              mvals,
                                                              p,
                                                              d=d),
                                                       h=self.h,
                                                       f0=x)
                        hess[p, p] = hdiag[p]
                    elif AGrad:
                        if self.bidirect:
                            if wq is not None:
                                apath = os.path.join(self.tdir, d, "current")
                                x = float(
                                    open(os.path.join(apath, 'objective.out')).
                                    readlines()[0].split()[1]) * self.factor
                                grad[p], _ = f12d3p(fdwrap(reader,
                                                           mvals,
                                                           p,
                                                           h=self.h),
                                                    h=self.h,
                                                    f0=x)
                            else:
                                grad[p], _ = f12d3p(fdwrap(self.driver,
                                                           mvals,
                                                           p,
                                                           d=d),
                                                    h=self.h,
                                                    f0=x)
                        else:
                            if wq is not None:
                                # Since the calculations are submitted as 3-point finite difference, this part of the code
                                # actually only reads from half of the completed calculations.
                                grad[p] = f1d2p(fdwrap(reader,
                                                       mvals,
                                                       p,
                                                       h=self.h),
                                                h=self.h,
                                                f0=x)
                            else:
                                grad[p] = f1d2p(fdwrap(self.driver,
                                                       mvals,
                                                       p,
                                                       d=d),
                                                h=self.h,
                                                f0=x)

            self.objd[d] = x
            self.gradd[d] = grad
            self.hdiagd[d] = hdiag
            X += x
            G += grad
            #H += np.diag(hdiag)
            H += hess
        if not in_fd():
            self.objective = X
            self.objvals = self.objd
        # print self.objd
        # print self.gradd
        # print self.hdiagd

        if float('Inf') in pvals:
            return {'X': 1e10, 'G': G, 'H': H}
        return {'X': X, 'G': G, 'H': H}
    def get(self, mvals, AGrad=False, AHess=False):
        Answer = {
            'X': 0.0,
            'G': np.zeros(self.FF.np),
            'H': np.zeros((self.FF.np, self.FF.np))
        }
        self.PrintDict = OrderedDict()

        def compute(mvals_, indicate=False):
            self.FF.make(mvals_)
            M_opts = None
            compute.emm = []
            compute.rmsd = []
            for i in range(self.ns):
                energy, rmsd, M_opt = self.engine.optimize(shot=i, align=False)
                # Create a molecule object to hold the MM-optimized structures
                compute.emm.append(energy)
                compute.rmsd.append(rmsd)
                if M_opts is None:
                    M_opts = deepcopy(M_opt)
                else:
                    M_opts += M_opt
            compute.emm = np.array(compute.emm)
            compute.emm -= compute.emm[self.smin]
            compute.rmsd = np.array(compute.rmsd)
            if indicate:
                if self.writelevel > 0:
                    M_opts.write('mm_minimized.xyz')
                    if self.ndim == 1:
                        import matplotlib.pyplot as plt
                        plt.switch_backend('agg')
                        fig, ax = plt.subplots()
                        dihedrals = np.array(
                            [i[0] for i in self.metadata['torsion_grid_ids']])
                        dsort = np.argsort(dihedrals)
                        ax.plot(dihedrals[dsort], self.eqm[dsort], label='QM')
                        if hasattr(self, 'emm_orig'):
                            ax.plot(dihedrals[dsort],
                                    compute.emm[dsort],
                                    label='MM Current')
                            ax.plot(dihedrals[dsort],
                                    self.emm_orig[dsort],
                                    label='MM Initial')
                        else:
                            ax.plot(dihedrals[dsort],
                                    compute.emm[dsort],
                                    label='MM Initial')
                            self.emm_orig = compute.emm.copy()
                        ax.legend()
                        ax.set_xlabel('Dihedral (degree)')
                        ax.set_ylabel('Energy (kcal/mol)')
                        fig.suptitle(
                            'Torsion profile: iteration %i\nSystem: %s' %
                            (Counter(), self.name))
                        fig.savefig('plot_torsion.pdf')
            return (np.sqrt(self.wts) / self.energy_denom) * (compute.emm -
                                                              self.eqm)

        compute.emm = None
        compute.rmsd = None

        V = compute(mvals, indicate=True)

        Answer['X'] = np.dot(V, V)

        # Energy RMSE
        e_rmse = np.sqrt(np.dot(self.wts, (compute.emm - self.eqm)**2))

        self.PrintDict[
            self.
            name] = '%10s %10s    %6.3f - %-6.3f   % 6.3f - %-6.3f    %6.3f    %7.4f   % 7.4f' % (
                ','.join([
                    '%i' % i
                    for i in self.metadata['torsion_grid_ids'][self.smin]
                ]), ','.join([
                    '%i' % i for i in self.metadata['torsion_grid_ids'][
                        np.argmin(compute.emm)]
                ]), min(self.eqm), max(self.eqm), min(compute.emm),
                max(compute.emm), max(compute.rmsd), e_rmse, Answer['X'])

        # compute gradients and hessian
        dV = np.zeros((self.FF.np, len(V)))
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p, :], _ = f12d3p(fdwrap(compute, mvals, p), h=self.h, f0=V)

        for p in self.pgrad:
            Answer['G'][p] = 2 * np.dot(V, dV[p, :])
            for q in self.pgrad:
                Answer['H'][p, q] = 2 * np.dot(dV[p, :], dV[q, :])
        if not in_fd():
            self.objective = Answer['X']
            self.FF.make(mvals)
        return Answer
Exemple #28
0
    def get(self, mvals, AGrad=False, AHess=False):
        """
        LPW 05-30-2012
        
        This subroutine builds the objective function (and optionally
        its derivatives) from a general software.  

        This subroutine interfaces with simulation software 'drivers'.
        The driver is expected to give exact values, fitting values, and weights.

        @param[in] mvals Mathematical parameter values
        @param[in] AGrad Switch to turn on analytic gradient
        @param[in] AHess Switch to turn on analytic Hessian
        @return Answer Contribution to the objective function
        """
        global LAST_MVALS, CHECK_BASIS
        # print mvals
        # print LAST_MVALS
        # print mvals == LAST_MVALS
        if LAST_MVALS == None or not (mvals == LAST_MVALS).all():
            CHECK_BASIS = False
        else:
            CHECK_BASIS = False
        Answer = {}
        Fac = 1000000
        ## Dictionary for derivative terms
        dM = {}
        # Create the new force field!!
        np = len(mvals)
        G = zeros(np, dtype=float)
        H = zeros((np, np), dtype=float)
        pvals = self.FF.make(mvals)
        if float("Inf") in pvals:
            return {"X": 1e10, "G": G, "H": H}
        Ans = self.driver()
        W = Ans[:, 2]
        M = Ans[:, 1]
        Q = Ans[:, 0]
        D = M - Q

        self.MAQ = mean(abs(Q))

        ns = len(M)
        # Wrapper to the driver, which returns just the part that changes.
        def callM(mvals_):
            self.FF.make(mvals_)
            Ans2 = self.driver()
            M_ = Ans2[:, 1]
            D_ = M_ - Q
            return Ans2[:, 1]

        if AGrad:
            # Leaving comment here if we want to reintroduce second deriv someday.
            #     dM[p,:], ddM[p,:] = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = M)
            for p in range(np):
                if self.call_derivatives[p] == False:
                    continue
                dM_arr = f1d2p(fdwrap(callM, mvals, p), h=self.h, f0=M)
                if max(abs(dM_arr)) == 0.0 and Counter() == 0:
                    print "\r Simulation %s will skip over parameter %i in subsequent steps" % (self.name, p)
                    self.call_derivatives[p] = False
                else:
                    dM[p] = dM_arr.copy()
        Objective = dot(W, D ** 2) * Fac
        if AGrad:
            for p in range(np):
                if self.call_derivatives[p] == False:
                    continue
                G[p] = 2 * dot(W, D * dM[p])
                if not AHess:
                    continue
                H[p, p] = 2 * dot(W, dM[p] ** 2)
                for q in range(p):
                    if self.call_derivatives[q] == False:
                        continue
                    GNP = 2 * dot(W, dM[p] * dM[q])
                    H[q, p] = GNP
                    H[p, q] = GNP
        G *= Fac
        H *= Fac
        Answer = {"X": Objective, "G": G, "H": H}
        if not in_fd():
            self.D = D
            self.objective = Answer["X"]
            LAST_MVALS = mvals.copy()
        return Answer
Exemple #29
0
    def get(self, mvals, AGrad=False, AHess=False):
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}
        self.PrintDict = OrderedDict()
        self.RMSDDict = OrderedDict()
        #pool = Pool(processes=4)
        def compute(mvals_):
            # This function has automatically assigned variable names from the interaction master file
            # Thus, all variable names in here are protected using an underscore.
            self.FF.make(mvals_)
            VectorD_ = []
            for sys_ in self.sys_opts:
                Energy_, RMSD_ = self.system_driver(sys_)
                #print "Setting %s to" % sys_, Energy_
                exec("%s = Energy_" % sys_) in locals()
                RMSDNrm_ = RMSD_ / self.rmsd_denom
                w_ = self.sys_opts[sys_]['rmsd_weight'] if 'rmsd_weight' in self.sys_opts[sys_] else 1.0
                VectorD_.append(np.sqrt(w_)*RMSDNrm_)
                if not in_fd() and RMSD_ != 0.0:
                    self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_*RMSDNrm_**2)
            VectorE_ = []
            for inter_ in self.inter_opts:
                Calculated_ = eval(self.inter_opts[inter_]['equation'])
                Reference_ = self.inter_opts[inter_]['reference_physical']
                Delta_ = Calculated_ - Reference_
                Denom_ = self.energy_denom
                if self.cauchy:
                    Divisor_ = np.sqrt(Denom_**2 + Reference_**2)
                elif self.attenuate:
                    if Reference_ < Denom_:
                        Divisor_ = Denom_
                    else:
                        Divisor_ = np.sqrt(Denom_**2 + (Reference_-Denom_)**2)
                else:
                    Divisor_ = Denom_
                DeltaNrm_ = Delta_ / Divisor_
                w_ = self.inter_opts[inter_]['weight'] if 'weight' in self.inter_opts[inter_] else 1.0
                VectorE_.append(np.sqrt(w_)*DeltaNrm_)
                if not in_fd():
                    self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (Calculated_, Reference_, Delta_, w_*DeltaNrm_**2)
                # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_
            # The return value is an array of normalized interaction energy differences.
            if not in_fd():
                self.rmsd_part = np.dot(np.array(VectorD_),np.array(VectorD_))
                if len(VectorE_) > 0:
                    self.energy_part = np.dot(np.array(VectorE_),np.array(VectorE_))
                else:
                    self.energy_part = 0.0
            if len(VectorE_) > 0 and len(VectorD_) > 0:
                return np.array(VectorD_ + VectorE_)
            elif len(VectorD_) > 0:
                return np.array(VectorD_)
            elif len(VectorE_) > 0:
                return np.array(VectorE_)
                    
        V = compute(mvals)

        dV = np.zeros((self.FF.np,len(V)))
        if AGrad or AHess:
            for p in range(self.FF.np):
                dV[p,:], _ = f12d3p(fdwrap(compute, mvals, p), h = self.h, f0 = V)

        Answer['X'] = np.dot(V,V)
        for p in range(self.FF.np):
            Answer['G'][p] = 2*np.dot(V, dV[p,:])
            for q in range(self.FF.np):
                Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:])

        if not in_fd():
            self.objective = Answer['X']
            self.FF.make(mvals)

        return Answer
Exemple #30
0
    def get(self, mvals, AGrad=False, AHess=False):
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}
        self.PrintDict = OrderedDict()
        self.RMSDDict = OrderedDict()
        #pool = Pool(processes=4)
        def compute(mvals_):
            # This function has automatically assigned variable names from the interaction master file
            # Thus, all variable names in here are protected using an underscore.
            self.FF.make(mvals_)
            VectorD_ = []

            # The following code was odified by Chengwen Liu to accelarate the tinker analyze and optimize jobs
            def Energy_RMSD(systems):
              tinkerhome = os.environ["TINKERPATH"]
              f1 = open("runAna.sh", "w") 
              f2 = open("runMin.sh", "w") 
              i = 0
              for sys_ in systems: 
                opts = systems[sys_]
                optimize = (opts['optimize'] if 'optimize' in opts else False)
                if not optimize: 
                  if (i+1)%24 == 0:
                    cmd = "rm -f %s.out\n%s/analyze %s.xyz -k %s.key E > %s.out \n"%(sys_, os.environ["TINKERPATH"], sys_, sys_, sys_)
                    i += 1
                  else:
                    cmd = "rm -f %s.out\n%s/analyze %s.xyz -k %s.key E > %s.out & \n"%(sys_, os.environ["TINKERPATH"], sys_, sys_, sys_)
                    i += 1
                  f1.write(cmd)
                else:
                  if (i+1)%24 == 0:
                    cmd = "rm -f %s.xyz_2 %s.out \n%s/optimize %s.xyz -k %s.key 0.0001 > %s.out \n"%(sys_, sys_, os.environ["TINKERPATH"], sys_, sys_, sys_)
                    i += 1
                  else:
                    cmd = "rm -f %s.xyz_2 %s.out \n%s/optimize %s.xyz -k %s.key 0.0001 > %s.out & \n"%(sys_, sys_, os.environ["TINKERPATH"], sys_, sys_, sys_)
                    i += 1
                  f2.write(cmd)
              f1.write("wait\n")
              f2.write("wait\n")
              f1.close()
              f2.close()
              os.system("sh runAna.sh")
              os.system("sh runMin.sh")
              for sys_ in systems:
                while not os.path.isfile(os.path.join(os.getcwd(), sys_ + ".out")):
                  time.sleep(1.0)
              Es = {} 
              RMSDs = {} 
              for sys_ in systems:
                energ = 0.0
                rmsd = 0.0
                for line in open("%s.out"%sys_).readlines():
                  if "Total Potential Energy" in line:
                    energ = float(line.split()[-2].replace('D','e'))
                    Es[sys_] = energ
                    RMSDs[sys_] = 0.0
                  if "Final Function Value :" in line:
                    energ = float(line.split()[-1].replace('D','e'))
                    Es[sys_] = energ
                    M1 = Molecule("%s.xyz" % sys_, ftype="tinker")
                    M2 = Molecule("%s.xyz_2" % sys_, ftype="tinker")
                    M1 += M2
                    RMSDs[sys_] = M1.ref_rmsd(0)[1]
              return Es,RMSDs 

            Es, RMSDs = Energy_RMSD(self.sys_opts)
            for sys_ in self.sys_opts: 
                Energy_ = Es[sys_] 
                RMSD_ = RMSDs[sys_]
                exec("%s = Energy_" % sys_) in locals()
                RMSDNrm_ = RMSD_ / self.rmsd_denom
                w_ = self.sys_opts[sys_]['rmsd_weight'] if 'rmsd_weight' in self.sys_opts[sys_] else 1.0
                VectorD_.append(np.sqrt(w_)*RMSDNrm_)
                if not in_fd() and RMSD_ != 0.0:
                    self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_*RMSDNrm_**2)

            VectorE_ = []
            for inter_ in self.inter_opts:
                Calculated_ = eval(self.inter_opts[inter_]['equation'])
                Reference_ = self.inter_opts[inter_]['reference_physical']
                Delta_ = Calculated_ - Reference_
                Denom_ = self.energy_denom
                if self.cauchy:
                    Divisor_ = np.sqrt(Denom_**2 + Reference_**2)
                elif self.attenuate:
                    if Reference_ < Denom_:
                        Divisor_ = Denom_
                    else:
                        Divisor_ = np.sqrt(Denom_**2 + (Reference_-Denom_)**2)
                else:
                    Divisor_ = Denom_
                DeltaNrm_ = Delta_ / Divisor_
                w_ = self.inter_opts[inter_]['weight'] if 'weight' in self.inter_opts[inter_] else 1.0
                VectorE_.append(np.sqrt(w_)*DeltaNrm_)
                if not in_fd():
                    self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (Calculated_, Reference_, Delta_, w_*DeltaNrm_**2)
                # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_
            # The return value is an array of normalized interaction energy differences.
            if not in_fd():
                self.rmsd_part = np.dot(np.array(VectorD_),np.array(VectorD_))
                if len(VectorE_) > 0:
                    self.energy_part = np.dot(np.array(VectorE_),np.array(VectorE_))
                else:
                    self.energy_part = 0.0
            if len(VectorE_) > 0 and len(VectorD_) > 0:
                return np.array(VectorD_ + VectorE_)
            elif len(VectorD_) > 0:
                return np.array(VectorD_)
            elif len(VectorE_) > 0:
                return np.array(VectorE_)
                    
        V = compute(mvals)

        dV = np.zeros((self.FF.np,len(V)))

        if AGrad or AHess:
            for p in self.pgrad:
                dV[p,:], _ = f12d3p(fdwrap(compute, mvals, p), h = self.h, f0 = V)

        Answer['X'] = np.dot(V,V)
        for p in self.pgrad:
            Answer['G'][p] = 2*np.dot(V, dV[p,:])
            for q in self.pgrad:
                Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:])

        if not in_fd():
            self.objective = Answer['X']
            self.FF.make(mvals)

        return Answer
Exemple #31
0
    def submit_jobs(self, mvals, AGrad=True, AHess=True):
        # This routine is called by Objective.stage() will run before "get".
        # It submits the jobs to the Work Queue and the stage() function will wait for jobs to complete.
        #
        self.tdir = os.getcwd()
        wq = getWorkQueue()
        if wq == None:
            return

        def submit_psi(this_apath, mname, these_mvals):
            """ Create a grid file and a psi4 input file in the absolute path and submit it to the work queue. """
            cwd = os.getcwd()
            if not os.path.exists(this_apath) : os.makedirs(this_apath)
            os.chdir(this_apath)
            self.FF.make(these_mvals)
            o = wopen('objective.dat')
            for line in self.objfiles[d]:
                s = line.split()
                if len(s) > 2 and s[0] == 'path' and s[1] == '=':
                    print >> o, "path = '%s'" % os.getcwd()
                elif len(s) > 2 and s[0] == 'set' and s[1] == 'objective_path':
                    print >> o, "opath = '%s'" % os.getcwd()
                    print >> o, "set objective_path $opath"
                else:
                    print >> o, line,
            o.close()
            os.system("rm -f objective.out")
            if wq == None:
                logger.info("There is no Work Queue!!!\n")
                sys.exit()
            else:
                input_files = [(os.path.join(this_apath, i), i) for i in glob.glob("*")]
                # input_files += [(os.path.join(self.tgtdir,d,"build.dat"), "build.dat")]
                input_files += [(os.path.join(os.path.split(__file__)[0],"data","run_psi_rdvr3_objective.sh"), "run_psi_rdvr3_objective.sh")]
                logger.info("\r")
                queue_up_src_dest(wq,"sh run_psi_rdvr3_objective.sh %s &> run_psi_rdvr3_objective.log" % mname,
                                  input_files=input_files,
                                  output_files=[(os.path.join(this_apath, i),i) for i in ["run_psi_rdvr3_objective.log", "output.dat"]], verbose=False)
            os.chdir(cwd)

        for d in self.objfiles:
            logger.info("\rNow working on" + str(d) + 50*' ' + '\r')
            odir = os.path.join(os.getcwd(),d)
            #if os.path.exists(odir):
            #    shutil.rmtree(odir)
            if not os.path.exists(odir): os.makedirs(odir)
            apath = os.path.join(odir, "current")
            submit_psi(apath, d, mvals)
            for p in range(self.FF.np):
                def subjob(mvals_,h):
                    apath = os.path.join(odir, str(p), str(h))
                    submit_psi(apath, d, mvals_)
                    #logger.info("Will set up a job for %s, parameter %i\n" % (d, p))
                    return 0.0
                if self.callderivs[d][p]:
                    if AHess:
                        f12d3p(fdwrap(subjob, mvals, p, h=self.h), h = self.h, f0 = 0.0)
                    elif AGrad:
                        if self.bidirect:
                            f12d3p(fdwrap(subjob, mvals, p, h=self.h), h = self.h, f0 = 0.0)
                        else:
                            f1d2p(fdwrap(subjob, mvals, p, h=self.h), h = self.h, f0 = 0.0)
Exemple #32
0
    def get(self, mvals, AGrad=False, AHess=False):
	"""
        LPW 04-17-2013
        
        This subroutine builds the objective function from Psi4.

        @param[in] mvals Mathematical parameter values
        @param[in] AGrad Switch to turn on analytic gradient
        @param[in] AHess Switch to turn on analytic Hessian
        @return Answer Contribution to the objective function
        """
        Answer = {}
        Fac = 1000000
        n = len(mvals)
        X = 0.0
        G = np.zeros(n)
        H = np.zeros((n,n))
        pvals = self.FF.make(mvals)
        self.tdir = os.getcwd()
        self.objd = OrderedDict()
        self.gradd = OrderedDict()
        self.hdiagd = OrderedDict()
        wq = getWorkQueue()

        def fdwrap2(func,mvals0,pidx,qidx,key=None,**kwargs):
            def func2(arg1,arg2):
                mvals = list(mvals0)
                mvals[pidx] += arg1
                mvals[qidx] += arg2
                logger.info("\rfdwrap2:" + func.__name__ + "[%i] = % .1e , [%i] = % .1e" % (pidx, arg1, qidx, arg2) + ' '*50)
                if key != None:
                    return func(mvals,**kwargs)[key]
                else:
                    return func(mvals,**kwargs)
            return func2

        def f2d5p(f, h):
            fpp, fpm, fmp, fmm = [f(i*h,j*h) for i,j in [(1,1),(1,-1),(-1,1),(-1,-1)]]
            fpp = (fpp-fpm-fmp+fmm)/(4*h*h)
            return fpp

        def f2d4p(f, h, f0 = None):
            if f0 == None:
                fpp, fp0, f0p, f0 = [f(i*h,j*h) for i,j in [(1,1),(1,0),(0,1),(0,0)]]
            else:
                fpp, fp0, f0p = [f(i*h,j*h) for i,j in [(1,1),(1,0),(0,1)]]
            fpp = (fpp-fp0-f0p+f0)/(h*h)
            return fpp

        for d in self.objfiles:
            logger.info("\rNow working on" + str(d) + 50*' ' + '\r')
            if wq == None:
                x = self.driver(mvals, d)
            grad  = np.zeros(n)
            hdiag = np.zeros(n)
            hess  = np.zeros((n,n))
            apath = os.path.join(self.tdir, d, "current")
            x = float(open(os.path.join(apath,'objective.out')).readlines()[0].split()[1])*self.factor
            for p in range(self.FF.np):
                if self.callderivs[d][p]:
                    def reader(mvals_,h):
                        apath = os.path.join(self.tdir, d, str(p), str(h))
                        answer = float(open(os.path.join(apath,'objective.out')).readlines()[0].split()[1])*self.factor
                        return answer
                    if AHess:
                        if wq != None:
                            apath = os.path.join(self.tdir, d, "current")
                            x = float(open(os.path.join(apath,'objective.out')).readlines()[0].split()[1])*self.factor
                            grad[p], hdiag[p] = f12d3p(fdwrap(reader, mvals, p, h=self.h), h = self.h, f0 = x)
                        else:
                            grad[p], hdiag[p] = f12d3p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x)
                        hess[p,p] = hdiag[p]
                    elif AGrad:
                        if self.bidirect:
                            if wq != None:
                                apath = os.path.join(self.tdir, d, "current")
                                x = float(open(os.path.join(apath,'objective.out')).readlines()[0].split()[1])*self.factor
                                grad[p], _ = f12d3p(fdwrap(reader, mvals, p, h=self.h), h = self.h, f0 = x)
                            else:
                                grad[p], _ = f12d3p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x)
                        else:
                            if wq != None:
                                # Since the calculations are submitted as 3-point finite difference, this part of the code
                                # actually only reads from half of the completed calculations.
                                grad[p] = f1d2p(fdwrap(reader, mvals, p, h=self.h), h = self.h, f0 = x)
                            else:
                                grad[p] = f1d2p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x)
                            
            self.objd[d] = x
            self.gradd[d] = grad
            self.hdiagd[d] = hdiag
            X += x
            G += grad
            #H += np.diag(hdiag)
            H += hess
        if not in_fd():
            self.objective = X
            self.objvals = self.objd
        # print self.objd
        # print self.gradd
        # print self.hdiagd
                    
        if float('Inf') in pvals:
            return {'X' : 1e10, 'G' : G, 'H' : H}
        return {'X' : X, 'G' : G, 'H' : H}
Exemple #33
0
 def func1(arg):
     mvals = list(mvals0)
     mvals[pidxj] += arg
     return f1d5p(fdwrap(self.Objective.Full,mvals,pidxi,'X',Order=0),self.h)
Exemple #34
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {
            'X': 0.0,
            'G': np.zeros(self.FF.np),
            'H': np.zeros((self.FF.np, self.FF.np))
        }

        # If the weight is zero, turn all derivatives off.
        if (self.weight == 0.0):
            AGrad = False
            AHess = False

        def callM(mvals_, dielectric=False):
            logger.info("\r")
            pvals = self.FF.make(mvals_)
            return self.engine.interaction_energy(self.select1, self.select2)

        logger.info("Executing\r")
        emm = callM(mvals)

        D = emm - self.eqm
        dV = np.zeros((self.FF.np, len(emm)))

        if self.writelevel > 0:
            # Dump interaction energies to disk.
            np.savetxt('M.txt', emm)
            np.savetxt('Q.txt', self.eqm)
            import pickle
            pickle.dump((self.name, self.label, self.prefactor, self.eqm, emm),
                        open("qm_vs_mm.p", 'w'))
            # select the qm and mm data that has >0 weight to plot
            qm_data, mm_data = [], []
            for i in range(len(self.eqm)):
                if self.prefactor[i] != 0:
                    qm_data.append(self.eqm[i])
                    mm_data.append(emm[i])
            plot_interaction_qm_vs_mm(qm_data,
                                      mm_data,
                                      title="Interaction Energy " + self.name)

        # Do the finite difference derivative.
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p, :], _ = f12d3p(fdwrap(callM, mvals, p), h=self.h, f0=emm)
            # Create the force field one last time.
            pvals = self.FF.make(mvals)

        Answer['X'] = np.dot(self.prefactor * D / self.divisor,
                             D / self.divisor)
        for p in self.pgrad:
            Answer['G'][p] = 2 * np.dot(self.prefactor * D / self.divisor,
                                        dV[p, :] / self.divisor)
            for q in self.pgrad:
                Answer['H'][p, q] = 2 * np.dot(
                    self.prefactor * dV[p, :] / self.divisor,
                    dV[q, :] / self.divisor)

        if not in_fd():
            self.emm = emm
            self.objective = Answer['X']

        ## QYD: try to clean up OpenMM engine.simulation objects to free up GPU memory
        try:
            if self.engine.name == 'openmm':
                if hasattr(self.engine, 'simulation'):
                    del self.engine.simulation
                if hasattr(self.engine, 'A'): del self.engine.A
                if hasattr(self.engine, 'B'): del self.engine.B
        except:
            pass

        return Answer
Exemple #35
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}

        # If the weight is zero, turn all derivatives off.
        if (self.weight == 0.0):
            AGrad = False
            AHess = False

        def callM(mvals_, dielectric=False):
            logger.info("\r")
            pvals = self.FF.make(mvals_)
            return self.engine.interaction_energy(self.select1, self.select2)

        logger.info("Executing\r")
        emm = callM(mvals)

        D = emm - self.eqm
        dV = np.zeros((self.FF.np,len(emm)))

        if self.writelevel > 0:
            # Dump interaction energies to disk.
            np.savetxt('M.txt',emm)
            np.savetxt('Q.txt',self.eqm)
            import pickle
            pickle.dump((self.name, self.label, self.prefactor, self.eqm, emm), open("qm_vs_mm.p",'w'))
            # select the qm and mm data that has >0 weight to plot
            qm_data, mm_data = [], []
            for i in xrange(len(self.eqm)):
                if self.prefactor[i] != 0:
                    qm_data.append(self.eqm[i])
                    mm_data.append(emm[i])
            plot_interaction_qm_vs_mm(qm_data, mm_data, title="Interaction Energy "+self.name)

        # Do the finite difference derivative.
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p,:], _ = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = emm)
            # Create the force field one last time.
            pvals  = self.FF.make(mvals)

        Answer['X'] = np.dot(self.prefactor*D/self.divisor,D/self.divisor)
        for p in self.pgrad:
            Answer['G'][p] = 2*np.dot(self.prefactor*D/self.divisor, dV[p,:]/self.divisor)
            for q in self.pgrad:
                Answer['H'][p,q] = 2*np.dot(self.prefactor*dV[p,:]/self.divisor, dV[q,:]/self.divisor)

        if not in_fd():
            self.emm = emm
            self.objective = Answer['X']

        ## QYD: try to clean up OpenMM engine.simulation objects to free up GPU memory
        try:
            if self.engine.name == 'openmm':
                if hasattr(self.engine, 'simulation'): del self.engine.simulation
                if hasattr(self.engine, 'A'): del self.engine.A
                if hasattr(self.engine, 'B'): del self.engine.B
        except:
            pass

        return Answer
Exemple #36
0
    def get(self, mvals, AGrad=False, AHess=False):
        """ Evaluate objective function. """
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}
        def compute(mvals_):
            self.FF.make(mvals_)
            Xx, Gx, Hx, freqs, normal_modes, M_opt = self.hessian_driver()
            # convert into internal hessian
            Xx *= 1/ Bohr2nm
            Gx *= Bohr2nm/ Hartree2kJmol
            Hx *= Bohr2nm**2/ Hartree2kJmol
            Hq = self.IC.calcHess(Xx, Gx, Hx)
            compute.Hq_flat = Hq.flatten()
            compute.freqs = freqs
            compute.normal_modes = normal_modes
            compute.M_opt = M_opt
            diff = Hq - self.ref_Hq

            return (np.sqrt(self.wts)/self.denom) * (compute.Hq_flat - self.ref_Hq_flat)

        V = compute(mvals)
        Answer['X'] = np.dot(V,V) * len(compute.freqs) # HJ: len(compute.freqs) is multiplied to match the scale of X2 with vib freq target X2
        # compute gradients and hessian
        dV = np.zeros((self.FF.np,len(V)))
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p,:], _ = f12d3p(fdwrap(compute, mvals, p), h = self.h, f0 = V)

        for p in self.pgrad:
            Answer['G'][p] = 2*np.dot(V, dV[p,:]) * len(compute.freqs)
            for q in self.pgrad:
                Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) * len(compute.freqs)

        if not in_fd():
            self.Hq_flat = compute.Hq_flat
            self.Hq = self.Hq_flat.reshape(self.ref_Hq.shape)
            self.objective = Answer['X']
            self.FF.make(mvals)

        if self.writelevel > 0:
            # 1. write HessianCompare.txt
            hessian_comparison = np.array([
                self.ref_Hq_flat,
                compute.Hq_flat,
                compute.Hq_flat - self.ref_Hq_flat,
                np.sqrt(self.wts)/self.denom
            ]).T
            np.savetxt("HessianCompare.txt", hessian_comparison, header="%11s  %12s  %12s  %12s" % ("QMHessian", "MMHessian", "Delta(MM-QM)", "Weight"), fmt="% 12.6e")

            # 2. rearrange MM vibrational frequencies using overlap between normal modes in redundant internal coordinates
            ref_int_normal_modes = self.calc_int_normal_mode(self.ref_xyz, self.ref_eigvecs)
            int_normal_modes = self.calc_int_normal_mode(np.array(compute.M_opt.xyzs[0]), compute.normal_modes)
            a = np.array([[(1.0-np.abs(np.dot(v1/np.linalg.norm(v1),v2/np.linalg.norm(v2)))) for v2 in int_normal_modes] for v1 in ref_int_normal_modes])
            row, c2r = optimize.linear_sum_assignment(a)
            # old arrangement method, which uses overlap between mass weighted vibrational modes in cartesian coordinates
            # a = np.array([[(1.0-self.vib_overlap(v1, v2)) for v2 in compute.normal_modes] for v1 in self.ref_eigvecs])
            # row, c2r = optimize.linear_sum_assignment(a)

            freqs_rearr = compute.freqs[c2r]
            normal_modes_rearr = compute.normal_modes[c2r]

            # 3. Save rearranged frequencies and normal modes into a file for post-analysis
            with open('mm_vdata.txt', 'w') as outfile:
                outfile.writelines('%s\n' % line for line in compute.M_opt.write_xyz([0]))
                outfile.write('\n')
                for freq, normal_mode in zip(freqs_rearr, normal_modes_rearr):
                    outfile.write(f'{freq}\n')
                    for nx, ny, nz in normal_mode:
                        outfile.write(f'{nx:13.4f} {ny:13.4f} {nz:13.4f}\n')
                    outfile.write('\n')
            outfile.close()

            # 4. draw a scatter plot of vibrational frequencies and an overlap matrix of normal modes in cartessian coordinates
            draw_vibfreq_scatter_plot_n_overlap_matrix(self.name, self.engine, self.ref_eigvals, self.ref_eigvecs, freqs_rearr, normal_modes_rearr)
            return Answer
Exemple #37
0
    def get(self, mvals, AGrad=False, AHess=False):
        Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))}
        self.PrintDict = OrderedDict()
        self.RMSDDict = OrderedDict()
        EnergyDict = OrderedDict()
        #pool = Pool(processes=4)
        def compute(mvals_):
            # This function has automatically assigned variable names from the interaction master file
            # Thus, all variable names in here are protected using an underscore.
            self.FF.make(mvals_)
            VectorD_ = []
            for sys_ in self.sys_opts:
                Energy_, RMSD_ = self.system_driver(sys_)
                # Energies are stored in a dictionary.
                EnergyDict[sys_] = Energy_
                RMSDNrm_ = RMSD_ / self.rmsd_denom
                w_ = self.sys_opts[sys_]['rmsd_weight'] if 'rmsd_weight' in self.sys_opts[sys_] else 1.0
                VectorD_.append(np.sqrt(w_)*RMSDNrm_)
                if not in_fd() and RMSD_ != 0.0:
                    self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_*RMSDNrm_**2)
            VectorE_ = []
            for inter_ in self.inter_opts:
                def encloseInDictionary(matchobj):
                    return 'EnergyDict["' + matchobj.group(0)+'"]'
                # Here we need to evaluate a mathematical expression of the stored variables in EnergyDict.
                # We start by enclosing every variable in EnergyDict[""] and then calling eval on it.
                evalExpr = re.sub('[A-Za-z_][A-Za-z0-9_]*', encloseInDictionary, self.inter_opts[inter_]['equation'])
                Calculated_ = eval(evalExpr)
                Reference_ = self.inter_opts[inter_]['reference_physical']
                Delta_ = Calculated_ - Reference_
                Denom_ = self.energy_denom
                if self.cauchy:
                    Divisor_ = np.sqrt(Denom_**2 + Reference_**2)
                elif self.attenuate:
                    if Reference_ < Denom_:
                        Divisor_ = Denom_
                    else:
                        Divisor_ = np.sqrt(Denom_**2 + (Reference_-Denom_)**2)
                else:
                    Divisor_ = Denom_
                DeltaNrm_ = Delta_ / Divisor_
                w_ = self.inter_opts[inter_]['weight'] if 'weight' in self.inter_opts[inter_] else 1.0
                VectorE_.append(np.sqrt(w_)*DeltaNrm_)
                if not in_fd():
                    self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (Calculated_, Reference_, Delta_, w_*DeltaNrm_**2)
                # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_
            # The return value is an array of normalized interaction energy differences.
            if not in_fd():
                self.rmsd_part = np.dot(np.array(VectorD_),np.array(VectorD_))
                if len(VectorE_) > 0:
                    self.energy_part = np.dot(np.array(VectorE_),np.array(VectorE_))
                else:
                    self.energy_part = 0.0
            if len(VectorE_) > 0 and len(VectorD_) > 0:
                return np.array(VectorD_ + VectorE_)
            elif len(VectorD_) > 0:
                return np.array(VectorD_)
            elif len(VectorE_) > 0:
                return np.array(VectorE_)
                    
        V = compute(mvals)

        dV = np.zeros((self.FF.np,len(V)))
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p,:], _ = f12d3p(fdwrap(compute, mvals, p), h = self.h, f0 = V)

        Answer['X'] = np.dot(V,V)
        for p in self.pgrad:
            Answer['G'][p] = 2*np.dot(V, dV[p,:])
            for q in self.pgrad:
                Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:])

        if not in_fd():
            self.objective = Answer['X']
            self.FF.make(mvals)

        return Answer
Exemple #38
0
def property_derivatives(engine, FF, mvals, h, pgrad, kT, property_driver, property_kwargs, AGrad=True):

    """ 
    Function for double-checking property derivatives.  This function is called to perform
    a more explicit numerical derivative of the property, rather than going through the 
    fluctuation formula.  It takes longer and is potentially less precise, which means
    it's here mainly as a sanity check.

    @param[in] mvals Mathematical parameter values
    @param[in] h Finite difference step size
    @param[in] phase The phase (liquid, gas) to perform the calculation on
    @param[in] property_driver The function that calculates the property
    @param[in] property_driver A dictionary of arguments that goes into calculating the property
    @param[in] AGrad Switch to turn derivatives on or off; if off, return all zeros
    @return G First derivative of the property

    """
    G        = np.zeros(FF.np)
    if not AGrad:
        return G
    def energy_driver(mvals_):
        FF.make(mvals_)
        return engine.energy_dipole()

    ED0      = energy_driver(mvals)
    E0       = ED0[:,0]
    D0       = ED0[:,1:]
    P0       = property_driver(None, **property_kwargs)
    if 'h_' in property_kwargs:
        H0 = property_kwargs['h_'].copy()
    for i in pgrad:
        logger.info("%s\n" % (FF.plist[i] + " "*30))
        ED1      = fdwrap(energy_driver,mvals,i)(h)
        E1       = ED1[:,0]
        D1       = ED1[:,1:]
        b = np.exp(-(E1-E0)/kT)
        b /= np.sum(b)
        if 'h_' in property_kwargs:
            property_kwargs['h_'] = H0.copy() + (E1-E0)
        if 'd_' in property_kwargs:
            property_kwargs['d_'] = D1.copy()
        S = -1*np.dot(b,np.log(b))
        InfoContent = np.exp(S)
        if InfoContent / len(E0) < 0.1:
            logger.warn("Warning: Effective number of snapshots: % .1f (out of %i)\n" % (InfoContent, len(E0)))
        P1 = property_driver(b=b,**property_kwargs)
        EDM1      = fdwrap(energy_driver,mvals,i)(-h)
        EM1       = EDM1[:,0]
        DM1       = EDM1[:,1:]
        b = np.exp(-(EM1-E0)/kT)
        b /= np.sum(b)
        if 'h_' in property_kwargs:
            property_kwargs['h_'] = H0.copy() + (EM1-E0)
        if 'd_' in property_kwargs:
            property_kwargs['d_'] = DM1.copy()
        S = -1*np.dot(b,np.log(b))
        InfoContent = np.exp(S)
        if InfoContent / len(E0) < 0.1:
            logger.warn("Warning: Effective number of snapshots: % .1f (out of %i)\n" % (InfoContent, len(E0)))
        PM1 = property_driver(b=b,**property_kwargs)
        G[i] = (P1-PM1)/(2*h)
    if 'h_' in property_kwargs:
        property_kwargs['h_'] = H0.copy()
    if 'd_' in property_kwargs:
        property_kwargs['d_'] = D0.copy()
    return G
Exemple #39
0
    def get(self, mvals, AGrad=False, AHess=False):
        Answer = {
            'X': 0.0,
            'G': np.zeros(self.FF.np),
            'H': np.zeros((self.FF.np, self.FF.np))
        }
        self.PrintDict = OrderedDict()
        self.RMSDDict = OrderedDict()
        EnergyDict = OrderedDict()

        #pool = Pool(processes=4)
        def compute(mvals_):
            # This function has automatically assigned variable names from the interaction master file
            # Thus, all variable names in here are protected using an underscore.
            self.FF.make(mvals_)
            VectorD_ = []
            for sys_ in self.sys_opts:
                Energy_, RMSD_ = self.system_driver(sys_)
                # Energies are stored in a dictionary.
                EnergyDict[sys_] = Energy_
                RMSDNrm_ = RMSD_ / self.rmsd_denom
                w_ = self.sys_opts[sys_][
                    'rmsd_weight'] if 'rmsd_weight' in self.sys_opts[
                        sys_] else 1.0
                VectorD_.append(np.sqrt(w_) * RMSDNrm_)
                if not in_fd() and RMSD_ != 0.0:
                    self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_,
                                                              w_ * RMSDNrm_**2)
            VectorE_ = []
            for inter_ in self.inter_opts:

                def encloseInDictionary(matchobj):
                    return 'EnergyDict["' + matchobj.group(0) + '"]'

                # Here we need to evaluate a mathematical expression of the stored variables in EnergyDict.
                # We start by enclosing every variable in EnergyDict[""] and then calling eval on it.
                evalExpr = re.sub('[A-Za-z_][A-Za-z0-9_]*',
                                  encloseInDictionary,
                                  self.inter_opts[inter_]['equation'])
                Calculated_ = eval(evalExpr)
                Reference_ = self.inter_opts[inter_]['reference_physical']
                Delta_ = Calculated_ - Reference_
                Denom_ = self.energy_denom
                if self.cauchy:
                    Divisor_ = np.sqrt(Denom_**2 + Reference_**2)
                elif self.attenuate:
                    if Reference_ < Denom_:
                        Divisor_ = Denom_
                    else:
                        Divisor_ = np.sqrt(Denom_**2 +
                                           (Reference_ - Denom_)**2)
                else:
                    Divisor_ = Denom_
                DeltaNrm_ = Delta_ / Divisor_
                w_ = self.inter_opts[inter_][
                    'weight'] if 'weight' in self.inter_opts[inter_] else 1.0
                VectorE_.append(np.sqrt(w_) * DeltaNrm_)
                if not in_fd():
                    self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (
                        Calculated_, Reference_, Delta_, w_ * DeltaNrm_**2)
                # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_
            # The return value is an array of normalized interaction energy differences.
            if not in_fd():
                self.rmsd_part = np.dot(np.array(VectorD_), np.array(VectorD_))
                if len(VectorE_) > 0:
                    self.energy_part = np.dot(np.array(VectorE_),
                                              np.array(VectorE_))
                else:
                    self.energy_part = 0.0
            if len(VectorE_) > 0 and len(VectorD_) > 0:
                return np.array(VectorD_ + VectorE_)
            elif len(VectorD_) > 0:
                return np.array(VectorD_)
            elif len(VectorE_) > 0:
                return np.array(VectorE_)

        V = compute(mvals)

        dV = np.zeros((self.FF.np, len(V)))
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p, :], _ = f12d3p(fdwrap(compute, mvals, p), h=self.h, f0=V)

        Answer['X'] = np.dot(V, V)
        for p in self.pgrad:
            Answer['G'][p] = 2 * np.dot(V, dV[p, :])
            for q in self.pgrad:
                Answer['H'][p, q] = 2 * np.dot(dV[p, :], dV[q, :])

        if not in_fd():
            self.objective = Answer['X']
            self.FF.make(mvals)

        return Answer
Exemple #40
0
def property_derivatives(engine, FF, mvals, h, pgrad, kT, property_driver, property_kwargs, AGrad=True):

    """ 
    Function for double-checking property derivatives.  This function is called to perform
    a more explicit numerical derivative of the property, rather than going through the 
    fluctuation formula.  It takes longer and is potentially less precise, which means
    it's here mainly as a sanity check.

    @param[in] mvals Mathematical parameter values
    @param[in] h Finite difference step size
    @param[in] phase The phase (liquid, gas) to perform the calculation on
    @param[in] property_driver The function that calculates the property
    @param[in] property_driver A dictionary of arguments that goes into calculating the property
    @param[in] AGrad Switch to turn derivatives on or off; if off, return all zeros
    @return G First derivative of the property

    """
    G        = np.zeros(FF.np)
    if not AGrad:
        return G
    def energy_driver(mvals_):
        FF.make(mvals_)
        return engine.energy_dipole()

    ED0      = energy_driver(mvals)
    E0       = ED0[:,0]
    D0       = ED0[:,1:]
    P0       = property_driver(None, **property_kwargs)
    if 'h_' in property_kwargs:
        H0 = property_kwargs['h_'].copy()
    for i in pgrad:
        logger.info("%s\n" % (FF.plist[i] + " "*30))
        ED1      = fdwrap(energy_driver,mvals,i)(h)
        E1       = ED1[:,0]
        D1       = ED1[:,1:]
        b = np.exp(-(E1-E0)/kT)
        b /= np.sum(b)
        if 'h_' in property_kwargs:
            property_kwargs['h_'] = H0.copy() + (E1-E0)
        if 'd_' in property_kwargs:
            property_kwargs['d_'] = D1.copy()
        S = -1*np.dot(b,np.log(b))
        InfoContent = np.exp(S)
        if InfoContent / len(E0) < 0.1:
            logger.warn("Warning: Effective number of snapshots: % .1f (out of %i)\n" % (InfoContent, len(E0)))
        P1 = property_driver(b=b,**property_kwargs)
        EDM1      = fdwrap(energy_driver,mvals,i)(-h)
        EM1       = EDM1[:,0]
        DM1       = EDM1[:,1:]
        b = np.exp(-(EM1-E0)/kT)
        b /= np.sum(b)
        if 'h_' in property_kwargs:
            property_kwargs['h_'] = H0.copy() + (EM1-E0)
        if 'd_' in property_kwargs:
            property_kwargs['d_'] = DM1.copy()
        S = -1*np.dot(b,np.log(b))
        InfoContent = np.exp(S)
        if InfoContent / len(E0) < 0.1:
            logger.warn("Warning: Effective number of snapshots: % .1f (out of %i)\n" % (InfoContent, len(E0)))
        PM1 = property_driver(b=b,**property_kwargs)
        G[i] = (P1-PM1)/(2*h)
    if 'h_' in property_kwargs:
        property_kwargs['h_'] = H0.copy()
    if 'd_' in property_kwargs:
        property_kwargs['d_'] = D0.copy()
    return G
Exemple #41
0
    def get(self, mvals, AGrad=False, AHess=False):
	"""
        LPW 05-30-2012
        
        This subroutine builds the objective function (and optionally
        its derivatives) from a general software.  

        This subroutine interfaces with simulation software 'drivers'.
        The driver is expected to give exact values, fitting values, and weights.

        @param[in] mvals Mathematical parameter values
        @param[in] AGrad Switch to turn on analytic gradient
        @param[in] AHess Switch to turn on analytic Hessian
        @return Answer Contribution to the objective function
        """
        global LAST_MVALS, CHECK_BASIS
        # print mvals
        # print LAST_MVALS
        # print mvals == LAST_MVALS
        if LAST_MVALS is None or not (mvals == LAST_MVALS).all():
            CHECK_BASIS = False
        else:
            CHECK_BASIS = False
        Answer = {}
        Fac = 1000000
        ## Dictionary for derivative terms
        dM = {}
        # Create the new force field!!
        NP = len(mvals)
        G = np.zeros(NP)
        H = np.zeros((NP,NP))
        pvals = self.FF.make(mvals)
        if float('Inf') in pvals:
            return {'X' : 1e10, 'G' : G, 'H' : H}
        Ans = self.driver()
        W = Ans[:,2]
        M = Ans[:,1]
        Q = Ans[:,0]
        D = M - Q

        self.MAQ = np.mean(np.abs(Q))

        ns = len(M)
        # Wrapper to the driver, which returns just the part that changes.
        def callM(mvals_):
            self.FF.make(mvals_)
            Ans2 = self.driver()
            M_ = Ans2[:,1]
            D_ = M_ - Q
	    return Ans2[:,1]
        if AGrad:
            # Leaving comment here if we want to reintroduce second deriv someday.
            #     dM[p,:], ddM[p,:] = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = M)
            xgrad = []
            for p in self.pgrad:
                dM_arr = f1d2p(fdwrap(callM, mvals, p), h = self.h, f0 = M)
                if np.max(np.abs(dM_arr)) == 0.0 and (not self.evaluated):
                    logger.info("\r Simulation %s will skip over parameter %i in subsequent steps\n" % (self.name, p))
                    xgrad.append(p)
                else:
                    dM[p] = dM_arr.copy()
            for p in xgrad:
                self.pgrad.remove(p)
	Objective = np.dot(W, D**2) * Fac
        if AGrad:
            for p in self.pgrad:
                G[p] = 2 * np.dot(W, D*dM[p])
                if not AHess: continue
                H[p, p] = 2 * np.dot(W, dM[p]**2)
                for q in range(p):
                    if q not in self.pgrad: continue
                    GNP = 2 * np.dot(W, dM[p] * dM[q])
                    H[q,p] = GNP
                    H[p,q] = GNP
        G *= Fac
        H *= Fac
        Answer = {'X':Objective, 'G':G, 'H':H}
        if not in_fd():
            self.D = D
            self.objective = Answer['X']
            LAST_MVALS = mvals.copy()
        return Answer
Exemple #42
0
    def get(self, mvals, AGrad=False, AHess=False):
        """
        LPW 05-30-2012
        
        This subroutine builds the objective function (and optionally
        its derivatives) from a general software.  

        This subroutine interfaces with simulation software 'drivers'.
        The driver is expected to give exact values, fitting values, and weights.

        @param[in] mvals Mathematical parameter values
        @param[in] AGrad Switch to turn on analytic gradient
        @param[in] AHess Switch to turn on analytic Hessian
        @return Answer Contribution to the objective function
        """
        global LAST_MVALS, CHECK_BASIS
        # print mvals
        # print LAST_MVALS
        # print mvals == LAST_MVALS
        if LAST_MVALS is None or not (mvals == LAST_MVALS).all():
            CHECK_BASIS = False
        else:
            CHECK_BASIS = False
        Answer = {}
        Fac = 1000000
        ## Dictionary for derivative terms
        dM = {}
        # Create the new force field!!
        NP = len(mvals)
        G = np.zeros(NP)
        H = np.zeros((NP, NP))
        pvals = self.FF.make(mvals)
        if float('Inf') in pvals:
            return {'X': 1e10, 'G': G, 'H': H}
        Ans = self.driver()
        W = Ans[:, 2]
        M = Ans[:, 1]
        Q = Ans[:, 0]
        D = M - Q

        self.MAQ = np.mean(np.abs(Q))

        ns = len(M)

        # Wrapper to the driver, which returns just the part that changes.
        def callM(mvals_):
            self.FF.make(mvals_)
            Ans2 = self.driver()
            M_ = Ans2[:, 1]
            D_ = M_ - Q
            return Ans2[:, 1]

        if AGrad:
            # Leaving comment here if we want to reintroduce second deriv someday.
            #     dM[p,:], ddM[p,:] = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = M)
            xgrad = []
            for p in self.pgrad:
                dM_arr = f1d2p(fdwrap(callM, mvals, p), h=self.h, f0=M)
                if np.max(np.abs(dM_arr)) == 0.0 and (not self.evaluated):
                    logger.info(
                        "\r Simulation %s will skip over parameter %i in subsequent steps\n"
                        % (self.name, p))
                    xgrad.append(p)
                else:
                    dM[p] = dM_arr.copy()
            for p in xgrad:
                self.pgrad.remove(p)
        Objective = np.dot(W, D**2) * Fac
        if AGrad:
            for p in self.pgrad:
                G[p] = 2 * np.dot(W, D * dM[p])
                if not AHess: continue
                H[p, p] = 2 * np.dot(W, dM[p]**2)
                for q in range(p):
                    if q not in self.pgrad: continue
                    GNP = 2 * np.dot(W, dM[p] * dM[q])
                    H[q, p] = GNP
                    H[p, q] = GNP
        G *= Fac
        H *= Fac
        Answer = {'X': Objective, 'G': G, 'H': H}
        if not in_fd():
            self.D = D
            self.objective = Answer['X']
            LAST_MVALS = mvals.copy()
        return Answer
Exemple #43
0
    def get(self, mvals, AGrad=False, AHess=False):
        Answer = {
            'X': 0.0,
            'G': np.zeros(self.FF.np),
            'H': np.zeros((self.FF.np, self.FF.np))
        }
        self.PrintDict = OrderedDict()
        # enable self.system_mval_masks (supported by OptGeoTarget_SMIRNOFF)
        enable_system_mval_mask = hasattr(self, 'system_mval_masks')

        def compute(mvals, p_idx=None):
            ''' Compute total objective value for each system '''
            self.FF.make(mvals)
            v_obj_list = []
            for sysname, sysopt in self.sys_opts.items():
                # ref values of each type
                vref_bonds = self.internal_coordinates[sysname]['vref_bonds']
                vref_angles = self.internal_coordinates[sysname]['vref_angles']
                vref_dihedrals = self.internal_coordinates[sysname][
                    'vref_dihedrals']
                vref_impropers = self.internal_coordinates[sysname][
                    'vref_impropers']
                # counts of each type
                n_bonds = len(vref_bonds)
                n_angles = len(vref_angles)
                n_dihedrals = len(vref_dihedrals)
                n_impropers = len(vref_impropers)
                # use self.system_mval_masks to skip evaluations when computing gradients
                if enable_system_mval_mask and in_fd() and (
                        p_idx is not None) and (
                            self.system_mval_masks[sysname][p_idx] == False):
                    v_obj_list += [0] * (n_bonds + n_angles + n_dihedrals +
                                         n_impropers)
                    continue
                # read denominators from system options
                bond_denom = sysopt['bond_denom']
                angle_denom = sysopt['angle_denom']
                dihedral_denom = sysopt['dihedral_denom']
                improper_denom = sysopt['improper_denom']
                # inverse demon to be scaling factors, 0 for denom 0
                scale_bond = 1.0 / bond_denom if bond_denom != 0 else 0.0
                scale_angle = 1.0 / angle_denom if angle_denom != 0 else 0.0
                scale_dihedral = 1.0 / dihedral_denom if dihedral_denom != 0 else 0.0
                scale_improper = 1.0 / improper_denom if improper_denom != 0 else 0.0
                # calculate new internal coordinates
                v_ic = self.system_driver(sysname)
                # objective contribution from bonds
                vtar_bonds = v_ic['bonds']
                diff_bond = ((vref_bonds - vtar_bonds) *
                             scale_bond).tolist() if n_bonds > 0 else []
                # objective contribution from angles
                vtar_angles = v_ic['angles']
                diff_angle = (periodic_diff(vref_angles, vtar_angles, 360) *
                              scale_angle).tolist() if n_angles > 0 else []
                # objective contribution from dihedrals
                vtar_dihedrals = v_ic['dihedrals']
                diff_dihedral = (
                    periodic_diff(vref_dihedrals, vtar_dihedrals, 360) *
                    scale_dihedral).tolist() if n_dihedrals > 0 else []
                # objective contribution from improper dihedrals
                vtar_impropers = v_ic['impropers']
                diff_improper = (
                    periodic_diff(vref_impropers, vtar_impropers, 360) *
                    scale_improper).tolist() if n_impropers > 0 else []
                # combine objective values into a big result list
                sys_obj_list = diff_bond + diff_angle + diff_dihedral + diff_improper
                # extend the result v_obj_list by individual terms in this system
                v_obj_list += sys_obj_list
                # save print string
                if not in_fd():
                    # For printing, we group the RMSD by type
                    rmsd_bond = compute_rmsd(vref_bonds, vtar_bonds)
                    rmsd_angle = compute_rmsd(vref_angles,
                                              vtar_angles,
                                              v_periodic=360)
                    rmsd_dihedral = compute_rmsd(vref_dihedrals,
                                                 vtar_dihedrals,
                                                 v_periodic=360)
                    rmsd_improper = compute_rmsd(vref_impropers,
                                                 vtar_impropers,
                                                 v_periodic=360)
                    obj_total = sum(v**2 for v in sys_obj_list)
                    self.PrintDict[sysname] = "% 9.3f % 7.2f % 9.3f % 7.2f % 9.3f % 7.2f % 9.3f % 7.2f %17.3f" % (rmsd_bond, \
                        bond_denom, rmsd_angle, angle_denom, rmsd_dihedral, dihedral_denom, rmsd_improper, improper_denom, obj_total)
            return np.array(v_obj_list, dtype=float)

        V = compute(mvals)
        Answer['X'] = np.dot(V, V)
        # write objective decomposition if wanted
        if self.writelevel > 0:
            # recover mvals
            self.FF.make(mvals)
            with open('rmsd_decomposition.txt', 'w') as fout:
                for sysname in self.internal_coordinates:
                    fout.write("\n[ %s ]\n" % sysname)
                    fout.write('%-25s %15s %15s %15s\n' %
                               ("Internal Coordinate", "Ref QM Value",
                                "Cur MM Value", "Difference"))
                    # reference data
                    sys_data = self.internal_coordinates[sysname]
                    sys_data['ic_bonds']
                    # compute all internal coordinate values again
                    v_ic = self.system_driver(sysname)
                    for p in ['bonds', 'angles', 'dihedrals', 'impropers']:
                        fout.write('--- ' + p + ' ---\n')
                        ic_list = sys_data['ic_' + p]
                        ref_v = sys_data['vref_' + p]
                        tar_v = v_ic[p]
                        # print each value
                        for ic, v1, v2 in zip(ic_list, ref_v, tar_v):
                            diff = periodic_diff(
                                v1, v2,
                                v_periodic=360) if p != 'bonds' else v1 - v2
                            fout.write('%-25s %15.5f %15.5f %+15.3e\n' %
                                       (ic, v1, v2, diff))

        # compute gradients and hessian
        dV = np.zeros((self.FF.np, len(V)))
        if AGrad or AHess:
            for p in self.pgrad:
                dV[p, :], _ = f12d3p(fdwrap(compute, mvals, p, p_idx=p),
                                     h=self.h,
                                     f0=V)

        for p in self.pgrad:
            Answer['G'][p] = 2 * np.dot(V, dV[p, :])
            for q in self.pgrad:
                Answer['H'][p, q] = 2 * np.dot(dV[p, :], dV[q, :])
        if not in_fd():
            self.objective = Answer['X']
            self.FF.make(mvals)
        return Answer