Esempio n. 1
0
    def indicate(self):
        """ Print qualitative indicator. """
        logger.info("\rTarget: %-15s\n" % self.name)
        #print "Multipole Moments and Po"
        #print "Reference :", self.ref_moments
        #print "Calculated:", self.calc_moments
        #print "Objective = %.5e" % self.objective

        ref_momvals = self.unpack_moments(self.ref_moments)
        calc_momvals = self.unpack_moments(self.calc_moments)
        PrintDict = OrderedDict()
        i = 0
        for Ord in self.ref_moments:
            for Comp in self.ref_moments[Ord]:
                if abs(self.calc_moments[Ord][Comp]) > 1e-6 or abs(self.ref_moments[Ord][Comp]) > 1e-6:
                    PrintDict["%s-%s" % (Ord, Comp)] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (self.calc_moments[Ord][Comp],
                                                                                         self.ref_moments[Ord][Comp],
                                                                                         self.calc_moments[Ord][Comp]-self.ref_moments[Ord][Comp],
                                                                                         (ref_momvals[i] - calc_momvals[i])**2)

                i += 1
                
        printcool_dictionary(PrintDict,title="Moments and/or Polarizabilities, Objective = % .5e\n %-20s %9s %9s %9s %11s" % 
                             (self.objective, "Component", "Calc.", "Ref.", "Delta", "Term"))

        return
Esempio n. 2
0
    def __init__(self, User_Option, ForceField, Factor_Add=0.0, Factor_Mult=0.0, Factor_B=0.1, Alpha=1.0):
        self.fadd = Factor_Add
        self.fmul = Factor_Mult
        self.a    = Alpha
        self.b    = Factor_B
        self.FF   = ForceField
        self.ptyp = self.Pen_Names[User_Option.upper()]
        self.Pen_Tab = {1 : self.HYP, 2: self.L2_norm, 3: self.FUSE, 4:self.FUSE_L0, 5: self.FUSE_BARRIER}
        if User_Option.upper() == 'L1':
            logger.info("L1 norm uses the hyperbolic penalty, make sure penalty_hyperbolic_b is set sufficiently small\n")
        elif self.ptyp == 1:
            logger.info("Using hyperbolic regularization (Laplacian prior) with strength %.1e (+), %.1e (x) and tightness %.1e\n" % (Factor_Add, Factor_Mult, Factor_B))
        elif self.ptyp == 2:
            logger.info("Using parabolic regularization (Gaussian prior) with strength %.1e (+), %.1e (x)\n" % (Factor_Add, Factor_Mult))
        elif self.ptyp == 3:
            logger.info("Using L1 Fusion Penalty (only relevant for basis set optimizations at the moment) with strength %.1e\n" % Factor_Add)
        elif self.ptyp == 4:
            logger.info("Using L0-L1 Fusion Penalty (only relevant for basis set optimizations at the moment) with strength %.1e and switching distance %.1e\n" % (Factor_Add, Alpha))
        elif self.ptyp == 5:
            logger.info("Using L1 Fusion Penalty with Log Barrier (only relevant for basis set optimizations at the moment) with strength %.1e and barrier distance %.1e\n" % (Factor_Add, Alpha))

        ## Find exponential spacings.
        if self.ptyp in [3,4,5]:
            self.spacings = self.FF.find_spacings()
            printcool_dictionary(self.spacings, title="Starting zeta spacings\n(Pay attention to these)")
Esempio n. 3
0
    def __init__(self, User_Option, ForceField, Factor_Add=0.0, Factor_Mult=0.0, Factor_B=0.1, Alpha=1.0):
        self.fadd = Factor_Add
        self.fmul = Factor_Mult
        self.a    = Alpha
        self.b    = Factor_B
        self.FF   = ForceField
        self.ptyp = self.Pen_Names[User_Option.upper()]
        self.Pen_Tab = {1 : self.HYP, 2: self.L2_norm, 3: self.FUSE, 4:self.FUSE_L0, 5: self.FUSE_BARRIER}
        if User_Option.upper() == 'L1':
            logger.info("L1 norm uses the hyperbolic penalty, make sure penalty_hyperbolic_b is set sufficiently small\n")
        elif self.ptyp == 1:
            logger.info("Using hyperbolic regularization (Laplacian prior) with strength %.1e (+), %.1e (x) and tightness %.1e\n" % (Factor_Add, Factor_Mult, Factor_B))
        elif self.ptyp == 2:
            logger.info("Using parabolic regularization (Gaussian prior) with strength %.1e (+), %.1e (x)\n" % (Factor_Add, Factor_Mult))
        elif self.ptyp == 3:
            logger.info("Using L1 Fusion Penalty (only relevant for basis set optimizations at the moment) with strength %.1e\n" % Factor_Add)
        elif self.ptyp == 4:
            logger.info("Using L0-L1 Fusion Penalty (only relevant for basis set optimizations at the moment) with strength %.1e and switching distance %.1e\n" % (Factor_Add, Alpha))
        elif self.ptyp == 5:
            logger.info("Using L1 Fusion Penalty with Log Barrier (only relevant for basis set optimizations at the moment) with strength %.1e and barrier distance %.1e\n" % (Factor_Add, Alpha))

        ## Find exponential spacings.
        if self.ptyp in [3,4,5]:
            self.spacings = self.FF.find_spacings()
            printcool_dictionary(self.spacings, title="Starting zeta spacings\n(Pay attention to these)")
Esempio n. 4
0
 def indicate(self):
     delta = (self.emm - self.eqm)
     deltanrm = self.prefactor * (delta / self.divisor)**2
     if len(self.label) == self.ns:
         PrintDict = OrderedDict()
         for i, label in enumerate(self.label):
             PrintDict[label] = "% 9.3f % 9.3f % 9.3f % 9.3f % 11.5f" % (
                 self.emm[i], self.eqm[i], delta[i], self.divisor[i],
                 deltanrm[i])
         printcool_dictionary(
             PrintDict,
             title=
             "Target: %s\nInteraction Energies (kcal/mol), Objective = % .5e\n %-10s %9s %9s %9s %9s %11s"
             % (self.name, self.objective, "Label", "Calc.", "Ref.",
                "Delta", "Divisor", "Term"),
             keywidth=15)
     else:
         # logger.info("Target: %s Objective: % .5e (add LABEL keywords in qdata.txt for full printout)\n" % (self.name,self.objective))
         Headings = [
             "Observable", "Difference\nRMS (Calc-Ref)",
             "Denominator\n(Specified)", " Percent \nDifference"
         ]
         Data = OrderedDict([])
         Data['Energy (kcal/mol)'] = [
             "%8.4f" % np.sqrt(np.mean(delta**2)),
             "%8.4f" % np.mean(self.divisor),
             "%.4f%%" % (np.sqrt(np.mean(delta / self.divisor)**2) * 100)
         ]
         self.printcool_table(data=Data, headings=Headings, color=0)
         logger.info(
             "add LABEL keywords in qdata.txt to print out each snapshot\n")
Esempio n. 5
0
    def indicate(self):
        """Shows optimization state."""
        AGrad     = hasattr(self, 'Gp')
        PrintDict = OrderedDict()
        
        def print_item(key, physunit):
            if self.Xp[key] > 0:
                the_title = ("%s %s (%s)\n" % (self.name, key.capitalize(), physunit) +
                             "No.   Temperature  Pressure  Reference  " +
                             "Calculated +- Stddev " +
                             "   Delta    Weight    Term   ")
                    
                printcool_dictionary(self.Pp[key], title=the_title, bold=True,
                                     color=4, keywidth=15)
                
                bar = printcool(("%s objective function: % .3f%s" %
                                 (key.capitalize(), self.Xp[key],
                                  ", Derivative:" if AGrad else "")))
                if AGrad:
                    self.FF.print_map(vals=self.Gp[key])
                    logger.info(bar)

                PrintDict[key] = (("% 10.5f % 8.3f % 14.5e" %
                                   (self.Xp[key], self.Wp[key],
                                    self.Xp[key]*self.Wp[key])))

        for i, q in enumerate(self.quantities):
            print_item(q, self.points[0].ref["units"][i])

        PrintDict['Total'] = "% 10s % 8s % 14.5e" % ("","", self.Objective)

        Title = ("%s Thermodynamic Properties:\n %-20s %40s" %
                 (self.name, "Property", "Residual x Weight = Contribution"))
        printcool_dictionary(PrintDict, color=4, title=Title, keywidth=31)
        return
Esempio n. 6
0
    def indicate(self):
        """ Print qualitative indicator. """
        print "\rTarget: %-15s" % self.name
        #print "Multipole Moments and Po"
        #print "Reference :", self.ref_moments
        #print "Calculated:", self.calc_moments
        #print "Objective = %.5e" % self.objective

        ref_momvals = self.unpack_moments(self.ref_moments)
        calc_momvals = self.unpack_moments(self.calc_moments)
        PrintDict = OrderedDict()
        i = 0
        for Ord in self.ref_moments:
            for Comp in self.ref_moments[Ord]:
                if abs(self.calc_moments[Ord][Comp]) > 1e-6 or abs(self.ref_moments[Ord][Comp]) > 1e-6:
                    PrintDict["%s-%s" % (Ord, Comp)] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (self.calc_moments[Ord][Comp],
                                                                                         self.ref_moments[Ord][Comp],
                                                                                         self.calc_moments[Ord][Comp]-self.ref_moments[Ord][Comp],
                                                                                         (ref_momvals[i] - calc_momvals[i])**2)

                i += 1
                
        printcool_dictionary(PrintDict,title="Moments and/or Polarizabilities, Objective = % .5e\n %-20s %9s %9s %9s %11s" % 
                             (self.objective, "Component", "Calc.", "Ref.", "Delta", "Term"))

        return
Esempio n. 7
0
    def indicate(self):
        PrintDict = OrderedDict()
        for d in self.objvals:
            PrintDict[d] = "%15.9f" % self.objvals[d]
        printcool_dictionary(PrintDict,title="Target: %s\nR-DVR Objective Function, Total = %15.9f\n %-10s %15s" % 
                             (self.name, self.objective, "Molecule", "Objective"),keywidth=15)

        return
Esempio n. 8
0
def PrintEDA(EDA, N):
    # Get energy decomposition statistics.
    PrintDict = OrderedDict()
    for key, val in EDA.items():
        val_avg, val_err = mean_stderr(val)
        if val_avg == 0.0: continue
        if val_err == 0.0: continue
        PrintDict[key] = "% 12.4f +- %10.4f [ % 9.4f +- %7.4f ]" % (val_avg, val_err, val_avg/N, val_err/N)
    printcool_dictionary(PrintDict, "Energy Component Analysis, Mean +- Stderr [Per Molecule] (kJ/mol)")
Esempio n. 9
0
def PrintEDA(EDA, N):
    # Get energy decomposition statistics.
    PrintDict = OrderedDict()
    for key, val in EDA.items():
        val_avg, val_err = mean_stderr(val)
        if val_avg == 0.0: continue
        if val_err == 0.0: continue
        PrintDict[key] = "% 12.4f +- %10.4f [ % 9.4f +- %7.4f ]" % (val_avg, val_err, val_avg/N, val_err/N)
    printcool_dictionary(PrintDict, "Energy Component Analysis, Mean +- Stderr [Per Molecule] (kJ/mol)")
Esempio n. 10
0
    def __init__(self, options, tgt_opts, forcefield):

        super(Objective, self).__init__(options)
        self.set_option(options, 'penalty_type')
        self.set_option(options, 'penalty_additive')
        self.set_option(options, 'penalty_multiplicative')
        self.set_option(options, 'penalty_hyperbolic_b')
        self.set_option(options, 'penalty_alpha')
        self.set_option(options, 'normalize_weights')
        ## Work Queue Port (The specific target itself may or may not actually use this.)
        self.set_option(options, 'wq_port')
        ## Asynchronous objective function evaluation (i.e. execute Work Queue and local objective concurrently.)
        self.set_option(options, 'asynchronous')

        ## The list of fitting targets
        self.Targets = []
        for opts in tgt_opts:
            if opts['type'] not in Implemented_Targets:
                logger.error(
                    'The target type \x1b[1;91m%s\x1b[0m is not implemented!\n'
                    % opts['type'])
                raise RuntimeError
            if opts["remote"]:
                Tgt = forcebalance.target.RemoteTarget(options, opts,
                                                       forcefield)
            else:
                Tgt = Implemented_Targets[opts['type']](options, opts,
                                                        forcefield)
            self.Targets.append(Tgt)
            printcool_dictionary(Tgt.PrintOptionDict,
                                 "Setup for target %s :" % Tgt.name)
        if len(set([Tgt.name for Tgt in self.Targets])) != len(
            [Tgt.name for Tgt in self.Targets]):
            logger.error("The list of target names is not unique!\n")
            raise RuntimeError
        ## The force field (it seems to be everywhere)
        self.FF = forcefield
        ## Initialize the penalty function.
        self.Penalty = Penalty(self.penalty_type, forcefield,
                               self.penalty_additive,
                               self.penalty_multiplicative,
                               self.penalty_hyperbolic_b, self.penalty_alpha)
        ## Obtain the denominator.
        if self.normalize_weights:
            self.WTot = np.sum([i.weight for i in self.Targets])
        else:
            self.WTot = 1.0
        self.ObjDict = OrderedDict()
        self.ObjDict_Last = OrderedDict()

        # Create the work queue here.
        if self.wq_port != 0:
            createWorkQueue(self.wq_port)
            logger.info('Work Queue is listening on %d\n' % self.wq_port)

        printcool_dictionary(self.PrintOptionDict,
                             "Setup for objective function :")
Esempio n. 11
0
    def printcool_table(self, data=OrderedDict([]), headings=[], banner=None, footnote=None, color=0):
        """ Print target information in an organized table format.  Implemented 6/30 because
        multiple targets are already printing out tabulated information in very similar ways.
        This method is a simple wrapper around printcool_dictionary.  

        The input should be something like:

        @param data Column contents in the form of an OrderedDict, with string keys and list vals.
        The key is printed in the leftmost column and the vals are printed in the other columns.
        If non-strings are passed, they will be converted to strings (not recommended).
        
        @param headings Column headings in the form of a list.  It must be equal to the number to the list length
        for each of the "vals" in OrderedDict, plus one.  Use "\n" characters to specify long
        column names that may take up more than one line.

        @param banner Optional heading line, which will be printed at the top in the title.
        @param footnote Optional footnote line, which will be printed at the bottom.
        
        """
        tline="Target: %s  Type: %s  Objective = %.5e" % (self.name, self.__class__.__name__, self.objective)
        nc = len(headings)
        if banner != None:
            tlines = [banner, tline]
        else:
            tlines = [tline]
        # Sanity check.
        for val in data.values():
            if (len(val)+1) != nc:
                logger.error('There are %i column headings, so the values in the data dictionary must be lists of length %i (currently %i)\n' % (nc, nc-1, len(val)))
                raise RuntimeError
        cwidths = [0 for i in range(nc)]
        # Figure out maximum column width.
        # First look at all of the column headings...
        crows = []
        for cnum, cname in enumerate(headings):
            crows.append(len(cname.split('\n')))
            for l in cname.split('\n'):
                cwidths[cnum] = max(cwidths[cnum], len(l))
        # Then look at the row names to stretch out the first column width...
        for k in data.keys():
            cwidths[0] = max(cwidths[0], len(str(k)))
        # Then look at the data values to stretch out the other column widths.
        for v in data.values():
            for n, f in enumerate(v):
                cwidths[n+1] = max(cwidths[n+1], len(str(f)))
        for i in range(1, len(cwidths)):
            cwidths[i] += 2
        if cwidths[0] < 15:
            cwidths[0] = 15
        cblocks = [['' for i in range(max(crows) - len(cname.split('\n')))] + cname.split('\n') for cnum, cname in enumerate(headings)]
        # The formatting line consisting of variable column widths
        fline = ' '.join("%%%s%is" % (("-" if i==0 else ""), j) for i, j in enumerate(cwidths))
        vline = ' '.join(["%%%is" % j for i, j in enumerate(cwidths) if i > 0])
        clines = [fline % (tuple(cblocks[j][i] for j in range(nc))) for i in range(max(crows))]
        tlines += clines
        PrintDict = OrderedDict([(key, vline % (tuple(val))) for key, val in data.items()])
        printcool_dictionary(PrintDict, title='\n'.join(tlines), keywidth=cwidths[0], center=[i==0 for i in range(len(tlines))], leftpad=4, color=color)
Esempio n. 12
0
 def indicate(self):
     if len(self.label) == self.ns:
         PrintDict = OrderedDict()
         delta = (self.emm-self.eqm)
         deltanrm = self.prefactor*(delta/self.divisor)**2
         for i,label in enumerate(self.label):
             PrintDict[label] = "% 9.3f % 9.3f % 9.3f % 9.3f % 11.5f" % (self.emm[i]/4.184, self.eqm[i]/4.184, delta[i]/4.184, self.divisor[i]/4.184, deltanrm[i])
         printcool_dictionary(PrintDict,title="Target: %s\nInteraction Energies (kcal/mol), Objective = % .5e\n %-10s %9s %9s %9s %9s %11s" % 
                              (self.name, self.objective, "Label", "Calc.", "Ref.", "Delta", "Divisor", "Term"),keywidth=15)
     else:
         logger.info("Target: %s Objective: % .5e (add LABEL keywords in qdata.txt for full printout)\n" % (self.name,self.objective))
Esempio n. 13
0
def edit_mdp(fin, fout, options, verbose=False):
    """
    Create or edit a Gromacs MDP file.
    @param[in] fin Input file name.
    @param[in] fout Output file name, can be the same as input file name.
    @param[in] options Dictionary containing mdp options. Existing options are replaced, new options are added at the end.
    """
    # Make sure that the keys are lowercase, and the values are all strings.
    options = OrderedDict([(key.lower(), str(val)) for key, val in options.items()])
    # List of lines in the output file.
    out = []
    # List of options in the output file.
    haveopts = []
    if os.path.isfile(fin):
        for line in open(fin).readlines():
            line    = line.strip().expandtabs()
            # The line structure should look something like this:
            # key   = value  ; comments
            # First split off the comments.
            if len(line) == 0:
                out.append('')
            s = line.split(';',1)
            data = s[0]
            comms = s[1] if len(s) > 1 else None
            # Pure comment lines or empty lines get appended to the output.
            if set(data).issubset([' ']):
                out.append(line)
                continue
            # Now split off the key and value fields at the equals sign.
            keyf, valf = data.split('=',1)
            key = keyf.strip().lower()
            valen = len(valf)
            if key in options:
                val = options[key]
                if len(val) < len(valf):
                    valf = ' ' + val + ' '*(len(valf) - len(val)-1)
                else:
                    valf = ' ' + val + ' '
                lout = [keyf, '=', valf]
                if comms != None:
                    lout += [';',comms]
                out.append(''.join(lout))
                haveopts.append(key)
            else:
                out.append(line)
    for key, val in options.items():
        if key not in haveopts:
            out.append("%-20s = %s" % (key, val))
    file_out = open(fout,'w')
    for line in out:
        print >> file_out, line
    if verbose:
        printcool_dictionary(options, title="%s -> %s with options:" % (fin, fout))
    file_out.close()
Esempio n. 14
0
 def indicate(self):
     title_str = "Torsion Profile: %s, Objective = % .5e, Units = kcal/mol, Angstrom" % (
         self.name, self.objective)
     #LPW: This title is carefully placed to align correctly
     column_head_str1 = "%-50s %-10s %-12s %-18s %-12s %-10s %-11s %-10s" % (
         "System", "Min(QM)", "Min(MM)", "Range(QM)", "Range(MM)",
         "Max-RMSD", "Ene-RMSE", "Obj-Fn")
     printcool_dictionary(self.PrintDict,
                          title=title_str + '\n' + column_head_str1,
                          keywidth=50,
                          center=[True, False])
Esempio n. 15
0
 def indicate(self):
     title_str = "%s, Objective = % .5e" % (self.name, self.objective)
     #QYD: This title is carefully placed to align correctly
     column_head_str1 = " %-20s %13s     %13s     %15s   %15s   %17s " % (
         "System", "Bonds", "Angles", "Dihedrals", "Impropers", "Term.")
     column_head_str2 = " %-20s %9s %7s %9s %7s %9s %7s %9s %7s %17s " % (
         '', 'RMSD', 'denom', 'RMSD', 'denom', 'RMSD', 'denom', 'RMSD',
         'denom', '')
     printcool_dictionary(self.PrintDict,
                          title=title_str + '\n' + column_head_str1 + '\n' +
                          column_head_str2,
                          center=[True, False, False])
Esempio n. 16
0
    def indicate(self):
        PrintDict = OrderedDict()
        for d in self.objvals:
            PrintDict[d] = "%15.9f" % self.objvals[d]
        printcool_dictionary(
            PrintDict,
            title=
            "Target: %s\nR-DVR Objective Function, Total = %15.9f\n %-10s %15s"
            % (self.name, self.objective, "Molecule", "Objective"),
            keywidth=15)

        return
