Ejemplo n.º 1
0
def MatrixMultiply ( extent, cpuTimer, ndg ):
    a = Real2DArray ( extent, extent ) ; a.Set ( 0.0 )
    b = Real2DArray ( extent, extent ) ; b.Set ( 0.0 )
    c = Real2DArray ( extent, extent ) ; c.Set ( 0.0 )
    for i in range ( extent ):
        for j in range ( extent ):
            a[i,j] = ndg.NextDeviate ( )
            b[i,j] = ndg.NextDeviate ( )
    tStart = cpuTimer.Current ( )
    c.MatrixMultiply ( a, b )
    return ( cpuTimer.Current ( ) - tStart )
 def AddLinearConstraint ( self, constraint ):
     """Add a linear constraint."""
     if len ( constraint ) != self.nvariables: raise ValueError ( "Invalid linear constraint length." )
     # . Orthogonalize to existing constraints.
     if self.linearVectors is not None:
         constraint = Clone ( constraint )
         self.linearVectors.ProjectOutOfArray ( constraint )
     # . Check to see if the constraint is valid.
     cnorm2 = constraint.Norm2 ( )
     if cnorm2 > 1.0e-10:
         constraint.Scale ( 1.0 / cnorm2 )
         # . Allocate space for new constraints.
         ncolumns = 1
         if self.linearVectors is not None: ncolumns += self.linearVectors.columns
         newconstraints = Real2DArray.WithExtents ( len ( constraint ), ncolumns )
         # . Copy over constraints.
         if self.linearVectors is not None:
             for r in range ( self.linearVectors.rows ):
                 for c in range ( self.linearVectors.columns ):
                     newconstraints[r,c] = self.linearVectors[r,c]
         for r in range ( len ( constraint ) ): newconstraints[r,ncolumns-1] = constraint[r]
         self.linearVectors = newconstraints
         # . Determine the linear scalars.
         self.linearScalars = Real1DArray.WithExtent ( self.linearVectors.columns )
         reference          = Real1DArray.WithExtent ( self.linearVectors.rows    )
         if self.rtReference is None: self.system.coordinates3.CopyToArray ( reference )
         else:                        self.rtReference.CopyToArray ( reference )
         self.linearVectors.VectorMultiply ( reference, self.linearScalars, 1.0, 0.0, transpose = True )
         # . Reset the number of degrees of freedom.
         self.degreesOfFreedom = self.nvariables - len ( self.linearScalars )
Ejemplo n.º 3
0
 def Initialize(self,
                pressure=_Default_Pressure,
                temperature=_Default_Temperature):
     """Create the arrays needed for the WHAM equations."""
     # . Initialization.
     handler = self.handler
     histogram = self.histogram
     if (handler is not None) and (histogram is not None):
         p0 = pressure * UNITS_PRESSURE_ATMOSPHERES_TO_KILOJOULES_PER_MOLE
         t0 = temperature * CONSTANT_MOLAR_GAS * 1.0e-3
         # . Gather pressures and temperatures.
         pressures = []
         temperatures = []
         for (p, t) in zip(handler.pressures, handler.temperatures):
             if p is None: p = pressure
             if t is None: t = temperature
             pressures.append(
                 p * UNITS_PRESSURE_ATMOSPHERES_TO_KILOJOULES_PER_MOLE)
             temperatures.append(t * CONSTANT_MOLAR_GAS * 1.0e-3)
         # . Create c which in the most general case is Exp ( - ( (Bj - B0) * U_i + (Bj*Pj - B0*P0) * V_i + Bj * SC_ji ) ).
         c = Real2DArray.WithExtents(handler.numberOfWindows,
                                     histogram.bins)
         c.Set(0.0)
         for (i, midPoint) in enumerate(histogram.BinMidPointIterator()):
             # . Energy.
             if handler.hasEnergy:
                 e = midPoint.pop(0)
                 for (j, tj) in enumerate(temperatures):
                     c[j, i] += e * (1.0 / tj - 1.0 / t0)
             # . Volume.
             if handler.hasVolume:
                 v = midPoint.pop(0)
                 for (j, pj) in enumerate(pressures):
                     c[j, i] += v * (pj / tj - p0 / t0)
             # . Soft constraints.
             for (j, tj) in enumerate(temperatures):
                 for (s, model) in zip(midPoint, handler.energyModels[j]):
                     c[j, i] += model.Energy(s)[0] / tj
         c.Scale(-1.0)
         c.Exp()
         # . Create the points arrays.
         m = Real1DArray.WithExtent(histogram.bins)
         m.Set(0.0)
         n = Real1DArray.WithExtent(handler.numberOfWindows)
         n.Set(0.0)
         for (i, v) in enumerate(histogram.counts):
             m[i] = float(v)
         for (i, v) in enumerate(handler.windowPoints):
             n[i] = float(v)
         # . Save all.
         self.pointsPerBin = m
         self.pointsPerWindow = n
         self.pressure = pressure
         self.temperature = temperature
         self.temperatureFactor = t0
         self.weightMatrix = c
