diff --git a/openchemlib b/openchemlib index 17d264c8..9a3b2027 160000 --- a/openchemlib +++ b/openchemlib @@ -1 +1 @@ -Subproject commit 17d264c81ccea9176ce576daedf959294eb93ff4 +Subproject commit 9a3b2027e2bd31b0e5352881d503b161a1dc7b43 diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/AromaticityResolver.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/AromaticityResolver.java index ca0db78c..12775ea6 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/AromaticityResolver.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/AromaticityResolver.java @@ -168,7 +168,13 @@ public boolean locateDelocalizedDoubleBonds(boolean[] isAromaticBond, boolean ma } } - if (!bondsPromoted) { + + if (bondsPromoted) { + promoteObviousBonds(); + continue; + } + + if (!bondsPromoted) { // find and promote one aromatic bond // (should never happen, but to prevent an endless loop nonetheless) for (int bond=0; bond 3)) return false; @@ -552,5 +565,23 @@ && getFakeOxoCount(mol, mol.getConnAtom(conn, j)) != 0) } } return false; + } + + public static boolean isAmphiphilic(StereoMolecule mol) { + boolean amphiphilic=true; + + boolean acidic=false; + boolean basic=false; + for (int at = 0; at < mol.getAtoms(); at++) { + if(isAcidicOxygen(mol, at)){ + acidic=true; + } + if(isBasicNitrogen(mol, at)){ + basic=true; + } } + + amphiphilic = basic && acidic; + return amphiphilic; } +} diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/Canonizer.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/Canonizer.java index 0838b226..56f5d038 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/Canonizer.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/Canonizer.java @@ -172,7 +172,7 @@ public class Canonizer { private ArrayList mTHParityNormalizationGroupList; private int mMode,mNoOfRanks,mNoOfPseudoGroups; private boolean mIsOddParityRound; - private boolean mZCoordinatesAvailable; + private boolean mZCoordinatesAvailable,mAllHydrogensAreExplicit; private boolean mCIPParityNoDistinctionProblem; private boolean mEncodeAvoid127; @@ -226,6 +226,18 @@ public Canonizer(StereoMolecule mol, int mode) { mZCoordinatesAvailable = ((mode & COORDS_ARE_3D) != 0) || mMol.is3D(); + mAllHydrogensAreExplicit = false; + if (mMol.getAllAtoms() > mMol.getAtoms() + && !mMol.isFragment()) { + mAllHydrogensAreExplicit = true; + for (int i=0; i mMol.getAtoms() - && !mMol.isFragment()) { - includeHydrogenCoordinates = true; - for (int i=0; i + * If this Molecule is a substructure (mFragment=true) and has no 3-dimensional atom coordinates, + * then all explicit hydrogen atoms are converted into query features, unless setHydrogenProtection(true) + * was called before on this Molecule.
* cHelperRings: Aromatic and non-aromatic rings are detected. Atom and bond ring - * properties are set and a ring collection provides a total set of small rings (7 or less atoms). + * properties are set and a ring collection provides a total set of small rings (7 or fewer atoms). * Atoms being in allylic/benzylic or stabilized (neighbor of a carbonyl or similar group) position * are flagged as such.
* cHelperParities: Atom (tetrahedral or axial) and bond (E/Z or atrop) parities are calculated @@ -3501,7 +3507,7 @@ public void ensureHelperArrays(int required) { calculateNeighbours(); mValidHelperArrays |= cHelperBitNeighbours; - if (convertHydrogenToQueryFeatures()) { + if (mIsFragment && !is3D() && convertHydrogenToQueryFeatures()) { handleHydrogens(); calculateNeighbours(); mValidHelperArrays |= cHelperBitNeighbours; @@ -3989,9 +3995,6 @@ else if (atomRingBondCount[atom] > 3) * @return true if hydrogens were deleted and, thus, mConnAtoms are invalid */ private boolean convertHydrogenToQueryFeatures() { - if (!mIsFragment) - return false; - // if an atom has no free valence then cAtomQFNoMoreNeighbours is not necessary // and cAtomQFMoreNeighbours is not possible // unless it is an uncharged N- or O-family atom that could be e.g. methylated @@ -4001,12 +4004,15 @@ private boolean convertHydrogenToQueryFeatures() { mAtomQueryFeatures[atom] &= ~(cAtomQFNoMoreNeighbours | cAtomQFMoreNeighbours); } - // approximate explicit hydrogens by query features - // and remove explicit hydrogens except those with stereo bonds + if (mProtectHydrogen) + return false; + + // approximate explicit hydrogens by query features + // and remove explicit hydrogens except those with stereo bonds boolean deleteHydrogens = false; for (int atom=0; atom 0) { + if (explicitHydrogens > 0) { if ((mAtomQueryFeatures[atom] & cAtomQFNoMoreNeighbours) == 0) { // add query feature hydrogen to explicit hydrogens int queryFeatureHydrogens = @@ -4048,6 +4054,7 @@ private boolean convertHydrogenToQueryFeatures() { } } } + if (deleteHydrogens) compressMolTable(); diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/ExtendedMoleculeFunctions.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/ExtendedMoleculeFunctions.java index dba43b04..4a7b2469 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/ExtendedMoleculeFunctions.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/ExtendedMoleculeFunctions.java @@ -66,6 +66,8 @@ package com.actelion.research.chem; import com.actelion.research.calc.ArrayUtilsCalc; +import com.actelion.research.calc.statistics.StatisticsOverview; +import com.actelion.research.calc.statistics.median.MedianStatisticFunctions; import com.actelion.research.chem.descriptor.DescriptorEncoder; import com.actelion.research.chem.descriptor.DescriptorHandler; import com.actelion.research.util.BurtleHasher; @@ -770,6 +772,23 @@ public final static boolean atomAtomSubStrucMatch(StereoMolecule molecule, int a return arr; } + public final static int [] getTopologicalDistances(int [][] topoDistMatrix, int [] at1, int [] at2) { + + int [] d = new int[at1.length*at2.length]; + int cc=0; + for (int i = 0; i < at1.length; i++) { + for (int j = 0; j < at2.length; j++) { + d[cc++]=topoDistMatrix[at1[i]][at2[j]]; + } + } + + return d; + } + public final static int getMedianTopologicalDistance(int [][] topoDistMatrix, int [] at1, int [] at2) { + int [] d = getTopologicalDistances(topoDistMatrix, at1, at2); + int medTopoDist = MedianStatisticFunctions.getMedianForInteger(d).median; + return medTopoDist; + } public final static int getTopologicalDistance(ExtendedMolecule mol, int at1, int at2) { int dist = 0; @@ -1271,19 +1290,31 @@ public static int getNumCyanoGroups(StereoMolecule mol){ } - public static int getNumAlcoholicOxygen(StereoMolecule mol){ - + public static int getTotalCharge(StereoMolecule mol){ int n = 0; - for (int i = 0; i < mol.getAllAtoms(); i++) { + n+=mol.getAtomCharge(i); + } + return n; + } + public static int getNumAtomsCharged(StereoMolecule mol){ + int n = 0; + for (int i = 0; i < mol.getAllAtoms(); i++) { + if(mol.getAtomCharge(i)!=0){ + n++; + } + } + return n; + } + public static int getNumAlcoholicOxygen(StereoMolecule mol){ + int n = 0; + for (int i = 0; i < mol.getAllAtoms(); i++) { if(isAlcoholicOxygen(mol, i)){ n++; } } - return n; - } public static int getNumThioEther(StereoMolecule mol){ diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/IDCodeParserWithoutCoordinateInvention.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/IDCodeParserWithoutCoordinateInvention.java index 0262f05e..6d2b62ed 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/IDCodeParserWithoutCoordinateInvention.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/IDCodeParserWithoutCoordinateInvention.java @@ -75,7 +75,7 @@ public void neglectSpaceDelimitedCoordinates() { * @return */ public StereoMolecule getCompactMolecule(String idcode) { - return (idcode == null || idcode.isEmpty()) ? null : getCompactMolecule(idcode.getBytes(StandardCharsets.UTF_8), null); + return (idcode == null || idcode.isEmpty()) ? null : getCompactMolecule(idcode.getBytes(StandardCharsets.UTF_8)); } /** @@ -433,6 +433,7 @@ public void parse(StereoMolecule mol, byte[] idcode, byte[] coordinates, int idc mMol.setFragment(decodeBits(1) == 1); int[] aromaticSPBond = null; + int[] selectedHydrogenBits = null; int offset = 0; while (decodeBits(1) == 1) { @@ -724,6 +725,13 @@ public void parse(StereoMolecule mol, byte[] idcode, byte[] coordinates, int idc mMol.setBondType(bond, bondType); } break; + case 38: // datatype 'selected hydrogen' + no = decodeBits(abits); + int connBits = decodeBits(3); + selectedHydrogenBits = new int[allAtoms]; + for (int i=0; i dh) { - return TAG_SIMILARITY + dh.getInfo().shortName; - } - public static String getTagDescriptorSimilarity(String shortName) { - return TAG_SIMILARITY + shortName; + return shortName + TAG_SIMILARITY; } + public static String getTagDescriptorSimilarity(ISimilarityCalculator dh) { + return getTagDescriptorSimilarity(dh.getInfo().shortName); + } public static String getTagDescriptorSimilarity(SimilarityCalculatorInfo info) { - return TAG_SIMILARITY + info.shortName; + return getTagDescriptorSimilarity(info.shortName); } public static String getTagDescriptorSimilarity(DescriptorInfo dh){ - return TAG_SIMILARITY + dh.shortName; + return getTagDescriptorSimilarity(dh.shortName); } public static T create(DescriptorHandler dh, String idcode){ diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/descriptor/DescriptorWeightsHelper.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/descriptor/DescriptorWeightsHelper.java new file mode 100644 index 00000000..2d8148fb --- /dev/null +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/descriptor/DescriptorWeightsHelper.java @@ -0,0 +1,151 @@ +package com.actelion.research.chem.descriptor; + +import com.actelion.research.chem.Molecule3D; +import com.actelion.research.chem.descriptor.flexophore.ConstantsFlexophore; +import com.actelion.research.chem.descriptor.flexophore.generator.CreatorMolDistHistViz; +import com.actelion.research.chem.descriptor.flexophore.redgraph.SubGraphIndices; +import com.actelion.research.chem.phesa.DescriptorHandlerShape; +import com.actelion.research.chem.phesa.PheSAMolecule; +import com.actelion.research.chem.phesa.pharmacophore.pp.IPharmacophorePoint; +import com.actelion.research.chem.phesa.pharmacophore.pp.PPGaussian; +import com.actelion.research.util.datamodel.IntArray; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/* + + Copyright (c) 2024 Alipheron AG. All rights reserved. + + This file is part of the Alipheron AG software suite. + + Licensed under the Alipheron AG Software License Agreement (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at the company's official website or upon request. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Created by Modest von Korff + 26/07/2024 + + */ +public class DescriptorWeightsHelper { + + public static final String TAG_WEIGHTS_ATOMS_FLEXOPHORE = "Atom Weights Flexophore"; + public static final String TAG_WEIGHTS_ATOMS_PHESA = "Atom Weights PheSA"; + + + public static final int LABEL_WEIGHT_LOW = 0; + public static final int LABEL_WEIGHT_NORMAL = 1; + public static final int LABEL_WEIGHT_MANDATORY = 2; + public static final int LABEL_WEIGHT_HIGH_USER = 3; + + private CreatorMolDistHistViz creatorMolDistHistViz; + + + + public DescriptorWeightsHelper() { + this.creatorMolDistHistViz = new CreatorMolDistHistViz(); + + } + + /** + * The labels are used to calculate the weight values for Flexophore and PheSA. + * The labels can be given by the users in the + * @param molecule3D + * @return + */ + public int [] calcWeightLabelsFlexophore(Molecule3D molecule3D){ + List liSubGraphIndices = creatorMolDistHistViz.getSubGraphIndices(molecule3D); + int [] weights = calcWeightLabels(liSubGraphIndices, molecule3D); + return weights; + } + + /** + * - End standing pp points are set mandatory. + * - Charged pp points are set mandatory. + * @param liSubGraphIndices + * @param molecule3D + * @return + */ + public static int [] calcWeightLabels(List liSubGraphIndices, Molecule3D molecule3D){ + + int [] weights = getBasisWeightLabels(molecule3D); + + for (int i = 0; i < liSubGraphIndices.size(); i++) { + SubGraphIndices sgi = liSubGraphIndices.get(i); + int indexWeight = DescriptorWeightsHelper.LABEL_WEIGHT_NORMAL; + if (SubGraphIndices.isLinker(molecule3D, liSubGraphIndices, i)) { + if(!SubGraphIndices.isOnlyCarbon(molecule3D, sgi)) { + indexWeight = DescriptorWeightsHelper.LABEL_WEIGHT_MANDATORY; + } + if(SubGraphIndices.isCharged(molecule3D, sgi)) { + indexWeight = DescriptorWeightsHelper.LABEL_WEIGHT_MANDATORY; + } + } else { + indexWeight = DescriptorWeightsHelper.LABEL_WEIGHT_MANDATORY; + } + for (int atomIndex : sgi.getAtomIndices()) { + weights[atomIndex] = indexWeight; + } + } + + return weights; + } + + public static int [] getBasisWeightLabels(Molecule3D molecule3D){ + int [] weights = new int[molecule3D.getAtoms()]; + Arrays.fill(weights, DescriptorWeightsHelper.LABEL_WEIGHT_NORMAL); + return weights; + } + + public static int [] mergeWeightLabels(int[] arrWeightLabel, int[] arrWeightLabelUser) { + + if(arrWeightLabel.length!= arrWeightLabelUser.length){ + throw new RuntimeException("Weight labels differ in size!"); + } + int[] arrWeightLabelMerged = new int[arrWeightLabel.length]; + for (int i = 0; i < arrWeightLabel.length; i++) { + int label = arrWeightLabel[i]; + + if(arrWeightLabelUser[i]== LABEL_WEIGHT_LOW){ + label = arrWeightLabelUser[i]; + } else if(arrWeightLabel[i] == LABEL_WEIGHT_MANDATORY && arrWeightLabelUser[i] == LABEL_WEIGHT_MANDATORY){ + label = LABEL_WEIGHT_HIGH_USER; + } else if(arrWeightLabelUser[i] == LABEL_WEIGHT_MANDATORY){ + label = LABEL_WEIGHT_HIGH_USER; + } + arrWeightLabelMerged[i]=label; + } + + return arrWeightLabelMerged; + } + public static String toStringWeightLabels(int [] weightLabels){ + StringBuilder weightBuilder = new StringBuilder(); + for (int weightLabel : weightLabels) { + weightBuilder.append((char)('0'+weightLabel)); + } + return weightBuilder.toString(); + } + + /** + * + * @param s string with single digits '123456789'. + * @return + */ + public static int [] parseSingleDigitString(String s) { + if (s == null) + return null; + int[] arr = new int[s.length()]; + for (int i = 0; i < s.length(); i++) { + int c = Integer.parseInt(Character.toString(s.charAt(i))); + arr[i] = c; + } + return arr; + } +} diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/io/CompoundTableConstants.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/io/CompoundTableConstants.java index c2e40aef..9e088297 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/io/CompoundTableConstants.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/io/CompoundTableConstants.java @@ -175,6 +175,7 @@ public interface CompoundTableConstants { String cColumnPropertyFormula = "formula"; String cColumnPropertyCompoundProperty = "compoundProperty"; String cColumnPropertySuperposeMolecule = "superposeMol"; // idcode+coords to be displayed in every cell + String cColumnPropertyShowSuperposeMolecule = "showSuperposeMol"; // whether to show the superpose molecule (default is true) String cColumnPropertyProteinCavity = "proteinCavity"; // idcode+coords of protein cavity to be displayed in every cell String cColumnPropertyNaturalLigand = "naturalLigand"; // idcode+coords of natural ligand, if proteinCavity is given (not shown, used for surface creation) String cColumnPropertyShowNaturalLigand = "showNaturalLigand"; // whether to show the natural ligand in addition to row's structure; default is true diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragment3D.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragment3D.java index 71d1b3b3..c3c0f3cc 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragment3D.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragment3D.java @@ -3,9 +3,10 @@ import com.actelion.research.chem.conf.TorsionDescriptor; public class Fragment3D implements Comparable { - private String mIDCode,mIDCoords; - private TorsionDescriptor mTorsions; - private int[] mExitAtoms; + private final String mIDCode; + private String mIDCoords; + private final TorsionDescriptor mTorsions; + private final int[] mExitAtoms; public Fragment3D(String idcode, String coords, TorsionDescriptor td, int[] exitAtoms) { this.mIDCode = idcode; @@ -38,7 +39,7 @@ public boolean equals(Fragment3D f) { @Override public int compareTo(Fragment3D f) { int comparison = mIDCode.compareTo(f.mIDCode); if (comparison != 0 || mTorsions == null) // different structure or no rotatable bonds - return comparison; + return comparison; return mTorsions.compareTo(f.mTorsions); } diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/FragmentGeometry3D.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/FragmentGeometry3D.java new file mode 100644 index 00000000..ed7e9736 --- /dev/null +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/FragmentGeometry3D.java @@ -0,0 +1,305 @@ +package com.actelion.research.chem.shredder; + +import com.actelion.research.calc.Matrix; +import com.actelion.research.calc.SingularValueDecomposition; +import com.actelion.research.chem.Coordinates; +import com.actelion.research.chem.Molecule; +import com.actelion.research.chem.StereoMolecule; + +import java.util.ArrayList; +import java.util.Arrays; + +public class FragmentGeometry3D { + public static final int MODE_SELECTED_ATOMS = 1; // molecule with fragment atoms selected, exit vector atoms not selected + public static final int MODE_FRAGMENT_WITH_EXIT_VECTORS = 2; // defined as atom custom label "*" + + private final StereoMolecule mMol; + private ExitVector[] mExitVector; + private final String mFootPrint; // canonical String describing atomic numbers or exit vectors + private int[][] mPermutation; + private final Coordinates[] mAlignmentCoords; + private final Coordinates mAlignmentCOG; + + /** + * Creates a FragmentGeometry3D from a StereoMolecule with the mode defining the situation. + * This creates a canonical exit vector footprint. For geometries with the same footprint + * it provides geometry comparisons regarding alignment and exit vector similarity. + * A transformation mask is provided for the best alignment one object to another. + * Helper functions to attach properly aligned substituents are given. + * @param mol + */ + public FragmentGeometry3D(StereoMolecule mol, int mode) { + mMol = mol; + mMol.ensureHelperArrays(Molecule.cHelperNeighbours); + + switch (mode) { + case MODE_SELECTED_ATOMS: + initMoleculeWithSelection(); + break; + case MODE_FRAGMENT_WITH_EXIT_VECTORS: + initFragmentWithExitVectors(); + break; + } + + Arrays.sort(mExitVector); + + StringBuilder footprint = new StringBuilder(); + for (ExitVector ev : mExitVector) + footprint.append(Molecule.cAtomLabel[ev.atomicNo]); + mFootPrint = footprint.toString(); + + // compile coordinates of all root atoms and calculate their center of gravity + mAlignmentCoords = determineAlignmentCoords(); + mAlignmentCOG = centerOfGravity(mAlignmentCoords); + } + + public void initMoleculeWithSelection() { + ArrayList exitVectorList = new ArrayList<>(); + for (int atom=0; atom exitVectorList = new ArrayList<>(); + for (int atom=0; atom maxRMSD ? null : matrix; + } + + public boolean hasMatchingExitVectors(FragmentGeometry3D geometry, Coordinates[] coords, int permutation, double maxDiversion) { + for (int i = 0; i maxDiversion) + return false; + } + return true; + } + + public int getPermutationCount() { + if (mPermutation == null) { + int[] sameCount = new int[mExitVector.length]; + int[] permCount = new int[mExitVector.length]; + int index = 0; + int totalPermCount = 1; + while (index list = new ArrayList<>(); + addToPermutation(new int[1], objectCount, list); + return list.toArray(new int[0][]); + } + + private void addToPermutation(int[] input, int max, ArrayList list) { + int size = input.length + 1; + for (int pos=0; pos + * To actually perform the alignment with any set of coordinates do:
+ * for (Coordinates c : anyCoords) { c.sub(cog2); c.rotate(matrix); c.add(cog1); } + * @param coords1 + * @param coords2 + * @param cog1 + * @param cog2 + * @return + */ + public static double[][] kabschAlign(Coordinates[] coords1, Coordinates[] coords2, + Coordinates cog1, Coordinates cog2) { + double[][] m = new double[3][3]; + double[][] c1 = Arrays.stream(coords1).map(e -> new double[] {e.x-cog1.x,e.y-cog1.y,e.z-cog1.z}).toArray(double[][]::new); + double[][] c2 = Arrays.stream(coords2).map(e -> new double[] {e.x-cog2.x,e.y-cog2.y,e.z-cog2.z}).toArray(double[][]::new); + for(int i=0;i<3;i++) { + for(int j=0;j<3;j++) { + double rij = 0.0; + for(int a=0; a0.0); + rot = rot.getTranspose(); + return rot.getArray(); + } + + private static class ExitVector implements Comparable { + int rootAtom,exitAtom,atomicNo; + + public ExitVector(int rootAtom, int exitAtom, int atomicNo) { + this.rootAtom = rootAtom; + this.exitAtom = exitAtom; + this.atomicNo = atomicNo; + } + + @Override + public int compareTo(ExitVector o) { + return Integer.compare(o.atomicNo, atomicNo); + } + } +} diff --git a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragmenter3D.java b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragmenter3D.java index 6340d30f..89d76417 100644 --- a/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragmenter3D.java +++ b/src/com/actelion/research/gwt/chemlib/com/actelion/research/chem/shredder/Fragmenter3D.java @@ -2,30 +2,28 @@ import com.actelion.research.chem.Canonizer; import com.actelion.research.chem.StereoMolecule; -import com.actelion.research.chem.conf.TorsionDB; -import com.actelion.research.chem.conf.TorsionDescriptor; -import com.actelion.research.chem.conf.TorsionDescriptorHelper; +import com.actelion.research.chem.conf.*; import com.actelion.research.util.IntArrayComparator; import java.util.ArrayList; import java.util.TreeSet; public class Fragmenter3D { - private int mMinAtoms,mMaxAtoms,mMaxBonds,mMinExits,mMaxExits; - private ArrayList mFragmentList; + private final int mMinAtoms,mMaxAtoms,mMaxBondFlexibilitySum,mMinExits,mMaxExits; + private final ArrayList mFragmentList; /** * * @param minAtoms * @param maxAtoms - * @param maxBonds + * @param maxBondFlexibilitySum * @param minExits * @param maxExits */ - public Fragmenter3D(int minAtoms, int maxAtoms, int maxBonds, int minExits, int maxExits) { + public Fragmenter3D(int minAtoms, int maxAtoms, int maxBondFlexibilitySum, int minExits, int maxExits) { mMinAtoms = minAtoms; mMaxAtoms = maxAtoms; - mMaxBonds = maxBonds; + mMaxBondFlexibilitySum = maxBondFlexibilitySum; mMinExits = minExits; mMaxExits = maxExits; mFragmentList = new ArrayList<>(); @@ -37,16 +35,21 @@ public Fragmenter3D(int minAtoms, int maxAtoms, int maxBonds, int minExits, int * The list is re-used by subsequent calls to this nethod. Thus, process/consume the * fragment list before calling this method again. * @param mol - * @return Fragment3D list of passed molecule + * @param withHydrogen whether built fragments shall include hydrogen atoms + * @return Fragment3D list of given molecule */ - public ArrayList getFragments(StereoMolecule mol) { + public ArrayList buildFragments(StereoMolecule mol, boolean withHydrogen) { mFragmentList.clear(); mol.stripSmallFragments(); - mol.removeExplicitHydrogens(false, true); + if (withHydrogen) + new AtomAssembler(mol).addImplicitHydrogens(); + else + mol.removeExplicitHydrogens(false, true); boolean[] isRotatableBond = new boolean[mol.getAllBonds()]; - int count = TorsionDB.findRotatableBonds(mol, true, isRotatableBond); + TorsionDB.findRotatableBonds(mol, true, isRotatableBond); + float[] bondFlexibility = new MolecularFlexibilityCalculator().calculateBondFlexibilities(mol, isRotatableBond); int[] fragmentNo = new int[mol.getAllAtoms()]; int fragmentCount = mol.getFragmentNumbers(fragmentNo, isRotatableBond, true); @@ -55,16 +58,16 @@ public ArrayList getFragments(StereoMolecule mol) { for (int atom=0; atom baseFragmentCombinationSet = new TreeSet<>(new IntArrayComparator()); boolean[] isMemberFragment = new boolean[fragmentCount]; for (int i=0; i getFragments(StereoMolecule mol) { * provided that the size criteria are fullfilled. * @param mol */ - private void addNewFragments(StereoMolecule mol, int[] fragmentNo, + private void addNewFragments(StereoMolecule mol, int[] fragmentNo, float[] bondFlexibility, float bondFlexibilitySum, boolean[] isMemberFragment, int previousBaseFragment, int usedBaseFragmentCount, int atomCount, - TreeSet baseFragmentCombinationSet, Fragment3DData[] fragmentData) { - if (usedBaseFragmentCount - mMaxBonds > 1 || atomCount > mMaxAtoms) + TreeSet baseFragmentCombinationSet, BaseFragmentInfo[] baseFragmentInfo) { + if (atomCount > mMaxAtoms) return; int[] baseFragmentList = new int[usedBaseFragmentCount]; @@ -99,12 +102,17 @@ private void addNewFragments(StereoMolecule mol, int[] fragmentNo, if (atomCount >= mMinAtoms) addFragment(mol, fragmentNo, isMemberFragment); - for (int neighbour:fragmentData[previousBaseFragment].neighbourFragment) { - if (!isMemberFragment[neighbour]) { + BaseFragmentInfo previousBaseFragmentInfo = baseFragmentInfo[previousBaseFragment]; + for (int i=0; i centralCoreList = new ArrayList(); for (int fragment=0; fragment