Esempio n. 17
0
    def __init__(self, options, tgt_opts, forcefield):

        super(Objective, self).__init__(options)
        self.set_option(options, 'penalty_type')
        self.set_option(options, 'penalty_additive')
        self.set_option(options, 'penalty_multiplicative')
        self.set_option(options, 'penalty_hyperbolic_b')
        self.set_option(options, 'penalty_alpha')
        self.set_option(options, 'penalty_power')
        self.set_option(options, 'normalize_weights')
        ## Work Queue Port (The specific target itself may or may not actually use this.)
        self.set_option(options, 'wq_port')
        ## Asynchronous objective function evaluation (i.e. execute Work Queue and local objective concurrently.)
        self.set_option(options, 'asynchronous')

        ## The list of fitting targets
        self.Targets = []
        for opts in tgt_opts:
            if opts['type'] not in Implemented_Targets:
                logger.error('The target type \x1b[1;91m%s\x1b[0m is not implemented!\n' % opts['type'])
                raise RuntimeError
            # Create a target object.  This is done by looking up the
            # Target class from the Implemented_Targets dictionary
            # using opts['type'] as the key.  The object is created by
            # passing (options, opts, forcefield) to the constructor.
            if opts["remote"] and self.wq_port != 0: Tgt = forcebalance.target.RemoteTarget(options, opts, forcefield)
            else: Tgt = Implemented_Targets[opts['type']](options,opts,forcefield)
            self.Targets.append(Tgt)
            printcool_dictionary(Tgt.PrintOptionDict,"Setup for target %s :" % Tgt.name)
        if len(set([Tgt.name for Tgt in self.Targets])) != len([Tgt.name for Tgt in self.Targets]):
            logger.error("The list of target names is not unique!\n")
            raise RuntimeError
        ## The force field (it seems to be everywhere)
        self.FF = forcefield
        ## Initialize the penalty function.
        self.Penalty = Penalty(self.penalty_type,forcefield,self.penalty_additive,
                               self.penalty_multiplicative,self.penalty_hyperbolic_b,
                               self.penalty_alpha,self.penalty_power)
        ## Obtain the denominator.
        if self.normalize_weights:
            self.WTot = np.sum([i.weight for i in self.Targets])
        else:
            self.WTot = 1.0
        self.ObjDict = OrderedDict()
        self.ObjDict_Last = OrderedDict()

        # Create the work queue here.
        if self.wq_port != 0:
            createWorkQueue(self.wq_port)
            logger.info('Work Queue is listening on %d\n' % self.wq_port)

        printcool_dictionary(self.PrintOptionDict, "Setup for objective function :")
Esempio n. 18
0
    def indicate(self):
        """Print information to the output file about the last epoch."""

        title = "SMILES\nX"

        dict_for_print = {
            smiles: "%9.3e" % loss
            for smiles, loss in self._per_molecule_residuals.items()
        }

        printcool_dictionary(
            dict_for_print, title=title, bold=True, color=4, keywidth=15
        )
Esempio n. 19
0
 def indicate(self):
     printcool_dictionary(
         self.PrintDict,
         title=
         "Interaction Energies (kcal/mol), Objective = % .5e\n %-20s %9s %9s %9s %11s"
         % (self.energy_part, "Interaction", "Calc.", "Ref.", "Delta",
            "Term"))
     if len(self.RMSDDict) > 0:
         printcool_dictionary(
             self.RMSDDict,
             title=
             "Geometry Optimized Systems (Angstrom), Objective = %.5e\n %-38s %11s %11s"
             % (self.rmsd_part, "System", "RMSD", "Term"),
             keywidth=45)
Esempio n. 20
0
 def indicate(self):
     delta = (self.emm-self.eqm)
     deltanrm = self.prefactor*(delta/self.divisor)**2
     if len(self.label) == self.ns:
         PrintDict = OrderedDict()
         for i,label in enumerate(self.label):
             PrintDict[label] = "% 9.3f % 9.3f % 9.3f % 9.3f % 11.5f" % (self.emm[i], self.eqm[i], delta[i], self.divisor[i], deltanrm[i])
         printcool_dictionary(PrintDict,title="Target: %s\nInteraction Energies (kcal/mol), Objective = % .5e\n %-10s %9s %9s %9s %9s %11s" %
                              (self.name, self.objective, "Label", "Calc.", "Ref.", "Delta", "Divisor", "Term"),keywidth=15)
     else:
         # logger.info("Target: %s Objective: % .5e (add LABEL keywords in qdata.txt for full printout)\n" % (self.name,self.objective))
         Headings = ["Observable", "Difference\nRMS (Calc-Ref)", "Denominator\n(Specified)", " Percent \nDifference"]
         Data = OrderedDict([])
         Data['Energy (kcal/mol)'] = ["%8.4f" % np.sqrt(np.mean(delta**2)),
                                    "%8.4f" % np.mean(self.divisor),
                                    "%.4f%%" % (np.sqrt(np.mean(delta/self.divisor)**2)*100)]
         self.printcool_table(data=Data, headings=Headings, color=0)
         logger.info("add LABEL keywords in qdata.txt to print out each snapshot\n")
Esempio n. 21
0
    def __init__(self, options, tgt_opts, forcefield):

        super(Objective, self).__init__(options)
        self.set_option(options, 'penalty_type')
        self.set_option(options, 'penalty_additive')
        self.set_option(options, 'penalty_multiplicative')
        self.set_option(options, 'penalty_hyperbolic_b')
        self.set_option(options, 'penalty_alpha')
        self.set_option(options, 'normalize_weights')
        ## Work Queue Port (The specific target itself may or may not actually use this.)
        self.set_option(options, 'wq_port')
        ## Asynchronous objective function evaluation (i.e. execute Work Queue and local objective concurrently.)
        self.set_option(options, 'asynchronous')

        ## The list of fitting targets
        self.Targets = []
        for opts in tgt_opts:
            if opts['type'] not in Implemented_Targets:
                raise RuntimeError('The target type \x1b[1;91m%s\x1b[0m is not implemented!' % opts['type'])
            Tgt = Implemented_Targets[opts['type']](options,opts,forcefield)
            self.Targets.append(Tgt)
            printcool_dictionary(Tgt.PrintOptionDict,"Setup for target %s :" % Tgt.name)
        if len(set([Tgt.name for Tgt in self.Targets])) != len([Tgt.name for Tgt in self.Targets]):
            raise Exception("The list of target names is not unique!")
        ## The force field (it seems to be everywhere)
        self.FF = forcefield
        ## Initialize the penalty function.
        self.Penalty = Penalty(options['penalty_type'],forcefield,options['penalty_additive'],
                               options['penalty_multiplicative'],options['penalty_hyperbolic_b'],
                               options['penalty_alpha'])
        ## Obtain the denominator.
        if self.normalize_weights:
            self.WTot = sum([i.weight for i in self.Targets])
        else:
            self.WTot = 1.0
        self.ObjDict = OrderedDict()
        self.ObjDict_Last = OrderedDict()

        # Create the work queue here.
        if self.wq_port != 0:
            createWorkQueue(self.wq_port)
            print('Work Queue is listening on %d' % self.wq_port)

        printcool_dictionary(self.PrintOptionDict, "Setup for objective function :")
Esempio n. 22
0
 def Indicate(self):
     """ Print objective function contributions. """
     PrintDict = OrderedDict()
     Total = 0.0
     Change = False
     color = "\x1b[0m"
     for key, val in self.ObjDict.items():
         if key == 'Total': continue
         color = "\x1b[94m"
         if key in self.ObjDict_Last:
             Change = True
             # print(self.ObjDict[key], self.ObjDict_Last[key])
             if self.ObjDict[key]['x'] <= self.ObjDict_Last[key]['x']:
                 color = "\x1b[92m"
             elif self.ObjDict[key]['x'] > self.ObjDict_Last[key]['x']:
                 color = "\x1b[91m"
         PrintDict[key] = "% 12.5f % 10.3f %s% 16.5e%s" % (
             val['x'], val['w'], color, val['x'] * val['w'], "\x1b[0m")
         if Change:
             xnew = self.ObjDict[key]['x'] * self.ObjDict[key]['w']
             xold = self.ObjDict_Last[key]['x'] * self.ObjDict_Last[key]['w']
             PrintDict[key] += " ( %+10.3e )" % (xnew - xold)
         Total += val['x'] * val['w']
     self.ObjDict['Total'] = Total
     if 'Total' in self.ObjDict_Last:
         Change = True
         if self.ObjDict['Total'] <= self.ObjDict_Last['Total']:
             color = "\x1b[92m"
         elif self.ObjDict['Total'] > self.ObjDict_Last['Total']:
             color = "\x1b[91m"
     PrintDict['Total'] = "% 12s % 10s %s% 16.5e%s" % ("", "", color, Total,
                                                       "\x1b[0m")
     if Change:
         xnew = self.ObjDict['Total']
         xold = self.ObjDict_Last['Total']
         PrintDict['Total'] += " ( %+10.3e )" % (xnew - xold)
         Title = "Objective Function Breakdown\n %-20s %55s" % (
             "Target Name",
             "Residual  x  Weight  =  Contribution (Current-Prev)")
     else:
         Title = "Objective Function Breakdown\n %-20s %40s" % (
             "Target Name", "Residual  x  Weight  =  Contribution")
     printcool_dictionary(PrintDict, color=4, title=Title)
     return
Esempio n. 23
0
 def indicate(self):
     """
     print information into the output file about the last objective function evaluated
     This function should be called after get()
     """
     for property_name, details in self._last_obj_details.items():
         dict_for_print = {
             "  %s %s %s"
             % detail[:3]: "%9.3f %14.3f +- %-7.3f % 7.3f % 9.5f % 9.5f % 9.5f "
             % detail[3:]
             for detail in details
         }
         title = (
             "%s %s\nTemperature  Pressure Substance  Reference  Calculated +- "
             "Stdev     Delta    Weight    Denom     Term  " % (self.name, property_name)
         )
         printcool_dictionary(
             dict_for_print, title=title, bold=True, color=4, keywidth=15
         )
Esempio n. 24
0
    def __init__(self, User_Option, ForceField, Factor_Add=0.0, Factor_Mult=0.0, Factor_B=0.1, Alpha=1.0, Power=2.0):
        self.fadd = Factor_Add
        self.fmul = Factor_Mult
        self.a    = Alpha
        self.b    = Factor_B
        self.p    = Power
        self.FF   = ForceField
        self.ptyp = self.Pen_Names[User_Option.upper()]
        self.Pen_Tab = {1 : self.HYP, 2: self.L2_norm, 3: self.BOX, 4: self.FUSE, 5:self.FUSE_L0, 6: self.FUSE_BARRIER}
        if User_Option.upper() == 'L1':
            logger.info("L1 norm uses the hyperbolic penalty, make sure penalty_hyperbolic_b is set sufficiently small\n")
        elif self.ptyp == 1:
            logger.info("Using hyperbolic regularization (Laplacian prior) with strength %.1e (+), %.1e (x) and tightness %.1e\n" % (Factor_Add, Factor_Mult, Factor_B))
        elif self.ptyp == 2:
            if Power == 2.0:
                logger.info("Using parabolic regularization (Gaussian prior) with strength %.1e (+), %.1e (x)\n" % (Factor_Add, Factor_Mult))
            elif Power > 2.0:
                logger.info("Using customized L2-regularization with exponent %.1f, strength %.1e (+), %.1e (x)\n" % (Power, Factor_Add, Factor_Mult))
            else:
                logger.error("In L2-regularization, penalty_power must be >= 2.0 (currently %.1f)\n" % (Power))
                raise RuntimeError
        elif self.ptyp == 3:
            if Power == 2.0:
                logger.info("Using box-style regularization with exponent %.1f, strength %.1e (+), %.1e (x): same as L2\n" % (Power, Factor_Add, Factor_Mult))
            elif Power > 2.0:
                logger.info("Using box-style regularization with exponent %.1f, strength %.1e (+), %.1e (x)\n" % (Power, Factor_Add, Factor_Mult))
            else:
                logger.error("In box-style regularization, penalty_power must be >= 2.0 (currently %.1f)\n" % (Power))
                raise RuntimeError
        elif self.ptyp == 4:
            logger.info("Using L1 Fusion Penalty (only relevant for basis set optimizations at the moment) with strength %.1e\n" % Factor_Add)
        elif self.ptyp == 5:
            logger.info("Using L0-L1 Fusion Penalty (only relevant for basis set optimizations at the moment) with strength %.1e and switching distance %.1e\n" % (Factor_Add, Alpha))
        elif self.ptyp == 6:
            logger.info("Using L1 Fusion Penalty with Log Barrier (only relevant for basis set optimizations at the moment) with strength %.1e and barrier distance %.1e\n" % (Factor_Add, Alpha))
        if self.ptyp not in (2, 3) and Power != 2.0:
            logger.error("Custom power %.2f is only supported with L2 or box-style regularization (penalty_type L2 or box)\n" % Power)
            raise RuntimeError

        ## Find exponential spacings.
        if self.ptyp in [4,5,6]:
            self.spacings = self.FF.find_spacings()
            printcool_dictionary(self.spacings, title="Starting zeta spacings\n(Pay attention to these)")
Esempio n. 25
0
        def print_item(key, physunit):
            if self.Xp[key] > 0:
                the_title = ("%s %s (%s)\n" % (self.name, key.capitalize(), physunit) +
                             "No.   Temperature  Pressure  Reference  " +
                             "Calculated +- Stddev " +
                             "   Delta    Weight    Term   ")
                    
                printcool_dictionary(self.Pp[key], title=the_title, bold=True,
                                     color=4, keywidth=15)
                
                bar = printcool(("%s objective function: % .3f%s" %
                                 (key.capitalize(), self.Xp[key],
                                  ", Derivative:" if AGrad else "")))
                if AGrad:
                    self.FF.print_map(vals=self.Gp[key])
                    logger.info(bar)

                PrintDict[key] = (("% 10.5f % 8.3f % 14.5e" %
                                   (self.Xp[key], self.Wp[key],
                                    self.Xp[key]*self.Wp[key])))
Esempio n. 26
0
    def indicate(self):
        """ Print qualitative indicator. """
        logger.info("\rTarget: %-15s\n" % self.name)

        ref_momvals = self.unpack_moments(self.ref_moments)
        calc_momvals = self.unpack_moments(self.calc_moments)
        PrintDict = OrderedDict()
        i = 0
        for Ord in self.ref_moments:
            if abs(self.calc_moments[Ord]) > 1e-6 or abs(self.ref_moments[Ord]) > 1e-6:
                PrintDict["%s" % (Ord)] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (self.calc_moments[Ord],
                                                                                     self.ref_moments[Ord],
                                                                                     self.calc_moments[Ord]-self.ref_moments[Ord],
                                                                                     (ref_momvals[i] - calc_momvals[i])**2)

            i += 1
                
        printcool_dictionary(PrintDict,title="Moments and/or Polarizabilities, Objective = % .5e\n %-20s %9s %9s %9s %11s" % 
                             (self.objective, "Component", "Calc.", "Ref.", "Delta", "Term"))

        return
Esempio n. 27
0
 def Indicate(self):
     """ Print objective function contributions. """
     PrintDict = OrderedDict()
     Total = 0.0
     Change = False
     color = "\x1b[0m"
     for key, val in self.ObjDict.items():
         if key == 'Total' : continue
         color = "\x1b[94m"
         if key in self.ObjDict_Last:
             Change = True
             # print(self.ObjDict[key], self.ObjDict_Last[key])
             if self.ObjDict[key]['x'] <= self.ObjDict_Last[key]['x']:
                 color = "\x1b[92m"
             elif self.ObjDict[key]['x'] > self.ObjDict_Last[key]['x']:
                 color = "\x1b[91m"
         PrintDict[key] = "% 12.5f % 10.3f %s% 16.5e%s" % (val['x'],val['w'],color,val['x']*val['w'],"\x1b[0m")
         if Change:
             xnew = self.ObjDict[key]['x'] * self.ObjDict[key]['w']
             xold = self.ObjDict_Last[key]['x'] * self.ObjDict_Last[key]['w']
             PrintDict[key] += " ( %+10.3e )" % (xnew - xold)
         Total += val['x']*val['w']
     self.ObjDict['Total'] = Total
     if 'Total' in self.ObjDict_Last:
         Change = True
         if self.ObjDict['Total'] <= self.ObjDict_Last['Total']:
             color = "\x1b[92m"
         elif self.ObjDict['Total'] > self.ObjDict_Last['Total']:
             color = "\x1b[91m"
     PrintDict['Total'] = "% 12s % 10s %s% 16.5e%s" % ("","",color,Total,"\x1b[0m")
     if Change:
         xnew = self.ObjDict['Total']
         xold = self.ObjDict_Last['Total']
         PrintDict['Total'] += " ( %+10.3e )" % (xnew - xold)
         Title = "Objective Function Breakdown\n %-20s %55s" % ("Target Name", "Residual  x  Weight  =  Contribution (Current-Prev)")
     else:
         Title = "Objective Function Breakdown\n %-20s %40s" % ("Target Name", "Residual  x  Weight  =  Contribution")
     printcool_dictionary(PrintDict,color=4,title=Title)
     return