Ejemplo n.º 4
0
def Eigenvalues ( extent, cpuTimer, ndg ):
    s = SymmetricMatrix ( extent         ) ; s.Set ( 0.0 )
    e = Real1DArray     ( extent         ) ; e.Set ( 0.0 )
    v = Real2DArray     ( extent, extent ) ; v.Set ( 0.0 )
    for i in range ( extent ):
        for j in range ( i+1 ): s[i,j] = ndg.NextDeviate ( )
        s[i,i] *= 2.0
    tStart = cpuTimer.Current ( )
    s. Diagonalize ( e, eigenVectors = v )
    return ( cpuTimer.Current ( ) - tStart )
def CoordinateFluctuations(*arguments, **keywordArguments):
    """Calculate the coordinate fluctuations for selected particles."""

    # . Initialization.
    fluctuations = None

    # . Get the trajectory and associated system data.
    (system, trajectories) = _GetSystemAndTrajectoriesFromArguments(*arguments)

    # . Get the selection and the size of the problem.
    selection = keywordArguments.pop("selection", None)
    if selection is None:
        selection = Selection.FromIterable(range(len(system.atoms)))
    n = len(selection)

    # . Get the average positions.
    averagePositions = keywordArguments.pop("averagePositions", None)
    if averagePositions is None:
        averagePositions = AveragePositions(trajectories, selection=selection)

    # . Various other options.
    anisotropic = keywordArguments.pop("anisotropic", False)
    asBFactors = keywordArguments.pop("asBFactors", False)
    _CheckForUnknownOptions(keywordArguments)

    # . Continue processing.
    if (n > 0) and (averagePositions is not None):

        # . Allocate space.
        displacement = Coordinates3.WithExtent(n)
        if anisotropic: fluctuations = Real2DArray.WithExtents(n, 6)
        else: fluctuations = Real1DArray.WithExtent(n)
        displacement.Set(0.0)
        fluctuations.Set(0.0)

        # . Loop over trajectory frames.
        numberFrames = 0
        for trajectory in trajectories:
            trajectory.ReadHeader()
            while trajectory.RestoreOwnerData():
                frame = system.coordinates3
                if anisotropic:
                    for (p, i) in enumerate(selection):
                        dx = frame[i, 0] - averagePositions[p, 0]
                        dy = frame[i, 1] - averagePositions[p, 1]
                        dz = frame[i, 2] - averagePositions[p, 2]
                        fluctuations[p, 0] += dx * dx
                        fluctuations[p, 1] += dy * dx
                        fluctuations[p, 2] += dy * dy
                        fluctuations[p, 3] += dz * dx
                        fluctuations[p, 4] += dz * dy
                        fluctuations[p, 5] += dz * dz
                else:
                    for (p, i) in enumerate(selection):
                        fluctuations[p] += ( ( frame[i,0] - averagePositions[p,0] )**2 + \
                                             ( frame[i,1] - averagePositions[p,1] )**2 + \
                                             ( frame[i,2] - averagePositions[p,2] )**2 )
            trajectory.ReadFooter()
            trajectory.Close()
            numberFrames += len(trajectory)

        # . Scale.
        if numberFrames > 0: fluctuations.Scale(1.0 / float(numberFrames))

        # . Convert to B-factors if necessary.
        if asBFactors:
            conversionFactor = 8.0 * math.pi**2
            if not anisotropic: conversionFactor /= 3.0
            fluctuations.Scale(conversionFactor)

    # . Finish up.
    return fluctuations
