All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.poznan.put.structure.BasePair Maven / Gradle / Ivy

package pl.poznan.put.structure;

import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.immutables.value.Value;
import pl.poznan.put.atom.AtomName;
import pl.poznan.put.pdb.PdbAtomLine;
import pl.poznan.put.pdb.PdbNamedResidueIdentifier;
import pl.poznan.put.pdb.analysis.PdbResidue;

import java.io.Serializable;
import java.util.stream.Stream;

/** A pairing between two nucleotides' bases. */
@Value.Immutable
public abstract class BasePair implements Serializable, Comparable {
  private static final double GU_DISTANCE_O6_N3 = 2.83 + (0.13 * 3.0);
  private static final double GU_DISTANCE_N1_O2 = 2.79 + (0.13 * 3.0);
  private static final double AU_DISTANCE_N6_O4 = 3.00 + (0.17 * 3.0);
  private static final double AU_DISTANCE_N1_N3 = 2.84 + (0.12 * 3.0);
  private static final double CG_DISTANCE_N4_O6 = 2.96 + (0.17 * 3.0);
  private static final double CG_DISTANCE_O2_N2 = 2.77 + (0.15 * 3.0);
  private static final double CG_DISTANCE_N3_N1 = 2.89 + (0.11 * 3.0);

  /**
   * Checks if two residues are canonical base pairs by means of (1) distance between atoms which
   * form hydrogen bonds and (2) checking if two bases face each other.
   *
   * @param left First residue.
   * @param right Second residue.
   * @return True if there is a pair of C-G, A-U or G-U.
   */
  public static boolean isCanonicalPair(final PdbResidue left, final PdbResidue right) {
    final char leftName = Character.toUpperCase(left.oneLetterName());
    final char rightName = Character.toUpperCase(right.oneLetterName());

    if (leftName > rightName) {
      return BasePair.isCanonicalPair(right, left);
    }

    if ((leftName == 'C') && (rightName == 'G')) {
      return BasePair.isCanonicalCG(left, right);
    }
    if ((leftName == 'A') && (rightName == 'U' || rightName == 'T')) {
      return BasePair.isCanonicalAU(left, right);
    }
    return (leftName == 'G') && (rightName == 'U') && BasePair.isCanonicalGU(left, right);
  }

  private static boolean isCanonicalGU(final PdbResidue guanine, final PdbResidue uracil) {
    if (!guanine.hasAtom(AtomName.N1) || !guanine.hasAtom(AtomName.O6)) {
      return false;
    }
    if (!uracil.hasAtom(AtomName.O2) || !uracil.hasAtom(AtomName.N3)) {
      return false;
    }

    final PdbAtomLine n1 = guanine.findAtom(AtomName.N1);
    final PdbAtomLine o6 = guanine.findAtom(AtomName.O6);
    final PdbAtomLine o2 = uracil.findAtom(AtomName.O2);
    final PdbAtomLine n3 = uracil.findAtom(AtomName.N3);
    final double n1o2 = n1.distanceTo(o2);
    final double o6n3 = o6.distanceTo(n3);
    return (n1o2 <= BasePair.GU_DISTANCE_N1_O2)
        && (o6n3 <= BasePair.GU_DISTANCE_O6_N3)
        && BasePair.isFacingYR(uracil, guanine);
  }

  private static boolean isCanonicalAU(final PdbResidue adenine, final PdbResidue uracil) {
    if (!adenine.hasAtom(AtomName.N1) || !adenine.hasAtom(AtomName.N6)) {
      return false;
    }
    if (!uracil.hasAtom(AtomName.N3) || !uracil.hasAtom(AtomName.O4)) {
      return false;
    }

    final PdbAtomLine n1 = adenine.findAtom(AtomName.N1);
    final PdbAtomLine n6 = adenine.findAtom(AtomName.N6);
    final PdbAtomLine n3 = uracil.findAtom(AtomName.N3);
    final PdbAtomLine o4 = uracil.findAtom(AtomName.O4);
    final double n1n3 = n1.distanceTo(n3);
    final double n6o4 = n6.distanceTo(o4);
    return (n1n3 <= BasePair.AU_DISTANCE_N1_N3)
        && (n6o4 <= BasePair.AU_DISTANCE_N6_O4)
        && BasePair.isFacingYR(uracil, adenine);
  }

  private static boolean isCanonicalCG(final PdbResidue cytosine, final PdbResidue guanine) {
    if (Stream.of(AtomName.N3, AtomName.O2, AtomName.N4)
        .anyMatch(atomName -> !cytosine.hasAtom(atomName))) {
      return false;
    }
    if (Stream.of(AtomName.N1, AtomName.N2, AtomName.O6)
        .anyMatch(atomName -> !guanine.hasAtom(atomName))) {
      return false;
    }

    final PdbAtomLine n3 = cytosine.findAtom(AtomName.N3);
    final PdbAtomLine o2 = cytosine.findAtom(AtomName.O2);
    final PdbAtomLine n4 = cytosine.findAtom(AtomName.N4);
    final PdbAtomLine n1 = guanine.findAtom(AtomName.N1);
    final PdbAtomLine n2 = guanine.findAtom(AtomName.N2);
    final PdbAtomLine o6 = guanine.findAtom(AtomName.O6);
    final double n3n1 = n3.distanceTo(n1);
    final double o2n2 = o2.distanceTo(n2);
    final double n4o6 = n4.distanceTo(o6);
    return (n3n1 <= BasePair.CG_DISTANCE_N3_N1)
        && (o2n2 <= BasePair.CG_DISTANCE_O2_N2)
        && (n4o6 <= BasePair.CG_DISTANCE_N4_O6)
        && BasePair.isFacingYR(cytosine, guanine);
  }

  private static boolean isFacingYR(final PdbResidue pyrimidine, final PdbResidue purine) {
    if (Stream.of(AtomName.C6, AtomName.N3).anyMatch(atomName -> !pyrimidine.hasAtom(atomName))) {
      return false;
    }
    if (Stream.of(AtomName.C8, AtomName.N1).anyMatch(atomName -> !purine.hasAtom(atomName))) {
      return false;
    }

    final PdbAtomLine c6 = pyrimidine.findAtom(AtomName.C6);
    final PdbAtomLine n3 = pyrimidine.findAtom(AtomName.N3);
    final PdbAtomLine c8 = purine.findAtom(AtomName.C8);
    final PdbAtomLine n1 = purine.findAtom(AtomName.N1);

    final Vector3D v1 = n3.toVector3D().subtract(c6.toVector3D());
    final Vector3D v2 = n1.toVector3D().subtract(c8.toVector3D());
    final double dotProduct = v1.dotProduct(v2);
    return dotProduct < 0.0;
  }

  /** @return The first residue. */
  @Value.Parameter(order = 1)
  public abstract PdbNamedResidueIdentifier left();

  /** @return The second residue. */
  @Value.Parameter(order = 2)
  public abstract PdbNamedResidueIdentifier right();

  public final BasePair invert() {
    return ImmutableBasePair.of(right(), left());
  }

  /** @return True if the first residue is before the second one in 5'-3' order. */
  public final boolean is5to3() {
    return left().compareTo(right()) < 0;
  }

  @Override
  public final String toString() {
    return left() + " - " + right();
  }

  @Override
  public final int compareTo(final BasePair t) {
    return new CompareToBuilder().append(left(), t.left()).append(right(), t.right()).build();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy