com.actelion.research.chem.Molecule Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openchemlib Show documentation
Show all versions of openchemlib Show documentation
Open Source Chemistry Library
/*
* Copyright (c) 1997 - 2016
* Actelion Pharmaceuticals Ltd.
* Gewerbestrasse 16
* CH-4123 Allschwil, Switzerland
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package com.actelion.research.chem;
import com.actelion.research.gui.generic.GenericRectangle;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class Molecule implements Serializable {
// We need the serialVersionUID in order to make sure, that after obfuscation the Molecule keeps
// the same serialVersionUID since the inter-JVM drag & drop checks the Serializable version ID
// which is either generated at via hash or can explicitly set via serialVersionUID. Due to the
// fact, that the obfuscation process alters member/type names the generated hash is going to
// be changed as well.
// In addition to the above requirement, the class name should not be obfuscated at all!
// static final long serialVersionUID = 0x20220517; // after extending atom query features from int to long
static final long serialVersionUID = 0x20221130; // after introducing quadruple and quintuple bonds
public static final int cMaxAtomicNo = 190;
// parity based on atom positions in atom table (as MDL parity)
protected static final int cAtomFlagsParity = 0x000003;
public static final int cAtomParityNone = 0x000000;
public static final int cAtomParity1 = 0x000001;
public static final int cAtomParity2 = 0x000002;
public static final int cAtomParityUnknown = 0x000003;
public static final int cAtomParityIsPseudo = 0x000004;
protected static final int cAtomFlagSmallRing = 0x000008;
public static final int cAtomRadicalState = 0x000030;
public static final int cAtomRadicalStateShift = 4;
public static final int cAtomRadicalStateNone = 0x000000;
public static final int cAtomRadicalStateS = 0x000010;
public static final int cAtomRadicalStateD = 0x000020;
public static final int cAtomRadicalStateT = 0x000030;
private static final int cAtomFlagsColor = 0x0001C0;
public static final int cAtomColorNone = 0x000000;
public static final int cAtomColorBlue = 0x000040;
public static final int cAtomColorRed = 0x000080;
public static final int cAtomColorGreen = 0x0000C0;
public static final int cAtomColorMagenta = 0x000100;
public static final int cAtomColorOrange = 0x000140;
public static final int cAtomColorDarkGreen = 0x000180;
public static final int cAtomColorDarkRed = 0x0001C0;
private static final int cAtomFlagSelected = 0x000200;
protected static final int cAtomFlagsHelper2 = 0x00003C08;
protected static final int cAtomFlagsHelper3 = 0x0401C007;
protected static final int cAtomFlagsHelper = cAtomFlagsHelper2 | cAtomFlagsHelper3;
protected static final int cAtomFlagsRingBonds = 0x000C00;
protected static final int cAtomFlags2RingBonds = 0x000400;
protected static final int cAtomFlags3RingBonds = 0x000800;
protected static final int cAtomFlags4RingBonds = 0x000C00;
protected static final int cAtomFlagAllylic = 0x001000;
protected static final int cAtomFlagStabilized = 0x002000;
private static final int cAtomFlagsCIPParity = 0x00C000;
private static final int cAtomFlagsCIPParityShift = 14;
public static final int cAtomCIPParityNone = 0x000000;
public static final int cAtomCIPParityRorM = 0x000001;
public static final int cAtomCIPParitySorP = 0x000002;
public static final int cAtomCIPParityProblem = 0x000003;
protected static final int cAtomFlagStereoProblem = 0x010000;
protected static final int cAtomFlagMarked = 0x020000;
// MDL's enhanced stereochemical representation (ESR group and type may be assigned
// to TH and allene stereo centers as well as to BINAP kind of stereo bonds)
public static final int cESRTypeAbs = 0;
public static final int cESRTypeAnd = 1;
public static final int cESRTypeOr = 2;
public static final int cESRMaxGroups = 32;
public static final int cESRGroupBits = 5;
protected static final int cAtomFlagsESR = 0x01FC0000;
private static final int cAtomFlagsESRType = 0x000C0000;
private static final int cAtomFlagsESRTypeShift = 18;
private static final int cAtomFlagsESRGroup = 0x01F00000;
private static final int cAtomFlagsESRGroupShift = 20;
protected static final int cAtomFlagConfigurationUnknown = 0x02000000;
private static final int cAtomFlagIsStereoCenter = 0x04000000;
protected static final int cAtomFlagsValence = 0x78000000;
private static final int cAtomFlagsValenceShift = 27;
public static final int cAtomQFNoOfBits = 46;
public static final int cAtomQFAromStateBits = 2;
public static final int cAtomQFAromStateShift = 1;
public static final int cAtomQFRingStateBits = 4;
public static final int cAtomQFRingStateShift = 3;
public static final int cAtomQFHydrogenBits = 4;
public static final int cAtomQFHydrogenShift = 7;
public static final int cAtomQFPiElectronBits = 3;
public static final int cAtomQFPiElectronShift = 14;
public static final int cAtomQFNeighbourBits = 5;
public static final int cAtomQFNeighbourShift = 17;
public static final int cAtomQFSmallRingSizeBits = 3;
public static final int cAtomQFSmallRingSizeShift = 22;
public static final int cAtomQFChargeBits = 3;
public static final int cAtomQFChargeShift = 25;
public static final int cAtomQFRxnParityBits = 2;
public static final int cAtomQFRxnParityShift = 30;
public static final int cAtomQFNewRingSizeBits = 7;
public static final int cAtomQFNewRingSizeShift = 32;
public static final int cAtomQFENeighbourBits = 5;
public static final int cAtomQFENeighbourShift = 39;
public static final int cAtomQFStereoStateBits = 2;
public static final int cAtomQFStereoStateShift = 44;
public static final long cAtomQFSimpleFeatures = 0x00007F800E3FC7FEL;
public static final long cAtomQFNarrowing = 0x00007FFF0FFFFFFEL;
public static final long cAtomQFAny = 0x00000001;
public static final long cAtomQFAromState = 0x0000400000000006L;
public static final long cAtomQFAromatic = 0x00000002;
public static final long cAtomQFNotAromatic = 0x00000004;
public static final long cAtomQFRingState = 0x00000078;
public static final long cAtomQFNotChain = 0x00000008;
public static final long cAtomQFNot2RingBonds = 0x00000010;
public static final long cAtomQFNot3RingBonds = 0x00000020;
public static final long cAtomQFNot4RingBonds = 0x00000040;
public static final long cAtomQFHydrogen = 0x00000780;
public static final long cAtomQFNot0Hydrogen = 0x00000080;
public static final long cAtomQFNot1Hydrogen = 0x00000100;
public static final long cAtomQFNot2Hydrogen = 0x00000200;
public static final long cAtomQFNot3Hydrogen = 0x00000400;
public static final long cAtomQFNoMoreNeighbours= 0x00000800;
public static final long cAtomQFMoreNeighbours = 0x00001000;
public static final long cAtomQFMatchStereo = 0x00002000;
public static final long cAtomQFPiElectrons = 0x0001C000;
public static final long cAtomQFNot0PiElectrons = 0x00004000;
public static final long cAtomQFNot1PiElectron = 0x00008000;
public static final long cAtomQFNot2PiElectrons = 0x00010000;
public static final long cAtomQFNeighbours = 0x003E0000; // these QF refer to non-H neighbours
public static final long cAtomQFNot0Neighbours = 0x00020000;
public static final long cAtomQFNot1Neighbour = 0x00040000;
public static final long cAtomQFNot2Neighbours = 0x00080000;
public static final long cAtomQFNot3Neighbours = 0x00100000;
public static final long cAtomQFNot4Neighbours = 0x00200000; // this is not 4-or-more neighbours
public static final long cAtomQFSmallRingSize = 0x01C00000; // legacy: used to just define the smallest ring an atom is member of
public static final long cAtomQFCharge = 0x0E000000;
public static final long cAtomQFNotChargeNeg = 0x02000000;
public static final long cAtomQFNotCharge0 = 0x04000000;
public static final long cAtomQFNotChargePos = 0x08000000;
public static final long cAtomQFFlatNitrogen = 0x0000000010000000L; // Currently, only used in TorsionDetail
public static final long cAtomQFExcludeGroup = 0x0000000020000000L; // These atoms must not exist in SS-matches
public static final long cAtomQFRxnParityHint = 0x00000000C0000000L; // Retain,invert,racemise configuration in reaction
public static final long cAtomQFRxnParityRetain = 0x0000000040000000L;
public static final long cAtomQFRxnParityInvert = 0x0000000080000000L;
public static final long cAtomQFRxnParityRacemize=0x00000000C0000000L;
public static final long cAtomQFNewRingSize = 0x0000007F00000000L;
public static final long cAtomQFRingSize0 = 0x0000000100000000L;
public static final long cAtomQFRingSize3 = 0x0000000200000000L;
public static final long cAtomQFRingSize4 = 0x0000000400000000L;
public static final long cAtomQFRingSize5 = 0x0000000800000000L;
public static final long cAtomQFRingSize6 = 0x0000001000000000L;
public static final long cAtomQFRingSize7 = 0x0000002000000000L;
public static final long cAtomQFRingSizeLarge = 0x0000004000000000L;
public static final long cAtomQFENeighbours = 0x00000F8000000000L;
public static final long cAtomQFNot0ENeighbours = 0x0000008000000000L;
public static final long cAtomQFNot1ENeighbour = 0x0000010000000000L;
public static final long cAtomQFNot2ENeighbours = 0x0000020000000000L;
public static final long cAtomQFNot3ENeighbours = 0x0000040000000000L;
public static final long cAtomQFNot4ENeighbours = 0x0000080000000000L;
public static final long cAtomQFStereoState = 0x0000300000000000L;
public static final long cAtomQFIsStereo = 0x0000100000000000L;
public static final long cAtomQFIsNotStereo = 0x0000200000000000L;
public static final long cAtomQFHeteroAromatic = 0x0000400000000000L;
public static final int cBondTypeSingle = 0x00000001;
public static final int cBondTypeDouble = 0x00000002;
public static final int cBondTypeTriple = 0x00000004;
public static final int cBondTypeQuadruple = 0x00000008;
public static final int cBondTypeQuintuple = 0x00000010;
public static final int cBondTypeMetalLigand = 0x00000020;
public static final int cBondTypeDelocalized = 0x00000040;
public static final int cBondTypeDown = 0x00000081;
public static final int cBondTypeUp = 0x00000101;
public static final int cBondTypeCross = 0x00000182;
public static final int cBondTypeDeleted = 0x00000200;
public static final int cBondTypeIncreaseOrder = 0x000001FF;
public static final int cBondTypeMaskSimple = 0x0000007F; // masks
public static final int cBondTypeMaskStereo = 0x00000180;
protected static final int cBondFlagsHelper2 = 0x000002C0;
protected static final int cBondFlagsHelper3 = 0x0000003F;
// double bond E/Z parities based on atom positions in atom table
protected static final int cBondFlagsParity = 0x00000003;
public static final int cBondParityNone = 0x00000000;
public static final int cBondParityEor1 = 0x00000001;
public static final int cBondParityZor2 = 0x00000002;
public static final int cBondParityUnknown = 0x00000003;
private static final int cBondParityIsPseudo = 0x00000004;
private static final int cBondFlagsCIPParity = 0x00000030;
protected static final int cBondFlagsCIPParityShift = 4;
public static final int cBondCIPParityNone = 0x00000000;
public static final int cBondCIPParityEorP = 0x00000001;
public static final int cBondCIPParityZorM = 0x00000002;
public static final int cBondCIPParityProblem = 0x00000003;
protected static final int cBondFlagRing = 0x00000040;
protected static final int cBondFlagSmallRing = 0x00000080;
protected static final int cBondFlagsESR = 0x00007F00;
private static final int cBondFlagsESRType = 0x00000300;
private static final int cBondFlagsESRTypeShift = 8;
private static final int cBondFlagsESRGroup = 0x00007C00;
private static final int cBondFlagsESRGroupShift = 10;
private static final int cBondFlagBGHilited = 0x00008000;
private static final int cBondFlagFGHilited = 0x00010000;
private static final int cBondParityUnknownOrNone = 0x0020000;
// This hint/flag is set by CoordinateInventor for double bonds without
// given EZ-parity because coordinates may imply a not intended EZ-parity.
// The setBondParity() method clears this flag. The Canonizer considers
// this flag when calculating EZ-parities.
public static final int cBondQFNoOfBits = 23;
public static final int cBondQFBondTypesBits = 5;
public static final int cBondQFBondTypesShift = 0;
public static final int cBondQFRareBondTypesBits = 2;
public static final int cBondQFRareBondTypesShift = 5;
public static final int cBondQFRingStateBits = 2;
public static final int cBondQFRingStateShift = 7;
public static final int cBondQFBridgeBits = 8;
public static final int cBondQFBridgeShift = 9;
public static final int cBondQFBridgeMinBits = 4;
public static final int cBondQFBridgeMinShift = 9;
public static final int cBondQFBridgeSpanBits = 4;
public static final int cBondQFBridgeSpanShift = 13;
public static final int cBondQFRingSizeBits = 3;
public static final int cBondQFRingSizeShift = 17;
public static final int cBondQFAromStateBits = 2;
public static final int cBondQFAromStateShift = 21;
public static final int cBondQFAllFeatures = 0x00FFFFFF;
public static final int cBondQFSimpleFeatures = 0x006001FF;
public static final int cBondQFNarrowing = 0x00600180;
public static final int cBondQFBondTypes = 0x0000001F; // original 5 bond types for idcode
public static final int cBondQFRareBondTypes = 0x00000060; // using OR logic for all 7 bond types
public static final int cBondQFSingle = 0x00000001;
public static final int cBondQFDouble = 0x00000002;
public static final int cBondQFTriple = 0x00000004;
public static final int cBondQFDelocalized = 0x00000008;
public static final int cBondQFMetalLigand = 0x00000010;
public static final int cBondQFQuadruple = 0x00000020;
public static final int cBondQFQuintuple = 0x00000040;
public static final int cBondQFRingState = 0x00000180;
public static final int cBondQFNotRing = 0x00000080;
public static final int cBondQFRing = 0x00000100;
public static final int cBondQFBridge = 0x0001FE00;
public static final int cBondQFBridgeMin = 0x00001E00;
public static final int cBondQFBridgeSpan = 0x0001E000;
public static final int cBondQFRingSize = 0x000E0000;
public static final int cBondQFMatchStereo = 0x00100000;
public static final int cBondQFAromState = 0x00600000;
public static final int cBondQFAromatic = 0x00200000;
public static final int cBondQFNotAromatic = 0x00400000;
public static final int cBondQFMatchFormalOrder = 0x00800000; // matches the formal bond order considering also cBondQFBondTypes in query
public static final int cHelperAll = 0x00FF;
public static final int cHelperNone = 0x0000;
public static final int cHelperBitNeighbours = 0x0001;
public static final int cHelperBitRingsSimple = 0x0002; // small rings only, no aromaticity, no allylic nor stabilized flags
public static final int cHelperBitRings = 0x0004;
public static final int cHelperBitParities = 0x0008;
public static final int cHelperBitCIP = 0x0010;
public static final int cHelperBitSymmetrySimple = 0x0020;
public static final int cHelperBitSymmetryStereoHeterotopicity = 0x0040;
public static final int cHelperBitIncludeNitrogenParities = 0x0080;
public static final int cHelperBitsStereo = 0x00F8;
public static final int cHelperNeighbours = cHelperBitNeighbours;
public static final int cHelperRingsSimple = cHelperNeighbours | cHelperBitRingsSimple;
public static final int cHelperRings = cHelperRingsSimple | cHelperBitRings;
public static final int cHelperParities = cHelperRings | cHelperBitParities;
public static final int cHelperCIP = cHelperParities | cHelperBitCIP;
public static final int cHelperSymmetrySimple = cHelperCIP | cHelperBitSymmetrySimple;
public static final int cHelperSymmetryStereoHeterotopicity = cHelperCIP | cHelperBitSymmetryStereoHeterotopicity;
public static final int cChiralityIsomerCountMask = 0x00FFFF;
public static final int cChiralityUnknown = 0x000000;
public static final int cChiralityNotChiral = 0x010000;
public static final int cChiralityMeso = 0x020000; // this has added the number of meso isomers
public static final int cChiralityRacemic = 0x030000;
public static final int cChiralityKnownEnantiomer = 0x040000;
public static final int cChiralityUnknownEnantiomer = 0x050000;
public static final int cChiralityEpimers = 0x060000;
public static final int cChiralityDiastereomers = 0x070000; // this has added the number of diastereomers
public static final double cDefaultAVBL = 24.0;
private static double sDefaultAVBL = cDefaultAVBL;
public static final int cMoleculeColorDefault = 0;
public static final int cMoleculeColorNeutral = 1;
public static final int cPseudoAtomsHydrogenIsotops = 1; // D and T
public static final int cPseudoAtomsRGroups = 2; // R1 to R16
public static final int cPseudoAtomsAGroups = 4; // A1,A2,A3
public static final int cPseudoAtomR = 8; // R
public static final int cPseudoAtomA = 16; // A
public static final int cPseudoAtomX = 32; // X
public static final int cPseudoAtomsAminoAcids = 64; // all 20 amino acid 3-letter codes
public static final int cPseudoAtomPolymer = 128; // Pol
public static final int cPseudoAtomAttachmentPoint = 256; // ?
public static final int cPseudoAtomsAll = 511; // all of above
public static final int cDefaultAllowedPseudoAtoms = cPseudoAtomsHydrogenIsotops
| cPseudoAtomsAminoAcids
| cPseudoAtomAttachmentPoint;
public static final String[] cAtomLabel = { "?",
"H" ,"He" ,"Li" ,"Be" ,"B" ,"C" ,"N" ,"O" ,
"F" ,"Ne" ,"Na" ,"Mg" ,"Al" ,"Si" ,"P" ,"S" ,
"Cl" ,"Ar" ,"K" ,"Ca" ,"Sc" ,"Ti" ,"V" ,"Cr" ,
"Mn" ,"Fe" ,"Co" ,"Ni" ,"Cu" ,"Zn" ,"Ga" ,"Ge" ,
"As" ,"Se" ,"Br" ,"Kr" ,"Rb" ,"Sr" ,"Y" ,"Zr" ,
"Nb" ,"Mo" ,"Tc" ,"Ru" ,"Rh" ,"Pd" ,"Ag" ,"Cd" ,
"In" ,"Sn" ,"Sb" ,"Te" ,"I" ,"Xe" ,"Cs" ,"Ba" ,
"La" ,"Ce" ,"Pr" ,"Nd" ,"Pm" ,"Sm" ,"Eu" ,"Gd" ,
"Tb" ,"Dy" ,"Ho" ,"Er" ,"Tm" ,"Yb" ,"Lu" ,"Hf" ,
"Ta" ,"W" ,"Re" ,"Os" ,"Ir" ,"Pt" ,"Au" ,"Hg" ,
"Tl" ,"Pb" ,"Bi" ,"Po" ,"At" ,"Rn" ,"Fr" ,"Ra" ,
"Ac" ,"Th" ,"Pa" ,"U" ,"Np" ,"Pu" ,"Am" ,"Cm" ,
"Bk" ,"Cf" ,"Es" ,"Fm" ,"Md" ,"No" ,"Lr" ,"Rf" ,
"Db" ,"Sg" ,"Bh" ,"Hs" ,"Mt" ,"Ds" ,"Rg" ,"Cn" ,
"Nh" ,"Fl" ,"Mc" ,"Lv" ,"Ts" ,"Og" ,"??" ,"??" ,
"??" ,"??" ,"??" ,"??" ,"??" ,"??" ,"??" ,"??" ,
"R4" ,"R5" ,"R6" ,"R7" ,"R8" ,"R9" ,"R10","R11", // R4 to R16 do not belong to the MDL set
"R12","R13","R14","R15","R16","R1" ,"R2" ,"R3" ,
"A" ,"A1" ,"A2" ,"A3" ,"??" ,"??" ,"D" ,"T" ,
"X" ,"R" ,"H2" ,"H+" ,"Nnn","HYD","Pol","??" ,
"??" ,"??" ,"??" ,"??" ,"??" ,"??" ,"??" ,"??" ,
"??" ,"??" ,"Ala","Arg","Asn","Asp","Cys","Gln",
"Glu","Gly","His","Ile","Leu","Lys","Met","Phe",
"Pro","Ser","Thr","Trp","Tyr","Val" };
public static final short[] cRoundedMass = { 0,
1, 4, 7, 9, 11, 12, // H ,He ,Li ,Be ,B ,C ,
14, 16, 19, 20, 23, 24, // N , O ,F ,Ne ,Na ,Mg ,
27, 28, 31, 32, 35, 40, // Al ,Si ,P ,S ,Cl ,Ar ,
39, 40, 45, 48, 51, 52, // K ,Ca ,Sc ,Ti ,V ,Cr ,
55, 56, 59, 58, 63, 64, // Mn ,Fe ,Co ,Ni ,Cu ,Zn ,
69, 74, 75, 80, 79, 84, // Ga ,Ge ,As ,Se ,Br ,Kr ,
85, 88, 89, 90, 93, 98, // Rb ,Sr ,Y ,Zr ,Nb ,Mo ,
0, 102, 103, 106, 107, 114, // Tc ,Ru ,Rh ,Pd ,Ag ,Cd ,
115, 120, 121, 130, 127, 132, // In ,Sn ,Sb ,Te ,I ,Xe ,
133, 138, 139, 140, 141, 142, // Cs ,Ba ,La ,Ce ,Pr ,Nd ,
0, 152, 153, 158, 159, 164, // Pm ,Sm ,Eu ,Gd ,Tb ,Dy ,
165, 166, 169, 174, 175, 180, // Ho ,Er ,Tm ,Yb ,Lu ,Hf ,
181, 184, 187, 192, 193, 195, // Ta ,W , Re ,Os ,Ir ,Pt ,
197, 202, 205, 208, 209, 209, // Au ,Hg ,Tl ,Pb ,Bi ,Po ,
210, 222, 223, 226, 227, 232, // At ,Rn ,Fr ,Ra ,Ac ,Th ,
231, 238, 237, 244, 243, 247, // Pa ,U , Np ,Pu ,Am ,Cm ,
247, 251, 252, 257, 258, 259, // Bk ,Cf ,Es ,Fm ,Md ,No ,
262, 267, 268, 271, 270, 277, // Lr ,Rf ,Db ,Sg ,Bh ,Hs ,
276, 281, 281, 283, 285, 289, // Mt ,Ds ,Rg ,Cn ,Nh ,Fl ,
289, 293, 294, 294, 0, 0, // Mc ,Lv ,Ts ,Og ,?? ,?? ,
0, 0, 0, 0, 0, 0, // ?? ,?? ,?? ,?? ,?? ,?? ,
0, 0, 0, 0, 0, 0, // ?? ,?? ,R4 ,R5 ,R6 ,R7 ,
0, 0, 0, 0, 0, 0, // R8 ,R9 ,R10,R11,R12,R13,
0, 0, 0, 0, 0, 0, // R14,R15,R16,R1 ,R2 ,R3 ,
0, 0, 0, 0, 0, 0, // A ,A1 ,A2 ,A3 ,?? ,?? ,
2, 3, 0, 0, 0, 0, // D ,T ,X ,R ,H2 ,H+
0, 0, 0, 0, 0, 0, // Nnn,HYD,Pol,?? ,?? ,?? ,
0, 0, 0, 0, 0, 0, // ?? ,?? ,?? ,?? ,?? ,?? ,
0, 0, 71, 156, 114, 115, // ?? ,?? ,Ala,Arg,Asn,Asp,
103, 128, 129, 57, 137, 113, // Cys,Gln,Glu,Gly,His,Ile,
113, 128, 131, 147, 97, 87, // Leu,Lys,Met,Phe,Pro,Ser,
101, 186, 163, 99 }; // Thr,Trp,Tyr,Val,
public static final int cDefaultAtomValence = 6;
private static final byte[] cDefaultAtomValences = { cDefaultAtomValence };
private static final byte[] cAminoAcidValences = { 2 };
public static final byte[][] cAtomValence = {null,
{1}, {0}, {1}, {2}, {3}, {4}, {3}, {2}, {1}, {0}, // H to Ne
{1}, {2}, {3}, {4}, {3, 5}, {2, 4, 6}, {1, 3, 5, 7}, {0}, // Na to Ar
{1}, {2}, null, null, null, null, null, null, null, null, // K to Ni
null, null, {2, 3}, {2, 4}, {3, 5}, {2, 4, 6}, {1, 3, 5, 7}, {0, 2}, // Cu to Kr
{1}, {2}, null, null, null, null, null, null, null, null, // Rb to Pd
null, null, {1, 2, 3}, {2, 4}, {3, 5}, {2, 4, 6}, {1, 3, 5, 7}, // Ag to I
{0, 2, 4, 6}, {1}, {2}, // Xe to Ba
null, null, null, null, null, null, null, null, null, null, // La to Dy
null, null, null, null, null, null, null, null, null, null, // Ho to Os
null, null, null, null, null, null, null, null, null, null, // Ir to Rn
null, null, null, null, null, null, null, null, null, null, // Fr to Cm
null, null, null, null, null, null, null, null, null, null, // Bk to Sg
null, null, null, null, null, null, null, null, null, null, // Bh to Lv
null, null, null, null, null, null, null, null, null, null, // Ts to 126
null, null, null, null, null, null, null, null, null, null, // 127 to R5
null, null, null, null, null, null, null, null, null, null, // R6 to R15
null, null, null, null, null, null, null, null, null, null, // R16 to 156
null, null, null, null, null, null, null, null, null, null, // D to 166
null, null, null, null, // 167 to 170
{2}, {2}, {2}, {2}, {3}, {2}, {2}, {2}, {2}, {2}, // Ala to Ile
{2}, {2}, {2}, {2}, {2}, {2}, {2}, {2}, {2}, {2}, // Leu to Val
};
// Taken from http://www.cabrillo.edu/~aromero/Common%20Files/Periodic%20Table%20(Common%20Ionic%20Charges).pdf
public static final byte[][] cCommonOxidationState = { null,
{1}, null, {1}, {2}, null, null, // H, He, Li, Be, B, C,
{-3}, {-2}, {-1}, null, {1}, {2}, // N, O, F, Ne, Na, Mg,
{3}, null, {-3}, {-2}, {-1}, null, // Al, Si, P, S, Cl, Ar,
{1}, {2}, {3}, {2,3,4}, {2,3,4,5}, {2,3,6}, // K, Ca, Sc, Ti, V, Cr,
{2,3,4,7}, {2,3}, {2,3}, {2,3}, {1, 2}, {2}, // Mn, Fe, Co, Ni, Cu, Zn,
{3}, {2, 4}, {-3,3,5}, {-2}, {-1}, null, // Ga, Ge, As, Se, Br, Kr,
{1}, {2}, {3}, {4}, {3,5}, {6}, // Rb, Sr, Y, Zr, Nb, Mo,
{4,6,7}, {3}, {3}, {2,4}, {1}, {2}, // Tc, Ru, Rh, Pd, Ag, Cd,
{3}, {2,4}, {-3,3,5}, {-2,4,6}, {-1}, null, // In, Sn, Sb, Te, I, Xe,
{1}, {2}, {3}, {3,4}, {3}, {3}, // Cs, Ba, La ,Ce, Pr, Nd,
{3}, {2,3}, {2,3}, {3}, {3}, {3}, // Pm, Sm, Eu, Gd, Tb, Dy,
{3}, {3}, {3}, {2,3}, {3}, {4}, // Ho, Er, Tm, Yb, Lu, Hf,
{5}, {6}, {4,6,7}, {3, 4}, {3,4}, {2,4}, // Ta, W, Re, Os, Ir, Pt,
{1,3}, {1,2}, {1,3}, {2,4}, {3,5}, {-2,2,4}, // Au, Hg, Tl, Pb, Bi, Po,
{-1,1}, null, {1}, {2}, {3}, {4}, // At, Rn, Fr, Ra, Ac, Th,
{4,5}, {3,4,5,6}, {3,4,5,6}, {3,4,5,6}, {3,4,5,6}, // Pa, U, Np, Pu, Am,
{3}, {3,4}, {3}, {3}, {3}, {2,3}, // Cm, Bk, Cf, Es, Fm, Md,
{2,3}, {3} // No, Lr
};
transient protected int mMaxAtoms;
transient protected int mMaxBonds;
transient protected int mValidHelperArrays;
transient protected int mAllAtoms;
transient protected int mAllBonds;
transient protected int[] mAtomicNo;
transient protected int[] mAtomCharge;
transient protected int[] mAtomMapNo;
transient protected int[] mAtomMass;
transient protected int[] mAtomFlags;
transient protected long[] mAtomQueryFeatures;
transient protected int[][] mBondAtom;
transient protected int[] mBondType;
transient protected int[] mBondFlags;
transient protected int[] mBondQueryFeatures;
transient protected Coordinates[] mCoordinates;
transient protected boolean mIsFragment;
transient protected boolean mIsRacemate; // to indicate a molfileV2's chiral flat to be 0
transient protected boolean mProtectHydrogen; // protects hydrogens atoms from being converted to query features
transient protected int mChirality; // property set by Canonizer
transient protected int[][] mAtomList;
transient protected byte[][] mAtomCustomLabel;
transient private int mMoleculeColor;
transient private double mZoomRotationX,mZoomRotationY;
transient private double[] mOriginalAngle;
transient private double[] mOriginalDistance;
transient private String mName;
transient private Object mUserData;
public static int getAtomicNoFromLabel(String atomLabel) {
return getAtomicNoFromLabel(atomLabel, cDefaultAllowedPseudoAtoms);
}
public static int getAtomicNoFromLabel(String atomLabel, int allowedPseudoAtomGroups) {
if (((allowedPseudoAtomGroups & cPseudoAtomAttachmentPoint) != 0) && atomLabel.equals("?"))
return 0;
for (int i=1; i<=128; i++)
if (!atomLabel.equals("??") && atomLabel.equalsIgnoreCase(cAtomLabel[i]))
return i;
if ((allowedPseudoAtomGroups & cPseudoAtomsRGroups) != 0)
for (int i=129; i<=144; i++)
if (atomLabel.equalsIgnoreCase(cAtomLabel[i]))
return i;
if ((allowedPseudoAtomGroups & cPseudoAtomsAGroups) != 0)
for (int i=146; i<=148; i++)
if (atomLabel.equalsIgnoreCase(cAtomLabel[i]))
return i;
if ((allowedPseudoAtomGroups & cPseudoAtomsHydrogenIsotops) != 0)
for (int i=151; i<=152; i++)
if (atomLabel.equalsIgnoreCase(cAtomLabel[i]))
return i;
if ((allowedPseudoAtomGroups & cPseudoAtomX) != 0)
if (atomLabel.equalsIgnoreCase(cAtomLabel[153]))
return 153;
if ((allowedPseudoAtomGroups & cPseudoAtomR) != 0)
if (atomLabel.equalsIgnoreCase(cAtomLabel[154]))
return 154;
if ((allowedPseudoAtomGroups & cPseudoAtomA) != 0)
if (atomLabel.equalsIgnoreCase(cAtomLabel[145]))
return 145;
if ((allowedPseudoAtomGroups & cPseudoAtomPolymer) != 0)
if (atomLabel.equalsIgnoreCase(cAtomLabel[159]))
return 159;
if ((allowedPseudoAtomGroups & cPseudoAtomsAminoAcids) != 0)
for (int i=171; i<=190; i++)
if (atomLabel.equalsIgnoreCase(cAtomLabel[i]))
return i;
return 0;
}
/**
* For any known atomicNo this returns all allowed atom valences.
* For amino acid pseudo atoms it returns {2} and for all other atomicNos
* this returns {cDefaultAtomValence}.
* @param atomicNo
* @return array of allowed valences with a guaranteed minimum size of 1
*/
public static byte[] getAllowedValences(int atomicNo) {
return (atomicNo >= 0)
&& (atomicNo < cAtomValence.length)
&& (cAtomValence[atomicNo] != null) ? cAtomValence[atomicNo]
: (atomicNo >= 171 && atomicNo <= 190) ? cAminoAcidValences : cDefaultAtomValences;
}
/**
* Calculates the angle of the line leading from (x1,y1) to (x2,y2).
* @param x1
* @param y1
* @param x2
* @param y2
* @return -Pi to Pi
*/
public static double getAngle(double x1, double y1, double x2, double y2) {
double angle;
double xdiff = x2 - x1;
double ydiff = y2 - y1;
if (ydiff != 0) {
angle = Math.atan(xdiff/ydiff);
if (ydiff < 0) {
if (xdiff < 0)
angle -= Math.PI;
else
angle += Math.PI;
}
}
else
angle = (xdiff > 0f) ? Math.PI/2 : -Math.PI/2;
return angle;
}
/**
* Calculates the difference of two angles as angle1-angle2
* @param angle1
* @param angle2
* @return -Pi to Pi
*/
public static double getAngleDif(double angle1, double angle2) {
double angleDif = angle1 - angle2;
while (angleDif < -Math.PI)
angleDif += 2 * Math.PI;
while (angleDif > Math.PI)
angleDif -= 2 * Math.PI;
return angleDif;
}
public static int bondTypeToOrder(int bondType) {
int simpleType = bondType & cBondTypeMaskSimple;
return (simpleType == cBondTypeSingle
|| simpleType == cBondTypeDelocalized) ? 1
: simpleType == cBondTypeDouble ? 2
: simpleType == cBondTypeTriple ? 3
: simpleType == cBondTypeQuadruple ? 4
: simpleType == cBondTypeQuintuple ? 5 : 0; // dative bonds
}
public static int bondOrderToType(int bondOrder, boolean useCrossBond) {
return bondOrder == 0 ? Molecule.cBondTypeMetalLigand
: bondOrder == 1 ? Molecule.cBondTypeSingle
: bondOrder == 2 ? (useCrossBond ? Molecule.cBondTypeCross : Molecule.cBondTypeDouble)
: bondOrder == 3 ? Molecule.cBondTypeTriple
: bondOrder == 4 ? Molecule.cBondTypeQuadruple
: Molecule.cBondTypeQuintuple;
}
public Molecule() {
mMaxAtoms = mMaxBonds = 256;
init();
}
public Molecule(int maxAtoms, int maxBonds) {
mMaxAtoms = Math.max(1, maxAtoms);
mMaxBonds = Math.max(1, maxBonds);
init();
}
private void init() {
mValidHelperArrays = cHelperNone;
mAtomicNo = new int[mMaxAtoms];
mAtomCharge = new int[mMaxAtoms];
mAtomMapNo = new int[mMaxAtoms];
mCoordinates = new Coordinates[mMaxAtoms];
for (int i=0; i= mMaxAtoms)
setMaxAtoms(mMaxAtoms*2);
mAtomicNo[mAllAtoms] = 0; // default
setAtomicNo(mAllAtoms, atomicNo); // sets atomicNo and mass
mAtomCharge[mAllAtoms] = 0;
mAtomFlags[mAllAtoms] = 0;
mAtomQueryFeatures[mAllAtoms] = 0;
mAtomMapNo[mAllAtoms] = 0;
mCoordinates[mAllAtoms].set(0, 0, 0);
if (mAtomList != null)
mAtomList[mAllAtoms] = null;
if (mAtomCustomLabel != null)
mAtomCustomLabel[mAllAtoms] = null;
mValidHelperArrays = cHelperNone;
return mAllAtoms++;
}
/**
* Suggests either cBondTypeSingle or cBondTypeMetalLigand
* whatever seems more appropriate for a new bond between the two atoms.
* @param atom1
* @param atom2
* @return preferred bond type
*/
public int suggestBondType(int atom1, int atom2) {
return isMetalAtom(atom1) || isMetalAtom(atom2) ?
cBondTypeMetalLigand : cBondTypeSingle;
}
/**
* High level function for constructing a molecule.
* Adds a single or metal bond between the two atoms
* depending on whether one of them is a metal atom.
* @param atom1
* @param atom2
* @return new bond index
*/
public int addBond(int atom1, int atom2) {
return addBond(atom1, atom2, suggestBondType(atom1, atom2));
}
/**
* High level function for constructing a molecule.
* @param atom1
* @param atom2
* @param type
* @return new bond index
*/
public int addBond(int atom1, int atom2, int type) {
if (atom1 == atom2)
return -1;
for (int bnd=0; bnd= mMaxBonds)
setMaxBonds(mMaxBonds*2);
mBondAtom[0][mAllBonds] = atom1;
mBondAtom[1][mAllBonds] = atom2;
mBondType[mAllBonds] = type;
mBondFlags[mAllBonds] = 0;
mBondQueryFeatures[mAllBonds] = 0;
mValidHelperArrays = cHelperNone;
// checkAtomParity(atm1);
// checkAtomParity(atm2);
return mAllBonds++;
}
/**
* High level function for constructing a molecule.
* @param x
* @param y
* @param atomicNo
* @param mass
* @param abnormalValence
* @param radical
* @return
*/
public boolean addOrChangeAtom(double x, double y, int atomicNo, int mass, int abnormalValence, int radical, String customLabel) {
int atom = findAtom(x,y);
if (atom == -1) {
if (mAllAtoms >= mMaxAtoms)
setMaxAtoms(mMaxAtoms*2);
atom = addAtom(atomicNo);
mCoordinates[atom].set(x, y, 0);
mAtomMass[atom] = mass;
setAtomAbnormalValence(atom, abnormalValence);
setAtomRadical(atom, radical);
setAtomCustomLabel(atom, customLabel);
return true;
}
boolean changed = changeAtom(atom, atomicNo, mass, abnormalValence, radical);
setAtomCustomLabel(atom, customLabel);
return changed;
}
/**
* High level function for constructing a molecule.
* @param atm1
* @param atm2
* @param type
* @return
*/
public int addOrChangeBond(int atm1,int atm2,int type) {
for (int bnd=0; bnd= mMaxBonds)
setMaxBonds(mMaxBonds*2);
mBondAtom[0][mAllBonds] = atm1;
mBondAtom[1][mAllBonds] = atm2;
mBondType[mAllBonds] = type;
mBondFlags[mAllBonds] = 0;
mBondQueryFeatures[mAllBonds] = 0;
mValidHelperArrays = cHelperNone;
return mAllBonds++;
}
/**
* High level function for constructing a molecule.
* @param x
* @param y
* @param ringSize
* @param aromatic
* @return
*/
public boolean addRing(double x, double y, int ringSize, boolean aromatic, double bondLength) {
while(mAllAtoms + ringSize > mMaxAtoms)
setMaxAtoms(mMaxAtoms*2);
while(mAllBonds + ringSize > mMaxBonds)
setMaxBonds(mMaxBonds*2);
int atom = findAtom(x,y);
if (atom != -1)
return addRingToAtom(atom, ringSize, aromatic, bondLength);
int bond = findBond(x,y);
if (bond != -1)
return addRingToBond(bond, ringSize, aromatic, bondLength);
// new ring in empty space
atom = addAtom(x,y);
double cornerAngle = Math.PI * (ringSize-2)/ringSize;
polygon(atom, ringSize, atom,aromatic, 0, Math.PI - cornerAngle, bondLength);
mValidHelperArrays = cHelperNone;
return true;
}
/**
* High level function for constructing a molecule.
* @param atom
* @param ringSize
* @param aromatic
* @return
*/
public boolean addRingToAtom(int atom, int ringSize, boolean aromatic, double bondLength) {
if ((aromatic && getOccupiedValence(atom) > 1)
|| (!aromatic && getOccupiedValence(atom) > 2))
return false;
int angles = 0;
double[] angle = new double[4];
for (int i=0; i Math.PI) ? (angle[0] + angle[1])/2
: (angle[0] + angle[1])/2 + Math.PI;
double cornerAngle = (Math.PI * (ringSize-2))/ringSize;
polygon(atom, ringSize, atom, aromatic, newAngle-cornerAngle/2, Math.PI - cornerAngle, bondLength);
mValidHelperArrays = cHelperNone;
// checkAtomParity(atom);
return true;
}
/**
* High level function for constructing a molecule.
* @param bond
* @param ringSize
* @param aromatic
* @return
*/
public boolean addRingToBond(int bond, int ringSize, boolean aromatic, double bondLength) {
int[] bondAtom = new int[2];
double[] bondAngle = new double[2];
bondAtom[0] = mBondAtom[0][bond];
bondAtom[1] = mBondAtom[1][bond];
if (getOccupiedValence(bondAtom[0]) > 3) return false;
if (getOccupiedValence(bondAtom[1]) > 3) return false;
int angles = 0;
double[] angle = new double[4];
for (int i=0; i bondAngle[0]) && (angle[i] < bondAngle[1]))
side--;
else
side++;
}
atomNo = (side > 0) ? 1-atomNo : atomNo;
double cornerAngle = (Math.PI * (ringSize-2))/ringSize;
polygon(bondAtom[atomNo], ringSize-1,
bondAtom[1-atomNo], aromatic,
bondAngle[(side > 0) ? 0 : 1] + Math.PI - cornerAngle, Math.PI - cornerAngle, bondLength);
mValidHelperArrays = cHelperNone;
// checkAtomParity(bondAtom[0]);
// checkAtomParity(bondAtom[1]);
return true;
}
/**
* High level function for constructing a molecule.
* @param atom
* @param atomicNo
* @param mass
* @param abnormalValence
* @param radical
* @return
*/
public boolean changeAtom(int atom, int atomicNo, int mass, int abnormalValence, int radical) {
if ((atomicNo == 1 || atomicNo == 151 || atomicNo == 152)
&& getOccupiedValence(atom) > 1)
return false;
mAtomQueryFeatures[atom] &= ~cAtomQFAny;
if (mAtomList != null)
mAtomList[atom] = null;
if (mAtomCustomLabel != null)
mAtomCustomLabel[atom] = null;
if (atomicNo == mAtomicNo[atom]
&& mass == mAtomMass[atom]
&& abnormalValence == getAtomAbnormalValence(atom)
&& radical == getAtomRadical(atom))
return false;
if (atomicNo == 151 || atomicNo == 152) { // 'D' or 'T'
mass = atomicNo - 149;
atomicNo = 1;
}
mAtomFlags[atom] &= (cAtomFlagsColor | cAtomFlagSelected);
mAtomicNo[atom] = atomicNo;
mAtomMass[atom] = mass;
mAtomCharge[atom] = 0;
mAtomQueryFeatures[atom] = 0;
setAtomAbnormalValence(atom, abnormalValence);
setAtomRadical(atom, radical);
removeMappingNo(mAtomMapNo[atom]);
mValidHelperArrays = cHelperNone;
// checkAtomParity(atom);
return true;
}
/**
* High level function for constructing a molecule.
* @param x
* @param y
* @param positive
* @return
*/
public boolean changeAtomCharge(double x, double y, boolean positive) {
int atom = findAtom(x,y);
return atom != -1 && changeAtomCharge(atom, positive);
}
/**
* High level function for constructing a molecule.
* @param atom
* @param positive
* @return
*/
public boolean changeAtomCharge(int atom, boolean positive) {
if (positive) {
if (mAtomCharge[atom] > 8) return false;
mAtomCharge[atom]++;
}
else {
if (mAtomCharge[atom] < -8) return false;
mAtomCharge[atom]--;
}
mValidHelperArrays = cHelperNone;
// checkAtomParity(atom);
return true;
}
/**
* High level function for constructing a molecule.
* @param bnd
* @param type
* @return
*/
public boolean changeBond(int bnd, int type) {
boolean bondWasChanged = false;
int oldType = mBondType[bnd];
if (type == cBondTypeIncreaseOrder) {
bondWasChanged = incrementBondOrder(bnd);
}
else if (validateBondType(bnd, type)) {
if (type == cBondTypeUp || type == cBondTypeDown) {
boolean bondAtAtom1Qualifies = qualifiesAsStereoBond(bnd, mBondAtom[0][bnd]);
boolean bondAtAtom2Qualifies = qualifiesAsStereoBond(bnd, mBondAtom[1][bnd]);
if (type == oldType) {
// If both atoms are stereocenters (or none is recognized yet as stereo center)
// or if only one atom is a stereo center and the bond points to the other one
// then we can invert the bond direction.
if (bondAtAtom1Qualifies == bondAtAtom2Qualifies
|| bondAtAtom2Qualifies) {
int temp = mBondAtom[0][bnd];
mBondAtom[0][bnd] = mBondAtom[1][bnd];
mBondAtom[1][bnd] = temp;
bondWasChanged = true;
}
}
else {
// if stereo center information available assure proper bond direction
if (!bondAtAtom1Qualifies && bondAtAtom2Qualifies) {
int temp = mBondAtom[0][bnd];
mBondAtom[0][bnd] = mBondAtom[1][bnd];
mBondAtom[1][bnd] = temp;
}
mBondType[bnd] = type;
bondWasChanged = true;
}
}
else {
mBondType[bnd] = type;
bondWasChanged = true;
}
}
if (bondWasChanged) {
mValidHelperArrays = (oldType & cBondTypeMaskSimple)
== (type & cBondTypeMaskSimple) ?
mValidHelperArrays & cHelperRings
: cHelperNone;
mBondQueryFeatures[bnd] = 0;
}
return bondWasChanged;
}
/**
* Checks whether this bond may rightfully be an up/down stereo bond with its pointed end
* connected to atom.
* i.e. whether it is a stereo center, an allene end atom, or an atom of a BINAP bond.
* @return true if an attached stereo bond aids in stereo recognition
*/
private boolean qualifiesAsStereoBond(int bond, int atom) {
if (getBondOrder(bond) != 1)
return false;
if ((mAtomFlags[atom] & cAtomFlagsParity) != cAtomParityNone)
return true;
// stereo bond at allene
for (int i=0; i= destMol.mMaxAtoms)
destMol.setMaxAtoms(destMol.mMaxAtoms*2);
int esrType = getAtomESRType(sourceAtom);
int esrGroup = -1;
if (esrType == cESRTypeAnd) {
if (esrGroupOffsetAND == -1) // create a new ESR group for this atom
esrGroup = destMol.renumberESRGroups(esrType);
else // take existing group and add offset that should be the
// ESR group member count of destMol before starting to add atoms
esrGroup = Math.min(cESRMaxGroups-1, esrGroupOffsetAND + getAtomESRGroup(sourceAtom));
}
else if (esrType == cESRTypeOr) {
if (esrGroupOffsetOR == -1) // create a new ESR group for this atom
esrGroup = destMol.renumberESRGroups(esrType);
else // take existing group and add offset that should be the
// ESR group member count of destMol before starting to add atoms
esrGroup = Math.min(cESRMaxGroups-1, esrGroupOffsetOR + getAtomESRGroup(sourceAtom));
}
destMol.mAtomicNo[destAtom] = mAtomicNo[sourceAtom];
destMol.mAtomCharge[destAtom] = mAtomCharge[sourceAtom];
destMol.mAtomMass[destAtom] = mAtomMass[sourceAtom];
destMol.mAtomFlags[destAtom] = mAtomFlags[sourceAtom];
destMol.mAtomQueryFeatures[destAtom] = destMol.mIsFragment ? mAtomQueryFeatures[sourceAtom] : 0;
destMol.mCoordinates[destAtom].set(mCoordinates[sourceAtom]);
destMol.mAtomMapNo[destAtom] = mAtomMapNo[sourceAtom];
if (destMol.mAtomList != null)
destMol.mAtomList[destAtom] = null;
if (mAtomList != null && mAtomList[sourceAtom] != null && destMol.mIsFragment) {
if (destMol.mAtomList == null)
destMol.mAtomList = new int[destMol.mAtomicNo.length][];
destMol.mAtomList[destAtom] = Arrays.copyOf(mAtomList[sourceAtom], mAtomList[sourceAtom].length);
}
if (destMol.mAtomCustomLabel != null)
destMol.mAtomCustomLabel[destAtom] = null;
if (mAtomCustomLabel != null && mAtomCustomLabel[sourceAtom] != null) {
if (destMol.mAtomCustomLabel == null)
destMol.mAtomCustomLabel = new byte[destMol.mAtomicNo.length][];
destMol.mAtomCustomLabel[destAtom] = Arrays.copyOf(mAtomCustomLabel[sourceAtom], mAtomCustomLabel[sourceAtom].length);
}
if (esrGroup != -1) {
destMol.mAtomFlags[destAtom] &= ~cAtomFlagsESRGroup;
destMol.mAtomFlags[destAtom] |= (esrGroup << cAtomFlagsESRGroupShift);
}
destMol.mAllAtoms++;
destMol.mValidHelperArrays = cHelperNone;
return destAtom;
}
/**
* @param destMol
* @param sourceBond
* @param esrGroupOffsetAND -1 to create new ESR group or destMol ESR group count from esrGroupCountAND()
* @param esrGroupOffsetOR -1 to create new ESR group or destMol ESR group count from esrGroupCountOR()
* @param atomMap
* @param useBondTypeDelocalized
* @return
*/
public int copyBond(Molecule destMol, int sourceBond, int esrGroupOffsetAND, int esrGroupOffsetOR,
int[] atomMap, boolean useBondTypeDelocalized) {
return copyBond(destMol, sourceBond, esrGroupOffsetAND, esrGroupOffsetOR,
(atomMap == null) ? mBondAtom[0][sourceBond] : atomMap[mBondAtom[0][sourceBond]],
(atomMap == null) ? mBondAtom[1][sourceBond] : atomMap[mBondAtom[1][sourceBond]],
useBondTypeDelocalized);
}
/**
* @param destMol
* @param sourceBond
* @param esrGroupOffsetAND -1 to create new ESR group or destMol ESR group count from esrGroupCountAND()
* @param esrGroupOffsetOR -1 to create new ESR group or destMol ESR group count from esrGroupCountOR()
* @param destAtom1 first bond atom index in destination molecule
* @param destAtom2 second bond atom index in destination molecule
* @param useBondTypeDelocalized
* @return
*/
public int copyBond(Molecule destMol, int sourceBond, int esrGroupOffsetAND, int esrGroupOffsetOR,
int destAtom1, int destAtom2, boolean useBondTypeDelocalized) {
int destBond = destMol.mAllBonds;
if (destBond >= destMol.mMaxBonds)
destMol.setMaxBonds(destMol.mMaxBonds * 2);
int esrType = getBondESRType(sourceBond);
int esrGroup = -1;
if (esrType == cESRTypeAnd) {
if (esrGroupOffsetAND == -1) // create a new ESR group for this atom
esrGroup = destMol.renumberESRGroups(esrType);
else // take existing group and add offset that should be the
// ESR group member count of destMol before starting to add atoms
esrGroup = Math.min(cESRMaxGroups, esrGroupOffsetAND + getBondESRGroup(sourceBond));
}
if (esrType == cESRTypeOr) {
if (esrGroupOffsetOR == -1) // create a new ESR group for this atom
esrGroup = destMol.renumberESRGroups(esrType);
else // take existing group and add offset that should be the
// ESR group member count of destMol before starting to add atoms
esrGroup = Math.min(cESRMaxGroups, esrGroupOffsetOR + getBondESRGroup(sourceBond));
}
destMol.mBondAtom[0][destBond] = destAtom1;
destMol.mBondAtom[1][destBond] = destAtom2;
int bondType = (useBondTypeDelocalized && isDelocalizedBond(sourceBond)) ?
cBondTypeDelocalized : mBondType[sourceBond];
destMol.mBondType[destBond] = bondType;
destMol.mBondFlags[destBond] = mBondFlags[sourceBond];
destMol.mBondQueryFeatures[destBond] = destMol.mIsFragment ? mBondQueryFeatures[sourceBond] : 0;
if (esrGroup != -1) {
destMol.mBondFlags[destBond] &= ~cBondFlagsESRGroup;
destMol.mBondFlags[destBond] |= (esrGroup << cBondFlagsESRGroupShift);
}
destMol.mAllBonds++;
destMol.mValidHelperArrays = cHelperNone;
return destBond;
}
/**
* Copies name,isFragment,chirality and validity of parity & CIP flags.
* When copying molecules parts only or when changing the atom order during copy,
* then atom parities or CIP parities may not be valid anymore and
* invalidateHelperArrays([affected bits]) should be called in these cases.
* @param destMol
*/
public void copyMoleculeProperties(Molecule destMol) {
destMol.mIsFragment = mIsFragment;
destMol.mIsRacemate = mIsRacemate;
destMol.mProtectHydrogen = mProtectHydrogen;
destMol.mChirality = mChirality;
destMol.mName = mName;
destMol.mValidHelperArrays = (mValidHelperArrays & (cHelperBitParities | cHelperBitCIP));
}
/**
* Clears helperBits from mValidHelperArrays.
* @param helperBits
*/
public void invalidateHelperArrays(int helperBits) {
mValidHelperArrays &= ~helperBits;
}
/**
* For the given ESR type (AND or OR) renumbers all group indexes starting from 0.
* Use this, if stereo center deletion or other operations caused an inconsisten ESR
* number state. Molecule and derived methods do this automatically.
* @param type cESRTypeAnd or cESRTypeOr
* @return number of ESR groups
*/
public int renumberESRGroups(int type) {
if (type == cESRTypeAbs)
return 0;
// reassign group numbers from bottom up
boolean[] groupUsed = null;
for (int atom=0; atom
* When multiple atoms and/or bonds need to be deleted, marking them and calling
* this method is more efficient than deleting them individually with deleteAtom() and
* deleteBond().
* Bonds, whose atoms carry opposite charges are treated in the following manner: If only one of
* the two bond atoms is kept, then its absolute charge will be reduced by 1.
* After the deletion the original order of atom and bond indexes is retained.
* @return mapping from old to new atom indices; null if no atoms nor bonds were deleted
*/
public int[] deleteMarkedAtomsAndBonds() {
boolean found = false;
for (int atom=0; atom bondLength / 2.0) continue;
double distance;
if (x2 == x1)// if pick posn closer to bond than cPickRange return bnd
distance = Math.abs(x1 - pickx);
else {
double constA = (y2-y1)/(x1-x2);
double constC = - constA * x1 - y1;
distance = Math.abs((constA * pickx + picky + constC)
/ Math.sqrt(constA * constA + 1));
}
if (distance < maxDistance
&& distance < foundDistance) {
foundDistance = distance;
foundBond = bond;
}
}
return foundBond;
}
/**
* @return the number of all atoms, which includes hydrogen atoms.
*/
public int getAllAtoms() {
return mAllAtoms;
}
/**
* @return the number of all bonds, which includes those connecting hydrogen atoms.
*/
public int getAllBonds() {
return mAllBonds;
}
/**
* Get an atom's defined maximum valance if different from the default one.
* @param atom
* @return valence 0-14: new maximum valence; -1: use default
*/
public int getAtomAbnormalValence(int atom) {
return ((mAtomFlags[atom] & cAtomFlagsValence) >>> cAtomFlagsValenceShift) -1;
}
/**
* @param atom
* @return the formal atom charge
*/
public int getAtomCharge(int atom) {
return mAtomCharge[atom];
}
/**
* The atom Cahn-Ingold-Prelog parity is a calculated property available above/equal helper level cHelperCIP.
* It encodes the stereo configuration of an atom with its neighbors using up/down-bonds
* or 3D-atom-coordinates, whatever is available. It depends on the atom indices of the neighbor
* atoms and their orientation is space. This method is called by the Canonizer and usually should not
* be called otherwise.
* @param atom
* @return one of cAtomCIPParityNone,cAtomCIPParityRorM,cAtomCIPParitySorP,cAtomCIPParityProblem
*/
public int getAtomCIPParity(int atom) {
return (mAtomFlags[atom] & cAtomFlagsCIPParity) >> cAtomFlagsCIPParityShift;
}
public int getAtomColor(int atom) {
return mAtomFlags[atom] & cAtomFlagsColor;
}
/**
* @return the entire atom coordinate array
*/
public Coordinates getAtomCoordinates(int atom) {
return mCoordinates[atom];
}
/**
* @return the entire atom coordinate array
*/
public Coordinates[] getAtomCoordinates() {
return mCoordinates;
}
/**
* This is MDL's enhanced stereo representation (ESR).
* Stereo atoms and bonds with the same ESR type (AND or OR) and the same ESR group number
* are in the same group, i.e. within this group they have the defined (relative) stereo configuration.
* @param atom
* @return group index starting with 0
*/
public int getAtomESRGroup(int atom) {
if (getAtomESRType(atom) != cESRTypeAnd
&& getAtomESRType(atom) != cESRTypeOr)
return -1;
else
return (mAtomFlags[atom] & cAtomFlagsESRGroup) >> cAtomFlagsESRGroupShift;
}
/**
* This is MDL's enhanced stereo representation (ESR).
* Stereo atoms and bonds with the same ESR type (AND or OR) and the same ESR group number
* are in the same group, i.e. within this group they have the defined (relative) stereo configuration.
* @param atom
* @return one of cESRTypeAbs,cESRTypeAnd,cESRTypeOr
*/
public int getAtomESRType(int atom) {
return (mAtomFlags[atom] & cAtomFlagsESRType) >> cAtomFlagsESRTypeShift;
}
/**
* In addition to the natural atomic numbers, we support additional pseudo atomic numbers.
* Most of these are for compatibility with the MDL atom table, e.g. for amino acids and R-groups.
* D and T are accepted for setting, but are on-the-fly translated to H with the proper atom mass.
* @param atom
* @return
*/
public int getAtomicNo(int atom) {
return mAtomicNo[atom];
}
/**
* If a custom atom label is set, a molecule depiction displays
* the custom label instead of the original one.
* @param atom
* @return null or previously defined atom custom label
*/
public String getAtomCustomLabel(int atom) {
return (mAtomCustomLabel == null) ? null
: (mAtomCustomLabel[atom] == null) ? null
: new String(mAtomCustomLabel[atom], StandardCharsets.UTF_8);
}
/**
* This method is more efficient than getAtomCustomLabel(),
* because internally atom custom labels are stored as a byte[].
* Use this if you can work with bytes and don't need a String.
* @param atom
* @return null or previously defined atom custom label as byte[]
*/
public byte[] getAtomCustomLabelBytes(int atom) {
return (mAtomCustomLabel == null) ? null : mAtomCustomLabel[atom];
}
/**
* @param atom
* @return standard atom label of the atom: C,Li,Sc,...
*/
public String getAtomLabel(int atom) {
return cAtomLabel[mAtomicNo[atom]];
}
/**
* The list of atoms that are allowed at this position during sub-structure search.
* (or refused atoms, if atom query feature cAtomQFAny is set).
* @param atom
* @return null or sorted list of unique atomic numbers, if defined
*/
public int[] getAtomList(int atom) {
return (mAtomList == null) ? null : mAtomList[atom];
}
public String getAtomListString(int atom) {
if (mAtomList == null || mAtomList[atom] == null)
return ((mAtomQueryFeatures[atom] & cAtomQFAny) != 0) ?
"" : cAtomLabel[mAtomicNo[atom]];
String listString = "";
for (int i=0; i 0)
listString = listString.concat(",");
int atomicNo = mAtomList[atom][i];
listString = listString.concat(Molecule.cAtomLabel[atomicNo]);
}
return listString;
}
/**
* Returns an atom mapping number within the context of a reaction.
* Atoms that share the same mapping number on the reactant and product side
* are considered to be the same atom.
* @param atom
* @return
*/
public int getAtomMapNo(int atom) {
return Math.abs(mAtomMapNo[atom]);
}
/**
* @param atom
* @return atom mass, if is specific isotop, otherwise 0 for natural abundance
*/
public int getAtomMass(int atom) {
return mAtomMass[atom];
}
/**
* The atom parity is a calculated property available above/equal helper level cHelperParities.
* It describes the stereo configuration of a chiral atom and is calculated either from
* 2D-atom-coordinates and up/down-bonds or from 3D-atom-coordinates, whatever is available.
* It depends on the atom indexes of the neighbor atoms and their orientation in space.
* The parity is defined as follows: Look at the chiral atom such that its neighbor atom with the
* highest atom index (or the hydrogen atom if it is implicit) is oriented to the back.
* If the remaining three neighbors are in clockwise order (considering ascending atom indexes)
* than the parity is 1. If they are in anti-clockwise order, then the parity is 2.
* For linear chirality (allenes): Look along the straight line of double bonds such that the
* rear neighbor with the lower atom index points to the top. If the front neighbor with the
* lower atom index points to the right than the parity is 1.
* @param atom
* @return one of cAtomParity1,cAtomParity2,cAtomParityNone,cAtomParityUnknown
*/
public int getAtomParity(int atom) {
return mAtomFlags[atom] & cAtomFlagsParity;
}
/**
* Returns all set query features for this atom. In order to get all features related to a certain subject
* use something like this: getAtomQueryFeatures() & cAtomQFHydrogen
* @param atom
* @return
*/
public long getAtomQueryFeatures(int atom) {
return mAtomQueryFeatures[atom];
}
/**
* Gets an atom's radical state as singulet,dublet,triplet or none
* @param atom
* @return one of cAtomRadicalStateNone,cAtomRadicalStateS,cAtomRadicalStateD,cAtomRadicalStateT
*/
public int getAtomRadical(int atom) {
return mAtomFlags[atom] & cAtomRadicalState;
}
public Coordinates getCoordinates(int atom) {
return mCoordinates[atom];
}
public Coordinates getCenterOfGravity() {
if (mAllAtoms == 0)
return null;
Coordinates c = new Coordinates();
for (int atom = 0; atommAllAtoms)
return null;
Coordinates c = new Coordinates();
for (int atom:atomIndex)
c.add(mCoordinates[atom]);
return c.scale(1.0 / atomIndex.length);
}
public double getAtomX(int atom) {
return mCoordinates[atom].x;
}
public double getAtomY(int atom) {
return mCoordinates[atom].y;
}
public double getAtomZ(int atom) {
return mCoordinates[atom].z;
}
// @Deprecated
// public Rectangle2D.Double getBounds(Rectangle2D.Double r) {
// if (mAllAtoms == 0)
// return null;
//
// GenericRectangle b = getBounds((GenericRectangle)null);
// if (r != null) {
// r.x = b.x;
// r.y = b.y;
// r.width = b.width;
// r.height = b.height;
// return r;
// }
//
// return new Rectangle2D.Double(b.x, b.y, b.width, b.height):
// }
public GenericRectangle getBounds(GenericRectangle r) {
if (mAllAtoms == 0)
return null;
double x1 = mCoordinates[0].x;
double y1 = mCoordinates[0].y;
double x2 = mCoordinates[0].x;
double y2 = mCoordinates[0].y;
for (int atom=1; atom mCoordinates[atom].x)
x1 = mCoordinates[atom].x;
else if (x2 < mCoordinates[atom].x)
x2 = mCoordinates[atom].x;
if (y1 > mCoordinates[atom].y)
y1 = mCoordinates[atom].y;
else if (y2 < mCoordinates[atom].y)
y2 = mCoordinates[atom].y;
}
if (r == null) {
r = new GenericRectangle(x1, y1, x2 - x1, y2 - y1);
}
else {
r.x = x1;
r.y = y1;
r.width = x2-x1;
r.height = y2-y1;
}
return r;
}
public static double getDefaultAverageBondLength() {
return sDefaultAVBL;
}
/**
* When the molecule adds a new bond to a new atom or a new ring,
* then atoms are positioned such that the lengths of the new bonds
* are equal to the average length of existing bonds. If there are no
* existing bonds, then this default is used.
* If the default is not set by this function, then it is 24.
* @param defaultAVBL
*/
public static void setDefaultAverageBondLength(double defaultAVBL) {
sDefaultAVBL = defaultAVBL;
}
/**
* Calculates and returns the mean bond length. If the molecule has
* no bonds, then the smallest distance between unconnected atoms is
* returned. If it has less than 2 atoms, cDefaultAverageBondLength is returned.
* @return
*/
public double getAverageBondLength() {
return getAverageBondLength(mAllAtoms, mAllBonds, sDefaultAVBL);
}
/**
* Calculates and returns the mean bond length. If the molecule has
* no bonds, then the smallest distance between unconnected atoms is
* returned. If it has less than 2 atoms, the given defaultBondLength is returned.
* @return
*/
public double getAverageBondLength(double defaultBondLength) {
return getAverageBondLength(mAllAtoms, mAllBonds, defaultBondLength);
}
/**
* Calculates and returns the mean bond length of all bonds 0...bonds.
* If there are no bonds, then the smallest distance between unconnected atoms is
* returned. If we have less than 2 atoms, cDefaultAverageBondLength is returned.
* @param atoms atom indexes >= this are not considered
* @param bonds bond indexes >= this are not considered
* @return
*/
public double getAverageBondLength(int atoms, int bonds) {
return getAverageBondLength(atoms, bonds, sDefaultAVBL);
}
/**
* Calculates and returns the mean bond length of all bonds 0...bonds.
* If there are no bonds, then the smallest distance between unconnected atoms is
* determined and a reasonable potential bond length derived from that is returned.
* If we have less than 2 atoms, defaultBondLength is returned.
* @param atoms atom indexes >= this are not considered
* @param bonds bond indexes >= this are not considered
* @param defaultBondLength
* @return
*/
public double getAverageBondLength(int atoms, int bonds, double defaultBondLength) {
return getAverageBondLength(atoms, bonds, defaultBondLength, mCoordinates);
}
/**
* Calculates and returns the mean bond length of all bonds 0...bonds.
* If there are no bonds, then the smallest distance between unconnected atoms is
* determined and a reasonable potential bond length derived from that is returned.
* If we have less than 2 atoms, defaultBondLength is returned.
* @param atoms atom indexes >= these are not considered
* @param bonds bond indexes >= these are not considered
* @param defaultBondLength
* @param coords to be used, either the molecule's coordinates, or an alternative, e.g. from a Conformer
* @return
*/
public double getAverageBondLength(int atoms, int bonds, double defaultBondLength, Coordinates[] coords) {
boolean considerMetalBonds = false;
int consideredBonds = 0;
// count all non-metal bonds
for (int bond=0; bond 0 && distance < lowDistance)
lowDistance = distance;
}
}
return (lowDistance != Double.MAX_VALUE) ? 0.6 * lowDistance : defaultBondLength;
}
double avblSum = 0.0;
for (int bond=0; bond> cBondFlagsCIPParityShift;
}
/**
* This is MDL's enhanced stereo representation (ESR).
* Stereo atoms and bonds with the same ESR type (AND or OR) and the same ESR group number
* are in the same group, i.e. within this group they have the defined (relative) stereo configuration.
* @param bond
* @return group index starting with 0
*/
public int getBondESRGroup(int bond) {
if (getBondESRType(bond) != cESRTypeAnd
&& getBondESRType(bond) != cESRTypeOr)
return -1;
else
return (mBondFlags[bond] & cBondFlagsESRGroup) >> cBondFlagsESRGroupShift;
}
/**
* This is MDL's enhanced stereo representation (ESR).
* Stereo atoms and bonds with the same ESR type (AND or OR) and the same ESR group number
* are in the same group, i.e. within this group they have the defined (relative) stereo configuration.
* @param bond
* @return one of cESRTypeAbs,cESRTypeAnd,cESRTypeOr
*/
public int getBondESRType(int bond) {
return (mBondFlags[bond] & cBondFlagsESRType) >> cBondFlagsESRTypeShift;
}
/**
* @param bond
* @return bond length calculated from atom 2D-coordinates.
*/
public double getBondLength(int bond) {
int atom1 = mBondAtom[0][bond];
int atom2 = mBondAtom[1][bond];
double xdif = mCoordinates[atom2].x - mCoordinates[atom1].x;
double ydif = mCoordinates[atom2].y - mCoordinates[atom1].y;
return Math.sqrt(xdif * xdif + ydif * ydif);
}
/**
* Returns the formal bond order. Delocalized rings have alternating single and double
* bonds, which are returned as such. Bonds that are explicitly marked as being delocalized
* are returned as 1. Dative bonds are returned as 0.
* In fragments with at least one bond type set as bond query feature, the smallest
* non-zero order of allowed bonds is returned.
* @param bond
* @return formal bond order 0 (dative bonds), 1, 2, 3, 4, or 5
*/
public int getBondOrder(int bond) {
if (mIsFragment && (mBondQueryFeatures[bond] & cBondQFBondTypes) != 0) {
if ((mBondQueryFeatures[bond] & (cBondQFSingle | cBondQFDelocalized)) != 0)
return 1;
if ((mBondQueryFeatures[bond] & cBondQFDouble) != 0)
return 2;
if ((mBondQueryFeatures[bond] & cBondQFTriple) != 0)
return 3;
if ((mBondQueryFeatures[bond] & cBondQFQuadruple) != 0)
return 4;
if ((mBondQueryFeatures[bond] & cBondQFQuintuple) != 0)
return 5;
if ((mBondQueryFeatures[bond] & cBondQFMetalLigand) != 0)
return 0;
}
switch (mBondType[bond] & cBondTypeMaskSimple) {
case cBondTypeSingle:
case cBondTypeDelocalized: return 1;
case cBondTypeDouble: return 2;
case cBondTypeTriple: return 3;
case cBondTypeQuadruple: return 4;
case cBondTypeQuintuple: return 5;
default: return 0; // dative bonds, ligand field bonds
}
}
/**
* Returns the pre-calculated bond parity, e.g. cBondParityEor1.
* To distinguish double bond parities (E/Z) from parities of axial
* chirality, e.g. BINAP type (1/2) simply check with getBondOrder(bond):
* If the order is 2, then the parity describes E/Z, otherwise an axial parity.
* @param bnd
* @return one of cBondParity???
*/
public int getBondParity(int bnd) {
return mBondFlags[bnd] & cBondFlagsParity;
}
public int getBondQueryFeatures(int bnd) {
return mBondQueryFeatures[bnd];
}
public boolean isBondBridge(int bond) {
return (mBondQueryFeatures[bond] & cBondQFBridge) != 0;
}
public int getBondBridgeMinSize(int bond) {
return (mBondQueryFeatures[bond] & cBondQFBridgeMin) >> cBondQFBridgeMinShift;
}
public int getBondBridgeMaxSize(int bond) {
return ((mBondQueryFeatures[bond] & cBondQFBridgeMin) >> cBondQFBridgeMinShift)
+ ((mBondQueryFeatures[bond] & cBondQFBridgeSpan) >> cBondQFBridgeSpanShift);
}
/**
* Returns bond type combining bond order and stereo orientation.
* @param bond
* @return one of cBondTypeSingle,cBondTypeDouble,cBondTypeUp,cBondTypeCross,...
*/
public int getBondType(int bond) {
return mBondType[bond];
}
/**
* This is the bond type without stereo information.
* @param bond
* @return cBondTypeSingle,cBondTypeDouble,cBondTypeTriple,(cBondTypeDelocalized if used)
*/
public int getBondTypeSimple(int bond) {
return mBondType[bond] & cBondTypeMaskSimple;
}
/**
* Gets the overall chirality of the molecule, which is a calculated information considering:
* Recognition of stereo centers and stereo bonds, defined ESR features, meso detection.
* The chirality combines the knowledge about how many stereo isomers are represented,
* whether all of these are meso, whether we have one defined stereo isomer, a mixture
* of racemates, epimers, or other diastereomers.
* The information is used during depiction.
*/
public int getChirality() {
return mChirality;
}
/**
* The currently defined maximum of atoms, which increases automatically when using high level
* construction methods and new atoms exceed the current maximum.
* @return
*/
public int getMaxAtoms() {
return mMaxAtoms;
}
/**
* Used instead of the 1.6 Features. Cartridge needs 1.5
* @param original
* @param newLength
* @return
*/
private static Coordinates[] copyOf(Coordinates[] original, int newLength) {
Coordinates[] copy = new Coordinates[newLength];
for (int i=0; i
* cMoleculeColorNeutral: all atoms and bonds and CIP letters are drawn in neutral color
* @return cMoleculeColorNeutral or cMoleculeColorDefault. In future may also return ARGB values.
*/
public int getMoleculeColor() {
return mMoleculeColor;
}
/**
* Currently, this method only allows to switch the default atomic number dependent atom coloring off
* by passing cMoleculeColorNeutral. In future updates it may also accept ARGB values.
* @param color currently supported values: cMoleculeColorDefault, cMoleculeColorNeutral
*/
public void setMoleculeColor(int color) {
mMoleculeColor = color;
}
/**
* Allows to set a molecule name or identifier, that is, for instance, written to or read from molfiles.
* @return
*/
public String getName() {
return mName;
}
/**
* The stereo problem flag is set by the stereo recognition (available equal/above helper level cHelperParities)
* if an atom has over- or under-specified stereo bonds attached, i.e. a stereo center with less or more than one
* up/down-bond, an non-stereo-center atom carrying (a) stereo bond(s), or a stereo center with neighbors coordinates
* such that the stereo configuration cannot be deduced. This flag is used by the depiction and causes affected atoms
* to be drawn in margenta.
* @param atom
* @return
*/
public boolean getStereoProblem(int atom) {
return ((mAtomFlags[atom] & cAtomFlagStereoProblem) != 0);
}
/**
* @param atom
* @return whether the atom's stereo configuration was explicitly declared unknown
*/
public boolean isAtomConfigurationUnknown(int atom) {
return ((mAtomFlags[atom] & cAtomFlagConfigurationUnknown) != 0);
}
/**
* Pseudo paries are parities that indicate a relative configuration.
* It always needs at least 2 pseudo parities (atom or bond) within
* a part of a molecule to be meaningful.
* This information is calculated by ensureHelperArrays(Molecule.cHelperCIP).
* Molecules extracted from IDCode don't know about pseudo parities.
* @param atom
* @return wether this atom's parity is a relative configuration
*/
public boolean isAtomParityPseudo(int atom) {
return ((mAtomFlags[atom] & cAtomParityIsPseudo) != 0);
}
/**
* Atoms with pseudo parities are not considered stereo centers.
* While parities are canonized and always refer to the full set
* of molecules (in case ESR groups are defined), this method
* returns true if this atom is a stereo center in any(!) of the
* individual molecules described by the ESR settings.
* @param atom
* @return true if atom is stereo center in at least one molecule after ESR resolution
*/
public boolean isAtomStereoCenter(int atom) {
return ((mAtomFlags[atom] & cAtomFlagIsStereoCenter) != 0);
}
public boolean isBondParityPseudo(int bond) {
return ((mBondFlags[bond] & cBondParityIsPseudo) != 0);
}
/**
* This hint/flag is set by CoordinateInventor for double bonds without given EZ-parity,
* because the new coordinates may imply a not intended EZ-parity. If parities are calculated
* later by the Canonizer is can correctly assign cBondParityUnknown if the bond is a stereo bond.
* The setBondParity() method clears this flag.
* This method usually should not be called for other purposes.
* @return whether the bond parity was unknown when 2D- atom coordinates were created
*/
public boolean isBondParityUnknownOrNone(int bond) {
return ((mBondFlags[bond] & cBondParityUnknownOrNone) != 0);
}
/**
* Molecule objects may represent complete molecules or sub-structure fragments,
* depending on, whether they are flagges as being a fragment or not. Both representations
* have much in common, but in certain aspects behave differently. Thus, complete molecules
* are considered to carry implicit hydrogens to fill unoccupied atom valences.
* Sub-structure fragments on the other hand may carry atom or bond query features.
* Depiction, sub-structure search, and other algorithms treat fragments and complete molecules differerently.
* @return
*/
public boolean isFragment() {
return mIsFragment;
}
public boolean isDelocalizedBond(int bond) {
return mBondType[bond] == cBondTypeDelocalized;
}
/**
* @return true if at least one z-coordinate is different from 0.0
*/
public boolean is3D() {
for (int atom=0; atom= -1 && valence <= 14) {
mAtomFlags[atom] &= ~cAtomFlagsValence;
mAtomFlags[atom] |= ((1+valence) << cAtomFlagsValenceShift);
if (mAtomicNo[atom] == 6) {
if (valence == -1 || valence == 0 || valence == 2 || valence == 4) {
mAtomFlags[atom] &= ~cAtomRadicalState;
if (valence == 2)
mAtomFlags[atom] |= cAtomRadicalStateS;
}
}
}
}
public void setAtomCharge(int atom, int charge) {
mAtomCharge[atom] = charge;
mValidHelperArrays = cHelperNone;
}
public void setAtomColor(int atom,int color) {
mAtomFlags[atom] &= ~cAtomFlagsColor;
mAtomFlags[atom] |= color;
}
/**
* This is a user applied information, rather than a calculated value.
* The stereo center configuration is declared to be unknown.
* If the atom is recognized a stereo center, then its parity will be cAtomParityUnknown.
* @param atom
* @param u
*/
public void setAtomConfigurationUnknown(int atom, boolean u) {
if (u)
mAtomFlags[atom] |= cAtomFlagConfigurationUnknown;
else
mAtomFlags[atom] &= ~cAtomFlagConfigurationUnknown;
mValidHelperArrays &= cHelperRings;
}
public void setAtomSelection(int atom,boolean s) {
if (s)
mAtomFlags[atom] |= cAtomFlagSelected;
else
mAtomFlags[atom] &= ~cAtomFlagSelected;
}
/**
* Atom marking may be used for any external purpose
*/
public void setAtomMarker(int atom,boolean s) {
if (s)
mAtomFlags[atom] |= cAtomFlagMarked;
else
mAtomFlags[atom] &= ~cAtomFlagMarked;
}
/**
* Set an atom's atomic number and defines the isotop to be natural abundance.
* @param atom
* @param no
*/
public void setAtomicNo(int atom,int no) {
if ((no >= 0) && (no <= cMaxAtomicNo)) {
if (no == 151 || no == 152) { // 'D' or 'T'
mAtomicNo[atom] = 1;
mAtomMass[atom] = no - 149;
}
else {
mAtomicNo[atom] = no;
mAtomMass[atom] = 0;
}
mAtomFlags[atom] &= ~cAtomFlagsValence;
mValidHelperArrays = cHelperNone;
}
}
/**
* Defines a list of allowed/excluded atomic numbers for sub-structure matching.
* If this atom's query feature cAtomQFAny (any atom) is set, then the list is considered to be a NOT-list.
* Depending on cAtomQFAny the list must contain at least 1 or 2 members.
* @param atom
* @param list null or int[] of valid unique, but not sorted, atomic numbers
*/
public void setAtomList(int atom, int[] list) {
if (mAtomList == null)
mAtomList = new int[mMaxAtoms][];
if (list != null)
Arrays.sort(list);
mAtomList[atom] = list;
mValidHelperArrays = cHelperNone;
mIsFragment = true;
}
/**
* Defines an atom list as query feature for substructure search
* @param atom
* @param list is null or a sorted int[] of valid atomic numbers
* @param isExcludeList true if atom is a wild card and list contains atoms to be excluded
*/
public void setAtomList(int atom, int[] list, boolean isExcludeList) {
if (list == null) {
if (mAtomList != null)
mAtomList[atom] = null;
return;
}
if (list.length == 1 && !isExcludeList) {
int atomicNo = list[0];
if (mAtomicNo[atom] != atomicNo)
changeAtom(atom, atomicNo, 0, -1, 0);
if (mAtomList != null)
mAtomList[atom] = null;
return;
}
if (mAtomList == null)
mAtomList = new int[mMaxAtoms][];
mAtomList[atom] = list;
if (isExcludeList)
mAtomQueryFeatures[atom] |= cAtomQFAny;
mValidHelperArrays = cHelperNone;
mIsFragment = true;
}
/**
* Defines an atom mapping number within the context of a reaction.
* Atoms that share the same mapping number on the reactant and product side
* are considered to be the same atom.
* @param atom
* @param mapNo
* @param autoMapped
*/
public void setAtomMapNo(int atom, int mapNo, boolean autoMapped) {
mAtomMapNo[atom] = (autoMapped) ? -mapNo : mapNo;
}
/**
* Set atom to specific isotop or to have a natural isotop distribution
* @param atom
* @param mass rounded atom mass or 0 (default) for natural abundance
*/
public void setAtomMass(int atom, int mass) {
mAtomMass[atom] = mass;
mValidHelperArrays &= (mAtomicNo[atom] == 1) ? cHelperNone : cHelperRings;
}
/**
* The atom parity is a calculated property available above/equal helper level cHelperParities.
* It describes the stereo configuration of a chiral atom and is calculated either from
* 2D-atom-coordinates and up/down-bonds or from 3D-atom-coordinates, whatever is available.
* It depends on the atom indices of the neighbor atoms and their orientation in space.
* The parity is defined as follows: Look at the chiral atom such that its neighbor atom with the
* highest atom index (or the hydrogen atom if it is implicit) is oriented to the back.
* If the remaining three neighbors are in clockwise order (considering ascending atom indexes)
* than the parity is 1. If they are in anti-clockwise order, then the parity is 2.
* For linear chirality (allenes): Look along the straight line of double bonds such that the
* rear neighbor with the lower atom index points to the top. If the front neighbor with the
* lower atom index points to the right than the parity is 1.
* This method is called by the Canonizer and usually should not be called otherwise.
* @param atom
* @param parity one of cAtomParity1,cAtomParity2,cAtomParityNone,cAtomParityUnknown
* @param isPseudo true if the configuration is only meaningful relative to another one
*/
public void setAtomParity(int atom, int parity, boolean isPseudo) {
mAtomFlags[atom] &= ~(cAtomFlagsParity | cAtomParityIsPseudo);
if (parity != cAtomParityUnknown)
mAtomFlags[atom] &= ~cAtomFlagConfigurationUnknown;
mAtomFlags[atom] |= parity;
if (isPseudo)
mAtomFlags[atom] |= cAtomParityIsPseudo;
}
/**
* An atom is considered a stereo center, if it is a stereo center in at least in one of the
* molecule configurations represented by the ESR definitions. Pseudo stereo centers are not(!)
* considered to be a stereo center.
* This method is called by the Canonizer and usually should not be called otherwise.
* @param atom
* @param isStereoCenter
*/
protected void setAtomStereoCenter(int atom, boolean isStereoCenter) {
mAtomFlags[atom] &= ~cAtomFlagIsStereoCenter;
if (isStereoCenter)
mAtomFlags[atom] |= cAtomFlagIsStereoCenter;
}
/**
* Introduce or remove an atom query feature and make sure, the molecule is flagged
* to be a sub-structure fragment (see setFragment()).
* A query feature is usually a flag, which if set, poses an additional atom/bond matching constraint
* for the sub-structure search and, thus, reduces the number of matching atoms and therefore also
* the number of molecules found. Often multiple query feature flags are related and grouped, e.g.
* to define the number of hydrogens atoms. These are the flags related to hydrogen neighbors:
* public static final int cAtomQFHydrogen = 0x00000780;
* public static final int cAtomQFNot0Hydrogen = 0x00000080;
* public static final int cAtomQFNot1Hydrogen = 0x00000100;
* public static final int cAtomQFNot2Hydrogen = 0x00000200;
* public static final int cAtomQFNot3Hydrogen = 0x00000400;
* An inverse logic needs to be applied to translate a user request to the bits needed. For example,
* to only accept atoms that have 1 or 2 hydrogen neighbors, we need to filter out all others. Thus, we
* would call
setAtomQueryFeature(atom, cAtomQFNot0Hydrogen | cAtomQFNot3Hydrogen, true);
* To match only atoms without hydrogen neighbors, call
setAtomQueryFeature(atom, cAtomQFHydrogen & ~cAtomQFNot0Hydrogen, true);
* This mechanism allows a very efficient atom matching and therefore very fast sub-structure search.
* @param atom
* @param feature one of cAtomQF...
* @param value if true, the feature is set, otherwise it is removed
*/
public void setAtomQueryFeature(int atom, long feature, boolean value) {
if (value)
mAtomQueryFeatures[atom] |= feature;
else
mAtomQueryFeatures[atom] &= ~feature;
mValidHelperArrays = 0; // there is an influence on occipied valence, bond order, etc.
mIsFragment = true;
}
/**
* Sets an atom's radical state as singulet,dublet,triplet or none
* @param atom
* @param radical one of cAtomRadicalStateNone,cAtomRadicalStateS,cAtomRadicalStateD,cAtomRadicalStateT
*/
public void setAtomRadical(int atom, int radical) {
mAtomFlags[atom] &= ~cAtomRadicalState;
mAtomFlags[atom] |= radical;
mValidHelperArrays &= cHelperRings;
}
/**
* The atom Cahn-Ingold-Prelog parity is a calculated property available above/equal helper level cHelperCIP.
* It encodes the stereo configuration of an atom with its neighbors using up/down-bonds
* or 3D-atom-coordinates, whatever is available. It depends on the atom indices of the neighbor
* atoms and their orientation is space. This method is called by the Canonizer and usually should not
* be called otherwise.
* @param atom
* @param parity one of cAtomCIPParityRorM,cAtomCIPParitySorP,cAtomCIPParityProblem
*/
public void setAtomCIPParity(int atom, int parity) {
mAtomFlags[atom] &= ~cAtomFlagsCIPParity;
mAtomFlags[atom] |= (parity << cAtomFlagsCIPParityShift);
}
public void setAtomX(int atom, double x) {
mCoordinates[atom].x = x;
mValidHelperArrays &= cHelperRings;
}
public void setAtomY(int atom, double y) {
mCoordinates[atom].y = y;
mValidHelperArrays &= cHelperRings;
}
public void setAtomZ(int atom, double z) {
mCoordinates[atom].z = z;
mValidHelperArrays &= cHelperRings;
}
public void setBondAtom(int no, int bond, int atom) {
mBondAtom[no][bond] = atom;
mValidHelperArrays = cHelperNone;
}
/**
* The bond Cahn-Ingold-Prelog parity is a calculated property available above/equal helper level cHelperCIP.
* It encodes the stereo configuration of a bond with its neighbors using 2D-coordinates and up/down-bonds
* or 3D-atom-coordinates, whatever is available. It depends on the atom indices of the neighbor
* atoms and their orientation is space. This method is called by the Canonizer and usually should not
* be called otherwise. Considered are E/Z-double bonds and M/P-BINAP type single bonds.
* @param bond
* @param parity one of cBondCIPParityEorP,cBondCIPParityZorM,cBondCIPParityProblem
*/
public void setBondCIPParity(int bond, int parity) {
mBondFlags[bond] &= ~cBondFlagsCIPParity;
mBondFlags[bond] |= (parity << cBondFlagsCIPParityShift);
}
/**
* Used for depiction only.
* @param bond
* @param s
*/
public void setBondBackgroundHiliting(int bond, boolean s) {
if (s)
mBondFlags[bond] |= cBondFlagBGHilited;
else
mBondFlags[bond] &= ~cBondFlagBGHilited;
}
/**
* Used for depiction only.
* @param bond
* @param s
*/
public void setBondForegroundHiliting(int bond, boolean s) {
if (s)
mBondFlags[bond] |= cBondFlagFGHilited;
else
mBondFlags[bond] &= ~cBondFlagFGHilited;
}
/**
* The bond parity is a calculated property available above/equal helper level cHelperParities.
* It encodes the stereo configuration of a double bond or BINAP type single bond from up/down-bonds
* and 2D-coordinates or 3D-atom-coordinates, whatever is available. It depends on the atom indices
* of the neighbor atoms and their orientation is space. This method is called by the Canonizer and
* usually should not be called otherwise.
* @param bond
* @param parity one of cBondParityEor1,cBondParityZor2,cBondParityNone,cBondParityUnknown
* @param isPseudo true if the configuration is only meaningful relative to another one
*/
public void setBondParity(int bond, int parity, boolean isPseudo) {
mBondFlags[bond] &= ~(cBondFlagsParity | cBondParityIsPseudo | cBondParityUnknownOrNone);
mBondFlags[bond] |= parity;
if (isPseudo)
mBondFlags[bond] |= cBondParityIsPseudo;
}
/**
* This hint/flag is set by CoordinateInventor for double bonds without given EZ-parity,
* because the new coordinates may imply a not intended EZ-parity. If parities are calculated
* later by the Canonizer is can correctly assign cBondParityUnknown if the bond is a stereo bond.
* The setBondParity() method clears this flag.
* This method usually should not be called for other purposes.
* @param bond
*/
public void setBondParityUnknownOrNone(int bond) {
mBondFlags[bond] |= cBondParityUnknownOrNone;
}
public void setBondQueryFeature(int bond, int feature, boolean value) {
if (value)
mBondQueryFeatures[bond] |= feature;
else
mBondQueryFeatures[bond] &= ~feature;
mValidHelperArrays = cHelperNone; // there is an influence on occipied valence, bond order, etc.
mIsFragment = true;
}
/**
* Sets the bond type based on bond order without stereo orientation.
* @param bond
* @param order 1,2, or 3
*/
public void setBondOrder(int bond,int order) {
mBondType[bond] = (order == 1) ? cBondTypeSingle
: (order == 2) ? cBondTypeDouble
: (order == 3) ? cBondTypeTriple
: cBondTypeMetalLigand;
mValidHelperArrays = cHelperNone;
}
/**
* Defines a bond type combining bod order and stereo orientation.
* @param bond
* @param type one of cBondTypeSingle,cBondTypeDouble,cBondTypeUp,cBondTypeCross,...
*/
public void setBondType(int bond,int type) {
mBondType[bond] = type;
mValidHelperArrays = cHelperNone;
}
/**
* Sets the overall chirality of the molecule taking into account:
* Recognition of stereo centers and stereo bonds, defined ESR features, meso detection.
* The chirality combines the knowledge about how many stereo isomers are represented,
* whether all of these are meso, whether we have one defined stereo isomer, a mixture
* of racemates, epimers, or other diastereomers.
* The information is used during depiction.
* This method is called by the Canonizer and usually should not be called otherwise.
* @param c
*/
public void setChirality(int c) {
mChirality = c;
}
/**
* Fragment's query features are checked for consistency and normalized
* during helper array creation. As part of this, simple hydrogen atoms
* are converted into hydrogen-count query features. If hydrogen protection
* is enabled, explicit hydrogens are not touched.
* @param protectHydrogen
*/
public void setHydrogenProtection(boolean protectHydrogen) {
mProtectHydrogen = protectHydrogen;
}
/**
* Use this method with extreme care. If you make a change to the molecule,
* the validity of the helper arrays is typically set to cHelperNone.
* If you make a small change to a molecule that doesn't change its topology,
* you may override the automatic automatically cleared helper validity with
* this method and avoid a new calculation of the neighbour arrays and ring
* detection.
* @param helperValidity cHelperNeighbours or cHelperRings
*/
public void setHelperValidity(int helperValidity) {
mValidHelperArrays = helperValidity;
}
/**
* This is for compatibility with old MDL stereo representation
* that contained a 'chiral' flag to indicate that the molecule
* is not a racemate. If a molecule is constructed from a source
* format (e.g. a molfile version 2) that contains a 'chiral' flag
* then setToRacemate() needs to be called if the chiral flag is
* not(!) set. This causes after stereo center recognition to
* turn all absolute stereo centers into racemic ones.
*/
public void setToRacemate() {
mIsRacemate = true;
}
/**
* If a custom atom label is set, a molecule depiction displays
* the custom label instead of the original one. Custom labels
* are not interpreted otherwise. However, they may optionally
* be encoded into idcodes; see Canonizer.encodeAtomCustomLabels().
* If a custom label start with ']' then the label without the ']'
* symbol is shown at the top left of the original atom label rather than
* replacing the original atom label.
* the
* @param atom
* @param label null to remove custom label
*/
public void setAtomCustomLabel(int atom, byte[] label) {
if (label != null && label.length == 0)
label = null;
if (label == null) {
if (mAtomCustomLabel != null)
mAtomCustomLabel[atom] = null;
}
else {
if (mAtomCustomLabel == null)
mAtomCustomLabel = new byte[mMaxAtoms][];
mAtomCustomLabel[atom] = label;
}
}
/**
* If a custom atom label is set, a molecule depiction displays
* the custom label instead of the original one. Custom labels
* are not interpreted otherwise. However, they may optionally
* be encoded into idcodes; see Canonizer.encodeAtomCustomLabels().
* If a custom label start with ']' then the label without the ']'
* symbol is shown at the top left of the original atom label rather than
* replacing the original atom label.
* If label is null or equals the normal atom label, then the custom label
* is removed. This method is less efficient than the byte[] version:
* setAtomCustomLabel(int, byte[])
* @param atom
* @param label null to remove custom label
*/
public void setAtomCustomLabel(int atom, String label) {
if (label != null) {
if (label.length() == 0)
label = null;
else {
int atomicNo = getAtomicNoFromLabel(label);
if ((atomicNo != 0 && label.equals(cAtomLabel[atomicNo]))
|| label.equals("?")) {
setAtomicNo(atom, atomicNo);
label = null;
}
}
}
if (label == null) {
if (mAtomCustomLabel != null)
mAtomCustomLabel[atom] = null;
}
else {
if (mAtomCustomLabel == null)
mAtomCustomLabel = new byte[mMaxAtoms][];
mAtomCustomLabel[atom] = label.getBytes(StandardCharsets.UTF_8);
}
}
/**
* This is MDL's enhanced stereo representation (ESR).
* Stereo atoms and bonds with the same ESR type (AND or OR) and the same ESR group number
* are in the same group, i.e. within this group they have the defined (relative) stereo configuration.
* @param atom
* @param type one of cESRTypeAbs,cESRTypeAnd,cESRTypeOr
* @param group index starting with 0 (not considered if type is cESRTypeAbs)
*/
public void setAtomESR(int atom, int type, int group) {
if (type == cESRTypeAbs) {
mAtomFlags[atom] &= ~cAtomFlagsESR;
mAtomFlags[atom] |= (type << cAtomFlagsESRTypeShift);
}
else {
if (group >= cESRMaxGroups)
return;
if (group == -1) { // find unused group
int maxGroup = -1;
for (int i=0; i= cESRMaxGroups)
return;
}
mAtomFlags[atom] &= ~cAtomFlagsESR;
mAtomFlags[atom] |= ((type << cAtomFlagsESRTypeShift)
| (group << cAtomFlagsESRGroupShift));
}
mValidHelperArrays &= cHelperRings;
}
/**
* MDL's enhanced stereo representation for BINAP type of stereo bonds.
* Stereo atoms and bonds with the same ESR type (AND or OR) and the same ESR group number
* are in the same group, i.e. within this group they have the defined (relative) stereo configuration.
* @param bond
* @param type one of cESRTypeAbs,cESRTypeAnd,cESRTypeOr
* @param group index starting with 0
*/
public void setBondESR(int bond, int type, int group) {
if (type == cESRTypeAbs) {
mBondFlags[bond] &= ~cBondFlagsESR;
mBondFlags[bond] |= (type << cBondFlagsESRTypeShift);
}
else {
if (group >= cESRMaxGroups)
return;
if (group == -1) { // find unused group
int maxGroup = -1;
for (int i=0; i= cESRMaxGroups)
return;
}
mBondFlags[bond] &= ~cBondFlagsESR;
mBondFlags[bond] |= ((type << cBondFlagsESRTypeShift)
| (group << cBondFlagsESRGroupShift));
}
mValidHelperArrays &= cHelperRings;
}
/**
* Molecule objects may represent complete molecules or sub-structure fragments,
* depending on, whether they are flagges as being a fragment or not. Both representations
* have much in common, but in certain aspects behave differently. Thus, complete molecules
* are considered to carry implicit hydrogens to fill unoccupied atom valences.
* Sub-structure fragments on the other hand may carry atom or bond query features.
* Depiction, sub-structure search, and other algorithms treat fragments and complete molecules
* differently.
* @param isFragment if false, then all query features are removed
*/
public void setFragment(boolean isFragment) {
if (mIsFragment != isFragment) {
mIsFragment = isFragment;
if (!isFragment)
removeQueryFeatures();
mValidHelperArrays = cHelperNone;
}
}
public void setName(String name) {
mName = name;
}
public Object getUserData() {
return mUserData;
}
public void setUserData(Object userData) {
mUserData = userData;
}
/**
* Removes any query features from the molecule
* @return whether any query features were removed
*/
public boolean removeQueryFeatures() {
boolean isChanged = false;
for (int atom=0; atom max)
maxBondOrder = max;
}
return maxBondOrder;
}
private boolean incrementBondOrder(int bond) {
int maxBondOrder = getMaximumBondOrder(bond);
boolean hasMetal = isMetalAtom(mBondAtom[0][bond]) || isMetalAtom(mBondAtom[1][bond]);
int startBond = hasMetal ? cBondTypeMetalLigand : cBondTypeSingle;
if (mBondType[bond] == cBondTypeQuintuple) {
mBondType[bond] = startBond;
mValidHelperArrays = cHelperNone;
return true;
}
if (mBondType[bond] == cBondTypeQuadruple) {
mBondType[bond] = (maxBondOrder > 4) ? cBondTypeQuintuple : startBond;
mValidHelperArrays = cHelperNone;
return true;
}
if (mBondType[bond] == cBondTypeTriple) {
mBondType[bond] = (maxBondOrder > 3) ? cBondTypeQuadruple : startBond;
mValidHelperArrays = cHelperNone;
return true;
}
if (mBondType[bond] == cBondTypeDouble) {
mBondType[bond] = cBondTypeCross;
mValidHelperArrays &= cHelperRings;
if ((mBondFlags[bond] & cBondFlagSmallRing) == 0)
return true;
}
if (mBondType[bond] == cBondTypeCross) {
if (maxBondOrder > 2)
mBondType[bond] = cBondTypeTriple;
else
mBondType[bond] = startBond;
mValidHelperArrays = cHelperNone;
return true;
}
if ((cBondTypeMaskStereo & mBondType[bond]) != 0) {
mBondType[bond] = cBondTypeSingle;
mValidHelperArrays &= cHelperRings;
return true;
}
if (!hasMetal && maxBondOrder < 2)
return false;
if (mBondType[bond] == cBondTypeSingle) {
mBondType[bond] = cBondTypeDouble;
mValidHelperArrays = cHelperNone;
return true;
}
if (maxBondOrder < 1)
return false;
if (mBondType[bond] == cBondTypeMetalLigand) {
mBondType[bond] = cBondTypeSingle;
mValidHelperArrays = cHelperNone;
return true;
}
return false;
}
protected boolean validateBondType(int bond, int type) {
int simpleType = type & Molecule.cBondTypeMaskSimple;
int maxBondOrder = getMaximumBondOrder(bond);
switch (simpleType) {
case cBondTypeSingle:
case cBondTypeDelocalized:
return maxBondOrder >= 1;
case cBondTypeDouble:
return maxBondOrder >= 2;
case cBondTypeTriple:
return maxBondOrder >= 3;
case cBondTypeQuadruple:
return maxBondOrder >= 4;
case cBondTypeQuintuple:
return maxBondOrder >= 5;
case cBondTypeMetalLigand:
return true;
default:
return false;
}
}
/**
* The sum of bond orders of explicitly connected neighbour atoms.
* @param atom
* @return explicitly used valence
*/
protected int getOccupiedValence(int atom) {
// ExtendedMolecule overwrites this function by updateing and using neighbour arrays
return simpleGetValence(atom);
}
private int simpleGetValence(int atom) {
int val=0; // this version doesn't change helper arrays
for (int bnd=0; bnd 3.
* @param atom
* @return
*/
public int getMaxValenceUncharged(int atom) {
int valence = getAtomAbnormalValence(atom);
if (valence == -1)
valence = getDefaultMaxValenceUncharged(atom);
return valence;
}
/**
* This is the default maximum valence of the atom
* neglecting atom charge or radical influences, e.g. N or N(+) -> 3.
* If the atomic no has multiple valid max valences, it is the highest one.
* @param atom
* @return
*/
public int getDefaultMaxValenceUncharged(int atom) {
byte[] valenceList = (mAtomicNo[atom] < cAtomValence.length) ?
cAtomValence[mAtomicNo[atom]] : null;
return (valenceList == null) ? cDefaultAtomValence : valenceList[valenceList.length-1];
}
/**
* This is the defined maximum valence (or set abnormal valence)
* corrected by atom charge or radical influences, e.g. N(+) -> 4.
* @param atom
* @return
*/
public int getMaxValence(int atom) {
int valence = getMaxValenceUncharged(atom);
return valence + getElectronValenceCorrection(atom, valence);
}
/**
* This is the maximum valence correction caused by atom charge
* or radical status, e.g. N+ -> 1; N- -> -1; Al+ -> -1; C+,C- -> -1.
* In some cases, where the atomicNo can have multiple valences,
* the influence of a charge depends on the atom's actual valence, e.g.
* valence corrections for R3P(+) and R5P(+) are 1 and -1, respectively.
* Criteria are:
* -in the given valence state is there a lone pair that can be protonated
* -can we introduce a negative substituent as in BH3 or PF5 vs. SF6
* @param atom
* @param occupiedValence
* @return
*/
public int getElectronValenceCorrection(int atom, int occupiedValence) {
return getElectronValenceCorrection(atom, occupiedValence, mAtomicNo[atom]);
}
protected int getElectronValenceCorrection(int atom, int occupiedValence, int atomicNo) {
if (atomicNo >= 171 && atomicNo <= 190)
return 0;
int correction = 0;
if ((mAtomFlags[atom] & cAtomRadicalState) == cAtomRadicalStateD)
correction -= 1;
if ((mAtomFlags[atom] & cAtomRadicalState) == cAtomRadicalStateS
|| (mAtomFlags[atom] & cAtomRadicalState) == cAtomRadicalStateT)
correction -= 2;
int charge = mAtomCharge[atom];
if (charge == 0 && mIsFragment) {
if ((mAtomQueryFeatures[atom] & cAtomQFCharge) == cAtomQFNotCharge0+cAtomQFNotChargePos)
charge = -1;
if ((mAtomQueryFeatures[atom] & cAtomQFCharge) == cAtomQFNotCharge0+cAtomQFNotChargeNeg)
charge = 1;
}
if (atomicNo == 7 // N
|| atomicNo == 8 // O
|| atomicNo == 9) // F
correction += charge;
else if (atomicNo == 6 // C
|| atomicNo == 14 // Si
|| atomicNo == 32) // Ge
correction -= Math.abs(charge);
else if (atomicNo == 15 // P
|| atomicNo == 33) { // As
if (occupiedValence - correction - charge <= 3)
correction += charge;
else
correction -= charge;
}
else if (atomicNo == 16 // S
|| atomicNo == 34 // Se
|| atomicNo == 52) { // Te
if (occupiedValence - correction - charge <= 4)
correction += charge;
else
correction -= Math.abs(charge);
}
else if (atomicNo == 17 // Cl
|| atomicNo == 35 // Br
|| atomicNo == 53) { // I
if (occupiedValence - correction - charge <= 5)
correction += charge;
else
correction -= Math.abs(charge);
}
else { // B, Al, other metals
correction -= charge;
}
return correction;
}
public static boolean isAtomicNoElectronegative(int atomicNo) {
switch (atomicNo) {
case 7: // N
case 8: // O
case 9: // F
case 15: // P
case 16: // S
case 17: // Cl
case 33: // As
case 34: // Se
case 35: // Br
case 52: // Te
case 53: // I
return true;
}
return false;
}
/**
* @param atom
* @return whether atom is an electronegative one
*/
public boolean isElectronegative(int atom) {
if (mIsFragment) {
if ((mAtomQueryFeatures[atom] & cAtomQFAny) != 0)
return false;
if (mAtomList != null && mAtomList[atom] != null)
for (int atomicNo:mAtomList[atom])
if (!isAtomicNoElectronegative(atomicNo))
return false;
}
return isAtomicNoElectronegative(mAtomicNo[atom]);
}
public static boolean isAtomicNoElectropositive(int atomicNo) {
if (atomicNo == 1
|| atomicNo == 6)
return false;
if (isAtomicNoElectronegative(atomicNo))
return false;
if (atomicNo == 2 // He
|| atomicNo == 10 // Ne
|| atomicNo == 18 // Ar
|| atomicNo == 36 // Kr
|| atomicNo == 54) // Xe
return false;
if (atomicNo > 103) // amino acids etc.
return false;
return true;
}
/**
* @param atom
* @return whether atom is an electropositive one
*/
public boolean isElectropositive(int atom) {
if (mIsFragment) {
if ((mAtomQueryFeatures[atom] & cAtomQFAny) != 0)
return false;
if (mAtomList != null && mAtomList[atom] != null)
for (int atomicNo:mAtomList[atom])
if (!isAtomicNoElectropositive(atomicNo))
return false;
}
return isAtomicNoElectropositive(mAtomicNo[atom]);
}
/**
* @param atom
* @return whether atom is a metal atom
*/
public boolean isMetalAtom(int atom) {
if (mIsFragment) {
if ((mAtomQueryFeatures[atom] & cAtomQFAny) != 0)
return false;
if (mAtomList != null && mAtomList[atom] != null)
for (int atomicNo:mAtomList[atom])
if (!isAtomicNoMetal(atomicNo))
return false;
}
return isAtomicNoMetal(mAtomicNo[atom]);
}
/**
* @param atom
* @return whether atom is a transition metal atom
*/
public boolean isTransitionMetalAtom(int atom) {
if (mIsFragment) {
if ((mAtomQueryFeatures[atom] & cAtomQFAny) != 0)
return false;
if (mAtomList != null && mAtomList[atom] != null)
for (int atomicNo:mAtomList[atom])
if (!isAtomicNoTransitionMetal(atomicNo))
return false;
}
return isAtomicNoTransitionMetal(mAtomicNo[atom]);
}
public static boolean isAtomicNoMetal(int atomicNo) {
return (atomicNo >= 3 && atomicNo <= 4)
|| (atomicNo >= 11 && atomicNo <= 13)
|| (atomicNo >= 19 && atomicNo <= 31)
|| (atomicNo >= 37 && atomicNo <= 51)
|| (atomicNo >= 55 && atomicNo <= 84)
|| (atomicNo >= 87 && atomicNo <= 112);
}
public static boolean isAtomicNoTransitionMetal(int atomicNo) {
return (atomicNo >= 21 && atomicNo <= 30)
|| (atomicNo >= 39 && atomicNo <= 48)
|| atomicNo == 57
|| (atomicNo >= 72 && atomicNo <= 80)
|| atomicNo == 89
|| (atomicNo >= 104 && atomicNo <= 112);
}
/**
* @param atom
* @return true if this atom is not a metal and not a nobel gas
*/
public boolean isOrganicAtom(int atom) {
if (mIsFragment) {
if ((mAtomQueryFeatures[atom] & cAtomQFAny) != 0)
return false;
if (mAtomList != null && mAtomList[atom] != null)
for (int atomicNo:mAtomList[atom])
if (!isAtomicNoOrganic(atomicNo))
return false;
}
return isAtomicNoOrganic(mAtomicNo[atom]);
}
public static boolean isAtomicNoOrganic(int atomicNo) {
return atomicNo == 1
|| (atomicNo >= 5 && atomicNo <= 9) // B,C,N,O,F
|| (atomicNo >= 14 && atomicNo <= 17) // Si,P,S,Cl
|| (atomicNo >= 32 && atomicNo <= 35) // Ge,As,Se,Br
|| (atomicNo >= 52 && atomicNo <= 53); // Te,I
}
public void removeAtomMapping(boolean keepManualMapping) {
for (int atom=0; atom