Ejemplo n.º 6
0
def JaguarBondOrders(infile,
                     outfile,
                     bondOrdertolerance=_DEFAULTBONDORDERTOLERANCE,
                     chargetolerance=_DEFAULTCHARGETOLERANCE,
                     log=logFile,
                     QCROSS=False):
    """Calculate bond orders given Jaguar input and output files."""

    # . Parse the input file.
    infile = JaguarInputFileReader(infile)
    infile.Parse()
    infile.Summary(log=logFile)

    # . Parse the output file.
    outfile = JaguarOutputFileReader(outfile)
    outfile.Parse()
    outfile.Summary(log=logFile)

    # . Get data from the files.
    # . Input.
    atomicNumbersi = getattr(infile, "atomicNumbers", None)
    coordinates3 = getattr(infile, "coordinates3", None)
    orbitalsets = getattr(infile, "orbitalsets", None)

    # . Output.
    atomicNumberso = getattr(outfile, "atomicNumbers", None)
    nfunctions = getattr(outfile, "nfunctions", None)
    overlap = getattr(outfile, "overlap", None)

    # . Check for coordinates.
    if coordinates3 is None:
        raise ValueError("The coordinate data is missing from the input file.")

    # . Check the orbital data.
    QOK = (orbitalsets is not None) and (len(orbitalsets) > 0)
    if QOK:
        if (len(orbitalsets) == 1) and ("" in orbitalsets):
            spinDensitiesRESTRICTED = True
        elif (len(orbitalsets)
              == 2) and ("alpha" in orbitalsets) and ("beta" in orbitalsets):
            spinDensitiesRESTRICTED = False
        else:
            QOK = False
    if not QOK: raise ValueError("Invalid orbital data on input file.")
    if spinDensitiesRESTRICTED: nbasisi = infile.orbitalsets[""][1]
    else: nbasisi = infile.orbitalsets["alpha"][1]

    # . Check the overlap.
    if (overlap is None):
        raise ValueError("The overlap matrix is missing from the output file.")
    nbasiso = overlap.Dimension()

    # . Check the array giving the number of functions per atom.
    #    print nfunctions, len ( nfunctions ), len ( atomicNumberso ), sum ( nfunctions ), nbasiso
    if (nfunctions is None) or (len(nfunctions) != len(atomicNumberso) or
                                (sum(nfunctions) != nbasiso)):
        raise ValueError(
            "Basis function data on the output file is missing or invalid.")

    # . Create the function index array.
    findices = []
    first = 0
    last = 0
    for f in nfunctions:
        last += f
        findices.append((first, last))
        first += f

    # . Check for compatibility between the data.
    QOK = (atomicNumbersi is not None) and (atomicNumberso is not None) and (
        len(atomicNumbersi) == len(atomicNumberso)) and (nbasisi == nbasiso)
    if QOK:
        for (i, j) in zip(atomicNumbersi, atomicNumberso):
            if i != j:
                QOK = False
                break
    if not QOK:
        raise ValueError(
            "The systems on the input and output files are incompatible.")

    # . Set the keys for the calculation.
    if spinDensitiesRESTRICTED: keys = [""]
    else: keys = ["alpha", "beta"]

    # . Get the densities multiplied by the overlap.
    ps = {}
    for key in keys:
        p = _MakeDensity(orbitalsets[key])
        #        p.Print ( title = "**1**" )
        result = Real2DArray.WithExtents(nbasisi, nbasisi)
        result.Set(999.0)
        p.PostMultiply(overlap, result)
        #        overlap.Print ( title = "**2**" )
        #        result.Print ( title = "**3**" )
        ps[key] = result
