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)
242 IAtomContainer mol =
builder.newAtomContainer();
246 Vertex rootVrtx = graph.getSourceVertex();
249 IAtomContainer iacRootVrtx =
null;
253 removeUsedRCAs, rebuild);
255 if (iacRootVrtx ==
null)
257 String msg =
"ThreeDimTreeBuilder found a building block daclaring "
258 +
"to containg atoms, but returning null atom container. "
259 +
"Building blocks: " + rootVrtx;
260 throw new IllegalArgumentException(msg);
263 for (IAtom atm : iacRootVrtx.atoms())
265 Object prevPath = atm.getProperty(
270 idRootVrtx +
", " + prevPath.toString());
277 mol.add(iacRootVrtx);
281 Map<Long,ArrayList<AttachmentPoint>> apsPerVertexId =
new HashMap<>();
282 Map<Edge,ArrayList<AttachmentPoint>> apsPerEdge =
new HashMap<>();
283 Map<IAtom,ArrayList<AttachmentPoint>> apsPerAtom =
new HashMap<>();
284 Map<IBond,ArrayList<AttachmentPoint>> apsPerBond =
new HashMap<>();
285 ArrayList<AttachmentPoint> apsOnThisFrag =
new ArrayList<>();
289 ap.setAtomPositionNumberInMol(ap.getAtomPositionNumber());
290 apsOnThisFrag.add(ap);
293 IAtom srcAtm = iacRootVrtx.getAtom(ap.getAtomPositionNumber());
294 if (apsPerAtom.containsKey(srcAtm))
296 apsPerAtom.get(srcAtm).add(ap);
300 ArrayList<AttachmentPoint> apsOnThisAtm =
302 apsOnThisAtm.add(ap);
303 apsPerAtom.put(srcAtm,apsOnThisAtm);
307 apsPerVertexId.put(idRootVrtx,apsOnThisFrag);
310 for (
Edge edge : graph.getEdgesWithSrc(rootVrtx))
316 ArrayList<AttachmentPoint> apOnThisEdge =
317 new ArrayList<AttachmentPoint>();
318 apOnThisEdge.add(apSrc);
319 apOnThisEdge.add(edge.getTrgAP());
320 apsPerEdge.put(edge,apOnThisEdge);
325 Point3d srcPtApSrc =
new Point3d(
332 srcPtApSrc,trgPtApSrc,edge,removeUsedRCAs, rebuild,
333 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
338 removeUsedRCAs, rebuild,
339 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
358 if (setCDKRequirements)
368 StringBuilder sb =
new StringBuilder();
369 String file =
"/tmp/iacTree.sdf";
370 sb.append(
"Writing tree-like IAtomContainer to " + file+
NL);
371 IAtomContainer cmol =
builder.newAtomContainer();
381 sb.append(
"AP-per-VertexID"+
NL);
383 for (
long v : apsPerVertexId.keySet())
385 ArrayList<AttachmentPoint> aps = apsPerVertexId.get(v);
389 IAtom atm =
new PseudoAtom(String.valueOf(i),
390 new Point3d(ap.getDirectionVector()));
391 sb.append(
"Vertex: "+v+
" AP-"+i+
" = "+ap+
NL);
393 IBond bnd =
new Bond(cmol.getAtom(
394 ap.getAtomPositionNumber()),
395 cmol.getAtom(mol.getAtomCount()+i-1),
402 sb.append(
"AP-per-Edge"+
NL);
403 for (
Edge e : apsPerEdge.keySet())
405 ArrayList<AttachmentPoint> aps = apsPerEdge.get(e);
408 sb.append(
"Edge: "+e+
" AP = "+ap+
NL);
411 sb.append(
"AP-per-Atom"+
NL);
412 for (IAtom a : apsPerAtom.keySet())
414 ArrayList<AttachmentPoint> aps = apsPerAtom.get(a);
417 sb.append(
"Atom: "+mol.indexOf(a) +
" AP = "+ap+
NL);
420 sb.append(
"AP-per-Bond"+
NL);
421 for (IBond b : apsPerBond.keySet())
423 ArrayList<AttachmentPoint> aps = apsPerBond.get(b);
426 sb.append(
"Bond: "+mol.indexOf(b.getAtom(0))
427 +
"-"+mol.indexOf(b.getAtom(1))+
" AP = "+ap+
NL);
430 System.out.println(sb.toString());
434 LinkedHashMap<Integer,List<AttachmentPoint>> freeAPPerAtm =
435 new LinkedHashMap<>();
436 for (IAtom a : apsPerAtom.keySet())
438 int atmID = mol.indexOf(a);
446 ArrayList<AttachmentPoint> aps = apsPerAtom.get(a);
449 if (ap.isAvailableThroughout())
451 if (freeAPPerAtm.containsKey(atmID))
453 freeAPPerAtm.get(atmID).add(ap);
455 List<AttachmentPoint> lst =
456 new ArrayList<AttachmentPoint>();
458 freeAPPerAtm.put(atmID,lst);
513 int idSrcAtmA, Point3d srcApA, Point3d trgApA,
Edge edge,
514 boolean removeUsedRCAs,
boolean rebuild,
515 Map<Long, ArrayList<AttachmentPoint>> apsPerVertexId,
516 Map<
Edge,ArrayList<AttachmentPoint>> apsPerEdge,
517 Map<IAtom,ArrayList<AttachmentPoint>> apsPerAtom,
518 Map<IBond,ArrayList<AttachmentPoint>> apsPerBond)
521 logger.log(Level.FINE,
"Appending 3D fragment via edge: "+edge +
NL
522 +
"#Atoms on growing mol: "+mol.getAtomCount());
525 Vertex inVtx = edge.getTrgAP().getOwner();
531 logger.log(Level.FINE,
"Incoming vertex : "+inVtx);
533 int preNumAtms = mol.getAtomCount();
534 IAtomContainer inFrag =
null;
541 String msg =
"ThreeDimTreeBuilder found a building block "
543 +
"to containg atoms, but returning a null atom "
545 +
"Problematic building block is bbID="
548 throw new IllegalArgumentException(msg);
551 logger.log(Level.FINE,
"Incoming IAC #atoms: " +
552 inFrag.getAtomCount());
569 Point3d tr1 =
new Point3d();
570 tr1.sub(trgApB,srcApA);
571 for (IAtom atm : inFrag.atoms())
574 atm.getPoint3d().sub(tr1);
578 Point3d pt =
new Point3d(ap.getDirectionVector());
580 ap.setDirectionVector(pt);
587 Vector3d vectApA =
new Vector3d();
588 Vector3d vectApB =
new Vector3d();
589 vectApA.sub(trgApA,srcApA);
590 vectApB.sub(srcApB,trgApB);
595 "After 1st translation and before rotation" +
NL
596 +
"srcApA "+srcApA+
NL
597 +
"trgApA "+trgApA+
NL
598 +
"vectApA "+vectApA+
NL
599 +
"srcApB "+srcApB+
NL
600 +
"trgApB "+trgApB+
NL
601 +
"vectApB "+vectApB);
604 double rotAng = vectApA.angle(vectApB);
605 double threshold = 0.00001;
606 if (rotAng >= threshold)
608 Vector3d rotAxis =
new Vector3d();
609 if (rotAng <= (Math.PI-0.00001))
611 rotAxis.cross(vectApB,vectApA);
617 Matrix3d rotMat =
new Matrix3d();
619 rotMat.set(
new AxisAngle4d(rotAxis,rotAng));
621 logger.log(Level.FINE,
"rotAng "+rotAng+
NL
626 for (IAtom atm : inFrag.atoms())
629 atm.getPoint3d().sub(srcApA);
630 rotMat.transform(atm.getPoint3d());
631 atm.getPoint3d().add(srcApA);
637 Point3d pt =
new Point3d(ap.getDirectionVector());
639 rotMat.transform(pt);
641 ap.setDirectionVector(pt);
646 srcApB =
new Point3d(inFrag.getAtom(
651 logger.log(Level.FINE,
"RotAng below threshold. No rotation.");
655 "After rotation before 2nd translation"+
NL
656 +
"srcApA "+srcApA+
NL
657 +
"trgApA "+trgApA+
NL
658 +
"vectApA "+vectApA+
NL
659 +
"srcApB "+srcApB+
NL
660 +
"trgApB "+trgApB+
NL
661 +
"vectApB "+vectApB);
664 boolean edgeToRCA =
false;
668 if (edge.getSrcAP().getOwner().isRCV() ||
669 edge.getTrgAP().getOwner().isRCV())
677 vectApA.sub(trgApA,srcApA);
678 vectApB.sub(srcApB,trgApB);
680 Point3d tr2 =
new Point3d();
687 if (vectApA.length() > vectApB.length())
700 tr2.sub(vectApA,vectApB);
705 for (IAtom atm : inFrag.atoms())
707 atm.getPoint3d().add(tr2);
708 if ((atm.getPoint3d().x != atm.getPoint3d().x) ||
709 (atm.getPoint3d().y != atm.getPoint3d().y) ||
710 (atm.getPoint3d().z != atm.getPoint3d().z))
712 String str =
"ERROR! NaN coordinated from "
713 +
"rototranslation of 3D fragment. "
714 +
"Check source code. Atm: "+atm;
720 Point3d pt =
new Point3d(ap.getDirectionVector());
722 if ((pt.x != pt.x ) || (pt.y != pt.y ) || (pt.z != pt.z ))
724 String str =
"ERROR! NaN coordinated from "
725 +
"rototranslation of 3D fragment's APs. "
726 +
"Check source code.";
729 ap.setDirectionVector(pt);
734 for (IAtom atm : inFrag.atoms())
736 Object prevPath = atm.getProperty(
741 idInVrx +
", " + prevPath.toString());
757 BondType bndTyp = edge.getBondType();
761 IBond bnd =
new Bond(mol.getAtom(idSrcAtmA), atmToBind,
766 ArrayList<AttachmentPoint> apsOnBond =
new ArrayList<>();
767 apsOnBond.add(edge.getSrcAP());
768 apsOnBond.add(edge.getTrgAP());
769 apsPerBond.put(bnd,apsOnBond);
774 edge.getSrcAP().getAPClass());
776 ArrayList<Ring> rings = graph.getRingsInvolvingVertex(inVtx);
782 rings.get(0).getBondType());
788 edge.getSrcAP().getAPClass().getBondType());
794 ArrayList<AttachmentPoint> apsOnThisFrag =
new ArrayList<>();
799 ap.setAtomPositionNumberInMol(ap.getAtomPositionNumber()
801 apsOnThisFrag.add(ap);
805 IAtom srcAtm = mol.getAtom(ap.getAtomPositionNumberInMol());
806 if (apsPerAtom.containsKey(srcAtm))
808 apsPerAtom.get(srcAtm).add(ap);
812 ArrayList<AttachmentPoint> apsOnThisAtm =
813 new ArrayList<AttachmentPoint>();
814 apsOnThisAtm.add(ap);
815 apsPerAtom.put(srcAtm,apsOnThisAtm);
819 apsPerVertexId.put(idInVrx, apsOnThisFrag);
822 for (
Edge nextEdge : graph.getEdgesWithSrc(inVtx))
825 ArrayList<AttachmentPoint> apOnThisEdge =
826 new ArrayList<AttachmentPoint>();
827 apOnThisEdge.add(nextEdge.getSrcAP());
828 apOnThisEdge.add(nextEdge.getTrgAP());
829 apsPerEdge.put(nextEdge,apOnThisEdge);
834 Point3d trgNextApA =
new Point3d(
835 nextEdge.getSrcAP().getDirectionVector());
838 nextEdge.getSrcAP().getAtomPositionNumber())));
842 nextEdge.getSrcAP().getAtomPositionNumberInMol(),
843 srcNextApA, trgNextApA, nextEdge, removeUsedRCAs,
845 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
850 removeUsedRCAs, rebuild,
851 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
863 Point3d c =
new Point3d(0,0,0);
864 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 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 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()
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 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.