Пример #1
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
Пример #2
0
 def ParseECPs(self):
     """Parse the ECP section."""
     # . Initialization.
     ecpelectrons = []
     # . Header.
     self.GetLine()  # . Blank line.
     self.GetLine()  # . Table header.
     # . Loop over atom lines.
     while True:
         tokens = self.GetTokens()
         # . Blank line.
         if len(tokens) == 0:
             break
             # . Atom line.
         elif len(tokens) == 2:
             atomicNumber = PeriodicTable.AtomicNumber(tokens[0])
             if (atomicNumber > 0): ecpelectrons.append(int(tokens[1]))
     # . Finish up.
     self.ecpelectrons = ecpelectrons
     self.QECP = True
Пример #3
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")
Пример #4
0
def BuildHydrogenCoordinates3FromConnectivity(system,
                                              log=logFile,
                                              randomNumberGenerator=None):
    """Build hydrogen coordinates.

    The coordinates are built using connectivity information only (bonds
    and angles) which means that no account is taken of non-connectivity
    information (such as hydrogen-bonding). These interactions will have
    to be optimized separately using energy minimization or dynamics.

    Note that bonds to other hydrogens are ignored and unbound hydrogens
    or hydrogens linked to more than one heavy atom will not be built."""

    # . Check for a system object.
    if isinstance(system, System) and (system.connectivity is not None) and (
            system.connectivity.HasFullConnectivity()):

        # . Check whether there are undefined coordinates.
        coordinates3 = system.coordinates3
        numberUndefined0 = coordinates3.numberUndefined
        if numberUndefined0 > 0:

            # . Initialization.
            bonds = system.connectivity.bonds
            direction = Vector3.Null()
            if randomNumberGenerator is None:
                randomNumberGenerator = RandomNumberGenerator.WithRandomSeed()

            # . Loop over heavy atoms with defined coordinates.
            for (c, atom) in enumerate(system.atoms):
                if (atom.atomicNumber !=
                        1) and (c not in coordinates3.undefined):

                    # . Initialization.
                    built = []
                    builth = []
                    tobuild = []
                    unbuildable = []

                    # . Loop over the connected atoms.
                    others = bonds.GetConnectedAtoms(c)
                    for i in others:
                        other = system.atoms[i]
                        QBUILT = (i not in coordinates3.undefined)
                        # . Hydrogens.
                        if other.atomicNumber == 1:
                            if QBUILT: builth.append(i)
                            elif len(bonds.GetConnectedAtoms(i)) == 1:
                                tobuild.append(i)
                            else:
                                unbuildable.append(i)
                        # . Other atoms.
                        else:
                            if QBUILT: built.append(i)
                            else: unbuildable.append(i)

                    # . Skip this atom if the number of connections is greater than four, there are no hydrogens to build or there are unbuildable atoms.
                    if (len(others) > 4) or (len(tobuild)
                                             == 0) or (len(unbuildable) > 0):
                        continue

                    # . Order the lists and put built hydrogens after built heavy atoms as it is reasoned that heavy atom coordinates will be more reliable.
                    built.sort()
                    builth.sort()
                    tobuild.sort()
                    built += builth

                    # . Get coordination data for the center.
                    nconnections = len(built) + len(tobuild)
                    bondlength = PeriodicTable.Element(
                        atom.atomicNumber).GetSingleBondDistance(1)
                    if bondlength is None: bondlength = _DEFAULTBONDDISTANCE
                    angle = PeriodicTable.Element(
                        atom.atomicNumber).GetCoordinationAngle(nconnections)
                    if angle is None:
                        angle = _COORDINATIONANGLES.get(nconnections, 0.0)
                    planeangle = _COORDINATIONPLANEANGLES.get(
                        nconnections, 0.0)

                    # . Build the hydrogens.
                    while len(tobuild) > 0:

                        # . Get the hydrogen index.
                        h = tobuild.pop(0)

                        # . Build according to the number of built connected atoms.
                        nbuilt = len(built)

                        # . Get a random normalized vector.
                        if (nbuilt == 0) or (nbuilt == 1):
                            for i in range(3):
                                direction[i] = 2.0 * (
                                    randomNumberGenerator.NextReal() - 0.5)
                            direction.Normalize()

                        # . Put the hydrogen in a random direction from the center.
                        # . Works for all cases.
                        if nbuilt == 0:
                            coordinates3.BuildPointFromDistance(
                                h, c, bondlength, direction)

                            # . Put the hydrogen at the correct angle from the center and built atom but in a random plane.
                            # . Works for all cases given correct choice of angle.
                        elif nbuilt == 1:
                            coordinates3.BuildPointFromDistanceAngle(
                                h, c, built[0], bondlength, angle, direction)

                        # . Put the hydrogen away from the other built points at an appropriate angle from their plane.
                        # . The sign of the plane angle is arbitrary.
                        # . Works for cases 3, 4, 5 (square pyramidal), 6 with correct choice of planeangle.
                        elif nbuilt == 2:
                            coordinates3.BuildPointFromDistancePlaneAngle(
                                h, c, built[0], built[1], bondlength,
                                planeangle)

                        # . Put the hydrogen using a tetrahedral tripod.
                        # . Only works for tetrahedral coordination.
                        elif nbuilt == 3:
                            coordinates3.BuildPointFromDistanceTetrahedralTripod(
                                h, c, built[0], built[1], built[2], bondlength)

                        # . Cannot handle valencies greater than 4 for the moment.
                        else:
                            break

                        # . The hydrogen has been built.
                        built.append(h)
                        coordinates3.FlagCoordinateAsDefined(h)

            # . Output a summary.
            if LogFileActive(log):
                numberToBuild = coordinates3.numberUndefined
                numberBuilt = (numberUndefined0 - numberToBuild)
                if numberBuilt <= 0:
                    log.Paragraph("Coordinates for no hydrogens were built.")
                elif numberBuilt == 1:
                    log.Paragraph("Coordinates for one hydrogen were built.")
                else:
                    log.Paragraph(
                        "Coordinates for {:d} hydrogens were built.".format(
                            numberBuilt))
 def ToSystem(self, mmModel=None, parameters=None):
     """Create a system."""
     system = None
     if self.QPARSED:
         # . Get the sequence.
         sequence = self.ToSequence()
         # . Basic system.
         system = System.FromSequence(sequence)
         system.label = " ".join(self.title)
         # . Assign atomic numbers from masses.
         for (datum, atom) in zip(self.atoms, system.atoms):
             atom.atomicNumber = PeriodicTable.AtomicNumberFromMass(
                 datum[7])
         # . The MM model.
         if mmModel is None: mmModel = MMModelCHARMM()
         # . Build the model but only when PSF files are in XPLOR format.
         if (mmModel is not None) and (parameters
                                       is not None) and (self.isXPLOR):
             system.DefineMMModel(mmModel, buildModel=False)
             # . The MM atoms.
             mm = self.ToMMAtomContainer()
             if mm is not None: system.energyModel.mmAtoms = mm
             # . Various MM terms.
             mmTerms = []
             mm = self.ToHarmonicBondContainer(
                 rawParameters=parameters.bonds)
             if mm is not None: mmTerms.append(mm)
             mm = self.ToHarmonicAngleContainer(
                 rawParameters=parameters.angles)
             if mm is not None: mmTerms.append(mm)
             mm = self.ToHarmonicUreyBradleyContainer(
                 rawParameters=parameters.ureybradleys)
             if mm is not None: mmTerms.append(mm)
             mm = self.ToFourierDihedralContainer(
                 rawParameters=parameters.dihedrals,
                 rawParametersWild=parameters.dihedralwilds)
             if mm is not None: mmTerms.append(mm)
             mm = self.ToHarmonicImproperContainer(
                 rawParameters=parameters.impropers,
                 rawParametersWild=parameters.improperwilds)
             if mm is not None: mmTerms.append(mm)
             mm = self.ToCMAPDihedralContainer(
                 rawParameters=parameters.cmaps)
             if mm is not None: mmTerms.append(mm)
             if len(mmTerms) > 0:
                 system.energyModel.mmTerms = MMTermContainer(mmTerms)
             # . Exclusions.
             (exclusions, interactions14) = self.ToExclusionPairLists()
             if exclusions is not None:
                 system.energyModel.exclusions = exclusions
             if interactions14 is not None:
                 system.energyModel.interactions14 = interactions14
             # . LJ terms.
             ( ljParameters, ljParameters14 ) = self.ToLJParameterContainers ( parameters   = parameters.nonbonds  , parametersWild   = parameters.nonbondwilds,  \
                                                                               parameters14 = parameters.nonbond14s, parameters14Wild = parameters.nonbond14wilds )
             if ljParameters is not None:
                 system.energyModel.ljParameters = ljParameters
             if ljParameters14 is not None:
                 system.energyModel.ljParameters14 = ljParameters14
         # . Fixed atoms - do after MM model so MM terms are appropriately affected.
         self.ToFixedAtoms(system)
     return system