Esempio n. 28
0
def main():

    """
    Usage: (runcuda.sh) npt.py <openmm|gromacs|tinker> <liquid_nsteps> <liquid_timestep (fs)> <liquid_intvl (ps> <temperature> <pressure>

    This program is meant to be called automatically by ForceBalance on
    a GPU cluster (specifically, subroutines in openmmio.py).  It is
    not easy to use manually.  This is because the force field is read
    in from a ForceBalance 'FF' class.

    I wrote this program because automatic fitting of the density (or
    other equilibrium properties) is computationally intensive, and the
    calculations need to be distributed to the queue.  The main instance
    of ForceBalance (running on my workstation) queues up a bunch of these
    jobs (using Work Queue).  Then, I submit a bunch of workers to GPU
    clusters (e.g. Certainty, Keeneland).  The worker scripts connect to.
    the main instance and receives one of these jobs.

    This script can also be executed locally, if you want to (e.g. for
    debugging).  Just make sure you have the pickled 'forcebalance.p'
    file.

    """

    printcool("ForceBalance condensed phase simulation using engine: %s" % engname.upper(), color=4, bold=True)

    #----
    # Load the ForceBalance pickle file which contains:
    #----
    # - Force field object
    # - Optimization parameters
    # - Options from the Target object that launched this simulation
    # - Switch for whether to evaluate analytic derivatives.
    FF,mvals,TgtOptions,AGrad = lp_load(open('forcebalance.p'))
    FF.ffdir = '.'
    # Write the force field file.
    FF.make(mvals)

    #----
    # Load the options that are set in the ForceBalance input file.
    #----
    # Finite difference step size
    h = TgtOptions['h']
    pgrad = TgtOptions['pgrad']
    # MD options; time step (fs), production steps, equilibration steps, interval for saving data (ps)
    liquid_timestep = TgtOptions['liquid_timestep']
    liquid_nsteps = TgtOptions['liquid_md_steps']
    liquid_nequil = TgtOptions['liquid_eq_steps']
    liquid_intvl = TgtOptions['liquid_interval']
    liquid_fnm = TgtOptions['liquid_coords']
    gas_timestep = TgtOptions['gas_timestep']
    gas_nsteps = TgtOptions['gas_md_steps']
    gas_nequil = TgtOptions['gas_eq_steps']
    gas_intvl = TgtOptions['gas_interval']
    gas_fnm = TgtOptions['gas_coords']

    # Number of threads, multiple timestep integrator, anisotropic box etc.
    threads = TgtOptions.get('md_threads', 1)
    mts = TgtOptions.get('mts_integrator', 0)
    rpmd_beads = TgtOptions.get('rpmd_beads', 0)
    force_cuda = TgtOptions.get('force_cuda', 0)
    anisotropic = TgtOptions.get('anisotropic_box', 0)
    minimize = TgtOptions.get('minimize_energy', 1)

    # Print all options.
    printcool_dictionary(TgtOptions, title="Options from ForceBalance")
    liquid_snapshots = (liquid_nsteps * liquid_timestep / 1000) / liquid_intvl
    liquid_iframes = 1000 * liquid_intvl / liquid_timestep
    gas_snapshots = (gas_nsteps * gas_timestep / 1000) / gas_intvl
    gas_iframes = 1000 * gas_intvl / gas_timestep
    logger.info("For the condensed phase system, I will collect %i snapshots spaced apart by %i x %.3f fs time steps\n" \
        % (liquid_snapshots, liquid_iframes, liquid_timestep))
    if liquid_snapshots < 2:
        raise Exception('Please set the number of liquid time steps so that you collect at least two snapshots (minimum %i)' \
                            % (2000 * (liquid_intvl/liquid_timestep)))
    logger.info("For the gas phase system, I will collect %i snapshots spaced apart by %i x %.3f fs time steps\n" \
        % (gas_snapshots, gas_iframes, gas_timestep))
    if gas_snapshots < 2:
        raise Exception('Please set the number of gas time steps so that you collect at least two snapshots (minimum %i)' \
                            % (2000 * (gas_intvl/gas_timestep)))

    #----
    # Loading coordinates
    #----
    ML = Molecule(liquid_fnm)
    MG = Molecule(gas_fnm)
    # Determine the number of molecules in the condensed phase coordinate file.
    NMol = len(ML.molecules)

    #----
    # Setting up MD simulations
    #----
    EngOpts = OrderedDict()
    EngOpts["liquid"] = OrderedDict([("coords", liquid_fnm), ("mol", ML), ("pbc", True)])
    EngOpts["gas"] = OrderedDict([("coords", gas_fnm), ("mol", MG), ("pbc", False)])
    GenOpts = OrderedDict([('FF', FF)])
    if engname == "openmm":
        # OpenMM-specific options
        EngOpts["liquid"]["platname"] = 'CUDA'
        EngOpts["gas"]["platname"] = 'Reference'
        if force_cuda:
            try: Platform.getPlatformByName('CUDA')
            except: raise RuntimeError('Forcing failure because CUDA platform unavailable')
        if threads > 1: logger.warn("Setting the number of threads will have no effect on OpenMM engine.\n")
    elif engname == "gromacs":
        # Gromacs-specific options
        GenOpts["gmxpath"] = TgtOptions["gmxpath"]
        GenOpts["gmxsuffix"] = TgtOptions["gmxsuffix"]
        EngOpts["liquid"]["gmx_top"] = os.path.splitext(liquid_fnm)[0] + ".top"
        EngOpts["liquid"]["gmx_mdp"] = os.path.splitext(liquid_fnm)[0] + ".mdp"
        EngOpts["gas"]["gmx_top"] = os.path.splitext(gas_fnm)[0] + ".top"
        EngOpts["gas"]["gmx_mdp"] = os.path.splitext(gas_fnm)[0] + ".mdp"
        if force_cuda: logger.warn("force_cuda option has no effect on Gromacs engine.")
        if rpmd_beads > 0: raise RuntimeError("Gromacs cannot handle RPMD.")
        if mts: logger.warn("Gromacs not configured for multiple timestep integrator.")
        if anisotropic: logger.warn("Gromacs not configured for anisotropic box scaling.")
    elif engname == "tinker":
        # Tinker-specific options
        GenOpts["tinkerpath"] = TgtOptions["tinkerpath"]
        EngOpts["liquid"]["tinker_key"] = os.path.splitext(liquid_fnm)[0] + ".key"
        EngOpts["gas"]["tinker_key"] = os.path.splitext(gas_fnm)[0] + ".key"
        if force_cuda: logger.warn("force_cuda option has no effect on Tinker engine.")
        if rpmd_beads > 0: raise RuntimeError("TINKER cannot handle RPMD.")
        if mts: logger.warn("Tinker not configured for multiple timestep integrator.")
    EngOpts["liquid"].update(GenOpts)
    EngOpts["gas"].update(GenOpts)
    for i in EngOpts:
        printcool_dictionary(EngOpts[i], "Engine options for %s" % i)

    # Set up MD options
    MDOpts = OrderedDict()
    MDOpts["liquid"] = OrderedDict([("nsteps", liquid_nsteps), ("timestep", liquid_timestep),
                                    ("temperature", temperature), ("pressure", pressure),
                                    ("nequil", liquid_nequil), ("minimize", minimize),
                                    ("nsave", int(1000 * liquid_intvl / liquid_timestep)),
                                    ("verbose", True), ('save_traj', TgtOptions['save_traj']), 
                                    ("threads", threads), ("anisotropic", anisotropic), ("nbarostat", 10),
                                    ("mts", mts), ("rpmd_beads", rpmd_beads), ("faststep", faststep)])
    MDOpts["gas"] = OrderedDict([("nsteps", gas_nsteps), ("timestep", gas_timestep),
                                 ("temperature", temperature), ("nsave", int(1000 * gas_intvl / gas_timestep)),
                                 ("nequil", gas_nequil), ("minimize", minimize), ("threads", 1), ("mts", mts),
                                 ("rpmd_beads", rpmd_beads), ("faststep", faststep)])

    # Energy components analysis disabled for OpenMM MTS because it uses force groups
    if (engname == "openmm" and mts): logger.warn("OpenMM with MTS integrator; energy components analysis will be disabled.\n")

    # Create instances of the MD Engine objects.
    Liquid = Engine(name="liquid", **EngOpts["liquid"])
    Gas = Engine(name="gas", **EngOpts["gas"])

    #=================================================================#
    # Run the simulation for the full system and analyze the results. #
    #=================================================================#

    printcool("Condensed phase molecular dynamics", color=4, bold=True)

    # This line runs the condensed phase simulation.
    prop_return = Liquid.molecular_dynamics(**MDOpts["liquid"])
    Rhos = prop_return['Rhos']
    Potentials = prop_return['Potentials']
    Kinetics = prop_return['Kinetics']
    Volumes = prop_return['Volumes']
    Dips = prop_return['Dips']
    EDA = prop_return['Ecomps']

    # Create a bunch of physical constants.
    # Energies are in kJ/mol
    # Lengths are in nanometers.
    L = len(Rhos)
    kB = 0.008314472471220214
    T = temperature
    kT = kB * T
    mBeta = -1.0 / kT
    Beta = 1.0 / kT
    atm_unit = 0.061019351687175
    bar_unit = 0.060221417930000
    # This is how I calculated the prefactor for the dielectric constant.
    # eps0 = 8.854187817620e-12 * coulomb**2 / newton / meter**2
    # epsunit = 1.0*(debye**2) / nanometer**3 / BOLTZMANN_CONSTANT_kB / kelvin
    # prefactor = epsunit/eps0/3
    prefactor = 30.348705333964077

    # Gather some physical variables.
    Energies = Potentials + Kinetics
    Ene_avg, Ene_err = mean_stderr(Energies)
    pV = atm_unit * pressure * Volumes
    pV_avg, pV_err = mean_stderr(pV)
    Rho_avg, Rho_err = mean_stderr(Rhos)
    PrintEDA(EDA, NMol)

    #==============================================#
    # Now run the simulation for just the monomer. #
    #==============================================#

    # Run the OpenMM simulation, gather information.

    printcool("Gas phase molecular dynamics", color=4, bold=True)
    mprop_return = Gas.molecular_dynamics(**MDOpts["gas"])
    mPotentials = mprop_return['Potentials']
    mKinetics = mprop_return['Kinetics']
    mEDA = mprop_return['Ecomps']

    mEnergies = mPotentials + mKinetics
    mEne_avg, mEne_err = mean_stderr(mEnergies)
    PrintEDA(mEDA, 1)

    #============================================#
    #  Compute the potential energy derivatives. #
    #============================================#
    logger.info("Calculating potential energy derivatives with finite difference step size: %f\n" % h)
    # Switch for whether to compute the derivatives two different ways for consistency.
    FDCheck = False

    # Create a double-precision simulation object if desired (seems unnecessary).
    DoublePrecisionDerivatives = False
    if engname == "openmm" and DoublePrecisionDerivatives and AGrad:
        logger.info("Creating Double Precision Simulation for parameter derivatives\n")
        Liquid = Engine(name="liquid", openmm_precision="double", **EngOpts["liquid"])
        Gas = Engine(name="gas", openmm_precision="double", **EngOpts["gas"])

    # Compute the energy and dipole derivatives.
    printcool("Condensed phase energy and dipole derivatives\nInitializing array to length %i" % len(Energies), color=4, bold=True)
    G, GDx, GDy, GDz = energy_derivatives(Liquid, FF, mvals, h, pgrad, len(Energies), AGrad, dipole=True)
    printcool("Gas phase energy derivatives", color=4, bold=True)
    mG, _, __, ___ = energy_derivatives(Gas, FF, mvals, h, pgrad, len(mEnergies), AGrad, dipole=False)

    #==============================================#
    #  Condensed phase properties and derivatives. #
    #==============================================#

    #----
    # Density
    #----
    # Build the first density derivative.
    GRho = mBeta * (flat(np.mat(G) * col(Rhos)) / L - np.mean(Rhos) * np.mean(G, axis=1))
    # Print out the density and its derivative.
    Sep = printcool("Density: % .4f +- % .4f kg/m^3\nAnalytic Derivative:" % (Rho_avg, Rho_err))
    FF.print_map(vals=GRho)
    logger.info(Sep)

    def calc_rho(b = None, **kwargs):
        if b == None: b = np.ones(L,dtype=float)
        if 'r_' in kwargs:
            r_ = kwargs['r_']
        return bzavg(r_,b)

    # No need to calculate error using bootstrap, but here it is anyway
    # Rhoboot = []
    # for i in range(numboots):
    #    boot = np.random.randint(N,size=N)
    #    Rhoboot.append(calc_rho(None,**{'r_':Rhos[boot]}))
    # Rhoboot = np.array(Rhoboot)
    # Rho_err = np.std(Rhoboot)

    if FDCheck:
        Sep = printcool("Numerical Derivative:")
        GRho1 = property_derivatives(Liquid, FF, mvals, h, pgrad, kT, calc_rho, {'r_':Rhos})
        FF.print_map(vals=GRho1)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = ["% .4e  % .4e" % (i-j, (i-j)/j) for i,j in zip(GRho, GRho1)]
        FF.print_map(vals=absfrac)

    #----
    # Enthalpy of vaporization
    #----
    H = Energies + pV
    V = np.array(Volumes)

    # Print out the liquid enthalpy.
    logger.info("Liquid enthalpy: % .4f kJ/mol, stdev % .4f ; (% .4f from energy, % .4f from pV)\n" % 
                (np.mean(H), np.std(H), np.mean(Energies), np.mean(pV)))
    numboots = 1000

    # The enthalpy of vaporization in kJ/mol.
    Hvap_avg = mEne_avg - Ene_avg / NMol + kT - np.mean(pV) / NMol
    Hvap_err = np.sqrt(Ene_err**2 / NMol**2 + mEne_err**2 + pV_err**2/NMol**2)

    # Build the first Hvap derivative.
    GHvap = np.mean(G,axis=1)
    GHvap += mBeta * (flat(np.mat(G) * col(Energies)) / L - Ene_avg * np.mean(G, axis=1))
    GHvap /= NMol
    GHvap -= np.mean(mG,axis=1)
    GHvap -= mBeta * (flat(np.mat(mG) * col(mEnergies)) / L - mEne_avg * np.mean(mG, axis=1))
    GHvap *= -1
    GHvap -= mBeta * (flat(np.mat(G) * col(pV)) / L - np.mean(pV) * np.mean(G, axis=1)) / NMol

    Sep = printcool("Enthalpy of Vaporization: % .4f +- %.4f kJ/mol\nAnalytic Derivative:" % (Hvap_avg, Hvap_err))
    FF.print_map(vals=GHvap)

    # Define some things to make the analytic derivatives easier.
    Gbar = np.mean(G,axis=1)
    def deprod(vec):
        return flat(np.mat(G)*col(vec))/L
    def covde(vec):
        return flat(np.mat(G)*col(vec))/L - Gbar*np.mean(vec)
    def avg(vec):
        return np.mean(vec)

    #----
    # Thermal expansion coefficient
    #----
    def calc_alpha(b = None, **kwargs):
        if b == None: b = np.ones(L,dtype=float)
        if 'h_' in kwargs:
            h_ = kwargs['h_']
        if 'v_' in kwargs:
            v_ = kwargs['v_']
        return 1/(kT*T) * (bzavg(h_*v_,b)-bzavg(h_,b)*bzavg(v_,b))/bzavg(v_,b)
    Alpha = calc_alpha(None, **{'h_':H, 'v_':V})
    Alphaboot = []
    for i in range(numboots):
        boot = np.random.randint(L,size=L)
        Alphaboot.append(calc_alpha(None, **{'h_':H[boot], 'v_':V[boot]}))
    Alphaboot = np.array(Alphaboot)
    Alpha_err = np.std(Alphaboot) * max([np.sqrt(statisticalInefficiency(V)),np.sqrt(statisticalInefficiency(H))])

    # Thermal expansion coefficient analytic derivative
    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)
    GAlpha  = (GAlpha1 + GAlpha2 + GAlpha3 + GAlpha4)/(kT*T)
    Sep = printcool("Thermal expansion coefficient: % .4e +- %.4e K^-1\nAnalytic Derivative:" % (Alpha, Alpha_err))
    FF.print_map(vals=GAlpha)
    if FDCheck:
        GAlpha_fd = property_derivatives(Liquid, FF, mvals, h, pgrad, kT, calc_alpha, {'h_':H,'v_':V})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GAlpha_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = ["% .4e  % .4e" % (i-j, (i-j)/j) for i,j in zip(GAlpha, GAlpha_fd)]
        FF.print_map(vals=absfrac)

    #----
    # Isothermal compressibility
    #----
    def calc_kappa(b=None, **kwargs):
        if b == None: b = np.ones(L,dtype=float)
        if 'v_' in kwargs:
            v_ = kwargs['v_']
        return bar_unit / kT * (bzavg(v_**2,b)-bzavg(v_,b)**2)/bzavg(v_,b)
    Kappa = calc_kappa(None,**{'v_':V})
    Kappaboot = []
    for i in range(numboots):
        boot = np.random.randint(L,size=L)
        Kappaboot.append(calc_kappa(None,**{'v_':V[boot]}))
    Kappaboot = np.array(Kappaboot)
    Kappa_err = np.std(Kappaboot) * np.sqrt(statisticalInefficiency(V))

    # Isothermal compressibility analytic derivative
    Sep = printcool("Isothermal compressibility:  % .4e +- %.4e bar^-1\nAnalytic Derivative:" % (Kappa, Kappa_err))
    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)
    GKappa  = bar_unit*(GKappa1 + GKappa2 + GKappa3)
    FF.print_map(vals=GKappa)
    if FDCheck:
        GKappa_fd = property_derivatives(Liquid, FF, mvals, h, pgrad, kT, calc_kappa, {'v_':V})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GKappa_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = ["% .4e  % .4e" % (i-j, (i-j)/j) for i,j in zip(GKappa, GKappa_fd)]
        FF.print_map(vals=absfrac)

    #----
    # Isobaric heat capacity
    #----
    def calc_cp(b=None, **kwargs):
        if b == None: b = np.ones(L,dtype=float)
        if 'h_' in kwargs:
            h_ = kwargs['h_']
        Cp_  = 1/(NMol*kT*T) * (bzavg(h_**2,b) - bzavg(h_,b)**2)
        Cp_ *= 1000 / 4.184
        return Cp_
    Cp = calc_cp(None,**{'h_':H})
    Cpboot = []
    for i in range(numboots):
        boot = np.random.randint(L,size=L)
        Cpboot.append(calc_cp(None,**{'h_':H[boot]}))
    Cpboot = np.array(Cpboot)
    Cp_err = np.std(Cpboot) * np.sqrt(statisticalInefficiency(H))

    # Isobaric heat capacity analytic derivative
    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)
    GCp  = GCp1 + GCp2 + GCp3
    Sep = printcool("Isobaric heat capacity:  % .4e +- %.4e cal mol-1 K-1\nAnalytic Derivative:" % (Cp, Cp_err))
    FF.print_map(vals=GCp)
    if FDCheck:
        GCp_fd = property_derivatives(Liquid, FF, mvals, h, pgrad, kT, calc_cp, {'h_':H})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GCp_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = ["% .4e  % .4e" % (i-j, (i-j)/j) for i,j in zip(GCp,GCp_fd)]
        FF.print_map(vals=absfrac)

    #----
    # Dielectric constant
    #----
    def calc_eps0(b=None, **kwargs):
        if b == None: b = np.ones(L,dtype=float)
        if 'd_' in kwargs: # Dipole moment vector.
            d_ = kwargs['d_']
        if 'v_' in kwargs: # Volume.
            v_ = kwargs['v_']
        b0 = np.ones(L,dtype=float)
        dx = d_[:,0]
        dy = d_[:,1]
        dz = d_[:,2]
        D2  = bzavg(dx**2,b)-bzavg(dx,b)**2
        D2 += bzavg(dy**2,b)-bzavg(dy,b)**2
        D2 += bzavg(dz**2,b)-bzavg(dz,b)**2
        return prefactor*D2/bzavg(v_,b)/T
    Eps0 = calc_eps0(None,**{'d_':Dips, 'v_':V})
    Eps0boot = []
    for i in range(numboots):
        boot = np.random.randint(L,size=L)
        Eps0boot.append(calc_eps0(None,**{'d_':Dips[boot], 'v_':V[boot]}))
    Eps0boot = np.array(Eps0boot)
    Eps0_err = np.std(Eps0boot)*np.sqrt(np.mean([statisticalInefficiency(Dips[:,0]),statisticalInefficiency(Dips[:,1]),statisticalInefficiency(Dips[:,2])]))
 
    # Dielectric constant analytic derivative
    Dx = Dips[:,0]
    Dy = Dips[:,1]
    Dz = Dips[:,2]
    D2 = avg(Dx**2)+avg(Dy**2)+avg(Dz**2)-avg(Dx)**2-avg(Dy)**2-avg(Dz)**2
    GD2  = 2*(flat(np.mat(GDx)*col(Dx))/L - avg(Dx)*(np.mean(GDx,axis=1))) - Beta*(covde(Dx**2) - 2*avg(Dx)*covde(Dx))
    GD2 += 2*(flat(np.mat(GDy)*col(Dy))/L - avg(Dy)*(np.mean(GDy,axis=1))) - Beta*(covde(Dy**2) - 2*avg(Dy)*covde(Dy))
    GD2 += 2*(flat(np.mat(GDz)*col(Dz))/L - avg(Dz)*(np.mean(GDz,axis=1))) - Beta*(covde(Dz**2) - 2*avg(Dz)*covde(Dz))
    GEps0 = prefactor*(GD2/avg(V) - mBeta*covde(V)*D2/avg(V)**2)/T
    Sep = printcool("Dielectric constant:           % .4e +- %.4e\nAnalytic Derivative:" % (Eps0, Eps0_err))
    FF.print_map(vals=GEps0)
    if FDCheck:
        GEps0_fd = property_derivatives(Liquid, FF, mvals, h, pgrad, kT, calc_eps0, {'d_':Dips,'v_':V})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GEps0_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = ["% .4e  % .4e" % (i-j, (i-j)/j) for i,j in zip(GEps0,GEps0_fd)]
        FF.print_map(vals=absfrac)

    logger.info("Writing final force field.\n")
    pvals = FF.make(mvals)

    logger.info("Writing all simulation data to disk.\n")
    with wopen(os.path.join('npt_result.p')) as f: lp_dump((Rhos, Volumes, Potentials, Energies, Dips, G, [GDx, GDy, GDz], mPotentials, mEnergies, mG, Rho_err, Hvap_err, Alpha_err, Kappa_err, Cp_err, Eps0_err, NMol),f)
Esempio n. 29
0
    def __init__(self, options, tgt_opts, forcefield):

        super(Objective, self).__init__(options)
        self.set_option(options, 'penalty_type')
        self.set_option(options, 'penalty_additive')
        self.set_option(options, 'penalty_multiplicative')
        self.set_option(options, 'penalty_hyperbolic_b')
        self.set_option(options, 'penalty_alpha')
        self.set_option(options, 'penalty_power')
        self.set_option(options, 'normalize_weights')
        ## Work Queue Port (The specific target itself may or may not actually use this.)
        self.set_option(options, 'wq_port')
        ## Asynchronous objective function evaluation (i.e. execute Work Queue and local objective concurrently.)
        self.set_option(options, 'asynchronous')

        ## The list of fitting targets
        self.Targets = []
        enable_smirnoff_prints = False  # extra prints for SMIRNOFF forcefield
        for opts in tgt_opts:
            if opts['type'] not in Implemented_Targets:
                logger.error(
                    'The target type \x1b[1;91m%s\x1b[0m is not implemented!\n'
                    % opts['type'])
                raise RuntimeError
            elif opts['type'].endswith("SMIRNOFF"):
                enable_smirnoff_prints = True
            # Create a target object.  This is done by looking up the
            # Target class from the Implemented_Targets dictionary
            # using opts['type'] as the key.  The object is created by
            # passing (options, opts, forcefield) to the constructor.
            if opts["remote"] and self.wq_port != 0:
                Tgt = forcebalance.target.RemoteTarget(options, opts,
                                                       forcefield)
            else:
                Tgt = Implemented_Targets[opts['type']](options, opts,
                                                        forcefield)
            self.Targets.append(Tgt)
            printcool_dictionary(Tgt.PrintOptionDict,
                                 "Setup for target %s :" % Tgt.name)
        if len(set([Tgt.name for Tgt in self.Targets])) != len(
            [Tgt.name for Tgt in self.Targets]):
            logger.error("The list of target names is not unique!\n")
            raise RuntimeError
        if enable_smirnoff_prints:
            smirnoff_analyze_parameter_coverage(forcefield, tgt_opts)
        ## The force field (it seems to be everywhere)
        self.FF = forcefield
        ## Initialize the penalty function.
        self.Penalty = Penalty(self.penalty_type, forcefield,
                               self.penalty_additive,
                               self.penalty_multiplicative,
                               self.penalty_hyperbolic_b, self.penalty_alpha,
                               self.penalty_power)
        ## Obtain the denominator.
        if self.normalize_weights:
            self.WTot = np.sum([i.weight for i in self.Targets])
        else:
            self.WTot = 1.0
        self.ObjDict = OrderedDict()
        self.ObjDict_Last = OrderedDict()

        # Create the work queue here.
        if self.wq_port != 0:
            createWorkQueue(self.wq_port)
            logger.info('Work Queue is listening on %d\n' % self.wq_port)

        printcool_dictionary(self.PrintOptionDict,
                             "Setup for objective function :")
Esempio n. 30
0
 def indicate(self):
     printcool_dictionary(self.PrintDict,title="Interaction Energies (kcal/mol), Objective = % .5e\n %-20s %9s %9s %9s %11s" % 
                          (self.energy_part, "Interaction", "Calc.", "Ref.", "Delta", "Term"))
     if len(self.RMSDDict) > 0:
         printcool_dictionary(self.RMSDDict,title="Geometry Optimized Systems (Angstrom), Objective = %.5e\n %-38s %11s %11s" % (self.rmsd_part, "System", "RMSD", "Term"), keywidth=45)
