Example #1
0
 def WriteFrame(self, system, label=None, xyz=None):
     """Write a single frame."""
     # . Check the data.
     if xyz == None: xyz = system.coordinates3
     if (xyz is None) or (not isinstance(
             xyz, Coordinates3)) or (xyz.rows != len(system.atoms)):
         raise TextFileWriterError(
             "Invalid or missing data to write to Jaguar input file.")
     # . Check the label.
     if label is None: label = system.label
     if label is None: label = "Jaguar input file."
     # . Check the electronic state.
     if system.electronicState is None:
         charge = 0
         multip = 1
     else:
         charge = system.electronicState.charge
         multip = system.electronicState.multiplicity
     # . Header.
     self.file.write(label + "\n\n")
     # . General section.
     self.file.write("&gen\n")
     self.file.write("molchg={:d}\n".format(charge))
     self.file.write("multip={:d}\n".format(multip))
     self.file.write("&\n")
     # . Coordinates.
     self.file.write("&zmat\n")
     numbers = system.atoms.GetItemAttributes("atomicNumber")
     for (i, n) in enumerate(numbers):
         symbol = PeriodicTable.Symbol(n, index=i + 1)
         self.file.write("{:<5s}{:25.15f}{:25.15f}{:25.15f}\n".format(
             symbol, xyz[i, 0], xyz[i, 1], xyz[i, 2]))
     self.file.write("&\n")
    def runTest ( self ):
        """The test."""

        # . Initialization.
        isOK = True

        # . Output setup.
        dataPath = os.path.join ( os.getenv ( "PDYNAMO_PBABEL" ), "data", _Source )
        log = self.GetLog ( )

        # . Loop over the data.
        for ( label, isSpherical ) in _EMSLG94Data:

            # . Get the bases.
            bases = EMSLG94File_ToGaussianBases ( os.path.join ( dataPath, label + _Extension ), isSpherical = isSpherical )
            if log is not None:
                log.Paragraph ( "Processed bases for basis {:s} = {:d}.".format ( label, len ( bases ) ) )

            # . Check for an appropriate outPath.
            if self.resultPath is not None:
                outPath = os.path.join ( self.resultPath, _Destination )
                if not os.path.exists ( outPath ): os.mkdir ( outPath )
                outPath = os.path.join ( outPath, label.lower ( ) )
                if not os.path.exists ( outPath ): os.mkdir ( outPath )

                # . Save the bases.
                for basis in bases:
                    symbol = PeriodicTable.Symbol ( basis.atomicNumber )
                    YAMLPickle ( os.path.join ( outPath, symbol + YAMLPickleFileExtension ), basis )

        # . Success/failure.
        self.assertTrue ( isOK )
 def AtomToken(self, atom):
     """Return a SMILES token for an atom."""
     # . Check for a reduced atom representation.
     # . Basic checks.
     QREDUCED = (atom.atomicNumber
                 in ELEMENTSORGANIC) and (atom.formalCharge
                                          == 0) and (atom.isotope <= 0)
     # . Check for the expected number of implicit hydrogens (also ensures the atom has standard valence).
     if QREDUCED:
         valence = atom.valence - atom.implicithydrogens
         for v in VALENCIESORGANIC[atom.atomicNumber]:
             hcount = v - valence
             if hcount >= 0: break
         QREDUCED = (atom.implicithydrogens == hcount)
     # . Check for a reduced chirality representation.
     if atom.chiralityclass is not None:
         QCHIRALITYREDUCED = (CHIRALITYDEFAULTCLASSES.get(
             atom.connections,
             None) == atom.chiralityclass) and (atom.chiralitynumber <= 4)
         QREDUCED = QREDUCED and QCHIRALITYREDUCED
         # . Generate the string.
         if QCHIRALITYREDUCED: ctoken = atom.chiralitynumber * "@"
         else:
             ctoken = "@" + atom.chiralityclass + "{:d}".format(
                 atom.chiralitynumber)
     else:
         ctoken = ""
     # . Encode the string.
     if atom.isAromatic:
         atoken = PeriodicTable.Symbol(atom.atomicNumber).lower()
     else:
         atoken = PeriodicTable.Symbol(atom.atomicNumber)
     tokens = [atoken, ctoken]
     if not QREDUCED:
         tokens[0:0] = "["
         if atom.isotope != 0: tokens[1:1] = "{:d}".format(isotope)
         if atom.implicithydrogens == 1: tokens.append("H")
         elif atom.implicithydrogens > 1:
             tokens.append("H" + "{:d}".format(atom.implicithydrogens))
         if atom.formalCharge < 0:
             tokens.append("{:d}".format(atom.formalCharge))
         elif atom.formalCharge > 0:
             tokens.append("+" + "{:d}".format(atom.formalCharge))
         tokens.append("]")
     return "".join(tokens)
