Example #1
0
 def run_optimizer(self,
                   check_result=True,
                   check_iter=True,
                   use_pvals=False):
     optimizer = self.get_optimizer()
     ## Actually run the optimizer.
     self.logger.debug("Done setting up! Running optimizer...\n")
     result = optimizer.Run()
     self.logger.debug("\nOptimizer finished. Final results:\n")
     self.logger.debug(str(result) + '\n')
     ## Convert result to physical values if desired.
     if use_pvals:
         result = optimizer.FF.create_pvals(result)
     if check_result:
         msg = "\nCalculation results have changed from previously calculated values.\n " \
               "If this seems reasonable, update %s in test_system.py with these values" % self.expected_results_name
         np.testing.assert_allclose(self.expected_results,
                                    result,
                                    atol=self.absolute_tolerance,
                                    err_msg=msg)
     if check_iter:
         # Fail if calculation takes longer than previously to converge
         assert ITERATIONS_TO_CONVERGE >= Counter(), "Calculation took longer than expected to converge (%d iterations vs previous of %d)" %\
             (ITERATIONS_TO_CONVERGE, Counter())
     return result
Example #2
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.
        #
        # First dump the force field to a pickle file
        lp_dump((self.FF, mvals, self.OptionDict, AGrad), 'forcebalance.p')

        # Give the user an opportunity to copy over data from a previous (perhaps failed) run.
        if Counter() == First() and self.manual:
            warn_press_key(
                "Now's our chance to fill the temp directory up with data!\n(Considering using 'read' or 'continue' for better checkpointing)",
                timeout=7200)

        # If self.save_traj == 1, delete the trajectory files from a previous good optimization step.
        if Counter() > First() and GoodStep() and self.save_traj < 2:
            for fn in self.last_traj:
                if os.path.exists(fn):
                    os.remove(fn)
        self.last_traj = []

        # Set up and run the NPT simulations.
        snum = 0
        for label, pt in zip(self.Labels, self.PhasePoints):
            T = pt[0]
            P = pt[1]
            Punit = pt[2]
            if Punit == 'bar':
                P *= 1.0 / 1.01325
            if not os.path.exists(label):
                os.makedirs(label)
                os.chdir(label)
                self.npt_simulation(T, P, snum)
                os.chdir('..')
                snum += 1
Example #3
0
    def meta_get(self, mvals, AGrad=False, AHess=False, customdir=None):
        """ 
        Wrapper around the get function.  
        Create the directory for the target, and then calls 'get'.
        If we are reading existing data, go into the appropriate read directory and call read() instead.
        The 'get' method should not worry about the directory that it's running in.
        
        """
        ## Directory of the current iteration; if not None, then the simulation runs under
        ## temp/target_name/iteration_number
        ## The 'customdir' is customizable and can go below anything
        cwd = os.getcwd()

        absgetdir = os.path.join(self.root, self.tempdir)
        if Counter() is not None:
            # Not expecting more than ten thousand iterations
            if Counter() > 10000:
                logger.error(
                    'Cannot handle more than 10000 iterations due to current directory structure.  Consider revising code.\n'
                )
                raise RuntimeError
            iterdir = "iter_%04i" % Counter()
            absgetdir = os.path.join(absgetdir, iterdir)
        if customdir is not None:
            absgetdir = os.path.join(absgetdir, customdir)

        if not os.path.exists(absgetdir):
            os.makedirs(absgetdir)
        os.chdir(absgetdir)
        self.link_from_tempdir(absgetdir)
        self.rundir = absgetdir.replace(self.root + '/', '')
        ## Read existing information from disk (i.e. when recovering an aborted run)
        # Note that reading information is not supported for custom folders (e.g. microiterations during search)
        if self.rd is not None and (
                not self.evaluated
        ) and self.read_objective and customdir is None:
            os.chdir(self.absrd())
            logger.info("Reading objective function information from %s\n" %
                        os.getcwd())
            Answer = self.read(mvals, AGrad, AHess)
            os.chdir(absgetdir)
        else:
            ## Evaluate the objective function.
            Answer = self.get(mvals, AGrad, AHess)
            if self.write_objective:
                forcebalance.nifty.lp_dump(Answer, 'objective.p')

        ## Save the force field files to this directory, so that it
        ## reflects the objective function and properties that were
        ## printed out.
        if not in_fd():
            self.FF.make(mvals)

        os.chdir(cwd)

        return Answer
Example #4
0
    def stage(self,
              mvals,
              AGrad=False,
              AHess=False,
              use_iterdir=True,
              customdir=None,
              firstIteration=False):
        """

        Stages the directory for the target, and then launches Work Queue processes if any.
        The 'get' method should not worry about the directory that it's running in.

        """
        if self.sleepy > 0:
            logger.info("Sleeping for %i seconds as directed...\n" %
                        self.sleepy)
            time.sleep(self.sleepy)
        ## Directory of the current iteration; if not None, then the simulation runs under
        ## temp/target_name/iteration_number
        ## The 'customdir' is customizable and can go below anything
        cwd = os.getcwd()

        absgetdir = os.path.join(self.root, self.tempdir)
        if use_iterdir and Counter() is not None:
            ## Not expecting more than ten thousand iterations
            iterdir = "iter_%04i" % Counter()
            absgetdir = os.path.join(absgetdir, iterdir)
        if customdir is not None:
            absgetdir = os.path.join(absgetdir, customdir)
        ## Go into the directory where get() will be executed.
        if not os.path.exists(absgetdir):
            os.makedirs(absgetdir)
        os.chdir(absgetdir)
        self.link_from_tempdir(absgetdir)
        ## Write mathematical parameters to file; will be used to checkpoint calculation.
        if not in_fd():
            np.savetxt('mvals.txt', mvals)
        ## Read in file that specifies which derivatives may be skipped.
        if Counter() >= self.zerograd and self.zerograd >= 0:
            self.read_0grads()
        self.rundir = absgetdir.replace(self.root + '/', '')
        ## Submit jobs to the Work Queue.
        if self.rd is None or (not firstIteration):
            self.submit_jobs(mvals, AGrad, AHess)
        elif customdir is not None:
            # Allows us to submit micro-iteration jobs for remote targets
            self.submit_jobs(mvals, AGrad, AHess)
        os.chdir(cwd)

        return