Пример #6
0
 def GetAtomicNumber ( token ):
     """Convert a token into an atomic number."""
     symbol = token.upper ( )
     if   symbol == _DUMMYATOM:           return -3
     elif symbol in _NONDUMMYATOMSYMBOLS: return -2
     else: return PeriodicTable.AtomicNumber ( token )
Пример #7
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
Пример #8
0
 def AddAtomSite(self, **kwargs):
     """Add an atom site."""
     atom = None
     if self.QFINALIZED:
         raise ValueError("Cannot add an atom site to a finalized model.")
     else:
         # . Initialization.
         warningtag = "Atom Site {:d}".format(len(self.atoms))
         # . Get the entity.
         auth_asym_id = mmCIFModel.FetchFromKeywordArguments(
             kwargs, "auth_asym_id")
         label_asym_id = mmCIFModel.FetchFromKeywordArguments(
             kwargs, "label_asym_id")
         label_entity_id = mmCIFModel.FetchFromKeywordArguments(
             kwargs, "label_entity_id")
         entitykey = mmCIFModelEntity.MakeKey(label_entity_id,
                                              label_asym_id)
         entity = self.entities.get(entitykey, None)
         if entity is None: entity = self.AddEntity(entitykey)
         # . Check the alternate name.
         if entity is not None:
             if entity.alternateasymlabel is None:
                 entity.alternateasymlabel = auth_asym_id
             elif entity.alternateasymlabel != auth_asym_id:
                 self.Warning(
                     warningtag,
                     "Mismatch in alternate names for entity asymmetric unit - "
                     + entity.alternateasymlabel + " and " + auth_asym_id +
                     ".", False)
             # . Get the component.
             auth_comp_id = mmCIFModel.FetchFromKeywordArguments(
                 kwargs, "auth_comp_id")
             auth_seq_id = mmCIFModel.FetchFromKeywordArguments(
                 kwargs, "auth_seq_id")
             insertioncode = mmCIFModel.FetchFromKeywordArguments(
                 kwargs, "pdbx_pdb_ins_code")
             name = mmCIFModel.FetchFromKeywordArguments(
                 kwargs, "label_comp_id")
             sequencenumber = mmCIFModel.FetchFromKeywordArguments(
                 kwargs, "label_seq_id")
             if name == _UNDEFINEDCHARACTER:
                 name = auth_comp_id
                 auth_comp_id = None
             if sequencenumber == _UNDEFINEDCHARACTER:
                 sequencenumber = auth_seq_id
                 auth_seq_id = None
             componentkey = mmCIFModelComponent.MakeKey(
                 name, sequencenumber, insertioncode)
             component = entity.components.get(componentkey, None)
             if component is None:
                 component = entity.AddComponent(componentkey)
                 self.components.append(component)
             # . Check alternate names.
             if component is not None:
                 if auth_comp_id is not None:
                     if component.alternatename is None:
                         component.alternatename = auth_comp_id
                     elif component.alternatename != auth_comp_id:
                         self.Warning(
                             warningtag,
                             "Mismatch in alternate names for component - "
                             + component.alternatename + " and " +
                             auth_comp_id + ".", False)
                 if auth_seq_id is not None:
                     if component.alternatesequence is None:
                         component.alternatesequence = auth_seq_id
                     elif component.alternatesequence != auth_seq_id:
                         self.Warning(
                             warningtag,
                             "Mismatch in alternate sequences for component - "
                             + component.alternatesequence + " and " +
                             auth_seq_id + ".", False)
                 # . Get the atom data.
                 atomicNumber = PeriodicTable.AtomicNumber(
                     mmCIFModel.FetchFromKeywordArguments(
                         kwargs, "type_symbol"))
                 auth_atom_id = mmCIFModel.FetchFromKeywordArguments(
                     kwargs, "auth_atom_id")
                 name = mmCIFModel.FetchFromKeywordArguments(
                     kwargs, "label_atom_id")
                 if name == _UNDEFINEDCHARACTER:
                     name = auth_atom_id
                     auth_atom_id = None
                 atom = component.atoms.get(name, None)
                 atomKey = name
                 if atom is None:
                     atom = component.AddAtom(name,
                                              atomicNumber=atomicNumber,
                                              entity=entity)
                     self.atoms.append(atom)
                 # . Check alternate labels.
                 if atom is not None:
                     if auth_comp_id is not None:
                         if atom.alternatelabel is None:
                             atom.alternatelabel = auth_atom_id
                         elif atom.alternatelabel != auth_atom_id:
                             self.Warning(
                                 warningtag,
                                 "Mismatch in alternate labels for atom - "
                                 + atom.alternatelabel + " and " +
                                 auth_atom_id + ".", False)
                     # . Get the atom data.
                     label_alt_id = mmCIFModel.FetchFromKeywordArguments(
                         kwargs, "label_alt_id")
                     pdbx_pdb_model_num = mmCIFModel.FetchFromKeywordArguments(
                         kwargs,
                         "pdbx_pdb_model_num",
                         default=_DEFAULTMODELNUMBER)
                     self.altLocs.add(label_alt_id)
                     self.modelNumbers.add(pdbx_pdb_model_num)
                     datakey = mmCIFModelAtomData.MakeKey(
                         label_alt_id, pdbx_pdb_model_num)
                     data = atom.data.get(datakey, None)
                     if data is None:
                         try:
                             x = mmCIFModel.ToFloat(
                                 mmCIFModel.FetchFromKeywordArguments(
                                     kwargs, "cartn_x"))
                             y = mmCIFModel.ToFloat(
                                 mmCIFModel.FetchFromKeywordArguments(
                                     kwargs, "cartn_y"))
                             z = mmCIFModel.ToFloat(
                                 mmCIFModel.FetchFromKeywordArguments(
                                     kwargs, "cartn_z"))
                             occupancy = mmCIFModel.ToFloat(
                                 mmCIFModel.FetchFromKeywordArguments(
                                     kwargs, "occupancy"),
                                 default=_DEFAULTOCCUPANCY)
                         except:
                             self.Warning(
                                 warningtag,
                                 "Unable to convert atom site floating point data.",
                                 False)
                         atom.data[datakey] = mmCIFModelAtomData(
                             altLoc=label_alt_id,
                             atom=atom,
                             model=pdbx_pdb_model_num,
                             x=x,
                             y=y,
                             z=z,
                             occupancy=occupancy)
                     else:
                         self.Warning(
                             warningtag, "Adding duplicate atomsite (" +
                             _MAJORSEPARATOR.join([
                                 datakey, atomKey, componentkey, entitylabel
                             ]) + ") to model.", False)
     return atom
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
Пример #10
0
    "----": -4
}