Esempio n. 31
0
    def _initialize(self):
        """Initializes the property estimator target from an input json file.

        1. Reads the user specified input file.
        2. Creates a `propertyestimator` client object.
        3. Loads in a reference experimental data set.
        4. Assigns and normalises weights for each property.
        """

        # Load in the options from a user provided JSON file.
        print(os.path.join(self.tgtdir, self.prop_est_input))
        options_file_path = os.path.join(self.tgtdir, self.prop_est_input)
        self._options = self.OptionsFile.from_json(options_file_path)

        # Attempt to create a property estimator client object using the specified
        # connection options.
        self._client = PropertyEstimatorClient(
            connection_options=self._options.connection_options)

        # Load in the experimental data set.
        data_set_path = os.path.join(self.tgtdir, self._options.data_set_path)

        with open(data_set_path, 'r') as file:
            self._data_set = PhysicalPropertyDataSet.parse_json(file.read())

        if len(self._data_set.properties) == 0:
            raise ValueError(
                'The physical property data set to optimise against is empty.')

        # Convert the reference data into a more easily comparable form.
        self._reference_properties = self._refactor_properties_dictionary(
            self._data_set.properties)

        # Print the reference data, and count the number of instances of
        # each property type.
        printcool("Loaded experimental data from property estimator")

        number_of_properties = {
            property_name: 0.0
            for property_name in self._reference_properties
        }

        for property_name in self._reference_properties:

            for substance_id in self._reference_properties[property_name]:

                dict_for_print = {}

                for state_tuple in self._reference_properties[property_name][
                        substance_id]:

                    value = self._reference_properties[property_name][
                        substance_id][state_tuple]['value']
                    uncertainty = self._reference_properties[property_name][
                        substance_id][state_tuple]['uncertainty']

                    dict_for_print["%sK-%satm" %
                                   state_tuple] = ("%f+/-%f" %
                                                   (value, uncertainty))

                    number_of_properties[property_name] += 1.0

                printcool_dictionary(dict_for_print,
                                     title="Reference %s (%s) data" %
                                     (property_name, substance_id))

        # Assign and normalize weights for each phase point (average for now)
        self._normalised_weights = {}

        for property_name in self._reference_properties:

            self._normalised_weights[property_name] = (
                self._options.weights[property_name] /
                number_of_properties[property_name])
Esempio n. 32
0
def main():

    """
    Usage: (runcuda.sh) nvt.py <openmm|gromacs|tinker> <liquid_nsteps> <liquid_timestep (fs)> <liquid_intvl (ps> <temperature>

    This program is meant to be called automatically by ForceBalance on
    a GPU cluster (specifically, subroutines in openmmio.py).  It is
    not easy to use manually.  This is because the force field is read
    in from a ForceBalance 'FF' class.
    """

    printcool("ForceBalance condensed phase NVT simulation using engine: %s" % engname.upper(), color=4, bold=True)

    #----
    # Load the ForceBalance pickle file which contains:
    #----
    # - Force field object
    # - Optimization parameters
    # - Options from the Target object that launched this simulation
    # - Switch for whether to evaluate analytic derivatives.
    FF,mvals,TgtOptions,AGrad = lp_load('forcebalance.p')
    FF.ffdir = '.'
    # Write the force field file.
    FF.make(mvals)

    #----
    # Load the options that are set in the ForceBalance input file.
    #----
    # Finite difference step size
    h = TgtOptions['h']
    pgrad = TgtOptions['pgrad']
    # MD options; time step (fs), production steps, equilibration steps, interval for saving data (ps)
    nvt_timestep = TgtOptions['nvt_timestep']
    nvt_md_steps = TgtOptions['nvt_md_steps']
    nvt_eq_steps = TgtOptions['nvt_eq_steps']
    nvt_interval = TgtOptions['nvt_interval']
    liquid_fnm = TgtOptions['nvt_coords']

    # Number of threads, multiple timestep integrator, anisotropic box etc.
    threads = TgtOptions.get('md_threads', 1)
    mts = TgtOptions.get('mts_integrator', 0)
    rpmd_beads = TgtOptions.get('rpmd_beads', 0)
    force_cuda = TgtOptions.get('force_cuda', 0)
    nbarostat = TgtOptions.get('n_mcbarostat', 25)
    anisotropic = TgtOptions.get('anisotropic_box', 0)
    minimize = TgtOptions.get('minimize_energy', 1)

    # Print all options.
    printcool_dictionary(TgtOptions, title="Options from ForceBalance")
    nvt_snapshots = (nvt_timestep * nvt_md_steps / 1000) / nvt_interval
    nvt_iframes = 1000 * nvt_interval / nvt_timestep
    logger.info("For the condensed phase system, I will collect %i snapshots spaced apart by %i x %.3f fs time steps\n" \
        % (nvt_snapshots, nvt_iframes, nvt_timestep))
    if nvt_snapshots < 2:
        raise Exception('Please set the number of liquid time steps so that you collect at least two snapshots (minimum %i)' \
                            % (2000 * (nvt_interval/nvt_timestep)))

    #----
    # Loading coordinates
    #----
    ML = Molecule(liquid_fnm, toppbc=True)
    # Determine the number of molecules in the condensed phase coordinate file.
    NMol = len(ML.molecules)
    TgtOptions['n_molecules'] = NMol
    logger.info("There are %i molecules in the liquid\n" % (NMol))

    #----
    # Setting up MD simulations
    #----
    EngOpts = OrderedDict()
    EngOpts["liquid"] = OrderedDict([("coords", liquid_fnm), ("mol", ML), ("pbc", True)])
    if "nonbonded_cutoff" in TgtOptions:
        EngOpts["liquid"]["nonbonded_cutoff"] = TgtOptions["nonbonded_cutoff"]
    else:
        largest_available_cutoff = min(ML.boxes[0][:3]) / 2 - 0.1
        EngOpts["liquid"]["nonbonded_cutoff"] = largest_available_cutoff
        logger.info("nonbonded_cutoff is by default set to the largest available value: %g Angstrom" %largest_available_cutoff)
    if "vdw_cutoff" in TgtOptions:
        EngOpts["liquid"]["vdw_cutoff"] = TgtOptions["vdw_cutoff"]
    # Hard Code nonbonded_cutoff to 13A for test
    #EngOpts["liquid"]["nonbonded_cutoff"] = EngOpts["liquid"]["vdw_cutoff"] = 13.0
    GenOpts = OrderedDict([('FF', FF)])
    if engname == "openmm":
        # OpenMM-specific options
        EngOpts["liquid"]["platname"] = TgtOptions.get("platname", 'CUDA')
        if force_cuda:
            try: Platform.getPlatformByName('CUDA')
            except: raise RuntimeError('Forcing failure because CUDA platform unavailable')
            EngOpts["liquid"]["platname"] = 'CUDA'
        if threads > 1: logger.warn("Setting the number of threads will have no effect on OpenMM engine.\n")

    EngOpts["liquid"].update(GenOpts)
    for i in EngOpts:
        printcool_dictionary(EngOpts[i], "Engine options for %s" % i)

    # Set up MD options
    MDOpts = OrderedDict()
    MDOpts["liquid"] = OrderedDict([("nsteps", nvt_md_steps), ("timestep", nvt_timestep),
                                    ("temperature", temperature),
                                    ("nequil", nvt_eq_steps), ("minimize", minimize),
                                    ("nsave", int(1000 * nvt_interval / nvt_timestep)),
                                    ("verbose", True),
                                    ('save_traj', TgtOptions['save_traj']),
                                    ("threads", threads),
                                    ("mts", mts), ("rpmd_beads", rpmd_beads), ("faststep", faststep)])

    # Energy components analysis disabled for OpenMM MTS because it uses force groups
    if (engname == "openmm" and mts): logger.warn("OpenMM with MTS integrator; energy components analysis will be disabled.\n")

    # Create instances of the MD Engine objects.
    Liquid = Engine(name="liquid", **EngOpts["liquid"])

    #=================================================================#
    # Run the simulation for the full system and analyze the results. #
    #=================================================================#

    printcool("Condensed phase NVT molecular dynamics", color=4, bold=True)
    click()
    prop_return = Liquid.molecular_dynamics(**MDOpts["liquid"])
    logger.info("Liquid phase MD simulation took %.3f seconds\n" % click())
    Potentials = prop_return['Potentials']

    #============================================#
    #  Compute the potential energy derivatives. #
    #============================================#
    if AGrad:
        logger.info("Calculating potential energy derivatives with finite difference step size: %f\n" % h)
        # Switch for whether to compute the derivatives two different ways for consistency.
        FDCheck = False
        printcool("Condensed phase energy and dipole derivatives\nInitializing array to length %i" % len(Potentials), color=4, bold=True)
        click()
        G, GDx, GDy, GDz = energy_derivatives(Liquid, FF, mvals, h, pgrad, len(Potentials), AGrad, dipole=False)
        logger.info("Condensed phase energy derivatives took %.3f seconds\n" % click())

    #==============================================#
    #  Condensed phase properties and derivatives. #
    #==============================================#

    # Physical constants
    kB = 0.008314472471220214
    T = temperature
    kT = kB * T # Unit: kJ/mol

    #--- Surface Tension ----
    logger.info("Start Computing surface tension.\n")
    perturb_proportion = 0.0005
    box_vectors = np.array(Liquid.xyz_omms[0][1]/nanometer) # obtain original box vectors from first frame
    delta_S = np.sqrt(np.sum(np.cross(box_vectors[0], box_vectors[1])**2)) * perturb_proportion * 2 # unit: nm^2. *2 for 2 surfaces
    # perturb xy area +
    click()
    scale_x = scale_y = np.sqrt(1 + perturb_proportion)
    scale_z = 1.0 / (1+perturb_proportion) # keep the box volumn while changing the area of xy plane
    Liquid.scale_box(scale_x, scale_y, scale_z)
    logger.info("scale_box+ took %.3f seconds\n" %click())
    # Obtain energies and gradients
    Potentials_plus = Liquid.energy()
    logger.info("Calculation of energies for perturbed box+ took %.3f seconds\n" %click())
    if AGrad:
        G_plus, _, _, _ = energy_derivatives(Liquid, FF, mvals, h, pgrad, len(Potentials), AGrad, dipole=False)
        logger.info("Calculation of energy gradients for perturbed box+ took %.3f seconds\n" %click())
    # perturb xy area - ( Note: also need to cancel the previous scaling)
    scale_x = scale_y = np.sqrt(1 - perturb_proportion) * (1.0/scale_x)
    scale_z = 1.0 / (1-perturb_proportion) * (1.0/scale_z)
    Liquid.scale_box(scale_x, scale_y, scale_z)
    logger.info("scale_box- took %.3f seconds\n" %click())
    # Obtain energies and gradients
    Potentials_minus = Liquid.energy()
    logger.info("Calculation of energies for perturbed box- took %.3f seconds\n" %click())
    if AGrad:
        G_minus, _, _, _ = energy_derivatives(Liquid, FF, mvals, h, pgrad, len(Potentials), AGrad, dipole=False)
        logger.info("Calculation of energy gradients for perturbed box- took %.3f seconds\n" %click())
    # Compute surface tension
    dE_plus = Potentials_plus - Potentials # Unit: kJ/mol
    dE_minus = Potentials_minus - Potentials # Unit: kJ/mol
    prefactor = -0.5 * kT / delta_S / 6.0221409e-1 # Unit mJ m^-2
    # Following equation: γ = -kT/(2ΔS) * [ ln<exp(-ΔE+/kT)> - ln<exp(-ΔE-/kT)> ]
    #plus_avg, plus_err = mean_stderr(np.exp(-dE_plus/kT))
    #minus_avg, minus_err = mean_stderr(np.exp(-dE_minus/kT))
    #surf_ten = -0.5 * kT / delta_S * ( np.log(plus_avg) - np.log(minus_avg) ) / 6.0221409e-1 # convert to mJ m^-2
    #surf_ten_err = 0.5 * kT / delta_S * ( np.log(plus_avg+plus_err) - np.log(plus_avg-plus_err) + np.log(minus_avg+minus_err) - np.log(minus_avg-minus_err) ) / 6.0221409e-1
    exp_dE_plus = np.exp(-dE_plus/kT)
    exp_dE_minus = np.exp(-dE_minus/kT)
    surf_ten = prefactor * ( np.log(np.mean(exp_dE_plus)) - np.log(np.mean(exp_dE_minus)) )
    # Use bootstrap method to estimate the error
    num_frames = len(exp_dE_plus)
    numboots = 1000
    surf_ten_boots = np.zeros(numboots)
    for i in xrange(numboots):
        boots_ordering = np.random.randint(num_frames, size=num_frames)
        boots_exp_dE_plus = np.take(exp_dE_plus, boots_ordering)
        boots_exp_dE_minus = np.take(exp_dE_minus, boots_ordering)
        surf_ten_boots[i] = prefactor * ( np.log(np.mean(boots_exp_dE_plus)) - np.log(np.mean(boots_exp_dE_minus)) )
    surf_ten_err = np.std(surf_ten_boots) * np.sqrt(np.mean([statisticalInefficiency(exp_dE_plus), statisticalInefficiency(exp_dE_minus)]))

    printcool("Surface Tension:       % .4f +- %.4f mJ m^-2" % (surf_ten, surf_ten_err))
    # Analytic Gradient of surface tension
    # Formula:      β = 1/kT
    #           ∂γ/∂α = -kT/(2ΔS) * { 1/<exp(-βΔE+)> * [<-β ∂E+/∂α exp(-βΔE+)> - <-β ∂E/∂α><exp(-βΔE+)>]
    #                                -1/<exp(-βΔE-)> * [<-β ∂E-/∂α exp(-βΔE-)> - <-β ∂E/∂α><exp(-βΔE-)>] }
    n_params = len(mvals)
    G_surf_ten = np.zeros(n_params)
    if AGrad:
        beta = 1.0 / kT
        plus_denom = np.mean(np.exp(-beta*dE_plus))
        minus_denom = np.mean(np.exp(-beta*dE_minus))
        for param_i in xrange(n_params):
            plus_left = np.mean(-beta * G_plus[param_i] * np.exp(-beta*dE_plus))
            plus_right = np.mean(-beta * G[param_i]) * plus_denom
            minus_left = np.mean(-beta * G_minus[param_i] * np.exp(-beta*dE_minus))
            minus_right = np.mean(-beta * G[param_i]) * minus_denom
            G_surf_ten[param_i] = prefactor * (1.0/plus_denom*(plus_left-plus_right) - 1.0/minus_denom*(minus_left-minus_right))
        printcool("Analytic Derivatives:")
        FF.print_map(vals=G_surf_ten)

    logger.info("Writing final force field.\n")
    pvals = FF.make(mvals)

    logger.info("Writing all results to disk.\n")
    result_dict = {'surf_ten': surf_ten, 'surf_ten_err': surf_ten_err, 'G_surf_ten': G_surf_ten}
    lp_dump(result_dict, 'nvt_result.p')
Esempio n. 33
0
def main():
    """Usage:
    
    (gmxprefix.sh) md_chain.py <list of quantities>
                               --engine <gromacs>
                               --length <n>
                               --name <name>
                               --temperature <T>
                               --pressure <p>
                               --nequil <nequil>
                               --nsteps <nsteps>
        
    This program is meant to be called automatically by ForceBalance.
    
    """
    printcool("ForceBalance simulation using engine: %s" % engname.upper(),
              color=4,
              bold=True)
    #----
    # Load the ForceBalance pickle file which contains:
    #----
    # - Force field object
    # - Optimization parameters
    # - Options from the Target object that launched this simulation
    # - Switch for whether to evaluate analytic derivatives.
    FF, mvals, TgtOptions, AGrad = lp_load('forcebalance.p')
    FF.ffdir = '.'
    # Write the force field file.
    FF.make(mvals)

    #----
    # Load the options that are set in the ForceBalance input file.
    #----
    # Finite difference step size
    h = TgtOptions['h']
    pgrad = TgtOptions['pgrad']

    engines = []
    ## Setup and carry out simulations in chain
    for i in range(args.length):
        # Simulation files
        if engname == "gromacs":
            ndx_flag = False
            coords = args.name + str(i + 1) + ".gro"
            top_file = args.name + str(i + 1) + ".top"
            mdp_file = args.name + str(i + 1) + ".mdp"
            ndx_file = args.name + str(i + 1) + ".ndx"
            if os.path.exists(ndx_file):
                ndx_flag = True

        mol = Molecule(coords)
        #----
        # Set coordinates and molecule for engine
        #----
        EngOpts = OrderedDict([("FF", FF), ("pbc", True), ("coords", coords),
                               ("mol", mol)])

        if engname == "gromacs":
            # Gromacs-specific options
            EngOpts["gmx_top"] = top_file
            EngOpts["gmx_mdp"] = mdp_file
            if ndx_flag:
                EngOpts["gmx_ndx"] = ndx_file

        printcool_dictionary(EngOpts)

        # Create engine objects and store them for subsequent analysis.
        s = Engine(name=args.name + str(i + 1), **EngOpts)

        #=====================#
        # Run the simulation. #
        #=====================#
        MDOpts = OrderedDict([("nsteps", args.nsteps),
                              ("nequil", args.nequil)])

        printcool("Molecular dynamics simulation", color=4, bold=True)
        s.md(verbose=True, **MDOpts)

        engines.append(s)

    #======================================================================#
    # Extract the quantities of interest from the MD simulations and dump  #
    # the results to file.                                                 #
    # =====================================================================#
    results = OrderedDict()
    for q in args.quantities:
        logger.info("Extracting %s...\n" % q)

        # Initialize quantity
        objstr = "Quantity_" + q.capitalize()
        dm = il.import_module('..quantity', package='forcebalance.quantity')

        Quantity = getattr(dm, objstr)(engname, args.temperature,
                                       args.pressure)

        Q, Qerr, Qgrad = Quantity.extract(engines, FF, mvals, h, pgrad, AGrad)

        results.setdefault("values", []).append(Q)
        results.setdefault("errors", []).append(Qerr)
        results.setdefault("grads", []).append(Qgrad)

        logger.info("Finished!\n")

        # Print out results for the quantity and its derivative.
        Sep = printcool(("%s: % .4f +- % .4f \nAnalytic Derivative:" %
                         (q.capitalize(), Q, Qerr)))
        FF.print_map(vals=Qgrad)

    # Dump results to file
    logger.info("Writing final force field.\n")
    pvals = FF.make(mvals)

    logger.info("Writing all simulation data to disk.\n")
    lp_dump((np.asarray(results["values"]), np.asarray(
        results["errors"]), np.asarray(results["grads"])), 'md_result.p')
Esempio n. 34
0
    def _initialize(self):
        """Initializes the evaluator target from an input json file.

        1. Reads the user specified input file.
        2. Creates a `evaluator` client object.
        3. Loads in a reference experimental data set.
        4. Assigns and normalises weights for each property.
        """

        # Load in the options from a user provided JSON file.
        print(os.path.join(self.tgtdir, self.evaluator_input))
        options_file_path = os.path.join(self.tgtdir, self.evaluator_input)
        self._options = self.OptionsFile.from_json(options_file_path)

        for property_type, denominator in self._options.denominators.items():
            self._default_units[property_type] = denominator.units

        # Attempt to create an evaluator client object using the specified
        # connection options.
        self._client = EvaluatorClient(self._options.connection_options)

        # Load in the experimental data set.
        data_set_path = os.path.join(self.tgtdir, self._options.data_set_path)
        self._reference_data_set = PhysicalPropertyDataSet.from_json(data_set_path)

        if len(self._reference_data_set) == 0:

            raise ValueError(
                "The physical property data set to optimise against is empty."
            )

        # Print the reference data, and count the number of instances of
        # each property type.
        printcool("Loaded experimental data.")

        property_types = self._reference_data_set.property_types

        number_of_properties = {
            x: sum(1 for y in self._reference_data_set.properties_by_type(x))
            for x in property_types
        }

        for substance in self._reference_data_set.substances:

            dict_for_print = {}

            for physical_property in self._reference_data_set.properties_by_substance(
                substance
            ):

                property_type = physical_property.__class__.__name__

                value = physical_property.value.to(self._default_units[property_type])
                uncertainty = np.nan

                if physical_property.uncertainty != UNDEFINED:

                    uncertainty = physical_property.uncertainty.to(
                        self._default_units[property_type]
                    )

                tuple_key = (
                    property_type,
                    physical_property.thermodynamic_state.temperature,
                    physical_property.thermodynamic_state.pressure,
                )

                dict_for_print["%s %s-%s" % tuple_key] = "%s+/-%s" % (
                    value,
                    uncertainty,
                )

            printcool_dictionary(
                dict_for_print, title="Reference %s data" % substance.identifier,
            )

        # Assign and normalize weights for each phase point (average for now)
        self._normalised_weights = {}

        for property_type in self._reference_data_set.property_types:

            self._normalised_weights[property_type] = (
                self._options.weights[property_type]
                / number_of_properties[property_type]
            )