#    f = STOP
# . Scale ps correctly for the spin-restricted case.
    if spinDensitiesRESTRICTED: ps[""].Scale(2.0)

    # . If cross terms are not required condense the ps matrices.
    if (not QCROSS) and (not spinDensitiesRESTRICTED):
        tps = ps.pop(keys[0])
        for key in keys[1:]:
            tps.AddScaledMatrix(1.0, ps[key])
        ps = {"": tps}
        keys = [""]

    # . Get the bond-orders.
    bondOrders = {}
    for key1 in keys:
        for key2 in keys:
            bondOrders[(key1, key2)] = _MakeBondOrders(ps[key1], ps[key2],
                                                       findices)

    # . Make the total bond-order if necessary.
    bokeys = bondOrders.keys()
    if len(bokeys) > 1:
        bokeys.sort()
        tbo = Clone(bondOrders[bokeys[0]])
        for key in bokeys[1:]:
            tbo.AddScaledMatrix(1.0, bondOrders[key])
        tkey = ("", "")
        bokeys.append(tkey)
        bondOrders[tkey] = tbo

    # . Compute the electronic contribution to the Mulliken charges.
    qmulliken = Real1DArray.WithExtent(len(atomicNumbersi))
    qmulliken.Set(0.0)
    for key in keys:
        _MakeElectronicMullikenCharges(ps[key], findices, qmulliken)

    # . Determine atom valencies.
    free = Real1DArray.WithExtent(len(atomicNumbersi))
    free.Set(0.0)
    valencies = Real1DArray.WithExtent(len(atomicNumbersi))
    valencies.Set(0.0)
    tbo = bondOrders[("", "")]
    for i in range(len(atomicNumbersi)):
        valencies[i] = (-2.0 * qmulliken[i]) - tbo[i, i]
        totalbo = 0.0
        for j in range(len(atomicNumbersi)):
            totalbo += tbo[i, j]
        free[i] = (-2.0 * qmulliken[i]) - totalbo

    # . Add in the core contributions to the Mulliken charges.
    for (i, q) in enumerate(atomicNumbersi):
        qmulliken[i] += float(q)
    if outfile.QECP:
        for (i, q) in enumerate(outfile.ecpelectrons):
            qmulliken[i] -= float(q)

    # . Output the results.
    if LogFileActive(log):

        # . Get the spin label.
        if spinDensitiesRESTRICTED: spinlabel = "Spin Restricted"
        else: spinlabel = "Spin Unrestricted"

        # . Create the atom names.
        atomnames = []
        for (i, n) in enumerate(atomicNumbersi):
            atomnames.append(PeriodicTable.Symbol(n, index=i + 1))

        # . Atom data.
        columns = [10, 20, 20, 20]
        if not spinDensitiesRESTRICTED: columns.append(20)
        table = log.GetTable(columns=columns)
        table.Start()
        table.Title("Atom Data (" + spinlabel + ")")
        table.Heading("Atom")
        table.Heading("Charge")
        table.Heading("Self Bond Order")
        table.Heading("Valence")
        if not spinDensitiesRESTRICTED: table.Heading("Free Valence")
        for (i, ni) in enumerate(atomnames):
            table.Entry(ni)
            table.Entry("{:.3f}".format(qmulliken[i]))
            table.Entry("{:.3f}".format(tbo[i, i]))
            table.Entry("{:.3f}".format(valencies[i]))
            if not spinDensitiesRESTRICTED:
                table.Entry("{:.3f}".format(free[i]))
        table.Stop()

        # . Bond orders.
        for key in bokeys:
            orders = bondOrders[key]
            table = log.GetTable(columns=[10, 10, 20, 20])
            table.Start()
            if key == ("", ""): table.Title("Total Bond Orders")
            else:
                table.Title(key[0].title() + "/" + key[1].title() +
                            " Bond Orders")
            table.Heading("Atom 1")
            table.Heading("Atom 2")
            table.Heading("Order")
            table.Heading("Distance")
            for (i, ni) in enumerate(atomnames):
                for (j, nj) in enumerate(atomnames[0:i]):
                    b = orders[i, j]
                    if math.fabs(b) > bondOrdertolerance:
                        table.Entry(ni)
                        table.Entry(nj)
                        table.Entry("{:.3f}".format(b))
                        table.Entry("{:.3f}".format(coordinates3.Distance(
                            i, j)))
            table.Stop()

        # . Checks on the calculation.
        # . Free valence.
        if spinDensitiesRESTRICTED:
            deviation = free.AbsoluteMaximum()
            if deviation > chargetolerance:
                log.Paragraph(
                    "Warning: the largest deviation between the free valence values and zero is {:.3f}."
                    .format(deviation))

        # . Total charge.
        deviation = math.fabs(qmulliken.Sum() - float(infile.charge))
        if deviation > chargetolerance:
            log.Paragraph(
                "Warning: the total charge deviates from the formal charge by {:.3f}."
                .format(deviation))

        # . Check for a valid reference set of Mulliken charges.
        qreference = getattr(outfile, "qmulliken", None)
        if (qreference is not None) and (len(qreference)
                                         == len(atomicNumbersi)):
            qmulliken.AddScaledArray(-1.0, qreference)
            deviation = qmulliken.AbsoluteMaximum()
            if deviation > chargetolerance:
                log.Paragraph(
                    "Warning: the largest deviation between calculated and read Mulliken charges is {:.3f}."
                    .format(deviation))

    # . Finish up.
    return bondOrders