Example #5
0
    def get_G(self, mvals=None, customdir=None):
        """Computes the objective function contribution and its gradient.

        First the low-level 'get' method is called with the analytic gradient
        switch turned on.  Then we loop through the fd1_pids and compute
        the corresponding elements of the gradient by finite difference,
        if the 'fdgrad' switch is turned on.  Alternately we can compute
        the gradient elements and diagonal Hessian elements at the same time
        using central difference if 'fdhessdiag' is turned on.

        In this function we also record which parameters cause a
        nonzero change in the objective function contribution.
        Parameters which do not change the objective function will
        not be differentiated in subsequent calculations.  This is
        recorded in a text file in the targets directory.

        """
        Ans = self.meta_get(mvals, 1, 0, customdir=customdir)
        for i in self.pgrad:
            if any([j in self.FF.plist[i]
                    for j in self.fd1_pids]) or 'ALL' in self.fd1_pids:
                if self.fdhessdiag:
                    Ans['G'][i], Ans['H'][i,
                                          i] = f12d3p(fdwrap_G(self, mvals, i),
                                                      self.h,
                                                      f0=Ans['X'])
                elif self.fdgrad:
                    Ans['G'][i] = f1d2p(fdwrap_G(self, mvals, i),
                                        self.h,
                                        f0=Ans['X'])
        self.gct += 1
        if Counter() == self.zerograd and self.zerograd >= 0:
            self.write_0grads(Ans)
        return Ans
Example #6
0
    def submit_jobs(self, mvals, AGrad=False, AHess=False):

        id_string = "%s_iter%04i" % (self.name, Counter())

        self.serialize_ff(mvals, outside="forcefield-remote")
        forcebalance.nifty.lp_dump((AGrad, AHess, id_string, self.r_options, self.r_tgt_opts, self.pgrad),'options.p')
        
        # Link in the rpfx script.
        if len(self.rpfx) > 0:
            forcebalance.nifty.LinkFile(os.path.join(os.path.split(__file__)[0],"data",self.rpfx),self.rpfx)
        forcebalance.nifty.LinkFile(os.path.join(os.path.split(__file__)[0],"data","rtarget.py"),"rtarget.py")
        forcebalance.nifty.LinkFile(os.path.join(self.root, self.tempdir, "target.tar.bz2"),"target.tar.bz2")
        
        wq = getWorkQueue()
        
        # logger.info("Sending target '%s' to work queue for remote evaluation\n" % self.name)
        # input:
        #   forcefield.p: pickled force field
        #   options.p: pickled mvals, options
        #   rtarget.py: remote target evaluation script
        #   target.tar.bz2: tarred target
        # output:
        #   objective.p: pickled objective function dictionary
        #   indicate.log: results of target.indicate() written to file
        # if len(self.rpfx) > 0 and self.rpfx not in ['rungmx.sh', 'runcuda.sh']:
        #     logger.error('Unsupported prefix script for launching remote target')
        #     raise RuntimeError
        forcebalance.nifty.queue_up(wq, "%spython rtarget.py > rtarget.out 2>&1" % (("sh %s%s " % (self.rpfx, " -b" if self.rbak else "")) 
                                                                                    if len(self.rpfx) > 0 else ""),
                                    ["forcefield.p", "options.p", "rtarget.py", "target.tar.bz2"] + ([self.rpfx] if len(self.rpfx) > 0 else []),
                                    ['objective.p', 'indicate.log', 'rtarget.out'],
                                    tgt=self, tag=self.name, verbose=False)
Example #7
0
    def get_H(self,mvals=None,customdir=None):
        """Computes the objective function contribution and its gradient / Hessian.

        First the low-level 'get' method is called with the analytic gradient
        and Hessian both turned on.  Then we loop through the fd1_pids and compute
        the corresponding elements of the gradient by finite difference,
        if the 'fdgrad' switch is turned on.

        This is followed by looping through the fd2_pids and computing the corresponding
        Hessian elements by finite difference.  Forward finite difference is used
        throughout for the sake of speed.
        """
        Ans = self.meta_get(mvals,1,1,customdir=customdir)
        if self.fdhess:
            for i in self.pgrad:
                if any([j in self.FF.plist[i] for j in self.fd1_pids]) or 'ALL' in self.fd1_pids:
                    Ans['G'][i] = f1d2p(fdwrap_G(self,mvals,i),self.h,f0 = Ans['X'])
            for i in self.pgrad:
                if any([j in self.FF.plist[i] for j in self.fd2_pids]) or 'ALL' in self.fd2_pids:
                    FDSlice = f1d2p(fdwrap_H(self,mvals,i),self.h,f0 = Ans['G'])
                    Ans['H'][i,:] = FDSlice
                    Ans['H'][:,i] = FDSlice
        elif self.fdhessdiag:
            for i in self.pgrad:
                if any([j in self.FF.plist[i] for j in self.fd2_pids]) or 'ALL' in self.fd2_pids:
                    Ans['G'][i], Ans['H'][i,i] = f12d3p(fdwrap_G(self,mvals,i),self.h, f0 = Ans['X'])
        if Counter() == self.zerograd and self.zerograd >= 0: 
            self.write_0grads(Ans)
        self.hct += 1
        return Ans
 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)