Esempio n. 35
0
def main():
    
    """Usage:
    
    (gmxprefix.sh) md_chain.py <list of quantities>
                               --engine <gromacs>
                               --length <n>
                               --name <name>
                               --temperature <T>
                               --pressure <p>
                               --nequil <nequil>
                               --nsteps <nsteps>
        
    This program is meant to be called automatically by ForceBalance.
    
    """
    printcool("ForceBalance simulation using engine: %s" % engname.upper(),
              color=4, bold=True)
    #----
    # Load the ForceBalance pickle file which contains:
    #----
    # - Force field object
    # - Optimization parameters
    # - Options from the Target object that launched this simulation
    # - Switch for whether to evaluate analytic derivatives.
    FF, mvals, TgtOptions, AGrad = lp_load('forcebalance.p')
    FF.ffdir = '.'
    # Write the force field file.
    FF.make(mvals)

    #----
    # Load the options that are set in the ForceBalance input file.
    #----
    # Finite difference step size
    h = TgtOptions['h']
    pgrad = TgtOptions['pgrad']
    
    engines = []
    ## Setup and carry out simulations in chain
    for i in range(args.length):
        # Simulation files
        if engname == "gromacs":
            ndx_flag = False
            coords   = args.name + str(i+1) + ".gro"
            top_file = args.name + str(i+1) + ".top"
            mdp_file = args.name + str(i+1) + ".mdp"
            ndx_file = args.name + str(i+1) + ".ndx"
            if os.path.exists(ndx_file):
                ndx_flag = True
                
        mol = Molecule(coords)
        #----
        # Set coordinates and molecule for engine
        #----
        EngOpts = OrderedDict([("FF", FF),
                               ("pbc", True),
                               ("coords", coords),
                               ("mol", mol)])
    
        if engname == "gromacs":
            # Gromacs-specific options
            EngOpts["gmx_top"] = top_file
            EngOpts["gmx_mdp"] = mdp_file
            if ndx_flag:
                EngOpts["gmx_ndx"] = ndx_file
                
        printcool_dictionary(EngOpts)
                                
        # Create engine objects and store them for subsequent analysis.
        s = Engine(name=args.name+str(i+1), **EngOpts)
                
        #=====================#
        # Run the simulation. #
        #=====================#
        MDOpts = OrderedDict([("nsteps", args.nsteps),
                              ("nequil", args.nequil)])

        printcool("Molecular dynamics simulation", color=4, bold=True)
        s.md(verbose=True, **MDOpts)
                                    
        engines.append(s)
    
    #======================================================================#
    # Extract the quantities of interest from the MD simulations and dump  #
    # the results to file.                                                 #
    # =====================================================================#    
    results = OrderedDict()        
    for q in args.quantities:
        logger.info("Extracting %s...\n" % q)

        # Initialize quantity
        objstr = "Quantity_" + q.capitalize()
        dm     = il.import_module('..quantity',
                                  package='forcebalance.quantity')
            
        Quantity = getattr(dm, objstr)(engname, args.temperature, args.pressure)
            
        Q, Qerr, Qgrad = Quantity.extract(engines, FF, mvals, h, pgrad, AGrad)
                    
        results.setdefault("values", []).append(Q)
        results.setdefault("errors", []).append(Qerr)
        results.setdefault("grads",  []).append(Qgrad)
            
        logger.info("Finished!\n")
            
        # Print out results for the quantity and its derivative.
        Sep = printcool(("%s: % .4f +- % .4f \nAnalytic Derivative:"
                              % (q.capitalize(), Q, Qerr)))
        FF.print_map(vals=Qgrad)
            
    # Dump results to file
    logger.info("Writing final force field.\n")
    pvals = FF.make(mvals)
    
    logger.info("Writing all simulation data to disk.\n")
    lp_dump((np.asarray(results["values"]),
             np.asarray(results["errors"]),
             np.asarray(results["grads"])), 'md_result.p')
Esempio n. 36
0
def main():
    """Usage:
    
    (prefix.sh) md_one.py -T, --temperature <temperature in kelvin>
                          -P, --pressure <pressure in atm>
                          -g, --grad (if gradients of output timeseries are desired)
                          -eq, --nequil <number of equilibration MD steps>
                          -md, --nsteps <number of production MD steps>
                          -dt, --timestep <number of production MD steps>
                          -sp, --sample <number of production MD steps>
                          -nt, --threads <number of CPU threads to use>
                          -min, --minimize <minimize the energy>
        
    This program is meant to be called automatically by ForceBalance because 
    force field options are loaded from the 'forcefield.p' file, and 
    simulation options are loaded from the 'simulation.p' file.  
    The files are separated because the same force field file
    may be used for many simulations.
    
    """

    # Write the force field file.
    FF.make(mvals)

    # Read the command line options (they may override the options from file.)
    AGrad = args['gradient']
    for i in [
            'temperature', 'pressure', 'nequil', 'nsteps', 'timestep',
            'sample', 'threads', 'minimize'
    ]:
        if i in args:
            MDOpts[i] = args[i]
    MDOpts['nsave'] = int(1000.0 * MDOpts['sample'] / MDOpts['timestep'])
    if 'save_traj' in TgtOpts:
        MDOpts['save_traj'] = TgtOpts['save_traj']

    #----
    # Print some options.
    # At this point, engine and MD options should be SET!
    #----
    printcool("ForceBalance simulation using engine: %s" % engname.upper(),
              color=4,
              bold=True)
    printcool_dictionary(args, title="Options from command line")
    printcool_dictionary(EngOpts, title="Engine options")
    printcool_dictionary(MDOpts, title="Molecular dynamics options")

    #----
    # For convenience, assign some local variables.
    #----
    # Finite difference step size
    h = TgtOpts['h']
    # Active parameters to differentiate
    pgrad = TgtOpts['pgrad']
    # Create instances of the MD Engine objects.
    Engine = EngineClass(**EngOpts)
    click()  # Start timer.
    # This line runs the condensed phase simulation.
    #----
    # The molecular dynamics simulation returns a dictionary of properties
    # In the future, the properties will be stored as data inside the object
    Results = Engine.molecular_dynamics(**MDOpts)
    if AGrad:
        Results['Potential_Derivatives'] = energy_derivatives(
            Engine, FF, mvals, h, pgrad, dipole=False)['potential']
    # Set up engine and calculate the potential in the other phase.
    EngOpts_ = deepcopy(EngOpts)
    EngOpts_['implicit_solvent'] = not EngOpts['implicit_solvent']
    Engine_ = EngineClass(**EngOpts_)
    Engine_.xyz_omms = Engine.xyz_omms
    Energy_ = Engine_.energy()
    Results_ = {'Potentials': Energy_}
    if AGrad:
        Derivs_ = energy_derivatives(Engine_,
                                     FF,
                                     mvals,
                                     h,
                                     pgrad,
                                     dipole=False)['potential']
        Results_['Potential_Derivatives'] = Derivs_
    # Calculate the hydration energy of each snapshot and its parametric derivatives.
    if EngOpts['implicit_solvent']:
        Energy_liq = Results['Potentials']
        Energy_gas = Results_['Potentials']
        if AGrad:
            Derivs_liq = Results['Potential_Derivatives']
            Derivs_gas = Results_['Potential_Derivatives']
    else:
        Energy_gas = Results['Potentials']
        Energy_liq = Results_['Potentials']
        if AGrad:
            Derivs_gas = Results['Potential_Derivatives']
            Derivs_liq = Results_['Potential_Derivatives']
    Results['Hydration'] = Energy_liq - Energy_gas
    if AGrad:
        Results['Hydration_Derivatives'] = Derivs_liq - Derivs_gas
    # Code of the future!
    # Don't know how to use it yet though.
    # Engine.molecular_dynamics(**MDOpts)
    # logger.info("MD simulation took %.3f seconds\n" % click())
    # # Extract properties.
    # Results = Engine.md_extract(OrderedDict([(i, {}) for i in Tgt.timeseries.keys()]))
    # potential = properties['Potential']
    # Calculate energy and dipole derivatives if needed.
    # if AGrad:
    #     Results['derivatives'] = energy_derivatives(Engine, FF, mvals, h, pgrad, dipole='dipole' in Tgt.timeseries.keys())
    # Dump results to file
    logger.info("Writing final force field.\n")
    pvals = FF.make(mvals)
    logger.info("Writing all simulation data to disk.\n")
    lp_dump(Results, 'md_result.p')
Esempio n. 37
0
def main():
    """
    Usage: (runcuda.sh) npt.py <openmm|gromacs|tinker> <lipid_nsteps> <lipid_timestep (fs)> <lipid_intvl (ps> <temperature> <pressure>

    This program is meant to be called automatically by ForceBalance on
    a GPU cluster (specifically, subroutines in openmmio.py).  It is
    not easy to use manually.  This is because the force field is read
    in from a ForceBalance 'FF' class.

    I wrote this program because automatic fitting of the density (or
    other equilibrium properties) is computationally intensive, and the
    calculations need to be distributed to the queue.  The main instance
    of ForceBalance (running on my workstation) queues up a bunch of these
    jobs (using Work Queue).  Then, I submit a bunch of workers to GPU
    clusters (e.g. Certainty, Keeneland).  The worker scripts connect to.
    the main instance and receives one of these jobs.

    This script can also be executed locally, if you want to (e.g. for
    debugging).  Just make sure you have the pickled 'forcebalance.p'
    file.

    """

    printcool("ForceBalance condensed phase simulation using engine: %s" %
              engname.upper(),
              color=4,
              bold=True)

    #----
    # Load the ForceBalance pickle file which contains:
    #----
    # - Force field object
    # - Optimization parameters
    # - Options from the Target object that launched this simulation
    # - Switch for whether to evaluate analytic derivatives.
    FF, mvals, TgtOptions, AGrad = lp_load('forcebalance.p')
    FF.ffdir = '.'
    # Write the force field file.
    FF.make(mvals)

    #----
    # Load the options that are set in the ForceBalance input file.
    #----
    # Finite difference step size
    h = TgtOptions['h']
    pgrad = TgtOptions['pgrad']
    # MD options; time step (fs), production steps, equilibration steps, interval for saving data (ps)
    lipid_timestep = TgtOptions['lipid_timestep']
    lipid_nsteps = TgtOptions['lipid_md_steps']
    lipid_nequil = TgtOptions['lipid_eq_steps']
    lipid_intvl = TgtOptions['lipid_interval']
    lipid_fnm = TgtOptions['lipid_coords']

    # Number of threads, multiple timestep integrator, anisotropic box etc.
    threads = TgtOptions.get('md_threads', 1)
    mts = TgtOptions.get('mts_integrator', 0)
    force_cuda = TgtOptions.get('force_cuda', 0)
    anisotropic = TgtOptions.get('anisotropic_box', 0)
    minimize = TgtOptions.get('minimize_energy', 1)

    # Print all options.
    printcool_dictionary(TgtOptions, title="Options from ForceBalance")
    lipid_snapshots = int((lipid_nsteps * lipid_timestep / 1000) / lipid_intvl)
    lipid_iframes = int(1000 * lipid_intvl / lipid_timestep)
    logger.info("For the condensed phase system, I will collect %i snapshots spaced apart by %i x %.3f fs time steps\n" \
        % (lipid_snapshots, lipid_iframes, lipid_timestep))
    if lipid_snapshots < 2:
        raise Exception('Please set the number of lipid time steps so that you collect at least two snapshots (minimum %i)' \
                            % (2000 * int(lipid_intvl/lipid_timestep)))

    #----
    # Loading coordinates
    #----
    ML = Molecule(lipid_fnm, toppbc=True)
    # Determine the number of molecules in the condensed phase coordinate file.
    NMol = len(ML.molecules)

    #----
    # Setting up MD simulations
    #----
    EngOpts = OrderedDict()
    EngOpts["lipid"] = OrderedDict([("coords", lipid_fnm), ("mol", ML),
                                    ("pbc", True)])
    if "nonbonded_cutoff" in TgtOptions:
        EngOpts["lipid"]["nonbonded_cutoff"] = TgtOptions["nonbonded_cutoff"]
    if "vdw_cutoff" in TgtOptions:
        EngOpts["lipid"]["vdw_cutoff"] = TgtOptions["vdw_cutoff"]
    GenOpts = OrderedDict([('FF', FF)])
    if engname == "openmm":
        # OpenMM-specific options
        EngOpts["liquid"]["platname"] = TgtOptions.get("platname", 'CUDA')
        # For now, always run gas phase calculations on the reference platform
        EngOpts["gas"]["platname"] = 'Reference'
        if force_cuda:
            try:
                Platform.getPlatformByName('CUDA')
            except:
                raise RuntimeError(
                    'Forcing failure because CUDA platform unavailable')
            EngOpts["liquid"]["platname"] = 'CUDA'
        if threads > 1:
            logger.warn(
                "Setting the number of threads will have no effect on OpenMM engine.\n"
            )
    elif engname == "gromacs":
        # Gromacs-specific options
        GenOpts["gmxpath"] = TgtOptions["gmxpath"]
        GenOpts["gmxsuffix"] = TgtOptions["gmxsuffix"]
        EngOpts["lipid"]["gmx_top"] = os.path.splitext(lipid_fnm)[0] + ".top"
        EngOpts["lipid"]["gmx_mdp"] = os.path.splitext(lipid_fnm)[0] + ".mdp"
        EngOpts["lipid"]["gmx_eq_barostat"] = TgtOptions["gmx_eq_barostat"]
        if force_cuda:
            logger.warn("force_cuda option has no effect on Gromacs engine.")
        if mts:
            logger.warn(
                "Gromacs not configured for multiple timestep integrator.")
        if anisotropic:
            logger.warn("Gromacs not configured for anisotropic box scaling.")
    elif engname == "tinker":
        # Tinker-specific options
        GenOpts["tinkerpath"] = TgtOptions["tinkerpath"]
        EngOpts["lipid"]["tinker_key"] = os.path.splitext(
            lipid_fnm)[0] + ".key"
        if force_cuda:
            logger.warn("force_cuda option has no effect on Tinker engine.")
        if mts:
            logger.warn(
                "Tinker not configured for multiple timestep integrator.")
    EngOpts["lipid"].update(GenOpts)
    for i in EngOpts:
        printcool_dictionary(EngOpts[i], "Engine options for %s" % i)

    # Set up MD options
    MDOpts = OrderedDict()
    MDOpts["lipid"] = OrderedDict([("nsteps", lipid_nsteps),
                                   ("timestep", lipid_timestep),
                                   ("temperature", temperature),
                                   ("pressure", pressure),
                                   ("nequil", lipid_nequil),
                                   ("minimize", minimize),
                                   ("nsave",
                                    int(1000 * lipid_intvl / lipid_timestep)),
                                   ("verbose", False),
                                   ('save_traj', TgtOptions['save_traj']),
                                   ("threads", threads),
                                   ("anisotropic", anisotropic), ("mts", mts),
                                   ("faststep", faststep), ("bilayer", True)])

    # Energy components analysis disabled for OpenMM MTS because it uses force groups
    if (engname == "openmm" and mts):
        logger.warn(
            "OpenMM with MTS integrator; energy components analysis will be disabled.\n"
        )

    # Create instances of the MD Engine objects.
    Lipid = Engine(name="lipid", **EngOpts["lipid"])

    #=================================================================#
    # Run the simulation for the full system and analyze the results. #
    #=================================================================#

    printcool("Condensed phase molecular dynamics", color=4, bold=True)

    # This line runs the condensed phase simulation.
    prop_return = Lipid.molecular_dynamics(**MDOpts["lipid"])
    Rhos = prop_return['Rhos']
    Potentials = prop_return['Potentials']
    Kinetics = prop_return['Kinetics']
    Volumes = prop_return['Volumes']
    Dips = prop_return['Dips']
    EDA = prop_return['Ecomps']
    Als = prop_return['Als']
    Scds = prop_return['Scds']

    # Create a bunch of physical constants.
    # Energies are in kJ/mol
    # Lengths are in nanometers.
    L = len(Rhos)
    kB = 0.008314472471220214
    T = temperature
    kT = kB * T
    mBeta = -1.0 / kT
    Beta = 1.0 / kT
    atm_unit = 0.061019351687175
    bar_unit = 0.060221417930000
    # This is how I calculated the prefactor for the dielectric constant.
    # eps0 = 8.854187817620e-12 * coulomb**2 / newton / meter**2
    # epsunit = 1.0*(debye**2) / nanometer**3 / BOLTZMANN_CONSTANT_kB / kelvin
    # prefactor = epsunit/eps0/3
    prefactor = 30.348705333964077

    # Gather some physical variables.
    Energies = Potentials + Kinetics
    Ene_avg, Ene_err = mean_stderr(Energies)
    pV = atm_unit * pressure * Volumes
    pV_avg, pV_err = mean_stderr(pV)
    Rho_avg, Rho_err = mean_stderr(Rhos)
    PrintEDA(EDA, NMol)

    #============================================#
    #  Compute the potential energy derivatives. #
    #============================================#
    logger.info(
        "Calculating potential energy derivatives with finite difference step size: %f\n"
        % h)
    # Switch for whether to compute the derivatives two different ways for consistency.
    FDCheck = False

    # Create a double-precision simulation object if desired (seems unnecessary).
    DoublePrecisionDerivatives = False
    if engname == "openmm" and DoublePrecisionDerivatives and AGrad:
        logger.info(
            "Creating Double Precision Simulation for parameter derivatives\n")
        Lipid = Engine(name="lipid",
                       openmm_precision="double",
                       **EngOpts["lipid"])

    # Compute the energy and dipole derivatives.
    printcool(
        "Condensed phase energy and dipole derivatives\nInitializing array to length %i"
        % len(Energies),
        color=4,
        bold=True)
    G, GDx, GDy, GDz = energy_derivatives(Lipid,
                                          FF,
                                          mvals,
                                          h,
                                          pgrad,
                                          len(Energies),
                                          AGrad,
                                          dipole=True)

    #==============================================#
    #  Condensed phase properties and derivatives. #
    #==============================================#

    #----
    # Density
    #----
    # Build the first density derivative.
    GRho = mBeta * (flat(np.dot(G, col(Rhos))) / L -
                    np.mean(Rhos) * np.mean(G, axis=1))
    # Print out the density and its derivative.
    Sep = printcool("Density: % .4f +- % .4f kg/m^3\nAnalytic Derivative:" %
                    (Rho_avg, Rho_err))
    FF.print_map(vals=GRho)
    logger.info(Sep)

    def calc_rho(b=None, **kwargs):
        if b is None: b = np.ones(L, dtype=float)
        if 'r_' in kwargs:
            r_ = kwargs['r_']
        return bzavg(r_, b)

    # No need to calculate error using bootstrap, but here it is anyway
    # Rhoboot = []
    # for i in range(numboots):
    #    boot = np.random.randint(N,size=N)
    #    Rhoboot.append(calc_rho(None,**{'r_':Rhos[boot]}))
    # Rhoboot = np.array(Rhoboot)
    # Rho_err = np.std(Rhoboot)

    if FDCheck:
        Sep = printcool("Numerical Derivative:")
        GRho1 = property_derivatives(Lipid, FF, mvals, h, pgrad, kT, calc_rho,
                                     {'r_': Rhos})
        FF.print_map(vals=GRho1)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = [
            "% .4e  % .4e" % (i - j, (i - j) / j) for i, j in zip(GRho, GRho1)
        ]
        FF.print_map(vals=absfrac)

    #----
    # Enthalpy of vaporization.  Removed.
    #----
    H = Energies + pV
    V = np.array(Volumes)

    # Define some things to make the analytic derivatives easier.
    Gbar = np.mean(G, axis=1)

    def deprod(vec):
        return flat(np.dot(G, col(vec))) / L

    def covde(vec):
        return flat(np.dot(G, col(vec))) / L - Gbar * np.mean(vec)

    def avg(vec):
        return np.mean(vec)

    #----
    # Thermal expansion coefficient
    #----
    def calc_alpha(b=None, **kwargs):
        if b is None: b = np.ones(L, dtype=float)
        if 'h_' in kwargs:
            h_ = kwargs['h_']
        if 'v_' in kwargs:
            v_ = kwargs['v_']
        return 1 / (kT * T) * (bzavg(h_ * v_, b) -
                               bzavg(h_, b) * bzavg(v_, b)) / bzavg(v_, b)

    Alpha = calc_alpha(None, **{'h_': H, 'v_': V})
    Alphaboot = []
    numboots = 1000
    for i in range(numboots):
        boot = np.random.randint(L, size=L)
        Alphaboot.append(calc_alpha(None, **{'h_': H[boot], 'v_': V[boot]}))
    Alphaboot = np.array(Alphaboot)
    Alpha_err = np.std(Alphaboot) * max([
        np.sqrt(statisticalInefficiency(V)),
        np.sqrt(statisticalInefficiency(H))
    ])

    # Thermal expansion coefficient analytic derivative
    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)
    GAlpha = (GAlpha1 + GAlpha2 + GAlpha3 + GAlpha4) / (kT * T)
    Sep = printcool(
        "Thermal expansion coefficient: % .4e +- %.4e K^-1\nAnalytic Derivative:"
        % (Alpha, Alpha_err))
    FF.print_map(vals=GAlpha)
    if FDCheck:
        GAlpha_fd = property_derivatives(Lipid, FF, mvals, h, pgrad, kT,
                                         calc_alpha, {
                                             'h_': H,
                                             'v_': V
                                         })
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GAlpha_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = [
            "% .4e  % .4e" % (i - j, (i - j) / j)
            for i, j in zip(GAlpha, GAlpha_fd)
        ]
        FF.print_map(vals=absfrac)

    #----
    # Isothermal compressibility
    #----
    def calc_kappa(b=None, **kwargs):
        if b is None: b = np.ones(L, dtype=float)
        if 'v_' in kwargs:
            v_ = kwargs['v_']
        return bar_unit / kT * (bzavg(v_**2, b) - bzavg(v_, b)**2) / bzavg(
            v_, b)

    Kappa = calc_kappa(None, **{'v_': V})
    Kappaboot = []
    for i in range(numboots):
        boot = np.random.randint(L, size=L)
        Kappaboot.append(calc_kappa(None, **{'v_': V[boot]}))
    Kappaboot = np.array(Kappaboot)
    Kappa_err = np.std(Kappaboot) * np.sqrt(statisticalInefficiency(V))

    # Isothermal compressibility analytic derivative
    Sep = printcool(
        "Isothermal compressibility:  % .4e +- %.4e bar^-1\nAnalytic Derivative:"
        % (Kappa, Kappa_err))
    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)
    GKappa = bar_unit * (GKappa1 + GKappa2 + GKappa3)
    FF.print_map(vals=GKappa)
    if FDCheck:
        GKappa_fd = property_derivatives(Lipid, FF, mvals, h, pgrad, kT,
                                         calc_kappa, {'v_': V})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GKappa_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = [
            "% .4e  % .4e" % (i - j, (i - j) / j)
            for i, j in zip(GKappa, GKappa_fd)
        ]
        FF.print_map(vals=absfrac)

    #----
    # Isobaric heat capacity
    #----
    def calc_cp(b=None, **kwargs):
        if b is None: b = np.ones(L, dtype=float)
        if 'h_' in kwargs:
            h_ = kwargs['h_']
        Cp_ = 1 / (NMol * kT * T) * (bzavg(h_**2, b) - bzavg(h_, b)**2)
        Cp_ *= 1000 / 4.184
        return Cp_

    Cp = calc_cp(None, **{'h_': H})
    Cpboot = []
    for i in range(numboots):
        boot = np.random.randint(L, size=L)
        Cpboot.append(calc_cp(None, **{'h_': H[boot]}))
    Cpboot = np.array(Cpboot)
    Cp_err = np.std(Cpboot) * np.sqrt(statisticalInefficiency(H))

    # Isobaric heat capacity analytic derivative
    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)
    GCp = GCp1 + GCp2 + GCp3
    Sep = printcool(
        "Isobaric heat capacity:  % .4e +- %.4e cal mol-1 K-1\nAnalytic Derivative:"
        % (Cp, Cp_err))
    FF.print_map(vals=GCp)
    if FDCheck:
        GCp_fd = property_derivatives(Lipid, FF, mvals, h, pgrad, kT, calc_cp,
                                      {'h_': H})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GCp_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = [
            "% .4e  % .4e" % (i - j, (i - j) / j) for i, j in zip(GCp, GCp_fd)
        ]
        FF.print_map(vals=absfrac)

    #----
    # Dielectric constant
    #----
    def calc_eps0(b=None, **kwargs):
        if b is None: b = np.ones(L, dtype=float)
        if 'd_' in kwargs:  # Dipole moment vector.
            d_ = kwargs['d_']
        if 'v_' in kwargs:  # Volume.
            v_ = kwargs['v_']
        b0 = np.ones(L, dtype=float)
        dx = d_[:, 0]
        dy = d_[:, 1]
        dz = d_[:, 2]
        D2 = bzavg(dx**2, b) - bzavg(dx, b)**2
        D2 += bzavg(dy**2, b) - bzavg(dy, b)**2
        D2 += bzavg(dz**2, b) - bzavg(dz, b)**2
        return prefactor * D2 / bzavg(v_, b) / T

    Eps0 = calc_eps0(None, **{'d_': Dips, 'v_': V})
    Eps0boot = []
    for i in range(numboots):
        boot = np.random.randint(L, size=L)
        Eps0boot.append(calc_eps0(None, **{'d_': Dips[boot], 'v_': V[boot]}))
    Eps0boot = np.array(Eps0boot)
    Eps0_err = np.std(Eps0boot) * np.sqrt(
        np.mean([
            statisticalInefficiency(Dips[:, 0]),
            statisticalInefficiency(Dips[:, 1]),
            statisticalInefficiency(Dips[:, 2])
        ]))

    # Dielectric constant analytic derivative
    Dx = Dips[:, 0]
    Dy = Dips[:, 1]
    Dz = Dips[:, 2]
    D2 = avg(Dx**2) + avg(Dy**2) + avg(
        Dz**2) - avg(Dx)**2 - avg(Dy)**2 - avg(Dz)**2
    GD2 = 2 * (flat(np.dot(GDx, col(Dx))) / L - avg(Dx) *
               (np.mean(GDx, axis=1))) - Beta * (covde(Dx**2) -
                                                 2 * avg(Dx) * covde(Dx))
    GD2 += 2 * (flat(np.dot(GDy, col(Dy))) / L - avg(Dy) *
                (np.mean(GDy, axis=1))) - Beta * (covde(Dy**2) -
                                                  2 * avg(Dy) * covde(Dy))
    GD2 += 2 * (flat(np.dot(GDz, col(Dz))) / L - avg(Dz) *
                (np.mean(GDz, axis=1))) - Beta * (covde(Dz**2) -
                                                  2 * avg(Dz) * covde(Dz))
    GEps0 = prefactor * (GD2 / avg(V) - mBeta * covde(V) * D2 / avg(V)**2) / T
    Sep = printcool(
        "Dielectric constant:           % .4e +- %.4e\nAnalytic Derivative:" %
        (Eps0, Eps0_err))
    FF.print_map(vals=GEps0)
    if FDCheck:
        GEps0_fd = property_derivatives(Lipid, FF, mvals, h, pgrad, kT,
                                        calc_eps0, {
                                            'd_': Dips,
                                            'v_': V
                                        })
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GEps0_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = [
            "% .4e  % .4e" % (i - j, (i - j) / j)
            for i, j in zip(GEps0, GEps0_fd)
        ]
        FF.print_map(vals=absfrac)

    #----
    # Average area per lipid
    #----
    Al_avg, Al_err = mean_stderr(Als)
    # Build the first A_l derivative.
    GAl = mBeta * (flat(np.dot(G, col(Als))) / L -
                   np.mean(Als) * np.mean(G, axis=1))
    # Print out A_l and its derivative.
    Sep = printcool(
        "Average Area per Lipid: % .4f +- % .4f nm^2\nAnalytic Derivative:" %
        (Al_avg, Al_err))
    FF.print_map(vals=GAl)
    logger.info(Sep)

    def calc_al(b=None, **kwargs):
        if b is None: b = np.ones(L, dtype=float)
        if 'a_' in kwargs:
            a_ = kwargs['a_']
        return bzavg(a_, b)

    # calc_al(None, **{'a_': Als})

    #----
    # Bilayer Isothermal compressibility
    #----
    kbT = 1.3806488e-23 * T

    def calc_lkappa(b=None, **kwargs):
        if b is None: b = np.ones(L, dtype=float)
        if 'a_' in kwargs:
            a_ = kwargs['a_']
        al_var = bzavg(a_**2, b) - bzavg(a_, b)**2
        # Avoid dividing by zero if A_L time series is too short.
        if abs(al_var) > 0:
            return (1e3 * 2 * kbT / 128) * (bzavg(a_, b) / al_var)
        else:
            return 0 * bzavg(a_, b)

    # Convert Als time series from nm^2 to m^2
    Als_m2 = Als * 1e-18
    LKappa = calc_lkappa(None, **{'a_': Als_m2})
    al_avg = avg(Als_m2)
    al_sq_avg = avg(Als_m2**2)
    al_avg_sq = al_avg**2
    al_var = al_sq_avg - al_avg_sq

    LKappaboot = []
    for i in range(numboots):
        boot = np.random.randint(L, size=L)
        LKappaboot.append(calc_lkappa(None, **{'a_': Als_m2[boot]}))
    LKappaboot = np.array(LKappaboot)
    LKappa_err = np.std(LKappaboot) * np.sqrt(statisticalInefficiency(Als_m2))

    # Bilayer Isothermal compressibility analytic derivative
    Sep = printcool(
        "Lipid Isothermal compressibility:  % .4e +- %.4e N/nm^-1\nAnalytic Derivative:"
        % (LKappa, LKappa_err))
    GLKappa1 = covde(Als_m2) / al_var
    GLKappa2 = (al_avg / al_var**2) * (covde(Als_m2**2) -
                                       (2 * al_avg * covde(Als_m2)))
    GLKappa = (1e3 * 2 * kbT / 128) * (GLKappa1 - GLKappa2)
    FF.print_map(vals=GLKappa)
    if FDCheck:
        GLKappa_fd = property_derivatives(Lipid, FF, mvals, h, pgrad, kT,
                                          calc_lkappa, {'a_': Als_m2})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GLKappa_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = [
            "% .4e  % .4e" % (i - j, (i - j) / j)
            for i, j in zip(GLKappa, GLKappa_fd)
        ]
        FF.print_map(vals=absfrac)

    #----
    # Deuterium Order Parameter
    #----
    Scd_avg, Scd_e = mean_stderr(Scds)
    Scd_err = flat(Scd_e)
    # In case I did the conversion incorrectly, this is the code that was here previously:
    # GScd = mBeta * (((np.mat(G) * Scds) / L) - (np.mat(np.average(G, axis = 1)).T * np.average(Scds, axis = 0)))
    GScd = mBeta * (
        ((np.dot(G, Scds)) / L) -
        np.dot(col(np.average(G, axis=1)), row(np.average(Scds, axis=0))))
    # Print out S_cd and its derivative.
    scd_avgerr = ' '.join('%.4f +- %.4f \n' % F for F in zip(Scd_avg, Scd_err))
    Sep = printcool("Deuterium order parameter: %s \nAnalytic Derivative:" %
                    scd_avgerr)
    FF.print_map(vals=GScd)
    logger.info(Sep)

    def calc_scd(b=None, **kwargs):
        if b is None: b = np.ones(L, dtype=float)
        if 's_' in kwargs:
            s_ = kwargs['s_']
        return bzavg(s_, b)

    # calc_scd(None, **{'s_': Scds})

    logger.info("Writing final force field.\n")
    pvals = FF.make(mvals)

    logger.info("Writing all simulation data to disk.\n")
    lp_dump((Rhos, Volumes, Potentials, Energies, Dips, G, [GDx, GDy, GDz],
             Rho_err, Alpha_err, Kappa_err, Cp_err, Eps0_err, NMol, Als,
             Al_err, Scds, Scd_err, LKappa_err), 'npt_result.p')