def _GetHardSphereRadii(atoms):
    """Get the hard-sphere radii for the atoms."""
    hsradii = Real1DArray.WithExtent(len(atoms))
    hsradii.Set(0.0)
    atomicNumbers = atoms.GetItemAttributes("atomicNumber")
    for (i, atomicNumber) in enumerate(atomicNumbers):
        try:
            hsradii[i] = _HSRADII[atomicNumber]
        except:
            raise KeyError("Hard-sphere radius for element " +
                           PeriodicTable.Symbol(atomicNumber) + " unknown.")
    return hsradii
Example #5
0
 def WriteFrame ( self, system, label = None, xyz = None ):
     """Write a single frame."""
     # . Check the data.
     if xyz == None: xyz = system.coordinates3
     if ( xyz is None ) or ( not isinstance ( xyz, Coordinates3 ) ) or ( xyz.rows != len ( system.atoms ) ): raise TextFileWriterError ( "Invalid or missing data to write to XYZ file." )
     # . Check the label.
     if label is None: label = system.label
     # . Write the frame.
     self.file.write ( "{:6d}\n".format ( len ( system.atoms ) ) )
     if label is None:
         self.file.write ( "\n" )
     else:
         if len ( label ) > _MaximumLabelLength: label = label[0:_MaximumLabelLength]
         self.file.write ( label + "\n" )
     numbers = system.atoms.GetItemAttributes ( "atomicNumber" )
     for i in range ( xyz.rows ):
         symbol = PeriodicTable.Symbol ( numbers[i] )
         self.file.write ( "{:<5s}{:25.15f}{:25.15f}{:25.15f}\n".format ( symbol, xyz[i,0], xyz[i,1], xyz[i,2] ) )
Example #6
0
 def WriteFrame(self, system, label=None, xyz=None):
     """Write a single frame."""
     # . Get data.
     natoms = len(system.atoms)
     nbonds = len(system.connectivity.bonds)
     # . Check the data.
     if xyz == None: xyz = system.coordinates3
     if (xyz is None) or (not isinstance(
             xyz, Coordinates3)) or (xyz.rows != natoms):
         raise TextFileWriterError(
             "Invalid or missing data to write to MOL2 file.")
     # . Check the label.
     if label is None: label = system.label
     # . Molecule block.
     self.file.write(_RTISTRING + "MOLECULE\n")
     if label is None: self.file.write("\n")
     else:
         self.file.write(
             label.strip()[0:min(len(label), _MAXIMUMLINELENGTH)] + "\n")
     self.file.write("{:d} {:d}\n".format(natoms, nbonds))
     self.file.write(_MOLECULETYPE + "\n")
     self.file.write(_CHARGETYPE + "\n")
     self.file.write("\n")
     # . Atom block.
     self.file.write(_RTISTRING + "ATOM\n")
     for (i, atom) in enumerate(system.atoms):
         self.file.write(
             "{:6d} {:<6s} {:10.4f} {:10.4f} {:10.4f}   {:s}\n".format(
                 i + 1, PeriodicTable.Symbol(atom.atomicNumber, index=i),
                 xyz[i, 0], xyz[i, 1], xyz[i, 2], _ATOMTYPE))
     self.file.write("\n")
     # . Bond block.
     self.file.write(_RTISTRING + "BOND\n")
     for (i, bond) in enumerate(system.connectivity.bonds):
         self.file.write("{:6d} {:6d} {:6d} {:<s}\n".format(
             i + 1, bond.i + 1, bond.j + 1, _MOL2BONDTYPES[bond.type]))
     self.file.write("\n")
     # . Symmetry block.
     if system.symmetryParameters is not None:
         p = system.symmetryParameters
         self.file.write(_RTISTRING + "CRYSIN\n")
         self.file.write(
             "{:.3f} {:.3f} {:.3f} {:.1f} {:.1f} {:.1f}  1  1\n".format(
                 p.a, p.b, p.c, p.alpha, p.beta, p.gamma))