Ejemplo n.º 7
0
 def ParseGuessSection(self, line):
     """Parse the guess section."""
     # . Get the terminator as the opening character of the current line.
     terminator = line[0:1]
     # . Get the guess basis.
     words = line.split(None, 1)
     if len(words) > 1:
         tokens = words[1].split("=", 1)
         if (len(tokens) > 1) and (tokens[0] == "basgss"):
             guessbasis = tokens[1].strip()
     # . Initialization.
     coefficients = None
     nbasis = None
     orbitals = None
     orbitalsets = {}
     key = ""
     nwarnings0 = self.nwarnings
     # . Loop until an end of section is reached
     while True:
         items = self.GetTokens()
         # . The end found.
         if (len(items) == 1) and (items[0] == terminator):
             break
         # . An orbital set header.
         elif (len(items) > 2) and (items[-2]
                                    == "Molecular") and (items[-1]
                                                         == "Orbitals"):
             key = " ".join(items[0:-2])
             orbitals = None
         # . An orbital line.
         elif ("Orbital" in items):
             # . Orbital data.
             if "Energy" in items:
                 energy = float(items[items.index("Energy") + 1])
             else:
                 energy = 0.0
             if "Occupation" in items:
                 occupancy = float(items[items.index("Occupation") + 1])
             else:
                 occupancy = 0.0
             if (nbasis is None) and (coefficients is not None):
                 nbasis = len(coefficients)
             coefficients = []
             # . Orbital set data.
             if orbitals is None: orbitals = []
             orbitals.append((energy, occupancy, coefficients))
             # . Orbital collection data.
             if key is not None:
                 if key in orbitalsets:
                     self.Warning("Orbital sets with duplicate names.",
                                  False)
                 else:
                     orbitalsets[key] = orbitals
                     key = None
         # . A coefficient line.
         elif (len(items) > 0) and (coefficients is not None):
             for item in items:
                 coefficients.append(float(item))
             if (nbasis is not None) and (len(coefficients) > nbasis):
                 self.Warning(
                     "There are orbitals with differing numbers of coefficients.",
                     False)
         # . Other lines.
         else:
             self.Warning("Unable to interpret guess section line.", False)
     # . Save the data if there have been no warnings.
     if (nwarnings0 == self.nwarnings) and (nbasis is not None):
         # . Initialization.
         self.orbitalsets = {}
         # . Process each of the orbital sets in turn.
         for (key, orbitals) in orbitalsets.iteritems():
             norbitals = len(orbitals)
             energies = Real1DArray.WithExtent(norbitals)
             occupancies = Real1DArray.WithExtent(norbitals)
             vectors = Real2DArray.WithExtents(nbasis, norbitals)
             for (i, (energy, occupancy,
                      coefficients)) in enumerate(orbitals):
                 energies[i] = energy
                 occupancies[i] = occupancy
                 for (j, v) in enumerate(coefficients):
                     vectors[j, i] = v
             self.orbitalsets[key.lower()] = (norbitals, nbasis, energies,
                                              occupancies, vectors)