Esempio n. 38
0
def main():
    
    """Usage:
    
    (prefix.sh) md_one.py -T, --temperature <temperature in kelvin>
                          -P, --pressure <pressure in atm>
                          -g, --grad (if gradients of output timeseries are desired)
                          -eq, --nequil <number of equilibration MD steps>
                          -md, --nsteps <number of production MD steps>
                          -dt, --timestep <number of production MD steps>
                          -sp, --sample <number of production MD steps>
                          -nt, --threads <number of CPU threads to use>
                          -min, --minimize <minimize the energy>
        
    This program is meant to be called automatically by ForceBalance because 
    force field options are loaded from the 'forcefield.p' file, and 
    simulation options are loaded from the 'simulation.p' file.  
    The files are separated because the same force field file
    may be used for many simulations.
    
    """

    # Write the force field file.
    FF.make(mvals)

    # Read the command line options (they may override the options from file.)
    AGrad = args['gradient']
    for i in ['temperature', 'pressure', 'nequil', 'nsteps', 'timestep', 'sample', 'threads', 'minimize']:
        if i in args:
            MDOpts[i] = args[i]
    MDOpts['nsave'] = int(1000.0*MDOpts['sample']/MDOpts['timestep'])
    if 'save_traj' in TgtOpts:
        MDOpts['save_traj'] = TgtOpts['save_traj']

    #----
    # Print some options.
    # At this point, engine and MD options should be SET!
    #----
    printcool("ForceBalance simulation using engine: %s" % engname.upper(),
              color=4, bold=True)
    printcool_dictionary(args, title="Options from command line")
    printcool_dictionary(EngOpts, title="Engine options")
    printcool_dictionary(MDOpts, title="Molecular dynamics options")

    #----
    # For convenience, assign some local variables.
    #----
    # Finite difference step size
    h = TgtOpts['h']
    # Active parameters to differentiate
    pgrad = TgtOpts['pgrad']
    # Create instances of the MD Engine objects.
    Engine = EngineClass(**EngOpts)
    click() # Start timer.
    # This line runs the condensed phase simulation.
    #----
    # The molecular dynamics simulation returns a dictionary of properties
    # In the future, the properties will be stored as data inside the object
    Results = Engine.molecular_dynamics(**MDOpts)
    if AGrad:
        Results['Potential_Derivatives'] = energy_derivatives(Engine, FF, mvals, h, pgrad, dipole=False)['potential']
    # Set up engine and calculate the potential in the other phase.
    EngOpts_ = deepcopy(EngOpts)
    EngOpts_['implicit_solvent'] = not EngOpts['implicit_solvent']
    Engine_ = EngineClass(**EngOpts_)
    Engine_.xyz_omms = Engine.xyz_omms
    Energy_ = Engine_.energy()
    Results_ = {'Potentials' : Energy_}
    if AGrad:
        Derivs_ = energy_derivatives(Engine_, FF, mvals, h, pgrad, dipole=False)['potential']
        Results_['Potential_Derivatives'] = Derivs_
    # Calculate the hydration energy of each snapshot and its parametric derivatives.
    if EngOpts['implicit_solvent']:
        Energy_liq = Results['Potentials']
        Energy_gas = Results_['Potentials']
        if AGrad: 
            Derivs_liq = Results['Potential_Derivatives']
            Derivs_gas = Results_['Potential_Derivatives']
    else:  
        Energy_gas = Results['Potentials']
        Energy_liq = Results_['Potentials']
        if AGrad: 
            Derivs_gas = Results['Potential_Derivatives']
            Derivs_liq = Results_['Potential_Derivatives']
    Results['Hydration'] = Energy_liq - Energy_gas
    if AGrad:
        Results['Hydration_Derivatives'] = Derivs_liq - Derivs_gas
    # Code of the future!
    # Don't know how to use it yet though.
    # Engine.molecular_dynamics(**MDOpts)
    # logger.info("MD simulation took %.3f seconds\n" % click())
    # # Extract properties.
    # Results = Engine.md_extract(OrderedDict([(i, {}) for i in Tgt.timeseries.keys()]))
    # potential = properties['Potential']
    # Calculate energy and dipole derivatives if needed.
    # if AGrad:
    #     Results['derivatives'] = energy_derivatives(Engine, FF, mvals, h, pgrad, dipole='dipole' in Tgt.timeseries.keys())
    # Dump results to file
    logger.info("Writing final force field.\n")
    pvals = FF.make(mvals)
    logger.info("Writing all simulation data to disk.\n")
    lp_dump(Results, 'md_result.p')
Esempio n. 39
0
    def __init__(self,options,Objective,FF):
        """ Create an Optimizer object.
        
        The optimizer depends on both the FF and the fitting targets so there
        is a chain of dependencies: FF --> FitSim --> Optimizer, and FF --> Optimizer
        
        Here's what we do:
        - Take options from the parser
        - Pass in the objective function, force field, all fitting targets

        """
        super(Optimizer, self).__init__(options)

        ## A list of all the things we can ask the optimizer to do.
        self.OptTab    = {'NEWTONRAPHSON'     : self.NewtonRaphson, 
                          'NEWTON'            : self.NewtonRaphson, 
                          'NR'                : self.NewtonRaphson, 
                          'BFGS'              : self.BFGS,
                          'POWELL'            : self.Powell,
                          'SIMPLEX'           : self.Simplex,
                          'ANNEAL'            : self.Anneal,
                          'GENETIC'           : self.GeneticAlgorithm,
                          'CONJUGATEGRADIENT' : self.ConjugateGradient,
                          'SCAN_MVALS'        : self.ScanMVals,
                          'SCAN_PVALS'        : self.ScanPVals,
                          'SINGLE'            : self.SinglePoint,
                          'GRADIENT'          : self.Gradient,
                          'HESSIAN'           : self.Hessian,
                          'FDCHECKG'          : self.FDCheckG,
                          'FDCHECKH'          : self.FDCheckH
                          }
        
        #======================================#
        # Options that are given by the parser #
        #======================================#
        ## The root directory
        self.set_option(options,'root','root')
        ## The job type
        self.set_option(options,'jobtype','jobtype')
        ## Initial step size trust radius
        self.set_option(options,'trust0','trust0')
        ## Minimum trust radius (for noisy objective functions)
        self.set_option(options,'mintrust','mintrust')
        ## Lower bound on Hessian eigenvalue (below this, we add in steepest descent)
        self.set_option(options,'eig_lowerbound','eps')
        ## Guess value for Brent
        self.set_option(options,'lm_guess','lmg')
        ## Step size for numerical finite difference
        self.set_option(options,'finite_difference_h','h')
        ## Number of steps to average over
        self.set_option(options,'objective_history','hist')
        ## Function value convergence threshold
        self.set_option(options,'convergence_objective','conv_obj')
        ## Step size convergence threshold
        self.set_option(options,'convergence_step','conv_stp')
        ## Gradient convergence threshold
        self.set_option(options,'convergence_gradient','conv_grd')
        ## Maximum number of optimization steps
        self.set_option(options,'maxstep','maxstep')
        ## For scan[mp]vals: The parameter index to scan over
        self.set_option(options,'scanindex_num','idxnum')
        ## For scan[mp]vals: The parameter name to scan over, it just looks up an index
        self.set_option(options,'scanindex_name','idxname')
        ## For scan[mp]vals: The values that are fed into the scanner
        self.set_option(options,'scan_vals','scan_vals')
        ## Name of the checkpoint file that we're reading in
        self.set_option(options,'readchk','rchk_fnm')
        ## Name of the checkpoint file that we're writing out
        self.set_option(options,'writechk','wchk_fnm')
        ## Whether to write the checkpoint file at every step
        self.set_option(options,'writechk_step','wchk_step')
        ## Adaptive trust radius adjustment factor
        self.set_option(options,'adaptive_factor','adapt_fac')
        ## Adaptive trust radius adjustment damping
        self.set_option(options,'adaptive_damping','adapt_damp')
        ## Whether to print gradient during each step of the optimization
        self.set_option(options,'print_gradient','print_grad')
        ## Whether to print Hessian during each step of the optimization
        self.set_option(options,'print_hessian','print_hess')
        ## Whether to print parameters during each step of the optimization
        self.set_option(options,'print_parameters','print_vals')
        ## Error tolerance (if objective function rises by less than this, then the optimizer will forge ahead!)
        self.set_option(options,'error_tolerance','err_tol')
        ## Search tolerance (The nonlinear search will stop if the change is below this threshold)
        self.set_option(options,'search_tolerance','search_tol')
        self.set_option(options,'read_mvals')
        self.set_option(options,'read_pvals')
        
        #======================================#
        #     Variables which are set here     #
        #======================================#
        ## The objective function (needs to pass in when I instantiate)
        self.Objective = Objective
        ## Whether the penalty function is hyperbolic
        self.bhyp      = Objective.Penalty.ptyp != 2
        ## The force field itself
        self.FF        = FF
        
        #======================================#
        #    Variables from the force field    #
        #======================================#
        ## The indices to be excluded from the Hessian update
        self.excision  = list(FF.excision)

        ## Number of parameters
        self.np        = FF.np
        ## The original parameter values
        if options['read_mvals'] != None:
            self.mvals0    = np.array(options['read_mvals'])
        elif options['read_pvals'] != None:
            self.mvals0    = FF.create_mvals(options['read_pvals'])
        else:
            self.mvals0    = np.zeros(self.FF.np)

        ## Print the optimizer options.
        printcool_dictionary(self.PrintOptionDict, title="Setup for optimizer")
        ## Load the checkpoint file.
        self.readchk()