Example #7
0
def CreateElementSequence(system, entityDescription=None, entityLabel="E"):
    """Create a sequence of a single entity using element symbols for atom names and components and one atom per component."""
    # . Initialization.
    minorSeparator = Sequence.defaultAttributes["fieldSeparator"]
    sequence = Sequence()
    entity = SequenceEntity(label=entityLabel)
    sequence.AddChild(entity)
    # . Process the atoms.
    for (index, atom) in enumerate(system.atoms):
        symbol = PeriodicTable.Symbol(atom.atomicNumber).upper()
        component = SequenceComponent(genericLabel=symbol,
                                      label=symbol + minorSeparator +
                                      repr(index + 1))
        entity.AddChild(component)
        component.AddChild(atom)
        atom.index = index
        atom.label = symbol
    # . Finish up.
    system.__dict__["_sequence"] = sequence
Example #8
0
 def WriteFrame(self, system, label=None, xyz=None):
     """Write a single frame."""
     # . Check the data.
     if xyz == None: xyz = system.coordinates3
     if (xyz is None) or (not isinstance(
             xyz, Coordinates3)) or (xyz.rows != len(system.atoms)):
         raise TextFileWriterError(
             "Invalid or missing data to write to MOL file.")
     # . Check the label.
     if label is None: label = system.label
     # . Write the header block.
     if label is None: self.file.write("\n\n\n")
     else:
         self.file.write(
             label.strip()[0:min(len(label), _MAXIMUMLINELENGTH)] +
             "\n\n\n")
     # . Counts line.
     self.file.write("{:3d}{:3d}".format(len(system.atoms),
                                         len(system.connectivity.bonds)) +
                     8 * "  0" + "999 V2000\n")
     # . Atom block.
     for (i, atom) in enumerate(system.atoms):
         self.file.write("{:10.4f}{:10.4f}{:10.4f} {:<2s}".format(
             xyz[i, 0], xyz[i, 1], xyz[i, 2],
             PeriodicTable.Symbol(atom.atomicNumber)) + 5 * "  0" + "\n")
     # . Bond block.
     for (i, bond) in enumerate(system.connectivity.bonds):
         self.file.write("{:3d}{:3d}{:3d}".format(
             bond.i + 1, bond.j + 1, _MOLBONDTYPES[bond.type]) + 3 * "  0" +
                         "\n")
     # . Properties block.
     for (i, atom) in enumerate(system.atoms):
         formalCharge = getattr(atom, "formalCharge", 0)
         if formalCharge != 0:
             self.file.write("M  CHG  1{:4d}{:4d}\n".format(
                 i + 1, formalCharge))
     self.file.write("M  END\n")
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
def SolvateSystemBySuperposition ( solute, solvent, log = logFile, excludeHydrogens = True, reorientSolute = True, printPairs = False, scaleradii = 0.75 ):
    """Solvate a system by superposition."""

    # . Check that the solvent has a full connectivity.
    if not solvent.connectivity.HasFullConnectivity ( ): raise ValueError ( "The solvent must have a full connectivity." )

    # . Create a sequence.
    if solute.sequence is not None:
        entityLabel = DetermineUniqueEntityLabel ( solute, label = "W" )
        CreateHomogeneousIsolateSequence ( solvent, entityLabel = entityLabel )

    # . Merge the two systems.
    solution = MergeByAtom ( solute, solvent )

    # . Get the atom masses and selections corresponding to the solute and solvent atoms.
    masses       = solution.atoms.GetItemAttributes ( "mass" )
    nsolute      = len ( solute.atoms  )
    nsolvent     = len ( solvent.atoms )
    soluteatoms  = Selection.FromIterable ( range ( nsolute                     ) )
    solventatoms = Selection.FromIterable ( range ( nsolute, nsolute + nsolvent ) )

    # . Reorient the solute coordinates if required.
    if reorientSolute: solution.coordinates3.ToPrincipalAxes ( selection = soluteatoms, weights = masses )

    # . Check the extents of the solute and solvent - to ensure the box is big enough!
    ( origin1, extents1 ) = solution.coordinates3.EnclosingOrthorhombicBox ( selection = soluteatoms  )
    ( origin2, extents2 ) = solution.coordinates3.EnclosingOrthorhombicBox ( selection = solventatoms )
    extents2.AddScaledVector3 ( -1.0, extents1 )
    if min ( extents2 ) < 0.0: raise ValueError ( "It is likely that the solvent box is too small for the solute." )

    # . Move the center of the solute atoms to that of the solvent atoms.
    translation = Clone ( origin2 )
    translation.AddScaledVector3 (  0.5, extents2 )