Ejemplo n.º 8
0
def NormalModes_SystemGeometry(system,
                               hessian=None,
                               log=logFile,
                               modify=None,
                               title="Harmonic Frequencies (cm^(-1))"):
    """Determine the normal modes for a system."""

    # . Get some options.
    if modify is None: modopt = None
    else: modopt = modify.upper()

    # . Get the Hessian with mass-weighting.
    of = SystemGeometryObjectiveFunction.FromSystem(system)
    of.DefineWeights()
    n = of.NumberOfVariables()
    if hessian is None:
        x = Real1DArray.WithExtent(n)
        x.Set(0.0)
        of.VariablesGet(x)
        hessian = of.NumericalHessian(x)

    # . Get the mass-weighted rotation-translation vectors and count their number.
    of.RemoveRotationTranslation()
    if of.linearScalars is None: nrtmodes = 0
    else: nrtmodes = len(of.linearScalars)

    # . Modify the Hessian.
    if modopt in _MODIFYOPTIONS:
        if modopt == "PROJECT": hessian.ProjectOutVectors(of.linearVectors)
        elif modopt == "RAISE":
            hessian.Raise(of.linearVectors, _RAISEEIGENVALUE)

    # . Diagonalization.
    # . Maybe should save hessian here as it is destroyed by the diagonalization.
    eigenvalues = Real1DArray.WithExtent(n)
    eigenvalues.Set(0.0)
    eigenvectors = Real2DArray.WithExtents(n, n)
    eigenvectors.Set(0.0)
    hessian.Diagonalize(eigenvalues, eigenvectors)

    # . Convert eigenvalues to frequencies.
    for (i, e) in enumerate(eigenvalues):
        f = math.sqrt(math.fabs(e)) * _TO_WAVENUMBERS
        if e < 0.0: f *= -1.0
        eigenvalues[i] = f

    # . Un-mass-weight the modes.
    for r in range(n):
        w = 1.0 / of.variableWeights[r]
        for c in range(n):
            eigenvectors[r, c] *= w

    # . Do some printing.
    if LogFileActive(log):
        table = log.GetTable(columns=_NFREQUENCYCOLUMNS * [_FREQUENCYWIDTHS])
        table.Start()
        table.Title(title)
        for f in eigenvalues:
            table.Entry(_FREQUENCYFORMAT.format(f))
        table.Stop()

    # . Save all data.
    state = NormalModeState(dimension=n,
                            freeAtoms=of.freeAtoms,
                            frequencies=eigenvalues,
                            modes=eigenvectors,
                            nrtmodes=nrtmodes,
                            weights=of.variableWeights)
    system.configuration.SetTemporaryAttribute("nmState", state)

    # . Finish up.
    return state
