19package denoptim.molecularmodeling;
22import java.util.ArrayList;
23import java.util.HashMap;
24import java.util.LinkedHashMap;
27import java.util.logging.Level;
28import java.util.logging.Logger;
30import javax.vecmath.AxisAngle4d;
31import javax.vecmath.Matrix3d;
32import javax.vecmath.Point3d;
33import javax.vecmath.Vector3d;
35import org.openscience.cdk.Bond;
36import org.openscience.cdk.PseudoAtom;
37import org.openscience.cdk.interfaces.IAtom;
38import org.openscience.cdk.interfaces.IAtomContainer;
39import org.openscience.cdk.interfaces.IBond;
40import org.openscience.cdk.interfaces.IChemObjectBuilder;
41import org.openscience.cdk.silent.SilentChemObjectBuilder;
43import denoptim.constants.DENOPTIMConstants;
44import denoptim.exception.DENOPTIMException;
45import denoptim.graph.AttachmentPoint;
46import denoptim.graph.DGraph;
47import denoptim.graph.Edge;
48import denoptim.graph.Edge.BondType;
49import denoptim.graph.Ring;
50import denoptim.graph.Vertex;
51import denoptim.io.DenoptimIO;
52import denoptim.utils.GraphConversionTool;
53import denoptim.utils.GraphUtils;
54import denoptim.utils.MathUtils;
55import denoptim.utils.MoleculeUtils;
56import denoptim.utils.Randomizer;
92 private IChemObjectBuilder
builder = SilentChemObjectBuilder.getInstance();
97 private Logger
logger = Logger.getLogger(
"3dTreeBuilderLogger");
128 this.alignIn3D = align;
237 @SuppressWarnings(
"unused")
239 boolean removeUsedRCAs,
boolean setCDKRequirements,
boolean rebuild)
243 Map<Long,ArrayList<AttachmentPoint>> apsPerVertexId =
new HashMap<>();
244 Map<Edge,ArrayList<AttachmentPoint>> apsPerEdge =
new HashMap<>();
245 Map<IAtom,ArrayList<AttachmentPoint>> apsPerAtom =
new HashMap<>();
246 Map<IBond,ArrayList<AttachmentPoint>> apsPerBond =
new HashMap<>();
249 IAtomContainer mol =
builder.newAtomContainer();
252 Vertex rootVrtx = graph.getSourceVertex();
254 apsPerVertexId, apsPerEdge, apsPerAtom, apsPerBond);
257 for (
Vertex v : graph.getVertexList())
260 if (visited !=
null && visited ==
true)
265 Vertex nextBranchRoot = v;
266 List<Vertex> parentTree =
new ArrayList<Vertex>();
267 graph.getParentTree(v, parentTree);
268 if (parentTree.size() > 0)
270 nextBranchRoot = parentTree.get(parentTree.size()-1);
274 mol, graph, removeUsedRCAs, rebuild,
275 apsPerVertexId, apsPerEdge, apsPerAtom, apsPerBond);
277 for (
Vertex v : graph.getVertexList())
297 if (setCDKRequirements)
307 StringBuilder sb =
new StringBuilder();
308 String file =
"/tmp/iacTree.sdf";
309 sb.append(
"Writing tree-like IAtomContainer to " + file+
NL);
310 IAtomContainer cmol =
builder.newAtomContainer();
320 sb.append(
"AP-per-VertexID"+
NL);
322 for (
long v : apsPerVertexId.keySet())
324 ArrayList<AttachmentPoint> aps = apsPerVertexId.get(v);
328 IAtom atm =
new PseudoAtom(String.valueOf(i),
329 new Point3d(ap.getDirectionVector()));
330 sb.append(
"Vertex: "+v+
" AP-"+i+
" = "+ap+
NL);
332 IBond bnd =
new Bond(cmol.getAtom(
333 ap.getAtomPositionNumber()),
334 cmol.getAtom(mol.getAtomCount()+i-1),
341 sb.append(
"AP-per-Edge"+
NL);
342 for (
Edge e : apsPerEdge.keySet())
344 ArrayList<AttachmentPoint> aps = apsPerEdge.get(e);
347 sb.append(
"Edge: "+e+
" AP = "+ap+
NL);
350 sb.append(
"AP-per-Atom"+
NL);
351 for (IAtom a : apsPerAtom.keySet())
353 ArrayList<AttachmentPoint> aps = apsPerAtom.get(a);
356 sb.append(
"Atom: "+mol.indexOf(a) +
" AP = "+ap+
NL);
359 sb.append(
"AP-per-Bond"+
NL);
360 for (IBond b : apsPerBond.keySet())
362 ArrayList<AttachmentPoint> aps = apsPerBond.get(b);
365 sb.append(
"Bond: "+mol.indexOf(b.getAtom(0))
366 +
"-"+mol.indexOf(b.getAtom(1))+
" AP = "+ap+
NL);
369 logger.log(Level.FINEST, sb.toString());
373 LinkedHashMap<Integer,List<AttachmentPoint>> freeAPPerAtm =
374 new LinkedHashMap<>();
375 for (IAtom a : apsPerAtom.keySet())
377 int atmID = mol.indexOf(a);
385 ArrayList<AttachmentPoint> aps = apsPerAtom.get(a);
388 if (ap.isAvailableThroughout())
390 if (freeAPPerAtm.containsKey(atmID))
392 freeAPPerAtm.get(atmID).add(ap);
394 List<AttachmentPoint> lst =
395 new ArrayList<AttachmentPoint>();
397 freeAPPerAtm.put(atmID,lst);
437 IAtomContainer mol,
DGraph graph,
438 boolean removeUsedRCAs,
boolean rebuild,
439 Map<Long, ArrayList<AttachmentPoint>> apsPerVertexId,
440 Map<
Edge,ArrayList<AttachmentPoint>> apsPerEdge,
441 Map<IAtom,ArrayList<AttachmentPoint>> apsPerAtom,
442 Map<IBond,ArrayList<AttachmentPoint>> apsPerBond)
446 long idRootVrtx = rootVrtx.getVertexId();
448 int preNumAtms = mol.getAtomCount();
449 IAtomContainer iacRootVrtx =
null;
450 if (rootVrtx.containsAtoms())
453 removeUsedRCAs, rebuild);
455 if (iacRootVrtx ==
null)
457 String msg = this.getClass().getSimpleName()
458 +
" found a building block declaring "
459 +
"to containg atoms, "
460 +
"but returning null atom container. "
461 +
"Building blocks: " + rootVrtx;
462 throw new IllegalArgumentException(msg);
465 for (IAtom atm : iacRootVrtx.atoms())
467 Object prevPath = atm.getProperty(
472 idRootVrtx +
", " + prevPath.toString());
479 mol.add(iacRootVrtx);
483 ArrayList<AttachmentPoint> apsOnThisFrag =
new ArrayList<>();
488 ap.setAtomPositionNumberInMol(ap.getAtomPositionNumber() + preNumAtms);
489 apsOnThisFrag.add(ap);
491 if (rootVrtx.containsAtoms())
493 IAtom srcAtm = mol.getAtom(ap.getAtomPositionNumberInMol());
494 if (apsPerAtom.containsKey(srcAtm))
496 apsPerAtom.get(srcAtm).add(ap);
500 ArrayList<AttachmentPoint> apsOnThisAtm =
501 new ArrayList<AttachmentPoint>();
502 apsOnThisAtm.add(ap);
503 apsPerAtom.put(srcAtm,apsOnThisAtm);
507 apsPerVertexId.put(idRootVrtx,apsOnThisFrag);
510 for (
Edge edge : graph.getEdgesWithSrc(rootVrtx))
516 ArrayList<AttachmentPoint> apOnThisEdge =
517 new ArrayList<AttachmentPoint>();
518 apOnThisEdge.add(apSrc);
519 apOnThisEdge.add(edge.getTrgAP());
520 apsPerEdge.put(edge,apOnThisEdge);
522 if (rootVrtx.containsAtoms())
525 Point3d srcPtApSrc =
new Point3d(
532 srcPtApSrc,trgPtApSrc,edge,removeUsedRCAs, rebuild,
533 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
538 removeUsedRCAs, rebuild,
539 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
584 int idSrcAtmA, Point3d srcApA, Point3d trgApA,
Edge edge,
585 boolean removeUsedRCAs,
boolean rebuild,
586 Map<Long, ArrayList<AttachmentPoint>> apsPerVertexId,
587 Map<
Edge,ArrayList<AttachmentPoint>> apsPerEdge,
588 Map<IAtom,ArrayList<AttachmentPoint>> apsPerAtom,
589 Map<IBond,ArrayList<AttachmentPoint>> apsPerBond)
592 logger.log(Level.FINE,
"Appending 3D fragment via edge: "+edge +
NL
593 +
"#Atoms on growing mol: "+mol.getAtomCount());
596 Vertex inVtx = edge.getTrgAP().getOwner();
603 logger.log(Level.FINE,
"Incoming vertex : "+inVtx);
605 int preNumAtms = mol.getAtomCount();
606 IAtomContainer inFrag =
null;
613 String msg =
"ThreeDimTreeBuilder found a building block "
615 +
"to containg atoms, but returning a null atom "
617 +
"Problematic building block is bbID="
620 throw new IllegalArgumentException(msg);
623 logger.log(Level.FINE,
"Incoming IAC #atoms: " +
624 inFrag.getAtomCount());
641 Point3d tr1 =
new Point3d();
642 tr1.sub(trgApB,srcApA);
643 for (IAtom atm : inFrag.atoms())
646 atm.getPoint3d().sub(tr1);
650 Point3d pt =
new Point3d(ap.getDirectionVector());
652 ap.setDirectionVector(pt);
659 Vector3d vectApA =
new Vector3d();
660 Vector3d vectApB =
new Vector3d();
661 vectApA.sub(trgApA,srcApA);
662 vectApB.sub(srcApB,trgApB);
667 "After 1st translation and before rotation" +
NL
668 +
"srcApA "+srcApA+
NL
669 +
"trgApA "+trgApA+
NL
670 +
"vectApA "+vectApA+
NL
671 +
"srcApB "+srcApB+
NL
672 +
"trgApB "+trgApB+
NL
673 +
"vectApB "+vectApB);
676 double rotAng = vectApA.angle(vectApB);
677 double threshold = 0.00001;
678 if (rotAng >= threshold)
680 Vector3d rotAxis =
new Vector3d();
681 if (rotAng <= (Math.PI-0.00001))
683 rotAxis.cross(vectApB,vectApA);
689 Matrix3d rotMat =
new Matrix3d();
691 rotMat.set(
new AxisAngle4d(rotAxis,rotAng));
693 logger.log(Level.FINE,
"rotAng "+rotAng+
NL
698 for (IAtom atm : inFrag.atoms())
701 atm.getPoint3d().sub(srcApA);
702 rotMat.transform(atm.getPoint3d());
703 atm.getPoint3d().add(srcApA);
709 Point3d pt =
new Point3d(ap.getDirectionVector());
711 rotMat.transform(pt);
713 ap.setDirectionVector(pt);
718 srcApB =
new Point3d(inFrag.getAtom(
723 logger.log(Level.FINE,
"RotAng below threshold. No rotation.");
727 "After rotation before 2nd translation"+
NL
728 +
"srcApA "+srcApA+
NL
729 +
"trgApA "+trgApA+
NL
730 +
"vectApA "+vectApA+
NL
731 +
"srcApB "+srcApB+
NL
732 +
"trgApB "+trgApB+
NL
733 +
"vectApB "+vectApB);
736 boolean edgeToRCA =
false;
740 if (edge.getSrcAP().getOwner().isRCV() ||
741 edge.getTrgAP().getOwner().isRCV())
749 vectApA.sub(trgApA,srcApA);
750 vectApB.sub(srcApB,trgApB);
752 Point3d tr2 =
new Point3d();
759 if (vectApA.length() > vectApB.length())
772 tr2.sub(vectApA,vectApB);
777 for (IAtom atm : inFrag.atoms())
779 atm.getPoint3d().add(tr2);
780 if ((atm.getPoint3d().x != atm.getPoint3d().x) ||
781 (atm.getPoint3d().y != atm.getPoint3d().y) ||
782 (atm.getPoint3d().z != atm.getPoint3d().z))
784 String str =
"ERROR! NaN coordinated from "
785 +
"rototranslation of 3D fragment. "
786 +
"Check source code. Atm: "+atm;
792 Point3d pt =
new Point3d(ap.getDirectionVector());
794 if ((pt.x != pt.x ) || (pt.y != pt.y ) || (pt.z != pt.z ))
796 String str =
"ERROR! NaN coordinated from "
797 +
"rototranslation of 3D fragment's APs. "
798 +
"Check source code.";
801 ap.setDirectionVector(pt);
806 for (IAtom atm : inFrag.atoms())
808 Object prevPath = atm.getProperty(
813 idInVrx +
", " + prevPath.toString());
829 BondType bndTyp = edge.getBondType();
833 IBond bnd =
new Bond(mol.getAtom(idSrcAtmA), atmToBind,
838 ArrayList<AttachmentPoint> apsOnBond =
new ArrayList<>();
839 apsOnBond.add(edge.getSrcAP());
840 apsOnBond.add(edge.getTrgAP());
841 apsPerBond.put(bnd,apsOnBond);
846 edge.getSrcAP().getAPClass());
848 ArrayList<Ring> rings = graph.getRingsInvolvingVertex(inVtx);
854 rings.get(0).getBondType());
860 edge.getSrcAP().getAPClass().getBondType());
866 ArrayList<AttachmentPoint> apsOnThisFrag =
new ArrayList<>();
871 ap.setAtomPositionNumberInMol(ap.getAtomPositionNumber() + preNumAtms);
872 apsOnThisFrag.add(ap);
876 IAtom srcAtm = mol.getAtom(ap.getAtomPositionNumberInMol());
877 if (apsPerAtom.containsKey(srcAtm))
879 apsPerAtom.get(srcAtm).add(ap);
883 ArrayList<AttachmentPoint> apsOnThisAtm =
884 new ArrayList<AttachmentPoint>();
885 apsOnThisAtm.add(ap);
886 apsPerAtom.put(srcAtm,apsOnThisAtm);
890 apsPerVertexId.put(idInVrx, apsOnThisFrag);
893 for (
Edge nextEdge : graph.getEdgesWithSrc(inVtx))
896 ArrayList<AttachmentPoint> apOnThisEdge =
897 new ArrayList<AttachmentPoint>();
898 apOnThisEdge.add(nextEdge.getSrcAP());
899 apOnThisEdge.add(nextEdge.getTrgAP());
900 apsPerEdge.put(nextEdge,apOnThisEdge);
905 Point3d trgNextApA =
new Point3d(
906 nextEdge.getSrcAP().getDirectionVector());
909 nextEdge.getSrcAP().getAtomPositionNumber())));
913 nextEdge.getSrcAP().getAtomPositionNumberInMol(),
914 srcNextApA, trgNextApA, nextEdge, removeUsedRCAs,
916 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
921 removeUsedRCAs, rebuild,
922 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
934 Point3d c =
new Point3d(0,0,0);
935 if (mol.getAtomCount() > 0)
General set of constants used in DENOPTIM.
static final Object MOLPROPAPxBOND
Key for IAtomContainer property containing the map of AttachmentPoints per atom.
static final String APSTAG
SDF tag defining attachment points.
static final String EOL
new line character
static final String ATMPROPVERTEXID
String tag of Atom property used to store the unique ID of the Vertex corresponding to the molecular ...
static final Object RCAPROPRINGUSER
Property of a IAtom representing a RingClosingAttractor.
static final Object RCAPROPCHORDBNDTYP
Property of a IAtom representing a RingClosingAttractor.
static final Object MOLPROPAPxVID
Key for IAtomContainer property containing the map of AttachmentPoints per vertex ID.
static final Object MOLPROPAPxEDGE
Key for IAtomContainer property containing the map of AttachmentPoints per edge.
static final String ATMPROPVERTEXPATH
Name of Atom property used to store the unique ID of the Vertex that owns the atom and the IDs of any...
static final Object VISITEDBY3DBUILDER
Property used to mark vertices visited by the 3D tree builder.
static final Object MOLPROPAPxATOM
Key for IAtomContainer property containing the map of AttachmentPoints per vertex ID.
static final Object RCAPROPAPCTORCA
Property of a IAtom representing a RingClosingAttractor.
An attachment point (AP) is a possibility to attach a Vertex onto the vertex holding the AP (i....
int getAtomPositionNumberInMol()
The index of the source atom in the atom list of the entire molecule.
int getAtomPositionNumber()
The index of the source atom in the atom list of the fragment.
Point3d getDirectionVector()
Returns the end of the direction vector.
static String getAPDefinitionsForSDF(LinkedHashMap< Integer, List< AttachmentPoint > > apsPerIndex)
Prepares the two strings that can be used to define AttachmentPoints in SDF files.
Container for the list of vertices and the edges that connect them.
This class represents the edge between two vertices.
A vertex is a data structure that has an identity and holds a list of AttachmentPoints.
int getBuildingBlockId()
Returns the index of the building block that should correspond to the position of the building block ...
abstract boolean containsAtoms()
Vertex.BBType getBuildingBlockType()
abstract List< AttachmentPoint > getAttachmentPoints()
abstract IAtomContainer getIAtomContainer()
void setProperty(Object key, Object property)
Utility methods for input/output.
static void writeSDFFile(String fileName, IAtomContainer mol)
Writes IAtomContainer to SDF file.
static void writeGraphToJSON(File file, DGraph graph)
Writes the graph to JSON file.
Tool to build build three-dimensional (3D) tree-like molecular structures from DGraph.
Randomizer randomizer
Program-specific randomizer.
ThreeDimTreeBuilder(Logger logger, Randomizer randomizer)
Constructor providing the program-specific logger and randomizer.
void append3DFragmentsDisconnected(Vertex rootVrtx, IAtomContainer mol, DGraph graph, boolean removeUsedRCAs, boolean rebuild, Map< Long, ArrayList< AttachmentPoint > > apsPerVertexId, Map< Edge, ArrayList< AttachmentPoint > > apsPerEdge, Map< IAtom, ArrayList< AttachmentPoint > > apsPerAtom, Map< IBond, ArrayList< AttachmentPoint > > apsPerBond)
A a veretex 3D structure (if any) that is not connected to anything previously added.
void setAlignBBsIn3D(boolean align)
Sets the flag that controls whether building blocks have to be aligned according to the AP vectors or...
boolean alignIn3D
Flag controlling whether to align building blocks according to the AP vectors or not.
Point3d getRandomPoint(IAtomContainer mol)
void append3DFragmentsViaEdges(IAtomContainer mol, DGraph graph, int idSrcAtmA, Point3d srcApA, Point3d trgApA, Edge edge, boolean removeUsedRCAs, boolean rebuild, Map< Long, ArrayList< AttachmentPoint > > apsPerVertexId, Map< Edge, ArrayList< AttachmentPoint > > apsPerEdge, Map< IAtom, ArrayList< AttachmentPoint > > apsPerAtom, Map< IBond, ArrayList< AttachmentPoint > > apsPerBond)
Recursive method that appends branches of building blocks following the edges of the graph.
IAtomContainer convertGraphTo3DAtomContainer(DGraph graph, boolean removeUsedRCAs)
Creates a three-dimensional molecular representation from a given DGraph.
IAtomContainer convertGraphTo3DAtomContainer(DGraph graph)
Created a three-dimensional molecular representation from a given DGraph.
IChemObjectBuilder builder
Private builder of atom containers.
double maxCoord
Controls the maximum distance between a random place where unanchored building blocks are placed and ...
Logger logger
Program-specific logger.
static void writeSDFFields(IAtomContainer iac, DGraph g)
Some useful math operations.
static Vector3d getNormalDirection(Vector3d vecA)
Generate a vector that is perpendicular to the given one.
Utilities for molecule conversion.
static void removeUsedRCA(IAtomContainer mol, DGraph graph, Logger logger)
Replace used RCAs (i.e., those involved in Rings) while adding the ring closing bonds.
static void setZeroImplicitHydrogensToAllAtoms(IAtomContainer iac)
Sets zero implicit hydrogen count to all atoms.
static void ensureNoUnsetBondOrdersSilent(IAtomContainer iac)
Sets bond order = single to all otherwise unset bonds.
static Point3d calculateCentroid(IAtomContainer mol)
Calculated the centroid of the given molecule.
static Point3d getPoint3d(IAtom atm)
Return the 3D coordinates, if present.
Tool to generate random numbers and random decisions.
int nextInt(int i)
Returns a pseudo-random, uniformly distributed int value between 0 (inclusive) and the specified valu...
Possible chemical bond types an edge can represent.
boolean hasCDKAnalogue()
Checks if it is possible to convert this edge type into a CDK bond.