# . 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.
Пример #11
0
 def ParseAtomBlock(self, line, QLOOP):
     """Parse the block with atom information."""
     # . Initialization.
     atoms = []
     QFIRST = True
     if QLOOP:
         # . Initialization.
         index = {}
         converters = []
         QATOMS = False
         # . Atom lines.
         while True:
             if not QFIRST: line = self.GetLine()
             if line.startswith("#"):
                 break
                 # . Column headers.
             elif not QATOMS:
                 if line.startswith("_chem_comp_atom.atom_id"):
                     index["atom_id"] = len(converters)
                     converters.append(None)
                 elif line.startswith("_chem_comp_atom.charge"):
                     index["charge"] = len(converters)
                     converters.append(int)
                 elif line.startswith("_chem_comp_atom.comp_id"):
                     index["comp_id"] = len(converters)
                     converters.append(None)
                 elif line.startswith("_chem_comp_atom.pdbx_align"):
                     index["pdbx_align"] = len(converters)
                     converters.append(int)
                 elif line.startswith("_chem_comp_atom.type_symbol"):
                     index["type_symbol"] = len(converters)
                     converters.append(PeriodicTable.AtomicNumber)
                 elif line.startswith("_chem_comp_atom."):
                     converters.append(None)
                 else:
                     QATOMS = True
             # . Atoms.
             if QATOMS:
                 tokens = self.ParseTokens(line, converters=converters)
                 atoms.append ( PDBComponentAtom ( atomicNumber = tokens[index["type_symbol"]],  \
                                                   formalCharge = tokens[index["charge"     ]],  \
                                                   label        = tokens[index["atom_id"    ]],  \
                                                   pdbAlign     = tokens[index["pdbx_align" ]] ) )
             QFIRST = False
     # . Single atom.
     else:
         while True:
             if not QFIRST: line = self.GetLine()
             tokens = self.ParseTokens(line)
             if tokens[0] == "#": break
             elif len(tokens) > 2: self.Warning("Too many tokens.", True)
             elif tokens[0] == "_chem_comp_atom.atom_id": label = tokens[1]
             elif tokens[0] == "_chem_comp_atom.charge":
                 formalCharge = int(tokens[1])
             elif tokens[0] == "_chem_comp_atom.pdbx_align":
                 pdbAlign = int(tokens[1])
             elif tokens[0] == "_chem_comp_atom.type_symbol":
                 atomicNumber = PeriodicTable.AtomicNumber(tokens[1])
             QFIRST = False
         atoms.append ( PDBComponentAtom ( atomicNumber = atomicNumber,  \
                                           formalCharge = formalCharge,  \
                                           label        = label,         \
                                           pdbAlign     = pdbAlign     ) )
     # . Finish up.
     self.active.atoms = atoms