Ejemplo n.º 9
0
def QuasiHarmonic_SystemGeometry(system,
                                 log=logFile,
                                 modify=None,
                                 temperature=300.0,
                                 title="Quasi-Harmonic Frequencies (cm^(-1))",
                                 trajectories=None):
    """Determine the quasi-harmonic modes for a system."""

    # . Initialization.
    state = None

    # . Determine if any atoms are fixed.
    hc = system.hardConstraints
    if (hc is not None) and (hc.fixedAtoms
                             is not None) and (len(hc.fixedAtoms) > 0):
        fixedAtoms = hc.fixedAtoms
    else:
        fixedAtoms = None

    # . Get the covariance matrix.
    covariance = CovarianceMatrix(trajectories, selection=fixedAtoms)

    # . Proceed with the analysis.
    if covariance is not None:

        # . Get some options.
        if modify is None: modopt = None
        else: modopt = modify.upper()

        # . Mass-weight the covariance matrix.
        # . Weights are square roots of masses.
        of = SystemGeometryObjectiveFunction.FromSystem(system)
        of.DefineWeights()
        n = of.NumberOfVariables()
        for i in range(n):
            wI = of.variableWeights[i]
            for j in range(i + 1):
                wJ = of.variableWeights[j]
                covariance[i, j] *= (wI * wJ)

        # . Get the mass-weighted rotation-translation vectors and count their number.
        of.RemoveRotationTranslation()
        if of.linearScalars is None: nrtmodes = 0
        else: nrtmodes = len(of.linearScalars)

        # . Modify the Hessian.
        if modopt in _MODIFYOPTIONS:
            if modopt == "PROJECT":
                covariance.ProjectOutVectors(of.linearVectors)
            elif modopt == "RAISE":
                covariance.Raise(of.linearVectors, 0.0)

        # . Diagonalization.
        eigenValues = Real1DArray.WithExtent(n)
        eigenValues.Set(0.0)
        eigenVectors = Real2DArray.WithExtents(n, n)
        eigenVectors.Set(0.0)
        covariance.Diagonalize(eigenValues, eigenVectors)

        # . Convert eigenvalues to frequencies.
        conversionFactor = math.sqrt(_TO_KJMOL * temperature) * _TO_WAVENUMBERS
        numberZero = 0
        for (i, e) in enumerate(eigenValues):
            eAbs = math.fabs(e)
            if eAbs <= _QHTolerance:
                f = 0.0
                numberZero += 1
            else:
                f = math.sqrt(1.0 / eAbs) * conversionFactor
                if e < 0.0: f *= -1.0
            eigenValues[i] = f

        # . Un-mass-weight the modes.
        for r in range(n):
            w = 1.0 / of.variableWeights[r]
            for c in range(n):
                eigenVectors[r, c] *= w

        # . Reverse in place (excluding zero modes).
        temporary = Real1DArray.WithExtent(n)
        for i in range((n - numberZero) // 2):
            # . Indices.
            lower = i + numberZero
            upper = n - i - 1
            # . Eigenvalues.
            e = eigenValues[upper]
            eigenValues[upper] = eigenValues[lower]
            eigenValues[lower] = e
            # . Eigenvectors.
            for j in range(n):
                temporary[j] = eigenVectors[j, upper]
            for j in range(n):
                eigenVectors[j, upper] = eigenVectors[j, lower]
            for j in range(n):
                eigenVectors[j, lower] = temporary[j]

        # . Do some printing.
        if LogFileActive(log):
            table = log.GetTable(columns=_NFREQUENCYCOLUMNS *
                                 [_FREQUENCYWIDTHS])
            table.Start()
            table.Title(title)
            for f in eigenValues:
                table.Entry(_FREQUENCYFORMAT.format(f))
            table.Stop()

        # . Save all data.
        state = NormalModeState(dimension=n,
                                freeAtoms=of.freeAtoms,
                                frequencies=eigenValues,
                                modes=eigenVectors,
                                nrtmodes=nrtmodes,
                                weights=of.variableWeights)
        system.configuration.SetTemporaryAttribute("qhState", state)

    # . Finish up.
    return state
Ejemplo n.º 10
0
def ESPChargeFitting(system,
                     aresp=_DEFAULT_ARESP,
                     bresp=_DEFAULT_BRESP,
                     log=logFile,
                     QRESP=False):
    """Perform an ESP charge fit."""

    # . Check for a system with a qcModel.
    if not (hasattr(system, "energyModel")
            and hasattr(system.energyModel, "qcModel")):
        raise ValueError("System does not have a QC energy model.")

    # . Initialization.
    natoms = len(system.energyModel.qcAtoms)
    ndim = natoms + 1
    qtotal = 0.0
    if hasattr(system, "electronicState"):
        qtotal = float(system.electronicState.charge)

    #    atomicNumbers = system.atoms.GetItemAttributes ( "atomicNumber" )
    #    qtotal = float ( sum ( atomicNumbers ) )

    # . Get the grid points for the QC atoms only and convert to bohrs.
    gridPoints = GenerateVanDerWaalsSurface(
        system, log=log, qcAtomsOnly=True, scalingfactors=[1.4, 1.6, 1.8, 2.0])
    gridPoints.Scale(UNITS_LENGTH_ANGSTROMS_TO_BOHRS)

    # . Allocate space - one larger than necessary for fInteraction.
    fInteraction = Real2DArray.WithExtents(ndim, gridPoints.rows)
    fInteraction.Set(0.0)

    # . Get the observed potentials at the grid points.
    phi = system.energyModel.qcModel.GridPointPotentials(
        system.configuration, gridPoints)

    # . Get the interaction terms for each atom at the grid points.
    coordinates3 = system.energyModel.qcAtoms.GetCoordinates3(
        system.coordinates3, toBohrs=True)
    GetInteractionTerms(coordinates3, gridPoints, fInteraction)

    # . Get the A matrix and the B vector.
    A = Real2DArray.WithExtents(ndim, ndim)
    A.Set(0.0)
    B = Real1DArray.WithExtent(ndim)
    B.Set(0.0)
    A.MatrixMultiply(fInteraction, fInteraction, yTranspose=True)
    fInteraction.VectorMultiply(phi, B)

    # . Add the total charge constraint terms.
    for i in range(natoms):
        A[i, ndim - 1] = 1.0
        A[ndim - 1, i] = 1.0
    B[ndim - 1] = qtotal

    #    A.Print ( )
    #    B.Print ( )
    #    phi.Print ( )

    # . Get |phi^2|.
    phi2 = phi.Dot(phi)

    # . Iterative solution.
    if QRESP:
        (isConverged, sos, solution, condition,
         rank) = RESPIterator(natoms,
                              A,
                              B,
                              fInteraction,
                              phi,
                              aresp,
                              bresp,
                              log=log)

    # . Non-iterative solution.
    else:

        # . Solve the equations.
        (condition, rank) = A.SolveLinearEquationsBySVD(B)
        solution = B

        # . Determine the sum of squares.
        fInteraction.VectorMultiply(solution,
                                    phi,
                                    alpha=-1.0,
                                    beta=1.0,
                                    transpose=True)
        sos = phi.Dot(phi)

    # . Determine the error measure.
    error = math.sqrt(sos / phi2)

    # . Do some printing.
    if LogFileActive(log):
        summary = log.GetSummary()
        summary.Start("ESP Charge Fitting Summary")
        summary.Entry("Charges", "{:d}".format(natoms))
        summary.Entry("Rank", "{:d}".format(rank))
        summary.Entry("Error", "{:.5g}".format(error))
        summary.Entry("Condition", "{:.5g}".format(condition))
        if QRESP:
            if isConverged: summary.Entry("Converged", "True")
            else: summary.Entry("Converged", "False")
        summary.Stop()

    # . Return the charges.
    charges = Real1DArray.WithExtent(natoms)
    for i in range(natoms):
        charges[i] = solution[i]
    return charges
Ejemplo n.º 11
0
def RESPIterator(natoms,
                 A,
                 rhs,
                 fInteraction,
                 phi,
                 aresp,
                 bresp,
                 ftolerance=_DEFAULT_FTOLERANCE,
                 log=logFile,
                 logFrequency=_DEFAULT_LOGFREQUENCY,
                 maximumIterations=_DEFAULT_MAXIMUMITERATIONS,
                 qtolerance=_DEFAULT_QTOLERANCE):
    """Solve the RESP equations by simple iteration."""

    # . Allocate space.
    n = len(rhs)
    Atemp = Real2DArray.WithExtents(n, n)
    Btemp = Real1DArray.WithExtent(n)
    phitemp = Real1DArray.WithExtent(len(phi))
    q = Real1DArray.WithExtent(n, initializer=0.0)  # . With initial values.
    qold = Real1DArray.WithExtent(n)

    # . Check for printing.
    QPRINT = (logFrequency > 0) and (logFrequency <
                                     maximumIterations) and LogFileActive(log)
    if QPRINT:
        table = log.GetTable(columns=[10, 20, 20, 20, 20, 10])
        table.Start()
        table.Title("RESP Solver")
        table.Heading("Iteration")
        table.Heading("Function")
        table.Heading("Change in F")
        table.Heading("Change in Q")
        table.Heading("Condition")
        table.Heading("Rank")

    # . Determine the sum of squares with initial zero charges.
    f = phi.Dot(phi)

    # . Initialization.
    niterations = 0
    isConverged = False

    # . Perform the iterations.
    while (niterations < maximumIterations) and (not isConverged):

        # . Save old data.
        fold = f
        q.CopyTo(qold)

        # . Fill new A and RHS.
        A.CopyTo(Atemp)
        rhs.CopyTo(Btemp)

        # . Add in the constraints.
        GetRESPConstraints(natoms, aresp, bresp, q, Atemp)

        # . Solve the equations.
        (condition, rank) = Atemp.SolveLinearEquationsBySVD(Btemp)
        Btemp.CopyTo(q)

        # . Determine the sum of squares.
        phi.CopyTo(phitemp)
        fInteraction.VectorMultiply(q,
                                    phitemp,
                                    alpha=-1.0,
                                    beta=1.0,
                                    transpose=True)
        f = phitemp.Dot(phitemp)

        # . Check for convergence.
        qold.AddScaledArray(-1.0, q)
        fdifference = math.fabs(fold - f)
        qdifference = qold.AbsoluteMaximum()
        isConverged = (fdifference < ftolerance) and (qdifference < qtolerance)

        # . Printing.
        if QPRINT and (niterations % logFrequency == 0):
            table.Entry("{:d}".format(niterations))
            table.Entry("{:.6g}".format(f))
            table.Entry("{:.6g}".format(fdifference))
            table.Entry("{:.6g}".format(qdifference))
            table.Entry("{:.6g}".format(condition))
            table.Entry("{:d}".format(rank))

        # . End of loop.
        niterations += 1

    # . Stop printing.
    if QPRINT:
        table.Stop()
        if isConverged: log.Paragraph("RESP procedure converged.")
        else: log.Paragraph("Warning: RESP procedure not converged.")

    # . Finish up.
    return (isConverged, f, q, condition, rank)