Esempio n. 40
0
def main():

    """
    Usage: (runcuda.sh) npt.py <openmm|gromacs|tinker|amber> <liquid_nsteps> <liquid_timestep (fs)> <liquid_intvl (ps> <temperature> <pressure>

    This program is meant to be called automatically by ForceBalance on
    a GPU cluster (specifically, subroutines in openmmio.py).  It is
    not easy to use manually.  This is because the force field is read
    in from a ForceBalance 'FF' class.

    I wrote this program because automatic fitting of the density (or
    other equilibrium properties) is computationally intensive, and the
    calculations need to be distributed to the queue.  The main instance
    of ForceBalance (running on my workstation) queues up a bunch of these
    jobs (using Work Queue).  Then, I submit a bunch of workers to GPU
    clusters (e.g. Certainty, Keeneland).  The worker scripts connect to.
    the main instance and receives one of these jobs.

    This script can also be executed locally, if you want to (e.g. for
    debugging).  Just make sure you have the pickled 'forcebalance.p'
    file.

    """

    printcool("ForceBalance condensed phase simulation using engine: %s" % engname.upper(), color=4, bold=True)

    #----
    # Load the ForceBalance pickle file which contains:
    #----
    # - Force field object
    # - Optimization parameters
    # - Options from the Target object that launched this simulation
    # - Switch for whether to evaluate analytic derivatives.
    FF,mvals,TgtOptions,AGrad = lp_load('forcebalance.p')
    FF.ffdir = '.'
    # Write the force field file.
    FF.make(mvals)

    #----
    # Load the options that are set in the ForceBalance input file.
    #----
    # Finite difference step size
    h = TgtOptions['h']
    pgrad = TgtOptions['pgrad']
    # MD options; time step (fs), production steps, equilibration steps, interval for saving data (ps)
    liquid_timestep = TgtOptions['liquid_timestep']
    liquid_nsteps = TgtOptions['liquid_md_steps']
    liquid_nequil = TgtOptions['liquid_eq_steps']
    liquid_intvl = TgtOptions['liquid_interval']
    liquid_fnm = TgtOptions['liquid_coords']
    gas_timestep = TgtOptions['gas_timestep']
    gas_nsteps = TgtOptions['gas_md_steps']
    gas_nequil = TgtOptions['gas_eq_steps']
    gas_intvl = TgtOptions['gas_interval']
    gas_fnm = TgtOptions['gas_coords']

    # Number of threads, multiple timestep integrator, anisotropic box etc.
    threads = TgtOptions.get('md_threads', 1)
    mts = TgtOptions.get('mts_integrator', 0)
    rpmd_beads = TgtOptions.get('rpmd_beads', 0)
    force_cuda = TgtOptions.get('force_cuda', 0)
    nbarostat = TgtOptions.get('n_mcbarostat', 25)
    anisotropic = TgtOptions.get('anisotropic_box', 0)
    minimize = TgtOptions.get('minimize_energy', 1)

    # Print all options.
    printcool_dictionary(TgtOptions, title="Options from ForceBalance")
    liquid_snapshots = int((liquid_nsteps * liquid_timestep / 1000) / liquid_intvl)
    liquid_iframes = int(1000 * liquid_intvl / liquid_timestep)
    gas_snapshots = int((gas_nsteps * gas_timestep / 1000) / gas_intvl)
    gas_iframes = int(1000 * gas_intvl / gas_timestep)
    logger.info("For the condensed phase system, I will collect %i snapshots spaced apart by %i x %.3f fs time steps\n" \
        % (liquid_snapshots, liquid_iframes, liquid_timestep))
    if liquid_snapshots < 2:
        raise Exception('Please set the number of liquid time steps so that you collect at least two snapshots (minimum %i)' \
                            % (2000 * int(liquid_intvl/liquid_timestep)))
    logger.info("For the gas phase system, I will collect %i snapshots spaced apart by %i x %.3f fs time steps\n" \
        % (gas_snapshots, gas_iframes, gas_timestep))
    if gas_snapshots < 2:
        raise Exception('Please set the number of gas time steps so that you collect at least two snapshots (minimum %i)' \
                            % (2000 * int(gas_intvl/gas_timestep)))

    #----
    # Loading coordinates
    #----
    ML = Molecule(liquid_fnm, toppbc=True)
    MG = Molecule(gas_fnm)
    # Determine the number of molecules in the condensed phase coordinate file.
    NMol = TgtOptions['n_molecules']
    logger.info("There are %i molecules in the liquid\n" % (NMol))

    #----
    # Setting up MD simulations
    #----
    EngOpts = OrderedDict()
    EngOpts["liquid"] = OrderedDict([("coords", liquid_fnm), ("mol", ML), ("pbc", True)])
    if "nonbonded_cutoff" in TgtOptions:
        EngOpts["liquid"]["nonbonded_cutoff"] = TgtOptions["nonbonded_cutoff"]
    if "vdw_cutoff" in TgtOptions:
        EngOpts["liquid"]["vdw_cutoff"] = TgtOptions["vdw_cutoff"]
    EngOpts["gas"] = OrderedDict([("coords", gas_fnm), ("mol", MG), ("pbc", False)])
    GenOpts = OrderedDict([('FF', FF)])
    if engname in ["openmm", "smirnoff"]:
        # OpenMM-specific options
        EngOpts["liquid"]["platname"] = TgtOptions.get("platname", 'CUDA')
        # For now, always run gas phase calculations on the reference platform
        EngOpts["gas"]["platname"] = 'Reference'
        if force_cuda:
            try: Platform.getPlatformByName('CUDA')
            except: raise RuntimeError('Forcing failure because CUDA platform unavailable')
            EngOpts["liquid"]["platname"] = 'CUDA'
        if threads > 1: logger.warn("Setting the number of threads will have no effect on OpenMM engine.\n")
        if engname == "smirnoff":
            if not TgtOptions['liquid_coords'].endswith('.pdb'):
                logger.error("With SMIRNOFF engine, please pass a .pdb file to liquid_coords.")
                raise RuntimeError
            EngOpts["liquid"]["pdb"] = TgtOptions['liquid_coords']
            EngOpts["liquid"]["mol2"] = TgtOptions["mol2"]
            if not TgtOptions['gas_coords'].endswith('.pdb'):
                logger.error("With SMIRNOFF engine, please pass a .pdb file to gas_coords.")
                raise RuntimeError
            EngOpts["gas"]["pdb"] = TgtOptions['gas_coords']
            EngOpts["gas"]["mol2"] = TgtOptions["mol2"]
    elif engname == "gromacs":
        # Gromacs-specific options
        GenOpts["gmxpath"] = TgtOptions["gmxpath"]
        GenOpts["gmxsuffix"] = TgtOptions["gmxsuffix"]
        EngOpts["liquid"]["gmx_top"] = os.path.splitext(liquid_fnm)[0] + ".top"
        EngOpts["liquid"]["gmx_mdp"] = os.path.splitext(liquid_fnm)[0] + ".mdp"
        EngOpts["liquid"]["gmx_eq_barostat"] = TgtOptions["gmx_eq_barostat"]
        EngOpts["gas"]["gmx_top"] = os.path.splitext(gas_fnm)[0] + ".top"
        EngOpts["gas"]["gmx_mdp"] = os.path.splitext(gas_fnm)[0] + ".mdp"
        if force_cuda: logger.warn("force_cuda option has no effect on Gromacs engine.")
        if rpmd_beads > 0: raise RuntimeError("Gromacs cannot handle RPMD.")
        if mts: logger.warn("Gromacs not configured for multiple timestep integrator.")
        if anisotropic: logger.warn("Gromacs not configured for anisotropic box scaling.")
    elif engname == "tinker":
        # Tinker-specific options
        GenOpts["tinkerpath"] = TgtOptions["tinkerpath"]
        EngOpts["liquid"]["tinker_key"] = os.path.splitext(liquid_fnm)[0] + ".key"
        EngOpts["gas"]["tinker_key"] = os.path.splitext(gas_fnm)[0] + ".key"
        if force_cuda: logger.warn("force_cuda option has no effect on Tinker engine.")
        if rpmd_beads > 0: raise RuntimeError("TINKER cannot handle RPMD.")
        if mts: logger.warn("Tinker not configured for multiple timestep integrator.")
    elif engname == "amber":
        # AMBER-specific options
        GenOpts["amberhome"] = TgtOptions["amberhome"]
        if os.path.exists(os.path.splitext(liquid_fnm)[0] + ".mdin"):
            EngOpts["liquid"]["mdin"] = os.path.splitext(liquid_fnm)[0] + ".mdin"
        if os.path.exists(os.path.splitext(gas_fnm)[0] + ".mdin"):
            EngOpts["gas"]["mdin"] = os.path.splitext(gas_fnm)[0] + ".mdin"
        EngOpts["liquid"]["leapcmd"] = os.path.splitext(liquid_fnm)[0] + ".leap"
        EngOpts["gas"]["leapcmd"] = os.path.splitext(gas_fnm)[0] + ".leap"
        EngOpts["liquid"]["pdb"] = liquid_fnm
        EngOpts["gas"]["pdb"] = gas_fnm
        if force_cuda: logger.warn("force_cuda option has no effect on Amber engine.")
        if rpmd_beads > 0: raise RuntimeError("AMBER cannot handle RPMD.")
        if mts: logger.warn("Amber not configured for multiple timestep integrator.")
    EngOpts["liquid"].update(GenOpts)
    EngOpts["gas"].update(GenOpts)
    for i in EngOpts:
        printcool_dictionary(EngOpts[i], "Engine options for %s" % i)

    # Set up MD options
    MDOpts = OrderedDict()
    MDOpts["liquid"] = OrderedDict([("nsteps", liquid_nsteps), ("timestep", liquid_timestep),
                                    ("temperature", temperature), ("pressure", pressure),
                                    ("nequil", liquid_nequil), ("minimize", minimize),
                                    ("nsave", int(1000 * liquid_intvl / liquid_timestep)),
                                    ("verbose", True), ('save_traj', TgtOptions['save_traj']), 
                                    ("threads", threads), ("anisotropic", anisotropic), ("nbarostat", nbarostat),
                                    ("mts", mts), ("rpmd_beads", rpmd_beads), ("faststep", faststep)])
    MDOpts["gas"] = OrderedDict([("nsteps", gas_nsteps), ("timestep", gas_timestep),
                                 ("temperature", temperature), ("nsave", int(1000 * gas_intvl / gas_timestep)),
                                 ("nequil", gas_nequil), ("minimize", minimize), ("threads", 1), ("mts", mts),
                                 ("rpmd_beads", rpmd_beads), ("faststep", faststep)])

    # Energy components analysis disabled for OpenMM MTS because it uses force groups
    if (engname == "openmm" and mts): logger.warn("OpenMM with MTS integrator; energy components analysis will be disabled.\n")

    # Create instances of the MD Engine objects.
    Liquid = Engine(name="liquid", **EngOpts["liquid"])
    Gas = Engine(name="gas", **EngOpts["gas"])

    #=================================================================#
    # Run the simulation for the full system and analyze the results. #
    #=================================================================#

    printcool("Condensed phase molecular dynamics", color=4, bold=True)

    # This line runs the condensed phase simulation.
    click()
    prop_return = Liquid.molecular_dynamics(**MDOpts["liquid"])
    if hasattr(Liquid, 'freeze_atoms'):
        logger.info("Warning: freeze_atoms may result in incorrect system mass and incorrect density calculation\n")
    logger.info("Liquid phase MD simulation took %.3f seconds\n" % click())
    Rhos = prop_return['Rhos']
    Potentials = prop_return['Potentials']
    Kinetics = prop_return['Kinetics']
    Volumes = prop_return['Volumes']
    Dips = prop_return['Dips']
    EDA = prop_return['Ecomps']

    # Create a bunch of physical constants.
    # Energies are in kJ/mol
    # Lengths are in nanometers.
    L = len(Rhos)
    kB = 0.008314472471220214
    T = temperature
    kT = kB * T
    mBeta = -1.0 / kT
    Beta = 1.0 / kT
    atm_unit = 0.061019351687175
    bar_unit = 0.060221417930000
    # This is how I calculated the prefactor for the dielectric constant.
    # eps0 = 8.854187817620e-12 * coulomb**2 / newton / meter**2
    # epsunit = 1.0*(debye**2) / nanometer**3 / BOLTZMANN_CONSTANT_kB / kelvin
    # prefactor = epsunit/eps0/3
    prefactor = 30.348705333964077

    # Gather some physical variables.
    Energies = Potentials + Kinetics
    Ene_avg, Ene_err = mean_stderr(Energies)
    pV = atm_unit * pressure * Volumes
    pV_avg, pV_err = mean_stderr(pV)
    Rho_avg, Rho_err = mean_stderr(Rhos)
    PrintEDA(EDA, NMol)

    #==============================================#
    # Now run the simulation for just the monomer. #
    #==============================================#

    # Run the OpenMM simulation, gather information.

    printcool("Gas phase molecular dynamics", color=4, bold=True)
    click()
    mprop_return = Gas.molecular_dynamics(**MDOpts["gas"])
    logger.info("Gas phase MD simulation took %.3f seconds\n" % click())
    mPotentials = mprop_return['Potentials']
    mKinetics = mprop_return['Kinetics']
    mEDA = mprop_return['Ecomps']

    mEnergies = mPotentials + mKinetics
    mEne_avg, mEne_err = mean_stderr(mEnergies)
    PrintEDA(mEDA, 1)

    #============================================#
    #  Compute the potential energy derivatives. #
    #============================================#
    logger.info("Calculating potential energy derivatives with finite difference step size: %f\n" % h)
    # Switch for whether to compute the derivatives two different ways for consistency.
    FDCheck = False

    # Create a double-precision simulation object if desired (seems unnecessary).
    DoublePrecisionDerivatives = False
    if engname == "openmm" and DoublePrecisionDerivatives and AGrad:
        logger.info("Creating Double Precision Simulation for parameter derivatives\n")
        Liquid = Engine(name="liquid", openmm_precision="double", **EngOpts["liquid"])
        Gas = Engine(name="gas", openmm_precision="double", **EngOpts["gas"])

    # Compute the energy and dipole derivatives.
    printcool("Condensed phase energy and dipole derivatives\nInitializing array to length %i" % len(Energies), color=4, bold=True)
    click()
    G, GDx, GDy, GDz = energy_derivatives(Liquid, FF, mvals, h, pgrad, len(Energies), AGrad, dipole=True)
    logger.info("Condensed phase energy derivatives took %.3f seconds\n" % click())
    click()
    printcool("Gas phase energy derivatives", color=4, bold=True)
    mG, _, __, ___ = energy_derivatives(Gas, FF, mvals, h, pgrad, len(mEnergies), AGrad, dipole=False)
    logger.info("Gas phase energy derivatives took %.3f seconds\n" % click())

    #==============================================#
    #  Condensed phase properties and derivatives. #
    #==============================================#

    #----
    # Density
    #----
    # Build the first density derivative.
    GRho = mBeta * (flat(np.dot(G, col(Rhos))) / L - np.mean(Rhos) * np.mean(G, axis=1))
    # Print out the density and its derivative.
    Sep = printcool("Density: % .4f +- % .4f kg/m^3\nAnalytic Derivative:" % (Rho_avg, Rho_err))
    FF.print_map(vals=GRho)
    logger.info(Sep)

    def calc_rho(b = None, **kwargs):
        if b is None: b = np.ones(L,dtype=float)
        if 'r_' in kwargs:
            r_ = kwargs['r_']
        return bzavg(r_,b)

    # No need to calculate error using bootstrap, but here it is anyway
    # Rhoboot = []
    # for i in range(numboots):
    #    boot = np.random.randint(N,size=N)
    #    Rhoboot.append(calc_rho(None,**{'r_':Rhos[boot]}))
    # Rhoboot = np.array(Rhoboot)
    # Rho_err = np.std(Rhoboot)

    if FDCheck:
        Sep = printcool("Numerical Derivative:")
        GRho1 = property_derivatives(Liquid, FF, mvals, h, pgrad, kT, calc_rho, {'r_':Rhos})
        FF.print_map(vals=GRho1)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = ["% .4e  % .4e" % (i-j, (i-j)/j) for i,j in zip(GRho, GRho1)]
        FF.print_map(vals=absfrac)

    #----
    # Enthalpy of vaporization
    #----
    H = Energies + pV
    V = np.array(Volumes)

    # Print out the liquid enthalpy.
    logger.info("Liquid enthalpy: % .4f kJ/mol, stdev % .4f ; (% .4f from energy, % .4f from pV)\n" % 
                (np.mean(H), np.std(H), np.mean(Energies), np.mean(pV)))
    numboots = 1000

    # The enthalpy of vaporization in kJ/mol.
    Hvap_avg = mEne_avg - Ene_avg / NMol + kT - np.mean(pV) / NMol
    Hvap_err = np.sqrt(Ene_err**2 / NMol**2 + mEne_err**2 + pV_err**2/NMol**2)

    # Build the first Hvap derivative.
    GHvap = np.mean(G,axis=1)
    GHvap += mBeta * (flat(np.dot(G, col(Energies))) / L - Ene_avg * np.mean(G, axis=1))
    GHvap /= NMol
    GHvap -= np.mean(mG,axis=1)
    GHvap -= mBeta * (flat(np.dot(mG, col(mEnergies))) / L - mEne_avg * np.mean(mG, axis=1))
    GHvap *= -1
    GHvap -= mBeta * (flat(np.dot(G, col(pV))) / L - np.mean(pV) * np.mean(G, axis=1)) / NMol

    Sep = printcool("Enthalpy of Vaporization: % .4f +- %.4f kJ/mol\nAnalytic Derivative:" % (Hvap_avg, Hvap_err))
    FF.print_map(vals=GHvap)

    # Define some things to make the analytic derivatives easier.
    Gbar = np.mean(G,axis=1)
    def deprod(vec):
        return flat(np.dot(G,col(vec)))/L
    def covde(vec):
        return flat(np.dot(G,col(vec)))/L - Gbar*np.mean(vec)
    def avg(vec):
        return np.mean(vec)

    #----
    # Thermal expansion coefficient
    #----
    def calc_alpha(b = None, **kwargs):
        if b is None: b = np.ones(L,dtype=float)
        if 'h_' in kwargs:
            h_ = kwargs['h_']
        if 'v_' in kwargs:
            v_ = kwargs['v_']
        return 1/(kT*T) * (bzavg(h_*v_,b)-bzavg(h_,b)*bzavg(v_,b))/bzavg(v_,b)
    Alpha = calc_alpha(None, **{'h_':H, 'v_':V})
    Alphaboot = []
    for i in range(numboots):
        boot = np.random.randint(L,size=L)
        Alphaboot.append(calc_alpha(None, **{'h_':H[boot], 'v_':V[boot]}))
    Alphaboot = np.array(Alphaboot)
    Alpha_err = np.std(Alphaboot) * max([np.sqrt(statisticalInefficiency(V)),np.sqrt(statisticalInefficiency(H))])

    # Thermal expansion coefficient analytic derivative
    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)
    GAlpha  = (GAlpha1 + GAlpha2 + GAlpha3 + GAlpha4)/(kT*T)
    Sep = printcool("Thermal expansion coefficient: % .4e +- %.4e K^-1\nAnalytic Derivative:" % (Alpha, Alpha_err))
    FF.print_map(vals=GAlpha)
    if FDCheck:
        GAlpha_fd = property_derivatives(Liquid, FF, mvals, h, pgrad, kT, calc_alpha, {'h_':H,'v_':V})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GAlpha_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = ["% .4e  % .4e" % (i-j, (i-j)/j) for i,j in zip(GAlpha, GAlpha_fd)]
        FF.print_map(vals=absfrac)

    #----
    # Isothermal compressibility
    #----
    def calc_kappa(b=None, **kwargs):
        if b is None: b = np.ones(L,dtype=float)
        if 'v_' in kwargs:
            v_ = kwargs['v_']
        return bar_unit / kT * (bzavg(v_**2,b)-bzavg(v_,b)**2)/bzavg(v_,b)
    Kappa = calc_kappa(None,**{'v_':V})
    Kappaboot = []
    for i in range(numboots):
        boot = np.random.randint(L,size=L)
        Kappaboot.append(calc_kappa(None,**{'v_':V[boot]}))
    Kappaboot = np.array(Kappaboot)
    Kappa_err = np.std(Kappaboot) * np.sqrt(statisticalInefficiency(V))

    # Isothermal compressibility analytic derivative
    Sep = printcool("Isothermal compressibility:  % .4e +- %.4e bar^-1\nAnalytic Derivative:" % (Kappa, Kappa_err))
    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)
    GKappa  = bar_unit*(GKappa1 + GKappa2 + GKappa3)
    FF.print_map(vals=GKappa)
    if FDCheck:
        GKappa_fd = property_derivatives(Liquid, FF, mvals, h, pgrad, kT, calc_kappa, {'v_':V})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GKappa_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = ["% .4e  % .4e" % (i-j, (i-j)/j) for i,j in zip(GKappa, GKappa_fd)]
        FF.print_map(vals=absfrac)

    #----
    # Isobaric heat capacity
    #----
    def calc_cp(b=None, **kwargs):
        if b is None: b = np.ones(L,dtype=float)
        if 'h_' in kwargs:
            h_ = kwargs['h_']
        Cp_  = 1/(NMol*kT*T) * (bzavg(h_**2,b) - bzavg(h_,b)**2)
        Cp_ *= 1000 / 4.184
        return Cp_
    Cp = calc_cp(None,**{'h_':H})
    Cpboot = []
    for i in range(numboots):
        boot = np.random.randint(L,size=L)
        Cpboot.append(calc_cp(None,**{'h_':H[boot]}))
    Cpboot = np.array(Cpboot)
    Cp_err = np.std(Cpboot) * np.sqrt(statisticalInefficiency(H))

    # Isobaric heat capacity analytic derivative
    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)
    GCp  = GCp1 + GCp2 + GCp3
    Sep = printcool("Isobaric heat capacity:  % .4e +- %.4e cal mol-1 K-1\nAnalytic Derivative:" % (Cp, Cp_err))
    FF.print_map(vals=GCp)
    if FDCheck:
        GCp_fd = property_derivatives(Liquid, FF, mvals, h, pgrad, kT, calc_cp, {'h_':H})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GCp_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = ["% .4e  % .4e" % (i-j, (i-j)/j) for i,j in zip(GCp,GCp_fd)]
        FF.print_map(vals=absfrac)

    #----
    # Dielectric constant
    #----
    def calc_eps0(b=None, **kwargs):
        if b is None: b = np.ones(L,dtype=float)
        if 'd_' in kwargs: # Dipole moment vector.
            d_ = kwargs['d_']
        if 'v_' in kwargs: # Volume.
            v_ = kwargs['v_']
        b0 = np.ones(L,dtype=float)
        dx = d_[:,0]
        dy = d_[:,1]
        dz = d_[:,2]
        D2  = bzavg(dx**2,b)-bzavg(dx,b)**2
        D2 += bzavg(dy**2,b)-bzavg(dy,b)**2
        D2 += bzavg(dz**2,b)-bzavg(dz,b)**2
        return prefactor*D2/bzavg(v_,b)/T
    Eps0 = calc_eps0(None,**{'d_':Dips, 'v_':V})
    Eps0boot = []
    for i in range(numboots):
        boot = np.random.randint(L,size=L)
        Eps0boot.append(calc_eps0(None,**{'d_':Dips[boot], 'v_':V[boot]}))
    Eps0boot = np.array(Eps0boot)
    Eps0_err = np.std(Eps0boot)*np.sqrt(np.mean([statisticalInefficiency(Dips[:,0]),statisticalInefficiency(Dips[:,1]),statisticalInefficiency(Dips[:,2])]))
 
    # Dielectric constant analytic derivative
    Dx = Dips[:,0]
    Dy = Dips[:,1]
    Dz = Dips[:,2]
    D2 = avg(Dx**2)+avg(Dy**2)+avg(Dz**2)-avg(Dx)**2-avg(Dy)**2-avg(Dz)**2
    GD2  = 2*(flat(np.dot(GDx,col(Dx)))/L - avg(Dx)*(np.mean(GDx,axis=1))) - Beta*(covde(Dx**2) - 2*avg(Dx)*covde(Dx))
    GD2 += 2*(flat(np.dot(GDy,col(Dy)))/L - avg(Dy)*(np.mean(GDy,axis=1))) - Beta*(covde(Dy**2) - 2*avg(Dy)*covde(Dy))
    GD2 += 2*(flat(np.dot(GDz,col(Dz)))/L - avg(Dz)*(np.mean(GDz,axis=1))) - Beta*(covde(Dz**2) - 2*avg(Dz)*covde(Dz))
    GEps0 = prefactor*(GD2/avg(V) - mBeta*covde(V)*D2/avg(V)**2)/T
    Sep = printcool("Dielectric constant:           % .4e +- %.4e\nAnalytic Derivative:" % (Eps0, Eps0_err))
    FF.print_map(vals=GEps0)
    if FDCheck:
        GEps0_fd = property_derivatives(Liquid, FF, mvals, h, pgrad, kT, calc_eps0, {'d_':Dips,'v_':V})
        Sep = printcool("Numerical Derivative:")
        FF.print_map(vals=GEps0_fd)
        Sep = printcool("Difference (Absolute, Fractional):")
        absfrac = ["% .4e  % .4e" % (i-j, (i-j)/j) for i,j in zip(GEps0,GEps0_fd)]
        FF.print_map(vals=absfrac)

    logger.info("Writing final force field.\n")
    pvals = FF.make(mvals)

    logger.info("Writing all simulation data to disk.\n")
    lp_dump((Rhos, Volumes, Potentials, Energies, Dips, G, [GDx, GDy, GDz], mPotentials, mEnergies, mG, Rho_err, Hvap_err, Alpha_err, Kappa_err, Cp_err, Eps0_err, NMol),'npt_result.p')
