fingerprint.MyStructureFingerprint.java Source code

Java tutorial

Introduction

Here is the source code for fingerprint.MyStructureFingerprint.java

Source

/*
Author:
  Fabrice Moriaud <fmoriaud@ultimatepdb.org>
    
  Copyright (c) 2016 Fabrice Moriaud
    
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Lesser General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
    
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Lesser General Public License for more details.
    
  You should have received a copy of the GNU Lesser General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
package fingerprint;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;

import org.apache.commons.math3.geometry.euclidean.threed.SphericalCoordinates;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;

import database.SequenceTools;
import math.EquidistributionPhi;
import math.MathTools;
import math.ToolsMathAppliedToMyStructure;
import parameters.AlgoParameters;
import pointWithProperties.Point;
import pointWithProperties.PointIfc;
import pointWithProperties.PointsTools;
import shapeBuilder.ShapeBuildingException;
import shapeBuilder.StructureLocalToBuildAnyShape;
import shapeReduction.PhiThetaInterval;
import shapeReduction.ShapeReductorTools;
import mystructure.MyChainIfc;
import mystructure.MyMonomerIfc;
import mystructure.MyStructureIfc;

public class MyStructureFingerprint {
    // -------------------------------------------------------------------
    // Class variables
    // -------------------------------------------------------------------
    private MyStructureIfc myStructure;
    private AlgoParameters algoParameters;

    private List<Double> splittedPercentageOccupied;
    private List<List<Integer>> splittedHistogramD2OccupiedSolidAngle;

    // -------------------------------------------------------------------
    // Constructor
    // -------------------------------------------------------------------
    public MyStructureFingerprint(MyStructureIfc myStructure, AlgoParameters algoParameters) {
        this.myStructure = myStructure;
        this.algoParameters = algoParameters;
    }

    //-------------------------------------------------------------
    // Interface & Public methods
    //-------------------------------------------------------------
    public List<Integer> computeHistogramAminoAcidsTypes() {

        List<List<String>> equivalentResidues = SequenceTools.generateEquivalentResidues();

        List<Integer> histogramAminoAcidsTypes = new ArrayList<>();
        for (int i = 0; i < equivalentResidues.size(); i++) {
            histogramAminoAcidsTypes.add(0);
        }
        for (MyChainIfc chain : myStructure.getAllChainsRelevantForShapeBuilding()) {
            for (MyMonomerIfc monomer : chain.getMyMonomers()) {
                String threeLetterCode = String.valueOf(monomer.getThreeLetterCode());
                List<Integer> bins = returnBins(equivalentResidues, threeLetterCode);
                for (Integer binValue : bins) {
                    int currentVaue = histogramAminoAcidsTypes.get(binValue);
                    histogramAminoAcidsTypes.set(binValue, currentVaue + 1);
                }
            }
        }

        return histogramAminoAcidsTypes;
    }

    public List<Integer> computeHistogramSimple() {

        List<Integer> histogramSimple = new ArrayList<>();
        // only total number and hydrophobic count
        // aim is only to identify most similar in terms of cavity opening and its hydrophobicity
        int residueCount = 0;
        int hydrophobicResidueCount = 0;
        List<String> hydrophobicResidues = SequenceTools.getHydrophobicResiduesList();
        for (MyChainIfc chain : myStructure.getAllChainsRelevantForShapeBuilding()) {
            for (MyMonomerIfc monomer : chain.getMyMonomers()) {
                String threeLetterCode = String.valueOf(monomer.getThreeLetterCode());
                residueCount += 1;
                if (hydrophobicResidues.contains(threeLetterCode)) {
                    hydrophobicResidueCount += 1;
                }
            }
        }
        histogramSimple.add(residueCount);
        histogramSimple.add(hydrophobicResidueCount);
        return histogramSimple;
    }

    public boolean isItWorthComparing(List<Integer> histogramSimpleQuery, List<Integer> histogramSimpleTarget) {

        if (histogramSimpleTarget.get(0) > histogramSimpleQuery.get(0) * 1.2) {
            // if target has 20% or more amino acids in neighbors then it is unlikely to be a good hit
            //System.out.println("skipped total " + histogramSimpleTarget.get(0) + " > " + histogramSimpleQuery.get(0) * 1.2);
            return false;
        }

        double ratioHydrophobicTarget = (double) histogramSimpleTarget.get(1)
                / (double) histogramSimpleTarget.get(0);
        double ratioHydrophobicQuery = (double) histogramSimpleQuery.get(1) / (double) histogramSimpleQuery.get(0);

        // if target is off of more than 20% on hydrophobicity then it is skipped
        if (Math.abs(ratioHydrophobicTarget - ratioHydrophobicQuery) > 0.2) { // it is tough but I want very similar hits only
            //System.out.println("skipped hydro " + ratioHydrophobicTarget + " != " + ratioHydrophobicQuery);

            return false;
        }
        return true;
    }

    public void computePercentageAndHistogram(MyChainIfc peptide, int splittedSequenceLength) {

        splittedPercentageOccupied = new ArrayList<>();
        splittedHistogramD2OccupiedSolidAngle = new ArrayList<>();

        // i want to compute the distribution according to peptide
        // but it is a list now for each and every segment of the used length in the DockingPeptide algo

        // it can be for the query which might be longer than splittedsequeceLength

        // it can be for the splitted peptide and then it is gonna be the same length

        System.out.println("solid angle peptide length = " + peptide.getMyMonomers().length);

        // if it is of the same size then I do the job
        // get the barycenter of the peptide

        if (peptide.getMyMonomers().length == splittedSequenceLength) {
            List<PointIfc> pointsPeptide = PointsTools.createListOfPointIfcFromPeptide(peptide);
            PointIfc barycenter = ShapeReductorTools.computeLigandBarycenter(pointsPeptide);

            LinkedHashMap<PhiThetaInterval, List<PointIfc>> groupedResidues = groupResiduesAccordingToSolidAngleAccordingToLocalStructureBarycenter(
                    barycenter, myStructure);
            int countOccupied = 0;
            for (Entry<PhiThetaInterval, List<PointIfc>> entry : groupedResidues.entrySet()) {
                if (entry.getValue().size() > 0) {
                    countOccupied += 1;
                }
            }
            double percentageOccupied = (double) countOccupied / groupedResidues.size();
            List<Integer> histogramD2OccupiedSolidAngle = computeHistogramD2(groupedResidues);
            splittedPercentageOccupied.add(percentageOccupied);
            splittedHistogramD2OccupiedSolidAngle.add(histogramD2OccupiedSolidAngle);
        } else {

            // remember that the docking peptide class which is using this is docking the peptide chain bound to it already in the structure
            for (int i = 0; i < peptide.getMyMonomers().length; i++) {

                int startId = i;
                int endId = i + splittedSequenceLength;
                if (endId < peptide.getMyMonomers().length + 1) {

                    // I need to schrink myStructure to the env of this subpeptide
                    StructureLocalToBuildAnyShape structureLocalToBuildAnyShape = null;
                    try {
                        structureLocalToBuildAnyShape = new StructureLocalToBuildAnyShape(myStructure,
                                peptide.getChainId(), startId, splittedSequenceLength, algoParameters);
                    } catch (ShapeBuildingException e) {
                        continue;
                    }
                    MyStructureIfc myStructureLocal = structureLocalToBuildAnyShape.getMyStructureLocal();
                    if (myStructureLocal == null) {
                        continue;
                    }

                    // makes the subPeptide barycenter
                    MyChainIfc subPeptide = peptide.makeSubchain(startId, splittedSequenceLength);
                    List<PointIfc> pointsPeptide = PointsTools.createListOfPointIfcFromPeptide(subPeptide);
                    PointIfc barycenter = ShapeReductorTools.computeLigandBarycenter(pointsPeptide);

                    LinkedHashMap<PhiThetaInterval, List<PointIfc>> groupedResidues = groupResiduesAccordingToSolidAngleAccordingToLocalStructureBarycenter(
                            barycenter, myStructureLocal);
                    int countOccupied = 0;
                    for (Entry<PhiThetaInterval, List<PointIfc>> entry : groupedResidues.entrySet()) {
                        if (entry.getValue().size() > 0) {
                            countOccupied += 1;
                        }
                    }
                    double percentageOccupied = (double) countOccupied / groupedResidues.size();
                    List<Integer> histogramD2OccupiedSolidAngle = computeHistogramD2(groupedResidues);
                    splittedPercentageOccupied.add(percentageOccupied);
                    splittedHistogramD2OccupiedSolidAngle.add(histogramD2OccupiedSolidAngle);
                }
            }
        }
    }

    //   public void computePercentageAndHistogram(){
    //
    //      LinkedHashMap<PhiThetaInterval, List<PointIfc>> groupedResidues = groupResiduesAccordingToSolidAngleAccordingToLocalStructureBarycenter();
    //
    //      int countOccupied = 0;
    //      for (Entry<PhiThetaInterval, List<PointIfc>> entry: groupedResidues.entrySet()){
    //         if (entry.getValue().size() > 0){
    //            countOccupied += 1;
    //         }
    //      }
    //      percentageOccupied = (double) countOccupied / groupedResidues.size();
    //      histogramD2OccupiedSolidAngle = computeHistogramD2(groupedResidues);
    //   }

    private List<Integer> computeHistogramD2(LinkedHashMap<PhiThetaInterval, List<PointIfc>> groupedResidues) {

        List<Integer> histogramD2 = new ArrayList<>();

        List<PointIfc> onePointPerGroup = new ArrayList<>();
        for (Entry<PhiThetaInterval, List<PointIfc>> entry : groupedResidues.entrySet()) {
            if (entry.getValue().size() > 0) {
                onePointPerGroup.add(entry.getValue().get(0));
            }
        }

        List<Float> computelListDistanceBetweenTwoLists = SimilarityTools
                .computelListDistanceBetweenTwoLists(onePointPerGroup, onePointPerGroup, 1.0);
        int sizeList = 10;
        float distanceStep = (float) 20.0f / sizeList;
        float startAt = (float) 2.0;
        List<Integer> distributionDistance = SimilarityTools.binValues(computelListDistanceBetweenTwoLists,
                sizeList, distanceStep, startAt);
        histogramD2.addAll(distributionDistance);

        return histogramD2;
    }

    // -------------------------------------------------------------------
    // Implementation
    // -------------------------------------------------------------------
    private LinkedHashMap<PhiThetaInterval, List<PointIfc>> groupResiduesAccordingToSolidAngleAccordingToLocalStructureBarycenter(
            PointIfc barycenterShape, MyStructureIfc myStructureHere) { // strongly reusing code of groupPoints

        List<PointIfc> listRepresentativePoints = new ArrayList<>();

        for (MyChainIfc chain : myStructureHere.getAllChainsRelevantForShapeBuilding()) {
            for (MyMonomerIfc monomer : chain.getMyMonomers()) {
                float[] coords = ToolsMathAppliedToMyStructure.getCoordinatesOfRepresentativeAtom(monomer);
                PointIfc point = new Point(coords);
                listRepresentativePoints.add(point);
            }
        }

        // defining 36 zones in solid space
        double deltaOnlyForTheta = Math.PI / 8.0;
        int countOfIncrementAngle = 8;
        // group monomers

        EquidistributionPhi equidistributionPhi = new EquidistributionPhi();
        List<Double> phiValues = equidistributionPhi.getMapCountOfIntervalsAndPointValues()
                .get(countOfIncrementAngle);
        // theta in map ranges from -pi to +pi in agreement with apache spherical coodinates
        List<Double> tethaValues = ShapeReductorTools.doBinningThetaValues(deltaOnlyForTheta,
                countOfIncrementAngle);

        List<PhiThetaInterval> sectors = generateSector(deltaOnlyForTheta, phiValues, tethaValues);

        // create the Map to return
        LinkedHashMap<PhiThetaInterval, List<PointIfc>> groupPoints = new LinkedHashMap<>();

        Iterator<PhiThetaInterval> it = sectors.iterator();
        while (it.hasNext()) {
            PhiThetaInterval sector = it.next();
            List<PointIfc> listPoints = new ArrayList<>();
            groupPoints.put(sector, listPoints);
        }

        for (PointIfc point : listRepresentativePoints) {

            float[] pointRelativeToBarycenter = MathTools.v1minusV2(point.getCoords(), barycenterShape.getCoords());
            Vector3D pointRelativeToBarycenterV3d = new Vector3D(pointRelativeToBarycenter[0],
                    pointRelativeToBarycenter[1], pointRelativeToBarycenter[2]);

            SphericalCoordinates pointShericalRelative = new SphericalCoordinates(pointRelativeToBarycenterV3d);

            PhiThetaInterval intervalForThisPoint = getIntervalFromSphericalCoordinates(pointShericalRelative,
                    sectors);

            if (intervalForThisPoint == null) { // it could be that some points doesnt fit so I should make the binning a bit larger I guess
                continue;
            }
            groupPoints.get(intervalForThisPoint).add(point);
        }

        return groupPoints;
    }

    private PhiThetaInterval getIntervalFromSphericalCoordinates(SphericalCoordinates pointShericalRelative,
            List<PhiThetaInterval> sectors) {

        double phi = pointShericalRelative.getPhi();
        double theta = pointShericalRelative.getTheta();

        for (PhiThetaInterval phiThetaInterval : sectors) {
            double phiMin = phiThetaInterval.getPhiMin();
            double phiMax = phiThetaInterval.getPhiMax();
            double thetaMin = phiThetaInterval.getThetaMin();
            double thetaMax = phiThetaInterval.getThetaMax();

            if (phi < phiMin || phi > phiMax) {
                continue;
            }
            if (theta < thetaMin || theta > thetaMax) {
                continue;
            }

            return phiThetaInterval;

        }
        // sector was not found
        return null;
    }

    private List<PhiThetaInterval> generateSector(double deltaOnlyForTheta, List<Double> phiValues,
            List<Double> tethaValues) {

        List<PhiThetaInterval> listPhiThetaInterval = new ArrayList<>();

        for (int i = 0; i < phiValues.size() - 1; i++) { // phi values are from 0 to PI by construction so I dont take PI
            double minPhi = phiValues.get(i);
            double maxPhi = phiValues.get(i + 1);

            for (Double tetha : tethaValues) {

                double minTheta = tetha;
                double maxTheta = tetha + deltaOnlyForTheta;
                PhiThetaInterval phiThetainterval = new PhiThetaInterval(minPhi, maxPhi, minTheta, maxTheta);
                listPhiThetaInterval.add(phiThetainterval);
            }
        }
        return listPhiThetaInterval;
    }

    private List<Integer> returnBins(List<List<String>> equivalentResidues, String threeLetterCode) {

        List<Integer> bins = new ArrayList<>();

        for (int i = 0; i < equivalentResidues.size(); i++) {
            if (equivalentResidues.get(i).contains(threeLetterCode)) {
                bins.add(i);
            }
        }
        return bins;
    }

    // -------------------------------------------------------------------
    // Getter & Setter
    // -------------------------------------------------------------------
    public List<Double> getSplittedPercentageOccupied() {
        return splittedPercentageOccupied;
    }

    public List<List<Integer>> getSplittedHistogramD2OccupiedSolidAngle() {
        return splittedHistogramD2OccupiedSolidAngle;
    }
}