#    translation.AddScaledVector3 ( -0.5, extents1 ) # . Not needed as done above.
    translation.AddScaledVector3 ( -1.0, origin1  )
    solution.coordinates3.Translate ( translation, selection = soluteatoms )

    # . Reduce the selections if hydrogens are to be excluded.
    if excludeHydrogens:
        indices = []
        for i in soluteatoms:
            if solution.atoms[i].atomicNumber != 1: indices.append ( i )
        soluteatoms = Selection.FromIterable ( indices )
        indices = []
        for i in solventatoms:
            if solution.atoms[i].atomicNumber != 1: indices.append ( i )
        solventatoms = Selection.FromIterable ( indices )

    # . Get the radii.
    radii = solution.atoms.GetItemAttributes ( "vdwRadius" )
    radii.Scale ( scaleradii )

    # . Get the pairlist.
    pairlist = CrossPairList_FromSingleCoordinates3 ( solution.coordinates3, selection1 = solventatoms, selection2 = soluteatoms, radii = radii )
    npairs   = len ( pairlist )

    # . Find the solvent atoms in the pairlist (which are the first indices in the list).
    indices = set ( )
    for ( i, j ) in pairlist: indices.add ( i )

    # . Now find the indices of all the atoms in the corresponding solvent isolates.
    if len ( indices ) > 0:
        toremove  = solution.connectivity.isolates.GetAllIndices ( Selection.FromIterable ( indices ) )
        ntoremove = len ( toremove )
        # . Remove unwanted atoms.
        reduced = PruneByAtom ( solution, toremove.Complement ( upperBound = nsolute + nsolvent ) )
        if solution.sequence is not None: RenumberEntityComponents ( reduced, entityLabels = [ entityLabel ] )
    else:
        ntoremove = 0
        reduced   = solution

    # . Set the symmetry of solution by copying that of solvent.
    if ( solvent.symmetry is not None ) and ( solvent.symmetryParameters is not None ):
        keywordArguments = solvent.symmetryParameters.__getstate__ ( )
        keywordArguments["crystalClass"]    = solvent.symmetry.crystalClass
        keywordArguments["transformations"] = solvent.symmetry.transformations
        reduced.DefineSymmetry ( **keywordArguments )

    # . Do some printing.
    if LogFileActive ( log ):

        # . Distances.
        if printPairs:
            table   = log.GetTable ( columns = [ 10, 10, 20, 20 ] )
            table.Start ( )
            table.Title ( "Solute/Solvent Pairs" )
            table.Heading ( "Solvent"  )
            table.Heading ( "Solute"   )
            table.Heading ( "Distance" )
            table.Heading ( "Cutoff"   )
            for ( i, j ) in pairlist:
                table.Entry ( PeriodicTable.Symbol ( solution.atoms[i].atomicNumber, index = i ) )
                table.Entry ( PeriodicTable.Symbol ( solution.atoms[j].atomicNumber, index = j ) )
                table.Entry ( "{:.3f}".format ( solution.coordinates3.Distance ( i, j ) ) )
                table.Entry ( "{:.3f}".format ( radii[i] + radii[j]                     ) )
            table.Stop ( )

        # . Summary.
        summary = log.GetSummary ( )
        summary.Start ( "Solvation By Superposition Summary" )
        summary.Entry ( "Solute Atoms"         , "{:d}".format ( nsolute              ) )
        summary.Entry ( "Solvent Atoms"        , "{:d}".format ( nsolvent - ntoremove ) )
        summary.Entry ( "Atoms Removed"        , "{:d}".format ( ntoremove            ) )
        summary.Entry ( "Solute/Solvent Pairs" , "{:d}".format ( npairs               ) )
        summary.Stop ( )

    # . Finish up.
    return reduced
Example #11
0
}

# . Chirality.
_CHIRALITYFULL = {"AL": "AL", "OH": "OH", "SP": "SP", "TB": "TB", "TH": "TH"}
_CHIRALITYREDUCED = {
    "@": ("??", 1),
    "@@": ("??", 2),
    "@@@": ("??", 3),
    "@@@@": ("??", 4)
}