Пример #12
0
    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()
Пример #13
0
    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 ( )
def HardSphereIonMobilities(molecule,
                            nreflections=30,
                            ntrajectories=600000,
                            randomNumberGenerator=None,
                            temperature=298.0,
                            log=logFile):
    """Calculate ion mobilities with a hard-sphere model."""

    # . Get the atom data.
    hsradii = _GetHardSphereRadii(molecule.atoms)
    masses = molecule.atoms.GetItemAttributes("mass")
    totalmass = masses.Sum()

    # . Get initial coordinates, move to center of mass and convert to metres.
    xyz0 = Clone(molecule.coordinates3)
    xyz0.TranslateToCenter(weights=masses)
    xyz0.Scale(1.0e-10)

    # . Get the mass constant.
    massHe = PeriodicTable.Element(2).mass
    massconstant = _MASSCONSTANT * math.sqrt((1.0 / massHe) +
                                             (1.0 / totalmass))

    # . Get the random number generator.
    if randomNumberGenerator is None:
        randomNumberGenerator = RandomNumberGenerator.WithRandomSeed()
    rotation = Matrix33.Null()

    # . Initialize some calculation variables.
    cof = Real1DArray.WithExtent(nreflections)
    cof.Set(0.0)
    crof = Real1DArray.WithExtent(nreflections)
    crof.Set(0.0)
    crb = 0.0
    mreflections = 0

    # . Loop over the trajectories.
    for it in range(ntrajectories):

        # . Randomly rotate the coordinate set.
        rotation.RandomRotation(randomNumberGenerator)
        xyz = Clone(xyz0)
        xyz.Rotate(rotation)

        # . Loop over the collisions.
        QCOLLISION = False
        for ir in range(nreflections):

            # . Initial collision - at a random point in the yz plane along the x-axis.
            if ir == 0:
                (origin, extents) = xyz.EnclosingOrthorhombicBox(radii=hsradii)
                yzarea = extents[1] * extents[2]
                yc = origin[1] + extents[1] * randomNumberGenerator.NextReal()
                zc = origin[2] + extents[2] * randomNumberGenerator.NextReal()
                xaxis = Vector3.WithValues(1.0, 0.0, 0.0)
            # . Subsequent collisions - always along the x-axis.
            else:
                yc = 0.0
                zc = 0.0

            # . Initialization.
            ic = -1  # . The index of the colliding particle.
            xc = origin[0] + extents[0]  # . The largest x-coordinate.

            # . Loop over particles.
            for (i, h) in enumerate(hsradii):
                # . After the first collision only x-values > 0 are allowed.
                if (ir == 0) or (xyz[i, 0] > 1.0e-16):
                    # . yd and zd are the coordinates of the impact points for the ith atom
                    # . with respect to its own coordinates (if such a point exists).
                    # . dev is the impact parameter.
                    h2 = h * h
                    y = yc - xyz[i, 1]
                    z = zc - xyz[i, 2]
                    yz2 = y * y + z * z
                    # . If there is a collision with the ith atom, check to see if it occurs before previous collisions.
                    if yz2 < h2:
                        x = xyz[i, 0] - math.sqrt(h2 - yz2)
                        if x < xc:
                            xc = x
                            ic = i

            # . Check mreflections.
            if ir >= mreflections: mreflections = ir + 1

            # . There was a collision.
            if ic >= 0:
                QCOLLISION = True
                # . Translate the coordinates so that the collision point is at the origin.
                xyz.Translate(Vector3.WithValues(-xc, -yc, -zc))
                # . Rotate the coordinates so that the outgoing vector is along the x-axis.
                h = xyz.GetRow(
                    ic
                )  # . Normalized vector from the collision point to the ic-th atom.
                h.Normalize(tolerance=1.0e-20)
                axis = Vector3.WithValues(
                    0.0, h[2], -h[1])  # . Normalized axis of rotation.
                axis.Normalize(tolerance=1.0e-20)
                alpha = math.pi - 2.0 * math.acos(h[0])  # . Angle of rotation.
                rotation.RotationAboutAxis(alpha, axis)
                xyz.Rotate(rotation)
                rotation.ApplyTo(xaxis)
                # . Calculate the cosine of the angle between the incoming vector and the normal to a plane,
                # . the reflection from which would be equivalent to the accumulated reflection.
                # . This is equal to h[0] when ir = 0.
                cof[ir] = math.cos(0.5 * (math.pi - math.acos(xaxis[0])))
                # . Check outgoing.
                # . Get the outgoing vector (the ingoing vector is always [1,0,0]).
                out = Vector3.WithValues(1.0 - 2.0 * h[0] * h[0],
                                         -2.0 * h[0] * h[1],
                                         -2.0 * h[0] * h[2])
                rotation.ApplyTo(out)
                out[0] -= 1.0
                if out.Norm2() > 1.0e-6:
                    print(
                        "Invalid Rotation: {:10.3f} {:10.3f} {:10.3f}.".format(
                            out[0], out[1], out[2]))
            # . There was no collision.
            else:
                # . Top up the remaining elements of cof with the last valid value of cof.
                if ir == 0: t = 0.0
                else: t = cof[ir - 1]
                for i in range(ir, nreflections):
                    cof[i] = t
                # . Exit.
                break

        # . End of collisions.
        # . Projection approximation.
        if QCOLLISION: crb += yzarea
        # . Hard-sphere approximation.
        for ir in range(nreflections):
            crof[ir] += yzarea * cof[ir] * cof[ir]

    # . End of trajectories.
    crof.Scale(2.0 / float(ntrajectories))
    pacs = crb / float(ntrajectories)
    pamob = massconstant / (pacs * math.sqrt(temperature))
    hscs = crof[mreflections - 1]
    hsmob = massconstant / (hscs * math.sqrt(temperature))

    # . Output results.
    if LogFileActive(log):
        summary = log.GetSummary()
        summary.Start("Hard-Sphere Ion Mobilities")
        summary.Entry("MC Trajectories", "{:d}".format(ntrajectories))
        summary.Entry("Reflection Limit", "{:d}".format(nreflections))
        summary.Entry("PA Mobility", "{:.4g}".format(pamob))
        summary.Entry("PA Cross-Section", "{:.4g}".format(pacs * 1.0e+20))
        summary.Entry("HS Mobility", "{:.4g}".format(hsmob))
        summary.Entry("HS Cross-Section", "{:.4g}".format(hscs * 1.0e+20))
        summary.Entry("Max. Reflections", "{:d}".format(mreflections))
        summary.Stop()

    # . Finish up.
    results = {
        "MC Trajectories": ntrajectories,
        "Reflection Limit": nreflections,
        "PA Mobility": pamob,
        "PA Cross-Section": pacs * 1.0e+20,
        "HS Mobility": hsmob,
        "HS Cross-Section": hscs * 1.0e+20,
        "Maximum Reflections": mreflections
    }
    return results