Esempio n. 41
0
def main():
    """
    Usage: (runcuda.sh) nvt.py <openmm|gromacs|tinker> <liquid_nsteps> <liquid_timestep (fs)> <liquid_intvl (ps> <temperature>

    This program is meant to be called automatically by ForceBalance on
    a GPU cluster (specifically, subroutines in openmmio.py).  It is
    not easy to use manually.  This is because the force field is read
    in from a ForceBalance 'FF' class.
    """

    printcool("ForceBalance condensed phase NVT simulation using engine: %s" %
              engname.upper(),
              color=4,
              bold=True)

    #----
    # Load the ForceBalance pickle file which contains:
    #----
    # - Force field object
    # - Optimization parameters
    # - Options from the Target object that launched this simulation
    # - Switch for whether to evaluate analytic derivatives.
    FF, mvals, TgtOptions, AGrad = lp_load('forcebalance.p')
    FF.ffdir = '.'
    # Write the force field file.
    FF.make(mvals)

    #----
    # Load the options that are set in the ForceBalance input file.
    #----
    # Finite difference step size
    h = TgtOptions['h']
    pgrad = TgtOptions['pgrad']
    # MD options; time step (fs), production steps, equilibration steps, interval for saving data (ps)
    nvt_timestep = TgtOptions['nvt_timestep']
    nvt_md_steps = TgtOptions['nvt_md_steps']
    nvt_eq_steps = TgtOptions['nvt_eq_steps']
    nvt_interval = TgtOptions['nvt_interval']
    liquid_fnm = TgtOptions['nvt_coords']

    # Number of threads, multiple timestep integrator, anisotropic box etc.
    threads = TgtOptions.get('md_threads', 1)
    mts = TgtOptions.get('mts_integrator', 0)
    rpmd_beads = TgtOptions.get('rpmd_beads', 0)
    force_cuda = TgtOptions.get('force_cuda', 0)
    nbarostat = TgtOptions.get('n_mcbarostat', 25)
    anisotropic = TgtOptions.get('anisotropic_box', 0)
    minimize = TgtOptions.get('minimize_energy', 1)

    # Print all options.
    printcool_dictionary(TgtOptions, title="Options from ForceBalance")
    nvt_snapshots = int((nvt_timestep * nvt_md_steps / 1000) / nvt_interval)
    nvt_iframes = int(1000 * nvt_interval / nvt_timestep)
    logger.info("For the condensed phase system, I will collect %i snapshots spaced apart by %i x %.3f fs time steps\n" \
        % (nvt_snapshots, nvt_iframes, nvt_timestep))
    if nvt_snapshots < 2:
        raise Exception('Please set the number of liquid time steps so that you collect at least two snapshots (minimum %i)' \
                            % (2000 * int(nvt_interval,nvt_timestep)))

    #----
    # Loading coordinates
    #----
    ML = Molecule(liquid_fnm, toppbc=True)
    # Determine the number of molecules in the condensed phase coordinate file.
    NMol = len(ML.molecules)
    TgtOptions['n_molecules'] = NMol
    logger.info("There are %i molecules in the liquid\n" % (NMol))

    #----
    # Setting up MD simulations
    #----
    EngOpts = OrderedDict()
    EngOpts["liquid"] = OrderedDict([("coords", liquid_fnm), ("mol", ML),
                                     ("pbc", True)])
    if "nonbonded_cutoff" in TgtOptions:
        EngOpts["liquid"]["nonbonded_cutoff"] = TgtOptions["nonbonded_cutoff"]
    else:
        largest_available_cutoff = min(ML.boxes[0][:3]) / 2 - 0.1
        EngOpts["liquid"]["nonbonded_cutoff"] = largest_available_cutoff
        logger.info(
            "nonbonded_cutoff is by default set to the largest available value: %g Angstrom"
            % largest_available_cutoff)
    if "vdw_cutoff" in TgtOptions:
        EngOpts["liquid"]["vdw_cutoff"] = TgtOptions["vdw_cutoff"]
    # Hard Code nonbonded_cutoff to 13A for test
    #EngOpts["liquid"]["nonbonded_cutoff"] = EngOpts["liquid"]["vdw_cutoff"] = 13.0
    GenOpts = OrderedDict([('FF', FF)])
    if engname == "openmm":
        # OpenMM-specific options
        EngOpts["liquid"]["platname"] = TgtOptions.get("platname", 'CUDA')
        if force_cuda:
            try:
                Platform.getPlatformByName('CUDA')
            except:
                raise RuntimeError(
                    'Forcing failure because CUDA platform unavailable')
            EngOpts["liquid"]["platname"] = 'CUDA'
        if threads > 1:
            logger.warn(
                "Setting the number of threads will have no effect on OpenMM engine.\n"
            )

    EngOpts["liquid"].update(GenOpts)
    for i in EngOpts:
        printcool_dictionary(EngOpts[i], "Engine options for %s" % i)

    # Set up MD options
    MDOpts = OrderedDict()
    MDOpts["liquid"] = OrderedDict([("nsteps", nvt_md_steps),
                                    ("timestep", nvt_timestep),
                                    ("temperature", temperature),
                                    ("nequil", nvt_eq_steps),
                                    ("minimize", minimize),
                                    ("nsave",
                                     int(1000 * nvt_interval / nvt_timestep)),
                                    ("verbose", True),
                                    ('save_traj', TgtOptions['save_traj']),
                                    ("threads", threads), ("mts", mts),
                                    ("rpmd_beads", rpmd_beads),
                                    ("faststep", faststep)])

    # Energy components analysis disabled for OpenMM MTS because it uses force groups
    if (engname == "openmm" and mts):
        logger.warn(
            "OpenMM with MTS integrator; energy components analysis will be disabled.\n"
        )

    # Create instances of the MD Engine objects.
    Liquid = Engine(name="liquid", **EngOpts["liquid"])

    #=================================================================#
    # Run the simulation for the full system and analyze the results. #
    #=================================================================#

    printcool("Condensed phase NVT molecular dynamics", color=4, bold=True)
    click()
    prop_return = Liquid.molecular_dynamics(**MDOpts["liquid"])
    logger.info("Liquid phase MD simulation took %.3f seconds\n" % click())
    Potentials = prop_return['Potentials']

    #============================================#
    #  Compute the potential energy derivatives. #
    #============================================#
    if AGrad:
        logger.info(
            "Calculating potential energy derivatives with finite difference step size: %f\n"
            % h)
        # Switch for whether to compute the derivatives two different ways for consistency.
        FDCheck = False
        printcool(
            "Condensed phase energy and dipole derivatives\nInitializing array to length %i"
            % len(Potentials),
            color=4,
            bold=True)
        click()
        G, GDx, GDy, GDz = energy_derivatives(Liquid,
                                              FF,
                                              mvals,
                                              h,
                                              pgrad,
                                              len(Potentials),
                                              AGrad,
                                              dipole=False)
        logger.info("Condensed phase energy derivatives took %.3f seconds\n" %
                    click())

    #==============================================#
    #  Condensed phase properties and derivatives. #
    #==============================================#

    # Physical constants
    kB = 0.008314472471220214
    T = temperature
    kT = kB * T  # Unit: kJ/mol

    #--- Surface Tension ----
    logger.info("Start Computing surface tension.\n")
    perturb_proportion = 0.0005
    box_vectors = np.array(
        Liquid.xyz_omms[0][1] /
        nanometer)  # obtain original box vectors from first frame
    delta_S = np.sqrt(
        np.sum(np.cross(box_vectors[0], box_vectors[1])**
               2)) * perturb_proportion * 2  # unit: nm^2. *2 for 2 surfaces
    # perturb xy area +
    click()
    scale_x = scale_y = np.sqrt(1 + perturb_proportion)
    scale_z = 1.0 / (
        1 + perturb_proportion
    )  # keep the box volumn while changing the area of xy plane
    Liquid.scale_box(scale_x, scale_y, scale_z)
    logger.info("scale_box+ took %.3f seconds\n" % click())
    # Obtain energies and gradients
    Potentials_plus = Liquid.energy()
    logger.info(
        "Calculation of energies for perturbed box+ took %.3f seconds\n" %
        click())
    if AGrad:
        G_plus, _, _, _ = energy_derivatives(Liquid,
                                             FF,
                                             mvals,
                                             h,
                                             pgrad,
                                             len(Potentials),
                                             AGrad,
                                             dipole=False)
        logger.info(
            "Calculation of energy gradients for perturbed box+ took %.3f seconds\n"
            % click())
    # perturb xy area - ( Note: also need to cancel the previous scaling)
    scale_x = scale_y = np.sqrt(1 - perturb_proportion) * (1.0 / scale_x)
    scale_z = 1.0 / (1 - perturb_proportion) * (1.0 / scale_z)
    Liquid.scale_box(scale_x, scale_y, scale_z)
    logger.info("scale_box- took %.3f seconds\n" % click())
    # Obtain energies and gradients
    Potentials_minus = Liquid.energy()
    logger.info(
        "Calculation of energies for perturbed box- took %.3f seconds\n" %
        click())
    if AGrad:
        G_minus, _, _, _ = energy_derivatives(Liquid,
                                              FF,
                                              mvals,
                                              h,
                                              pgrad,
                                              len(Potentials),
                                              AGrad,
                                              dipole=False)
        logger.info(
            "Calculation of energy gradients for perturbed box- took %.3f seconds\n"
            % click())
    # Compute surface tension
    dE_plus = Potentials_plus - Potentials  # Unit: kJ/mol
    dE_minus = Potentials_minus - Potentials  # Unit: kJ/mol
    prefactor = -0.5 * kT / delta_S / 6.0221409e-1  # Unit mJ m^-2
    # Following equation: γ = -kT/(2ΔS) * [ ln<exp(-ΔE+/kT)> - ln<exp(-ΔE-/kT)> ]
    #plus_avg, plus_err = mean_stderr(np.exp(-dE_plus/kT))
    #minus_avg, minus_err = mean_stderr(np.exp(-dE_minus/kT))
    #surf_ten = -0.5 * kT / delta_S * ( np.log(plus_avg) - np.log(minus_avg) ) / 6.0221409e-1 # convert to mJ m^-2
    #surf_ten_err = 0.5 * kT / delta_S * ( np.log(plus_avg+plus_err) - np.log(plus_avg-plus_err) + np.log(minus_avg+minus_err) - np.log(minus_avg-minus_err) ) / 6.0221409e-1
    exp_dE_plus = np.exp(-dE_plus / kT)
    exp_dE_minus = np.exp(-dE_minus / kT)
    surf_ten = prefactor * (np.log(np.mean(exp_dE_plus)) -
                            np.log(np.mean(exp_dE_minus)))
    # Use bootstrap method to estimate the error
    num_frames = len(exp_dE_plus)
    numboots = 1000
    surf_ten_boots = np.zeros(numboots)
    for i in range(numboots):
        boots_ordering = np.random.randint(num_frames, size=num_frames)
        boots_exp_dE_plus = np.take(exp_dE_plus, boots_ordering)
        boots_exp_dE_minus = np.take(exp_dE_minus, boots_ordering)
        surf_ten_boots[i] = prefactor * (np.log(np.mean(boots_exp_dE_plus)) -
                                         np.log(np.mean(boots_exp_dE_minus)))
    surf_ten_err = np.std(surf_ten_boots) * np.sqrt(
        np.mean([
            statisticalInefficiency(exp_dE_plus),
            statisticalInefficiency(exp_dE_minus)
        ]))

    printcool("Surface Tension:       % .4f +- %.4f mJ m^-2" %
              (surf_ten, surf_ten_err))
    # Analytic Gradient of surface tension
    # Formula:      β = 1/kT
    #           ∂γ/∂α = -kT/(2ΔS) * { 1/<exp(-βΔE+)> * [<-β ∂E+/∂α exp(-βΔE+)> - <-β ∂E/∂α><exp(-βΔE+)>]
    #                                -1/<exp(-βΔE-)> * [<-β ∂E-/∂α exp(-βΔE-)> - <-β ∂E/∂α><exp(-βΔE-)>] }
    n_params = len(mvals)
    G_surf_ten = np.zeros(n_params)
    if AGrad:
        beta = 1.0 / kT
        plus_denom = np.mean(np.exp(-beta * dE_plus))
        minus_denom = np.mean(np.exp(-beta * dE_minus))
        for param_i in range(n_params):
            plus_left = np.mean(-beta * G_plus[param_i] *
                                np.exp(-beta * dE_plus))
            plus_right = np.mean(-beta * G[param_i]) * plus_denom
            minus_left = np.mean(-beta * G_minus[param_i] *
                                 np.exp(-beta * dE_minus))
            minus_right = np.mean(-beta * G[param_i]) * minus_denom
            G_surf_ten[param_i] = prefactor * (1.0 / plus_denom *
                                               (plus_left - plus_right) -
                                               1.0 / minus_denom *
                                               (minus_left - minus_right))
        printcool("Analytic Derivatives:")
        FF.print_map(vals=G_surf_ten)

    logger.info("Writing final force field.\n")
    pvals = FF.make(mvals)

    logger.info("Writing all results to disk.\n")
    result_dict = {
        'surf_ten': surf_ten,
        'surf_ten_err': surf_ten_err,
        'G_surf_ten': G_surf_ten
    }
    lp_dump(result_dict, 'nvt_result.p')
Esempio n. 42
0
    def printcool_table(self,
                        data=OrderedDict([]),
                        headings=[],
                        banner=None,
                        footnote=None,
                        color=0):
        """ Print target information in an organized table format.  Implemented 6/30 because
        multiple targets are already printing out tabulated information in very similar ways.
        This method is a simple wrapper around printcool_dictionary.  

        The input should be something like:

        @param data Column contents in the form of an OrderedDict, with string keys and list vals.
        The key is printed in the leftmost column and the vals are printed in the other columns.
        If non-strings are passed, they will be converted to strings (not recommended).
        
        @param headings Column headings in the form of a list.  It must be equal to the number to the list length
        for each of the "vals" in OrderedDict, plus one.  Use "\n" characters to specify long
        column names that may take up more than one line.

        @param banner Optional heading line, which will be printed at the top in the title.
        @param footnote Optional footnote line, which will be printed at the bottom.
        
        """
        tline = "Target: %s  Type: %s  Objective = %.5e" % (
            self.name, self.__class__.__name__, self.objective)
        nc = len(headings)
        if banner is not None:
            tlines = [banner, tline]
        else:
            tlines = [tline]
        # Sanity check.
        for val in data.values():
            if (len(val) + 1) != nc:
                logger.error(
                    'There are %i column headings, so the values in the data dictionary must be lists of length %i (currently %i)\n'
                    % (nc, nc - 1, len(val)))
                raise RuntimeError
        cwidths = [0 for i in range(nc)]
        # Figure out maximum column width.
        # First look at all of the column headings...
        crows = []
        for cnum, cname in enumerate(headings):
            crows.append(len(cname.split('\n')))
            for l in cname.split('\n'):
                cwidths[cnum] = max(cwidths[cnum], len(l))
        # Then look at the row names to stretch out the first column width...
        for k in data.keys():
            cwidths[0] = max(cwidths[0], len(str(k)))
        # Then look at the data values to stretch out the other column widths.
        for v in data.values():
            for n, f in enumerate(v):
                cwidths[n + 1] = max(cwidths[n + 1], len(str(f)))
        for i in range(1, len(cwidths)):
            cwidths[i] += 2
        if cwidths[0] < 15:
            cwidths[0] = 15
        cblocks = [['' for i in range(max(crows) - len(cname.split('\n')))] +
                   cname.split('\n') for cnum, cname in enumerate(headings)]
        # The formatting line consisting of variable column widths
        fline = ' '.join("%%%s%is" % (("-" if i == 0 else ""), j)
                         for i, j in enumerate(cwidths))
        vline = ' '.join(["%%%is" % j for i, j in enumerate(cwidths) if i > 0])
        clines = [
            fline % (tuple(cblocks[j][i] for j in range(nc)))
            for i in range(max(crows))
        ]
        tlines += clines
        PrintDict = OrderedDict([(key, vline % (tuple(val)))
                                 for key, val in data.items()])
        if len(clines[0]) > len(tlines[0]):
            centers = [0, 1]
        else:
            centers = [0]
        printcool_dictionary(PrintDict,
                             title='\n'.join(tlines),
                             keywidth=cwidths[0],
                             center=[i in centers for i in range(len(tlines))],
                             leftpad=4,
                             color=color)
Esempio n. 43
0
    def __init__(self,
                 User_Option,
                 ForceField,
                 Factor_Add=0.0,
                 Factor_Mult=0.0,
                 Factor_B=0.1,
                 Alpha=1.0,
                 Power=2.0):
        self.fadd = Factor_Add
        self.fmul = Factor_Mult
        self.a = Alpha
        self.b = Factor_B
        self.p = Power
        self.FF = ForceField
        self.ptyp = self.Pen_Names[User_Option.upper()]
        self.Pen_Tab = {
            1: self.HYP,
            2: self.L2_norm,
            3: self.BOX,
            4: self.FUSE,
            5: self.FUSE_L0,
            6: self.FUSE_BARRIER
        }
        if User_Option.upper() == 'L1':
            logger.info(
                "L1 norm uses the hyperbolic penalty, make sure penalty_hyperbolic_b is set sufficiently small\n"
            )
        elif self.ptyp == 1:
            logger.info(
                "Using hyperbolic regularization (Laplacian prior) with strength %.1e (+), %.1e (x) and tightness %.1e\n"
                % (Factor_Add, Factor_Mult, Factor_B))
        elif self.ptyp == 2:
            if Power == 2.0:
                logger.info(
                    "Using parabolic regularization (Gaussian prior) with strength %.1e (+), %.1e (x)\n"
                    % (Factor_Add, Factor_Mult))
            elif Power > 2.0:
                logger.info(
                    "Using customized L2-regularization with exponent %.1f, strength %.1e (+), %.1e (x)\n"
                    % (Power, Factor_Add, Factor_Mult))
            else:
                logger.error(
                    "In L2-regularization, penalty_power must be >= 2.0 (currently %.1f)\n"
                    % (Power))
                raise RuntimeError
        elif self.ptyp == 3:
            if Power == 2.0:
                logger.info(
                    "Using box-style regularization with exponent %.1f, strength %.1e (+), %.1e (x): same as L2\n"
                    % (Power, Factor_Add, Factor_Mult))
            elif Power > 2.0:
                logger.info(
                    "Using box-style regularization with exponent %.1f, strength %.1e (+), %.1e (x)\n"
                    % (Power, Factor_Add, Factor_Mult))
            else:
                logger.error(
                    "In box-style regularization, penalty_power must be >= 2.0 (currently %.1f)\n"
                    % (Power))
                raise RuntimeError
        elif self.ptyp == 4:
            logger.info(
                "Using L1 Fusion Penalty (only relevant for basis set optimizations at the moment) with strength %.1e\n"
                % Factor_Add)
        elif self.ptyp == 5:
            logger.info(
                "Using L0-L1 Fusion Penalty (only relevant for basis set optimizations at the moment) with strength %.1e and switching distance %.1e\n"
                % (Factor_Add, Alpha))
        elif self.ptyp == 6:
            logger.info(
                "Using L1 Fusion Penalty with Log Barrier (only relevant for basis set optimizations at the moment) with strength %.1e and barrier distance %.1e\n"
                % (Factor_Add, Alpha))
        if self.ptyp not in (2, 3) and Power != 2.0:
            logger.error(
                "Custom power %.2f is only supported with L2 or box-style regularization (penalty_type L2 or box)\n"
                % Power)
            raise RuntimeError

        ## Find exponential spacings.
        if self.ptyp in [4, 5, 6]:
            self.spacings = self.FF.find_spacings()
            printcool_dictionary(
                self.spacings,
                title="Starting zeta spacings\n(Pay attention to these)")