# . Element data.
# . All element tokens.
_ELEMENTTOKENS = {}
for atomicNumber in PeriodicTable.AtomicNumbers():
    _ELEMENTTOKENS[PeriodicTable.Symbol(atomicNumber)] = (atomicNumber, False)
for atomicNumber in ELEMENTSAROMATIC:
    _ELEMENTTOKENS[string.lower(
        PeriodicTable.Symbol(atomicNumber))] = (atomicNumber, True)

# . Tokens for elements that can take a reduced representation (outside of square brackets).
_REDUCEDELEMENTTOKENS = {}
for atomicNumber in ELEMENTSORGANIC:
    _REDUCEDELEMENTTOKENS[PeriodicTable.Symbol(atomicNumber)] = (atomicNumber,
                                                                 False)
    if atomicNumber in ELEMENTSAROMATIC:
        _REDUCEDELEMENTTOKENS[string.lower(
            PeriodicTable.Symbol(atomicNumber))] = (atomicNumber, True)

# . Hydrogen count.
_HCOUNTTOKENS = {"H": 1}
    def WriteSystem(self,
                    system,
                    data=None,
                    occupancies=None,
                    QCONECT=False,
                    selection=None,
                    suppressICodeField=False,
                    temperatureFactors=None,
                    title=None,
                    useSegmentEntityLabels=False):
        """Write out a system.

        |system|    is the system to be written.
        |data|      is the data to be written. The coordinates of system are written if |data| is absent.
        |QCONECT|   is the option for writing CONECT records. If |QCONECT| is True all connections are written (not just those to heteroatoms).
        |selection| gives the atoms to write. The default is to write all atoms.
        |title|     is an optional title.
        """
        # . Check |system|.
        if not isinstance(system, System):
            raise TypeError("Invalid |system| argument.")

        # . Get the sequence.
        sequence = getattr(system, "sequence", None)
        if sequence is None:
            sequence = Sequence.FromAtomContainer(system.atoms,
                                                  componentLabel="UNK.1")

        # . Get the coordinate data.
        if isinstance(data, Coordinates3): xyz = data
        else: xyz = system.coordinates3
        if xyz is None:
            raise TypeError(
                "Unable to obtain coordinate data from |system| or |data| arguments."
            )

        # . Check that the PDB model and coordinates are consistent.
        if len(system.atoms) != xyz.rows:
            raise TypeError(
                "The PDB model and coordinate data are of different lengths.")

        # . Get the selection.
        if selection is None: towrite = range(len(system.atoms))
        else: towrite = selection

        # . Get polymer terminating atoms as the last atom of the terminating component.
        polymerTerminatingAtoms = set()
        for polymer in sequence.linearPolymers:
            polymerTerminatingAtoms.add(
                polymer.rightTerminalComponent.children[-1])

        # . Get the label.
        label = None
        if isinstance(title, basestring): label = title.upper()
        elif isinstance(system.label, basestring): label = system.label.upper()
        if (label is not None) and (len(label) > _MAXIMUMTITLELENGTH):
            label = label[0:_MAXIMUMTITLELENGTH]

        # . Check for extra data.
        hasOccupancies = (occupancies is not None) and (len(occupancies)
                                                        == len(system.atoms))
        hasTemperatureFactors = (temperatureFactors
                                 is not None) and (len(temperatureFactors)
                                                   == len(system.atoms))

        # . Start writing.
        self.Open()
        # . Header.
        self.file.write(
            _HEADERLINEFORMAT.format("HEADER", "UNKNOWN",
                                     time.strftime("%d-%b-%y").upper()))
        # . Title.
        if (label is not None):
            self.file.write(_TITLELINEFORMAT.format("TITLE", label))
        # . Author.
        self.file.write(
            _AUTHORLINEFORMAT.format("AUTHOR", "GENERATED BY PDYNAMO",
                                     PDYNAMO_VERSION))
        # . Compound.
        self.file.write(_COMPOUNDLINEFORMAT.format("COMPND", "UNKNOWN"))
        # . Initialization.
        natm = 0
        ncon = 0
        nter = 0
        cIndices = {}
        # . Loop over atom indices.
        for iatom in towrite:
            # . Get data.
            atom = system.atoms[iatom]
            # . Atom data.
            element = PeriodicTable.Symbol(atom.atomicNumber).upper()
            if element == "*": element = ""
            # . Component data.
            (resName, resSeq, iCode) = sequence.ParseLabel(atom.parent.label,
                                                           fields=3)
            # . Entity data.
            entityLabel = atom.parent.parent.label
            if useSegmentEntityLabels:
                chainID = ""
                segID = entityLabel[0:4]
            else:
                chainID = entityLabel[0:1]
                segID = ""
            # . Atom output.
            if resName in _STANDARDRESIDUES: recordname = "ATOM"
            else: recordname = "HETATM"
            # . Output label.
            label = atom.label
            if len(label) >= 4: outputlabel = label[0:4]
            elif label[0:1].isdigit(): outputlabel = label
            else: outputlabel = " " + label
            # . Extra data.
            if hasOccupancies: occupancy = occupancies[iatom]
            else: occupancy = 0.0
            if hasTemperatureFactors:
                temperatureFactor = temperatureFactors[iatom]
            else:
                temperatureFactor = 0.0
            # . Output the line.
            if suppressICodeField:
                self.file.write(
                    _ATOMLINEFORMAT2.format(recordname, natm + nter + 1,
                                            outputlabel, " ", resName[0:3],
                                            chainID, resSeq[:5], xyz[iatom, 0],
                                            xyz[iatom, 1], xyz[iatom, 2],
                                            occupancy, temperatureFactor,
                                            segID, element, " "))
            else:
                self.file.write(
                    _ATOMLINEFORMAT1.format(recordname, natm + nter + 1,
                                            outputlabel, " ", resName[0:3],
                                            chainID, resSeq[:4], iCode,
                                            xyz[iatom, 0], xyz[iatom,
                                                               1], xyz[iatom,
                                                                       2],
                                            occupancy, temperatureFactor,
                                            segID, element, " "))
            # . Save the atom index.
            cIndices[iatom] = (natm + nter + 1)
            # . Polymer termination output.
            if atom in polymerTerminatingAtoms:
                nter += 1
                if suppressICodeField:
                    self.file.write(
                        _TERLINEFORMAT2.format("TER", natm + nter + 1, resName,
                                               chainID, resSeq))
                else:
                    self.file.write(
                        _TERLINEFORMAT1.format("TER", natm + nter + 1, resName,
                                               chainID, resSeq, iCode))
            # . Increment natm.
            natm += 1
        # . Connection data.
        if QCONECT and (system.connectivity.bonds
                        is not None) and (len(system.connectivity.bonds) > 0):
            system.connectivity.bonds.MakeConnections()
            for iatom in towrite:
                # . Get the connections.
                iconnections = system.connectivity.bonds.GetConnectedAtoms(
                    iatom)  # . Normal indices.
                # . Transform to pdb indices.
                iindex = cIndices[iatom]
                jindices = []
                for j in iconnections:
                    jindex = cIndices.get(j, -1)
                    if jindex > 0: jindices.append(jindex)
                # . Output.
                nindices = len(jindices)
                if nindices > 0:
                    for i in range(0, nindices, _NCONECTS):
                        self.file.write(
                            _CONECTLINEFORMAT1.format("CONECT", iindex))
                        for j in range(i, min(i + _NCONECTS, nindices)):
                            self.file.write(
                                _CONECTLINEFORMAT2.format(jindices[j]))
                        self.file.write("\n")
                        ncon += 1
        # . Master.
        self.file.write(
            _MASTERLINEFORMAT.format("MASTER", 0, 0, 0, 0, 0, 0, 0, 0,
                                     len(system.atoms), nter, ncon, 0))
        # . End.
        self.file.write(_ENDLINEFORMAT.format("END"))
        self.Close()
    def WriteSystem ( self, system, datalabel = _DEFAULTDATALABEL ):
        """Write out a system."""

        # . Check |system|.
        if not isinstance ( system, System ): raise TypeError ( "Invalid |system| argument." )

        # . Get the sequence and other data.
        sequence = getattr ( system, "sequence", None )
        if sequence is None: sequence = Sequence.FromAtomContainer ( system.atoms, componentLabel = "UNK.1" )
        xyz = system.coordinates3

        # . Find which entities are linear polymers.
        polymerEntities = set ( )
        for polymer in sequence.linearPolymers:
            polymerEntities.add ( polymer.leftTerminalComponent.parent  )
            polymerEntities.add ( polymer.rightTerminalComponent.parent )

        # . Start writing.
        self.Open ( )

        # . Initial comment.
        self.file.write ( "# . mmCIF file generated by pMolecule {:s} on {:s}.\n".format ( PDYNAMO_VERSION, time.strftime ( "%d-%b-%y" ) ) )

        # . Data header.
        self.file.write ( "data_" + datalabel.strip ( ) + "\n" )

        # . Atoms.
        self.file.write ( _ATOMSITEHEADER )
        self.file.write ( "loop_\n" )
        self.file.write ( "_atom_site.id\n"                )
        self.file.write ( "_atom_site.type_symbol\n"       )
        self.file.write ( "_atom_site.label_atom_id\n"     )
        self.file.write ( "_atom_site.label_comp_id\n"     )
        self.file.write ( "_atom_site.label_seq_id\n"      )
        self.file.write ( "_atom_site.auth_seq_id\n"       )
        self.file.write ( "_atom_site.pdbx_PDB_ins_code\n" )
        self.file.write ( "_atom_site.cartn_x\n"           )
        self.file.write ( "_atom_site.cartn_y\n"           )
        self.file.write ( "_atom_site.cartn_z\n"           )
        self.file.write ( "_atom_site.label_asym_id\n"     )
        self.file.write ( "_atom_site.label_entity_id\n"   )
        sequenceAtoms = sequence.GatherAtoms ( )
        for atom in sequenceAtoms:
            index   = atom.index
            element = PeriodicTable.Symbol ( system.atoms[index].atomicNumber )
            # . Entity data.
            entity      = atom.parent.parent
            fields      = sequence.ParseLabel ( entity.label, fields = 1 )
            asymlabel   = fields[0]
            if len ( asymlabel ) <= 0: asymlabel     = _UNDEFINEDCHARACTER
            entitylabel = entity.label
            if len ( entitylabel ) <= 0: entitylabel = _UNDEFINEDCHARACTER
            # . Component data.
            fields = sequence.ParseLabel ( atom.parent.label, fields = 3 )
            name          = fields[0]
            esequence     = fields[1]
            insertioncode = fields[2]
            if len ( insertioncode ) <= 0: insertioncode = _UNDEFINEDCHARACTER
            if entity in polymerEntities: psequence = esequence
            else:                         psequence = _UNDEFINEDCHARACTER
            self.file.write ( "{:6d} {:<3s} {:<5s} {:<4s} {:<6s} {:<6s} {:<2s} {:10.5f} {:10.5f} {:10.5f}  {:<2s}  {:<s}\n".format ( index, element, atom.label, name, psequence, esequence, insertioncode, xyz[index,0], xyz[index,1], xyz[index,2], asymlabel, entitylabel ) )
        # . Entities.
        npolymer = 0
        self.file.write ( _ENTITYHEADER )
        self.file.write ( "loop_\n" )
        self.file.write ( "_entity.id\n"   )
        self.file.write ( "_entity.type\n" )
        for entity in sequence.children:
            label = entity.label
            if len ( label ) <= 0: label = _UNDEFINEDCHARACTER
            entityType = "Non-Polymer"
            if entity in polymerEntities:
                entityType = "Polymer"
                npolymer += 1
            self.file.write ( "{:<10s} {:s}\n".format ( label, entityType ) )
        # . Entities - polymer sequence.
        if npolymer > 0:
            self.file.write ( _ENTITYPOLYMERSEQUENCEHEADER )
            self.file.write ( "loop_\n" )
            self.file.write ( "_entity_poly_seq.entity_id\n" )
            self.file.write ( "_entity_poly_seq.mon_id\n"    )
            self.file.write ( "_entity_poly_seq.num\n"       )
            for entity in sequence.children:
                if entity in polymerEntities:
                    label = entity.label
                    if len ( label ) <= 0: label = _UNDEFINEDCHARACTER
                    oldname     = None
                    oldsequence = None
                    for component in entity.children:
                        fields      = sequence.ParseLabel ( component.label, fields = 2 )
                        name        = fields[0]
                        newSequence = fields[1]
                        if ( name != oldname ) and ( newSequence != oldsequence ):
                            self.file.write ( "{:<10s} {:<4s} {:<6s}\n".format ( label, name, newSequence ) )
                            oldname     = name
                            oldsequence = newSequence
        # . Finish up.
        self.Close ( )