Пример #15
0
def GenerateVanDerWaalsSurface(system,
                               gridangularmomentum=21,
                               log=logFile,
                               qcAtomsOnly=False,
                               scalingfactors=[1.0]):
    """Generate a superposition of van der Waals surfaces represented by grid points."""

    # . QC atoms only (including link atoms).
    if qcAtomsOnly:
        qcAtoms = system.energyModel.qcAtoms
        atomicNumbers = qcAtoms.GetAtomicNumbers()
        coordinates3 = qcAtoms.GetCoordinates3(system.coordinates3)
    # . All atoms.
    else:
        atomicNumbers = system.atoms.GetItemAttributes("atomicNumber")
        coordinates3 = system.coordinates3

    # . Find the number of atoms.
    natoms = len(atomicNumbers)

    # . Set radii.
    radii = Real1DArray.WithExtent(natoms)
    for (i, n) in enumerate(atomicNumbers):
        radii[i] = PeriodicTable.Element(n).vdwRadius

    # . Get the grid points for a single center.
    (basicgrid, weights) = LebedevLaikovGrid_GetGridPoints(gridangularmomentum)

    # . Allocate space for the possible number of grid points.
    npossible = natoms * basicgrid.rows * len(scalingfactors)
    gridPoints = Coordinates3.WithExtent(npossible)
    gridPoints.Set(0.0)

    # . Initialization.
    nfound = 0
    atomgrid = Coordinates3.WithExtent(basicgrid.rows)
    translation = Vector3.Null()
    atomgrid.Set(0.0)

    # . Loop over scaling factors.
    for factor in scalingfactors:

        # . Loop over points.
        for i in range(natoms):

            # . Get the radius.
            iradius = factor * radii[i]

            # . Get the translation.
            translation[0] = coordinates3[i, 0]
            translation[1] = coordinates3[i, 1]
            translation[2] = coordinates3[i, 2]

            # . Get the scaled grid centered at the point.
            basicgrid.CopyTo(atomgrid)
            atomgrid.Scale(iradius)
            atomgrid.Translate(translation)

            # . Remove points that are within the current scaled radii of other points.
            for p in range(atomgrid.rows):
                QOK = True
                x = atomgrid[p, 0]
                y = atomgrid[p, 1]
                z = atomgrid[p, 2]
                for j in range(natoms):
                    if j != i:
                        dx = coordinates3[j, 0] - x
                        dy = coordinates3[j, 1] - y
                        dz = coordinates3[j, 2] - z
                        jradius2 = (factor * radii[j])**2
                        if (dx**2 + dy**2 + dz**2) <= jradius2:
                            QOK = False
                            break
                if QOK:
                    gridPoints[nfound, 0] = x
                    gridPoints[nfound, 1] = y
                    gridPoints[nfound, 2] = z
                    nfound += 1

    # . Reduce the array size if necessary.
    if nfound < npossible:
        newpoints = Coordinates3.WithExtent(nfound)
        for p in range(nfound):
            newpoints[p, 0] = gridPoints[p, 0]
            newpoints[p, 1] = gridPoints[p, 1]
            newpoints[p, 2] = gridPoints[p, 2]
        gridPoints = newpoints

    # . Create a system.
#    from pBabel  import XYZFile_FromSystem
#    from pMolecule import System
#    ngrid = gridPoints.rows
#    junk = System ( ngrid * [ 1 ] )
#    junk.coordinates3 = gridPoints
#    XYZFile_FromSystem ( "junk.xyz", junk )

# . Do some printing.
    if LogFileActive(log):
        summary = log.GetSummary()
        summary.Start("van der Waals Surface Generation Summary")
        summary.Entry("Atoms", "{:d}".format(natoms))
        summary.Entry("Surfaces", "{:d}".format(len(scalingfactors)))
        summary.Entry("Found Points", "{:d}".format(nfound))
        summary.Entry("Possible Points", "{:d}".format(npossible))
        summary.Stop()

    # . Finish up.
    return gridPoints