Example #9
0
def draw_vibfreq_scatter_plot_n_overlap_matrix(name, engine, ref_eigvals, ref_eigvecs, freqs_rearr, normal_modes_rearr):

    import matplotlib.pyplot as plt
    from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size

    plt.switch_backend('agg')
    fig, axs = plt.subplots(1,2, figsize=(10,6))
    overlap_matrix = np.array([[(vib_overlap(engine, v1, v2)) for v2 in normal_modes_rearr] for v1 in ref_eigvecs])
    qm_overlap_matrix = np.array([[(vib_overlap(engine,v1, v2)) for v2 in ref_eigvecs] for v1 in ref_eigvecs])

    axs[0].scatter(ref_eigvals, freqs_rearr, label='MM vibrational frequencies(rearr.)')
    axs[0].plot(ref_eigvals,ref_eigvals, 'k-')
    axs[0].legend()
    axs[0].set_xlabel(r'QM vibrational frequency ($cm^{-1}$)')
    axs[0].set_ylabel(r'MM vibrational frequency ($cm^{-1}$)')
    mae = np.sum(np.abs(ref_eigvals - freqs_rearr))/ len(ref_eigvals)
    axs[0].set_title(f'QM vs. MM vibrational frequencies\n MAE= {mae:.2f}')
    x0,x1 = axs[0].get_xlim()
    y0,y1 = axs[0].get_ylim()
    axs[0].set_aspect((x1-x0)/(y1-y0))

    # move ax x axis to top
    axs[1].xaxis.tick_top()
    # move ax x ticks inside
    axs[1].tick_params(axis="y", direction='in')
    axs[1].tick_params(axis="x", direction='in')
    # draw matrix
    im = axs[1].imshow(overlap_matrix, cmap= 'OrRd', vmin=0,vmax=1)
    # colorbar
    aspect = 20
    pad_fraction = 0.5
    divider = make_axes_locatable(axs[1])
    width = axes_size.AxesY(axs[1], aspect=1./aspect)
    pad = axes_size.Fraction(pad_fraction, width)
    cax = divider.append_axes("right", size=width, pad=pad)
    cax.yaxis.tick_right()
    cax.xaxis.set_visible(False)
    plt.colorbar(im, cax=cax)
    corr_coef = cal_corr_coef(overlap_matrix)
    err = np.linalg.norm(qm_overlap_matrix - overlap_matrix)/np.linalg.norm(qm_overlap_matrix) # measure of error in matrix (Relative error)
    axs[1].set_title(f'QM vs. MM normal modes\n Correlation coef. ={corr_coef:.4f}, Error={err:.4f}')

    # # move ax x axis to top
    # axs[2].xaxis.tick_top()
    # # move ax x ticks inside
    # axs[2].tick_params(axis="y", direction='in')
    # axs[2].tick_params(axis="x", direction='in')
    # # draw matrix
    # im = axs[2].imshow(qm_overlap_matrix, cmap= 'OrRd', vmin=0,vmax=1)
    # # colorbar
    # aspect = 20
    # pad_fraction = 0.5
    # divider = make_axes_locatable(axs[2])
    # width = axes_size.AxesY(axs[2], aspect=1./aspect)
    # pad = axes_size.Fraction(pad_fraction, width)
    # cax = divider.append_axes("right", size=width, pad=pad)
    # cax.yaxis.tick_right()
    # cax.xaxis.set_visible(False)
    # plt.colorbar(im, cax=cax)
    # axs[2].set_title(f'(QM normal modes for reference)')

    plt.tight_layout()
    plt.subplots_adjust(top=0.85)
    fig.suptitle('Hessian: iteration %i\nSystem: %s' % (Counter(), name))
    fig.savefig('vibfreq_scatter_plot_n_overlap_matrix.pdf')
Example #10
0
    def runTest(self):
        """Check water tutorial study runs without errors"""
        self.logger.debug("\nSetting input file to 'very_simple.in'\n")
        input_file = 'very_simple.in'

        ## The general options and target options that come from parsing the input file
        self.logger.debug("Parsing inputs...\n")
        options, tgt_opts = parse_inputs(input_file)
        self.logger.debug("options:\n%s\n\ntgt_opts:\n%s\n\n" %
                          (str(options), str(tgt_opts)))

        self.assertEqual(dict,
                         type(options),
                         msg="\nParser gave incorrect type for options")
        self.assertEqual(list,
                         type(tgt_opts),
                         msg="\nParser gave incorrect type for tgt_opts")
        for target in tgt_opts:
            self.assertEqual(
                dict,
                type(target),
                msg="\nParser gave incorrect type for target dict")

        ## The force field component of the project
        forcefield = FF(options)
        self.assertEqual(FF,
                         type(forcefield),
                         msg="\nExpected forcebalance forcefield object")

        ## The objective function
        objective = Objective(options, tgt_opts, forcefield)
        self.assertEqual(Objective,
                         type(objective),
                         msg="\nExpected forcebalance objective object")

        ## The optimizer component of the project
        self.logger.debug("Creating optimizer: ")
        optimizer = Optimizer(options, objective, forcefield)
        self.assertEqual(Optimizer,
                         type(optimizer),
                         msg="\nExpected forcebalance optimizer object")
        self.logger.debug(str(optimizer) + "\n")

        ## Actually run the optimizer.
        self.logger.debug("Done setting up! Running optimizer...\n")
        result = optimizer.Run()
        self.logger.debug("\nOptimizer finished. Final results:\n")
        self.logger.debug(str(result) + '\n')

        self.assertNdArrayEqual(
            EXPECTED_WATER_RESULTS,
            result,
            delta=0.001,
            msg=
            "\nCalculation results have changed from previously calculated values.\n"
            "If this seems reasonable, update EXPECTED_WATER_RESULTS in test_system.py with these values"
        )

        # Fail if calculation takes longer than previously to converge
        self.assertGreaterEqual(ITERATIONS_TO_CONVERGE, Counter(), msg="\nCalculation took longer than expected to converge (%d iterations vs previous of %d)" %\
        (ITERATIONS_TO_CONVERGE, Counter()))
