def LinearlyInterpolate(selfClass, path, system, npoints, point0, pointn): """Generate structures on a trajectory by linear interpolation between two end points.""" # . Check the number of points. npoints = max(npoints, 2) # . Check for fixed atoms. hasFixedAtoms = (system.hardConstraints is not None) and ( system.hardConstraints.NumberOfFixedAtoms() > 0) # . Create the trajectory. self = selfClass(path, system, mode="w") # . Create an intermediate array. xyz = Clone(pointn) if not hasFixedAtoms: xyz.Superimpose(point0) # . Find the step. dxyz = Clone(xyz) dxyz.AddScaledMatrix(-1.0, point0) dxyz.Scale(1.0 / float(npoints - 1)) # . First point. self.WriteFrame(point0) # . Intermediate and last points. point0.CopyTo(xyz) for i in range(npoints - 1): xyz.AddScaledMatrix(1.0, dxyz) self.WriteFrame(xyz) return self
def CrystalCenterCoordinates(system, log=logFile, mode="bymmisolate", selection=None): """Center the coordinates of a system in the primary image.""" # . Initialization. coordinates3 = None translations = None # . Basic checks. if isinstance(system, System) and (system.symmetry is not None) and ( system.coordinates3 is not None) and (system.symmetryParameters is not None): # . Check the centering mode. option = mode.lower() if (option not in _CENTERINGOPTIONS): raise ValueError("Unknown centering mode: " + option + ".") # . Get a set of cloned coordinates. coordinates3 = Clone(system.coordinates3) # . By atom. if (option == "byatom"): system.symmetryParameters.CenterCoordinatesByAtom( coordinates3, selection=selection) # . By isolate. elif (option == "byisolate"): if (system.isolates is None): raise ValueError("Isolates for the system are not defined.") else: system.symmetryParameters.CenterCoordinatesByIsolate( coordinates3, system.isolates, selection=selection) # . By MM isolate. elif (option == "bymmisolate"): mmisolates = _GetMMIsolates(system) system.symmetryParameters.CenterCoordinatesByIsolate( coordinates3, mmisolates, selection=selection) # . Get the translations. translations = Clone(coordinates3) translations.AddScaledMatrix(-1.0, system.coordinates3) return (coordinates3, translations)
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