Example #11
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 = 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 Counter() == First():
                    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
Example #12
0
    def get(self, mvals, AGrad=True, AHess=True):
        
        """
        Fitting of liquid bulk properties.  This is the current major
        direction of development for ForceBalance.  Basically, fitting
        the QM energies / forces alone does not always give us the
        best simulation behavior.  In many cases it makes more sense
        to try and reproduce some experimentally known data as well.

        In order to reproduce experimentally known data, we need to
        run a simulation and compare the simulation result to
        experiment.  The main challenge here is that the simulations
        are computationally intensive (i.e. they require energy and
        force evaluations), and furthermore the results are noisy.  We
        need to run the simulations automatically and remotely
        (i.e. on clusters) and a good way to calculate the derivatives
        of the simulation results with respect to the parameter values.

        This function contains some experimentally known values of the
        density and enthalpy of vaporization (Hvap) of liquid water.
        It launches the density and Hvap calculations on the cluster,
        and gathers the results / derivatives.  The actual calculation
        of results / derivatives is done in a separate file.

        After the results come back, they are gathered together to form
        an objective function.

        @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
        
        """
        
        unpack = forcebalance.nifty.lp_load('forcebalance.p')
        mvals1 = unpack[1]
        if (np.max(np.abs(mvals1 - mvals)) > 1e-3):
            warn_press_key("mvals from forcebalance.p does not match up with internal values! (Are you reading data from a previous run?)\nmvals(call)=%s mvals(disk)=%s" % (mvals, mvals1))

        mbar_verbose = False

        Answer = {}

        Results = {}
        Points = []  # These are the phase points for which data exists.
        BPoints = [] # These are the phase points for which we are doing MBAR for the condensed phase.
        mBPoints = [] # These are the phase points for which we are doing MBAR for the monomers.
        mPoints = [] # These are the phase points to use for enthalpy of vaporization; if we're scanning pressure then set hvap_wt for higher pressures to zero.
        tt = 0
        for label, PT in zip(self.Labels, self.PhasePoints):
            if os.path.exists('./%s/npt_result.p' % label):
                logger.info('Reading information from ./%s/npt_result.p\n' % label)
                Points.append(PT)
                Results[tt] = lp_load('./%s/npt_result.p' % label)
                if 'hvap' in self.RefData and PT[0] not in [i[0] for i in mPoints]:
                    mPoints.append(PT)
                if 'mbar' in self.RefData and PT in self.RefData['mbar'] and self.RefData['mbar'][PT]:
                    BPoints.append(PT)
                    if 'hvap' in self.RefData and PT[0] not in [i[0] for i in mBPoints]:
                        mBPoints.append(PT)
                tt += 1
            else:
                logger.warning('In %s :\n' % os.getcwd())
                logger.warning('The file ./%s/npt_result.p does not exist so we cannot read it\n' % label)
                pass
        if len(Points) == 0:
            logger.error('The liquid simulations have terminated with \x1b[1;91mno readable data\x1b[0m - this is a problem!\n')
            raise RuntimeError

        # Assign variable names to all the stuff in npt_result.p
        Rhos, Vols, Potentials, Energies, Dips, Grads, GDips, mPotentials, mEnergies, mGrads, \
            Rho_errs, Hvap_errs, Alpha_errs, Kappa_errs, Cp_errs, Eps0_errs, NMols = ([Results[t][i] for t in range(len(Points))] for i in range(17))
        # Determine the number of molecules
        if len(set(NMols)) != 1:
            logger.error(str(NMols))
            logger.error('The above list should only contain one number - the number of molecules\n')
            raise RuntimeError
        else:
            NMol = list(set(NMols))[0]
    
        if not self.adapt_errors:
            self.AllResults = defaultdict(lambda:defaultdict(list))

        astrm = astr(mvals)
        if len(Points) != len(self.Labels):
            logger.info("Data sets is not full, will not use for concatenation.")
            astrm += "_"*(Counter()+1)
        self.AllResults[astrm]['Pts'].append(Points)
        self.AllResults[astrm]['mPts'].append(Points)
        self.AllResults[astrm]['E'].append(np.array(Energies))
        self.AllResults[astrm]['V'].append(np.array(Vols))
        self.AllResults[astrm]['R'].append(np.array(Rhos))
        self.AllResults[astrm]['Dx'].append(np.array([d[:,0] for d in Dips]))
        self.AllResults[astrm]['Dy'].append(np.array([d[:,1] for d in Dips]))
        self.AllResults[astrm]['Dz'].append(np.array([d[:,2] for d in Dips]))
        self.AllResults[astrm]['G'].append(np.array(Grads))
        self.AllResults[astrm]['GDx'].append(np.array([gd[0] for gd in GDips]))
        self.AllResults[astrm]['GDy'].append(np.array([gd[1] for gd in GDips]))
        self.AllResults[astrm]['GDz'].append(np.array([gd[2] for gd in GDips]))
        self.AllResults[astrm]['L'].append(len(Energies[0]))
        self.AllResults[astrm]['Steps'].append(self.liquid_md_steps)

        if len(mPoints) > 0:
            self.AllResults[astrm]['mE'].append(np.array([i for pt, i in zip(Points,mEnergies) if pt in mPoints]))
            self.AllResults[astrm]['mG'].append(np.array([i for pt, i in zip(Points,mGrads) if pt in mPoints]))

        # Number of data sets belonging to this value of the parameters.
        Nrpt = len(self.AllResults[astrm]['R'])
        sumsteps = sum(self.AllResults[astrm]['Steps'])
        if self.liquid_md_steps != sumsteps:
            printcool("This objective function evaluation combines %i datasets\n" \
                          "Increasing simulation length: %i -> %i steps" % \
                          (Nrpt, self.liquid_md_steps, sumsteps), color=6)
            if self.liquid_md_steps * 2 != sumsteps:
                logger.error("Spoo!\n")
                raise RuntimeError
            self.liquid_eq_steps *= 2
            self.liquid_md_steps *= 2
            self.gas_eq_steps *= 2
            self.gas_md_steps *= 2

        # Concatenate along the data-set axis (more than 1 element  if we've returned to these parameters.)
        E, V, R, Dx, Dy, Dz = \
            (np.hstack(tuple(self.AllResults[astrm][i])) for i in \
                 ['E', 'V', 'R', 'Dx', 'Dy', 'Dz'])

        G, GDx, GDy, GDz = \
            (np.hstack((np.concatenate(tuple(self.AllResults[astrm][i]), axis=2))) for i in ['G', 'GDx', 'GDy', 'GDz'])

        if len(mPoints) > 0:
            mE = np.hstack(tuple(self.AllResults[astrm]['mE']))
            mG = np.hstack((np.concatenate(tuple(self.AllResults[astrm]['mG']), axis=2)))
        Rho_calc = OrderedDict([])
        Rho_grad = OrderedDict([])
        Rho_std  = OrderedDict([])
        Hvap_calc = OrderedDict([])
        Hvap_grad = OrderedDict([])
        Hvap_std  = OrderedDict([])
        Alpha_calc = OrderedDict([])
        Alpha_grad = OrderedDict([])
        Alpha_std  = OrderedDict([])
        Kappa_calc = OrderedDict([])
        Kappa_grad = OrderedDict([])
        Kappa_std  = OrderedDict([])
        Cp_calc = OrderedDict([])
        Cp_grad = OrderedDict([])
        Cp_std  = OrderedDict([])
        Eps0_calc = OrderedDict([])
        Eps0_grad = OrderedDict([])
        Eps0_std  = OrderedDict([])

        # The unit that converts atmospheres * nm**3 into kj/mol :)
        pvkj=0.061019351687175

        # Run MBAR using the total energies. Required for estimates that use the kinetic energy.
        BSims = len(BPoints)
        Shots = len(E[0])
        N_k = np.ones(BSims)*Shots
        # Use the value of the energy for snapshot t from simulation k at potential m
        U_kln = np.zeros([BSims,BSims,Shots])
        for m, PT in enumerate(BPoints):
            T = PT[0]
            P = PT[1] / 1.01325 if PT[2] == 'bar' else PT[1]
            beta = 1. / (kb * T)
            for k in range(BSims):
                # The correct Boltzmann factors include PV.
                # Note that because the Boltzmann factors are computed from the conditions at simulation "m",
                # the pV terms must be rescaled to the pressure at simulation "m".
                kk = Points.index(BPoints[k])
                U_kln[k, m, :]   = E[kk] + P*V[kk]*pvkj
                U_kln[k, m, :]  *= beta
        W1 = None
        if len(BPoints) > 1:
            logger.info("Running MBAR analysis on %i states...\n" % len(BPoints))
            mbar = pymbar.MBAR(U_kln, N_k, verbose=mbar_verbose, relative_tolerance=5.0e-8)
            W1 = mbar.getWeights()
            logger.info("Done\n")
        elif len(BPoints) == 1:
            W1 = np.ones((BPoints*Shots,BPoints))
            W1 /= BPoints*Shots
        
        def fill_weights(weights, phase_points, mbar_points, snapshots):
            """ Fill in the weight matrix with MBAR weights where MBAR was run, 
            and equal weights otherwise. """
            new_weights = np.zeros([len(phase_points)*snapshots,len(phase_points)])
            for m, PT in enumerate(phase_points):
                if PT in mbar_points:
                    mm = mbar_points.index(PT)
                    for kk, PT1 in enumerate(mbar_points):
                        k = phase_points.index(PT1)
                        logger.debug("Will fill W2[%i:%i,%i] with W1[%i:%i,%i]\n" % (k*snapshots,k*snapshots+snapshots,m,kk*snapshots,kk*snapshots+snapshots,mm))
                        new_weights[k*snapshots:(k+1)*snapshots,m] = weights[kk*snapshots:(kk+1)*snapshots,mm]
                else:
                    logger.debug("Will fill W2[%i:%i,%i] with equal weights\n" % (m*snapshots,(m+1)*snapshots,m))
                    new_weights[m*snapshots:(m+1)*snapshots,m] = 1.0/snapshots
            return new_weights
        
        W2 = fill_weights(W1, Points, BPoints, Shots)

        if len(mPoints) > 0:
            # Run MBAR on the monomers.  This is barely necessary.
            mW1 = None
            mShots = len(mE[0])
            if len(mBPoints) > 0:
                mBSims = len(mBPoints)
                mN_k = np.ones(mBSims)*mShots
                mU_kln = np.zeros([mBSims,mBSims,mShots])
                for m, PT in enumerate(mBPoints):
                    T = PT[0]
                    beta = 1. / (kb * T)
                    for k in range(mBSims):
                        kk = Points.index(mBPoints[k])
                        mU_kln[k, m, :]  = mE[kk]
                        mU_kln[k, m, :] *= beta
                if np.abs(np.std(mE)) > 1e-6 and mBSims > 1:
                    mmbar = pymbar.MBAR(mU_kln, mN_k, verbose=False, relative_tolerance=5.0e-8, method='self-consistent-iteration')
                    mW1 = mmbar.getWeights()
            elif len(mBPoints) == 1:
                mW1 = np.ones((mBSims*mShots,mSims))
                mW1 /= mBSims*mShots
            mW2 = fill_weights(mW1, mPoints, mBPoints, mShots)
         
        if self.do_self_pol:
            EPol = self.polarization_correction(mvals)
            GEPol = np.array([(f12d3p(fdwrap(self.polarization_correction, mvals, p), h = self.h, f0 = EPol)[0] if p in self.pgrad else 0.0) for p in range(self.FF.np)])
            bar = printcool("Self-polarization correction to \nenthalpy of vaporization is % .3f kJ/mol%s" % (EPol, ", Derivative:" if AGrad else ""))
            if AGrad:
                self.FF.print_map(vals=GEPol)
                logger.info(bar)

        # Arrays must be flattened now for calculation of properties.
        E = E.flatten()
        V = V.flatten()
        R = R.flatten()
        Dx = Dx.flatten()
        Dy = Dy.flatten()
        Dz = Dz.flatten()
        if len(mPoints) > 0: mE = mE.flatten()
            
        for i, PT in enumerate(Points):
            T = PT[0]
            P = PT[1] / 1.01325 if PT[2] == 'bar' else PT[1]
            PV = P*V*pvkj
            H = E + PV
            # The weights that we want are the last ones.
            W = flat(W2[:,i])
            C = weight_info(W, PT, np.ones(len(Points))*Shots, verbose=mbar_verbose)
            Gbar = flat(np.matrix(G)*col(W))
            mBeta = -1/kb/T
            Beta  = 1/kb/T
            kT    = kb*T
            # Define some things to make the analytic derivatives easier.
            def avg(vec):
                return np.dot(W,vec)
            def covde(vec):
                return flat(np.matrix(G)*col(W*vec)) - avg(vec)*Gbar
            def deprod(vec):
                return flat(np.matrix(G)*col(W*vec))
            ## Density.
            Rho_calc[PT]   = np.dot(W,R)
            Rho_grad[PT]   = mBeta*(flat(np.matrix(G)*col(W*R)) - np.dot(W,R)*Gbar)
            ## Enthalpy of vaporization.
            if PT in mPoints:
                ii = mPoints.index(PT)
                mW = flat(mW2[:,ii])
                mGbar = flat(np.matrix(mG)*col(mW))
                Hvap_calc[PT]  = np.dot(mW,mE) - np.dot(W,E)/NMol + kb*T - np.dot(W, PV)/NMol
                Hvap_grad[PT]  = mGbar + mBeta*(flat(np.matrix(mG)*col(mW*mE)) - np.dot(mW,mE)*mGbar)
                Hvap_grad[PT] -= (Gbar + mBeta*(flat(np.matrix(G)*col(W*E)) - np.dot(W,E)*Gbar)) / NMol
                Hvap_grad[PT] -= (mBeta*(flat(np.matrix(G)*col(W*PV)) - np.dot(W,PV)*Gbar)) / NMol
                if self.do_self_pol:
                    Hvap_calc[PT] -= EPol
                    Hvap_grad[PT] -= GEPol
                if hasattr(self,'use_cni') and self.use_cni:
                    if not ('cni' in self.RefData and self.RefData['cni'][PT]):
                        logger.error('Asked for a nonideality correction but not provided in reference data (data.csv).  Either disable the option in data.csv or add data.\n')
                        raise RuntimeError
                    logger.debug("Adding % .3f to enthalpy of vaporization at " % self.RefData['cni'][PT] + str(PT) + '\n')
                    Hvap_calc[PT] += self.RefData['cni'][PT]
                if hasattr(self,'use_cvib_intra') and self.use_cvib_intra:
                    if not ('cvib_intra' in self.RefData and self.RefData['cvib_intra'][PT]):
                        logger.error('Asked for a quantum intramolecular vibrational correction but not provided in reference data (data.csv).  Either disable the option in data.csv or add data.\n')
                        raise RuntimeError
                    logger.debug("Adding % .3f to enthalpy of vaporization at " % self.RefData['cvib_intra'][PT] + str(PT) + '\n')
                    Hvap_calc[PT] += self.RefData['cvib_intra'][PT]
                if hasattr(self,'use_cvib_inter') and self.use_cvib_inter:
                    if not ('cvib_inter' in self.RefData and self.RefData['cvib_inter'][PT]):
                        logger.error('Asked for a quantum intermolecular vibrational correction but not provided in reference data (data.csv).  Either disable the option in data.csv or add data.\n')
                        raise RuntimeError
                    logger.debug("Adding % .3f to enthalpy of vaporization at " % self.RefData['cvib_inter'][PT] + str(PT) + '\n')
                    Hvap_calc[PT] += self.RefData['cvib_inter'][PT]
            else:
                Hvap_calc[PT]  = 0.0
                Hvap_grad[PT]  = np.zeros(self.FF.np)
            ## Thermal expansion coefficient.
            Alpha_calc[PT] = 1e4 * (avg(H*V)-avg(H)*avg(V))/avg(V)/(kT*T)
            GAlpha1 = -1 * Beta * deprod(H*V) * avg(V) / avg(V)**2
            GAlpha2 = +1 * Beta * avg(H*V) * deprod(V) / avg(V)**2
            GAlpha3 = deprod(V)/avg(V) - Gbar
            GAlpha4 = Beta * covde(H)
            Alpha_grad[PT] = 1e4 * (GAlpha1 + GAlpha2 + GAlpha3 + GAlpha4)/(kT*T)
            ## Isothermal compressibility.
            bar_unit = 0.06022141793 * 1e6
            Kappa_calc[PT] = bar_unit / kT * (avg(V**2)-avg(V)**2)/avg(V)
            GKappa1 = +1 * Beta**2 * avg(V**2) * deprod(V) / avg(V)**2
            GKappa2 = -1 * Beta**2 * avg(V) * deprod(V**2) / avg(V)**2
            GKappa3 = +1 * Beta**2 * covde(V)
            Kappa_grad[PT] = bar_unit*(GKappa1 + GKappa2 + GKappa3)
            ## Isobaric heat capacity.
            Cp_calc[PT] = 1000/(4.184*NMol*kT*T) * (avg(H**2) - avg(H)**2)
            if hasattr(self,'use_cvib_intra') and self.use_cvib_intra:
                logger.debug("Adding " + str(self.RefData['devib_intra'][PT]) + " to the heat capacity\n")
                Cp_calc[PT] += self.RefData['devib_intra'][PT]
            if hasattr(self,'use_cvib_inter') and self.use_cvib_inter:
                logger.debug("Adding " + str(self.RefData['devib_inter'][PT]) + " to the heat capacity\n")
                Cp_calc[PT] += self.RefData['devib_inter'][PT]
            GCp1 = 2*covde(H) * 1000 / 4.184 / (NMol*kT*T)
            GCp2 = mBeta*covde(H**2) * 1000 / 4.184 / (NMol*kT*T)
            GCp3 = 2*Beta*avg(H)*covde(H) * 1000 / 4.184 / (NMol*kT*T)
            Cp_grad[PT] = GCp1 + GCp2 + GCp3
            ## Static dielectric constant.
            prefactor = 30.348705333964077
            D2 = avg(Dx**2)+avg(Dy**2)+avg(Dz**2)-avg(Dx)**2-avg(Dy)**2-avg(Dz)**2
            Eps0_calc[PT] = 1.0 + prefactor*(D2/avg(V))/T
            GD2  = 2*(flat(np.matrix(GDx)*col(W*Dx)) - avg(Dx)*flat(np.matrix(GDx)*col(W))) - Beta*(covde(Dx**2) - 2*avg(Dx)*covde(Dx))
            GD2 += 2*(flat(np.matrix(GDy)*col(W*Dy)) - avg(Dy)*flat(np.matrix(GDy)*col(W))) - Beta*(covde(Dy**2) - 2*avg(Dy)*covde(Dy))
            GD2 += 2*(flat(np.matrix(GDz)*col(W*Dz)) - avg(Dz)*flat(np.matrix(GDz)*col(W))) - Beta*(covde(Dz**2) - 2*avg(Dz)*covde(Dz))
            Eps0_grad[PT] = prefactor*(GD2/avg(V) - mBeta*covde(V)*D2/avg(V)**2)/T
            ## Estimation of errors.
            Rho_std[PT]    = np.sqrt(sum(C**2 * np.array(Rho_errs)**2))
            if PT in mPoints:
                Hvap_std[PT]   = np.sqrt(sum(C**2 * np.array(Hvap_errs)**2))
            else:
                Hvap_std[PT]   = 0.0
            Alpha_std[PT]   = np.sqrt(sum(C**2 * np.array(Alpha_errs)**2)) * 1e4
            Kappa_std[PT]   = np.sqrt(sum(C**2 * np.array(Kappa_errs)**2)) * 1e6
            Cp_std[PT]   = np.sqrt(sum(C**2 * np.array(Cp_errs)**2))
            Eps0_std[PT]   = np.sqrt(sum(C**2 * np.array(Eps0_errs)**2))

        # Get contributions to the objective function
        X_Rho, G_Rho, H_Rho, RhoPrint = self.objective_term(Points, 'rho', Rho_calc, Rho_std, Rho_grad, name="Density")
        X_Hvap, G_Hvap, H_Hvap, HvapPrint = self.objective_term(Points, 'hvap', Hvap_calc, Hvap_std, Hvap_grad, name="H_vap", SubAverage=self.hvap_subaverage)
        X_Alpha, G_Alpha, H_Alpha, AlphaPrint = self.objective_term(Points, 'alpha', Alpha_calc, Alpha_std, Alpha_grad, name="Thermal Expansion")
        X_Kappa, G_Kappa, H_Kappa, KappaPrint = self.objective_term(Points, 'kappa', Kappa_calc, Kappa_std, Kappa_grad, name="Compressibility")
        X_Cp, G_Cp, H_Cp, CpPrint = self.objective_term(Points, 'cp', Cp_calc, Cp_std, Cp_grad, name="Heat Capacity")
        X_Eps0, G_Eps0, H_Eps0, Eps0Print = self.objective_term(Points, 'eps0', Eps0_calc, Eps0_std, Eps0_grad, name="Dielectric Constant")

        Gradient = np.zeros(self.FF.np)
        Hessian = np.zeros((self.FF.np,self.FF.np))

        if X_Rho == 0: self.w_rho = 0.0
        if X_Hvap == 0: self.w_hvap = 0.0
        if X_Alpha == 0: self.w_alpha = 0.0
        if X_Kappa == 0: self.w_kappa = 0.0
        if X_Cp == 0: self.w_cp = 0.0
        if X_Eps0 == 0: self.w_eps0 = 0.0

        if self.w_normalize:
            w_tot = self.w_rho + self.w_hvap + self.w_alpha + self.w_kappa + self.w_cp + self.w_eps0
        else:
            w_tot = 1.0
        w_1 = self.w_rho / w_tot
        w_2 = self.w_hvap / w_tot
        w_3 = self.w_alpha / w_tot
        w_4 = self.w_kappa / w_tot
        w_5 = self.w_cp / w_tot
        w_6 = self.w_eps0 / w_tot

        Objective    = w_1 * X_Rho + w_2 * X_Hvap + w_3 * X_Alpha + w_4 * X_Kappa + w_5 * X_Cp + w_6 * X_Eps0
        if AGrad:
            Gradient = w_1 * G_Rho + w_2 * G_Hvap + w_3 * G_Alpha + w_4 * G_Kappa + w_5 * G_Cp + w_6 * G_Eps0
        if AHess:
            Hessian  = w_1 * H_Rho + w_2 * H_Hvap + w_3 * H_Alpha + w_4 * H_Kappa + w_5 * H_Cp + w_6 * H_Eps0

        if not in_fd():
            self.Xp = {"Rho" : X_Rho, "Hvap" : X_Hvap, "Alpha" : X_Alpha, 
                           "Kappa" : X_Kappa, "Cp" : X_Cp, "Eps0" : X_Eps0}
            self.Wp = {"Rho" : w_1, "Hvap" : w_2, "Alpha" : w_3, 
                           "Kappa" : w_4, "Cp" : w_5, "Eps0" : w_6}
            self.Pp = {"Rho" : RhoPrint, "Hvap" : HvapPrint, "Alpha" : AlphaPrint, 
                           "Kappa" : KappaPrint, "Cp" : CpPrint, "Eps0" : Eps0Print}
            if AGrad:
                self.Gp = {"Rho" : G_Rho, "Hvap" : G_Hvap, "Alpha" : G_Alpha, 
                               "Kappa" : G_Kappa, "Cp" : G_Cp, "Eps0" : G_Eps0}
            self.Objective = Objective

        Answer = {'X':Objective, 'G':Gradient, 'H':Hessian}
        return Answer
Example #13
0
    def read(self, mvals, AGrad=True, AHess=True):
        
        """
        Read in time series for all previous iterations.
        """

        unpack = forcebalance.nifty.lp_load('forcebalance.p')
        mvals1 = unpack[1]
        if (np.max(np.abs(mvals1 - mvals)) > 1e-3):
            warn_press_key("mvals from forcebalance.p does not match up with internal values! (Are you reading data from a previous run?)\nmvals(call)=%s mvals(disk)=%s" % (mvals, mvals1))

        for dn in range(Counter()-1, -1, -1):
            cwd = os.getcwd()
            os.chdir(self.absrd(inum=dn))
            mprev = np.loadtxt('mvals.txt')
            Results = {}
            Points = []  # These are the phase points for which data exists.
            mPoints = [] # These are the phase points to use for enthalpy of vaporization; if we're scanning pressure then set hvap_wt for higher pressures to zero.
            tt = 0
            logger.info('Reading liquid data from %s\n' % os.getcwd())
            for label, PT in zip(self.Labels, self.PhasePoints):
                if os.path.exists('./%s/npt_result.p' % label):
                    Points.append(PT)
                    Results[tt] = lp_load('./%s/npt_result.p' % label)
                    if 'hvap' in self.RefData and PT[0] not in [i[0] for i in mPoints]:
                        mPoints.append(PT)
                    tt += 1
                else:
                    logger.warning('In %s :\n' % os.getcwd())
                    logger.warning('The file ./%s/npt_result.p does not exist so we cannot read it\n' % label)
                    pass
            if len(Points) == 0:
                logger.error('The liquid simulations have terminated with \x1b[1;91mno readable data\x1b[0m - this is a problem!\n')
                raise RuntimeError
    
            # Assign variable names to all the stuff in npt_result.p
            Rhos, Vols, Potentials, Energies, Dips, Grads, GDips, mPotentials, mEnergies, mGrads, \
                Rho_errs, Hvap_errs, Alpha_errs, Kappa_errs, Cp_errs, Eps0_errs, NMols = ([Results[t][i] for t in range(len(Points))] for i in range(17))
            # Determine the number of molecules
            if len(set(NMols)) != 1:
                logger.error(str(NMols))
                logger.error('The above list should only contain one number - the number of molecules\n')
                raise RuntimeError
            else:
                NMol = list(set(NMols))[0]
        
            if not self.adapt_errors:
                self.AllResults = defaultdict(lambda:defaultdict(list))

            astrm = astr(mprev)
            if len(Points) != len(self.Labels):
                logger.info("Data sets is not full, will not use for concatenation.\n")
                astrm += "_"*(dn+1)
        
            self.AllResults[astrm]['Pts'].append(Points)
            self.AllResults[astrm]['mPts'].append(mPoints)
            self.AllResults[astrm]['E'].append(np.array(Energies))
            self.AllResults[astrm]['V'].append(np.array(Vols))
            self.AllResults[astrm]['R'].append(np.array(Rhos))
            self.AllResults[astrm]['Dx'].append(np.array([d[:,0] for d in Dips]))
            self.AllResults[astrm]['Dy'].append(np.array([d[:,1] for d in Dips]))
            self.AllResults[astrm]['Dz'].append(np.array([d[:,2] for d in Dips]))
            self.AllResults[astrm]['G'].append(np.array(Grads))
            self.AllResults[astrm]['GDx'].append(np.array([gd[0] for gd in GDips]))
            self.AllResults[astrm]['GDy'].append(np.array([gd[1] for gd in GDips]))
            self.AllResults[astrm]['GDz'].append(np.array([gd[2] for gd in GDips]))
            self.AllResults[astrm]['L'].append(len(Energies[0]))
            self.AllResults[astrm]['Steps'].append(self.liquid_md_steps)
    
            if len(mPoints) > 0:
                self.AllResults[astrm]['mE'].append(np.array([i for pt, i in zip(Points,mEnergies) if pt in mPoints]))
                self.AllResults[astrm]['mG'].append(np.array([i for pt, i in zip(Points,mGrads) if pt in mPoints]))

            os.chdir(cwd)

        return self.get(mvals, AGrad, AHess)
 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:
             energy_comparison = np.array([
                 self.eqm, compute.emm, compute.emm - self.eqm,
                 np.sqrt(self.wts) / self.energy_denom
             ]).T
             np.savetxt(
                 "EnergyCompare.txt",
                 energy_comparison,
                 header="%11s  %12s  %12s  %12s" %
                 ("QMEnergy", "MMEnergy", "Delta(MM-QM)", "Weight"),
                 fmt="% 12.6e")
             M_opts.write('mm_minimized.xyz')
             if self.ndim == 1:
                 try:
                     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')
                 except ImportError:
                     logger.warning(
                         "matplotlib package is needed to make torsion profile plots\n"
                     )
     return (np.sqrt(self.wts) / self.energy_denom) * (compute.emm -
                                                       self.eqm)