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 = this.getClass().getSimpleName()
258 +
" found a building block daclaring "
259 +
"to containg atoms, "
260 +
"but returning null atom container. "
261 +
"Building blocks: " + rootVrtx;
262 throw new IllegalArgumentException(msg);
265 for (IAtom atm : iacRootVrtx.atoms())
267 Object prevPath = atm.getProperty(
272 idRootVrtx +
", " + prevPath.toString());
279 mol.add(iacRootVrtx);
283 Map<Long,ArrayList<AttachmentPoint>> apsPerVertexId =
new HashMap<>();
284 Map<Edge,ArrayList<AttachmentPoint>> apsPerEdge =
new HashMap<>();
285 Map<IAtom,ArrayList<AttachmentPoint>> apsPerAtom =
new HashMap<>();
286 Map<IBond,ArrayList<AttachmentPoint>> apsPerBond =
new HashMap<>();
287 ArrayList<AttachmentPoint> apsOnThisFrag =
new ArrayList<>();
291 ap.setAtomPositionNumberInMol(ap.getAtomPositionNumber());
292 apsOnThisFrag.add(ap);
295 IAtom srcAtm = iacRootVrtx.getAtom(ap.getAtomPositionNumber());
296 if (apsPerAtom.containsKey(srcAtm))
298 apsPerAtom.get(srcAtm).add(ap);
302 ArrayList<AttachmentPoint> apsOnThisAtm =
304 apsOnThisAtm.add(ap);
305 apsPerAtom.put(srcAtm,apsOnThisAtm);
309 apsPerVertexId.put(idRootVrtx,apsOnThisFrag);
312 for (
Edge edge : graph.getEdgesWithSrc(rootVrtx))
318 ArrayList<AttachmentPoint> apOnThisEdge =
319 new ArrayList<AttachmentPoint>();
320 apOnThisEdge.add(apSrc);
321 apOnThisEdge.add(edge.getTrgAP());
322 apsPerEdge.put(edge,apOnThisEdge);
327 Point3d srcPtApSrc =
new Point3d(
334 srcPtApSrc,trgPtApSrc,edge,removeUsedRCAs, rebuild,
335 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
340 removeUsedRCAs, rebuild,
341 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
360 if (setCDKRequirements)
370 StringBuilder sb =
new StringBuilder();
371 String file =
"/tmp/iacTree.sdf";
372 sb.append(
"Writing tree-like IAtomContainer to " + file+
NL);
373 IAtomContainer cmol =
builder.newAtomContainer();
383 sb.append(
"AP-per-VertexID"+
NL);
385 for (
long v : apsPerVertexId.keySet())
387 ArrayList<AttachmentPoint> aps = apsPerVertexId.get(v);
391 IAtom atm =
new PseudoAtom(String.valueOf(i),
392 new Point3d(ap.getDirectionVector()));
393 sb.append(
"Vertex: "+v+
" AP-"+i+
" = "+ap+
NL);
395 IBond bnd =
new Bond(cmol.getAtom(
396 ap.getAtomPositionNumber()),
397 cmol.getAtom(mol.getAtomCount()+i-1),
404 sb.append(
"AP-per-Edge"+
NL);
405 for (
Edge e : apsPerEdge.keySet())
407 ArrayList<AttachmentPoint> aps = apsPerEdge.get(e);
410 sb.append(
"Edge: "+e+
" AP = "+ap+
NL);
413 sb.append(
"AP-per-Atom"+
NL);
414 for (IAtom a : apsPerAtom.keySet())
416 ArrayList<AttachmentPoint> aps = apsPerAtom.get(a);
419 sb.append(
"Atom: "+mol.indexOf(a) +
" AP = "+ap+
NL);
422 sb.append(
"AP-per-Bond"+
NL);
423 for (IBond b : apsPerBond.keySet())
425 ArrayList<AttachmentPoint> aps = apsPerBond.get(b);
428 sb.append(
"Bond: "+mol.indexOf(b.getAtom(0))
429 +
"-"+mol.indexOf(b.getAtom(1))+
" AP = "+ap+
NL);
432 System.out.println(sb.toString());
436 LinkedHashMap<Integer,List<AttachmentPoint>> freeAPPerAtm =
437 new LinkedHashMap<>();
438 for (IAtom a : apsPerAtom.keySet())
440 int atmID = mol.indexOf(a);
448 ArrayList<AttachmentPoint> aps = apsPerAtom.get(a);
451 if (ap.isAvailableThroughout())
453 if (freeAPPerAtm.containsKey(atmID))
455 freeAPPerAtm.get(atmID).add(ap);
457 List<AttachmentPoint> lst =
458 new ArrayList<AttachmentPoint>();
460 freeAPPerAtm.put(atmID,lst);
515 int idSrcAtmA, Point3d srcApA, Point3d trgApA,
Edge edge,
516 boolean removeUsedRCAs,
boolean rebuild,
517 Map<Long, ArrayList<AttachmentPoint>> apsPerVertexId,
518 Map<
Edge,ArrayList<AttachmentPoint>> apsPerEdge,
519 Map<IAtom,ArrayList<AttachmentPoint>> apsPerAtom,
520 Map<IBond,ArrayList<AttachmentPoint>> apsPerBond)
523 logger.log(Level.FINE,
"Appending 3D fragment via edge: "+edge +
NL
524 +
"#Atoms on growing mol: "+mol.getAtomCount());
527 Vertex inVtx = edge.getTrgAP().getOwner();
533 logger.log(Level.FINE,
"Incoming vertex : "+inVtx);
535 int preNumAtms = mol.getAtomCount();
536 IAtomContainer inFrag =
null;
543 String msg =
"ThreeDimTreeBuilder found a building block "
545 +
"to containg atoms, but returning a null atom "
547 +
"Problematic building block is bbID="
550 throw new IllegalArgumentException(msg);
553 logger.log(Level.FINE,
"Incoming IAC #atoms: " +
554 inFrag.getAtomCount());
571 Point3d tr1 =
new Point3d();
572 tr1.sub(trgApB,srcApA);
573 for (IAtom atm : inFrag.atoms())
576 atm.getPoint3d().sub(tr1);
580 Point3d pt =
new Point3d(ap.getDirectionVector());
582 ap.setDirectionVector(pt);
589 Vector3d vectApA =
new Vector3d();
590 Vector3d vectApB =
new Vector3d();
591 vectApA.sub(trgApA,srcApA);
592 vectApB.sub(srcApB,trgApB);
597 "After 1st translation and before rotation" +
NL
598 +
"srcApA "+srcApA+
NL
599 +
"trgApA "+trgApA+
NL
600 +
"vectApA "+vectApA+
NL
601 +
"srcApB "+srcApB+
NL
602 +
"trgApB "+trgApB+
NL
603 +
"vectApB "+vectApB);
606 double rotAng = vectApA.angle(vectApB);
607 double threshold = 0.00001;
608 if (rotAng >= threshold)
610 Vector3d rotAxis =
new Vector3d();
611 if (rotAng <= (Math.PI-0.00001))
613 rotAxis.cross(vectApB,vectApA);
619 Matrix3d rotMat =
new Matrix3d();
621 rotMat.set(
new AxisAngle4d(rotAxis,rotAng));
623 logger.log(Level.FINE,
"rotAng "+rotAng+
NL
628 for (IAtom atm : inFrag.atoms())
631 atm.getPoint3d().sub(srcApA);
632 rotMat.transform(atm.getPoint3d());
633 atm.getPoint3d().add(srcApA);
639 Point3d pt =
new Point3d(ap.getDirectionVector());
641 rotMat.transform(pt);
643 ap.setDirectionVector(pt);
648 srcApB =
new Point3d(inFrag.getAtom(
653 logger.log(Level.FINE,
"RotAng below threshold. No rotation.");
657 "After rotation before 2nd translation"+
NL
658 +
"srcApA "+srcApA+
NL
659 +
"trgApA "+trgApA+
NL
660 +
"vectApA "+vectApA+
NL
661 +
"srcApB "+srcApB+
NL
662 +
"trgApB "+trgApB+
NL
663 +
"vectApB "+vectApB);
666 boolean edgeToRCA =
false;
670 if (edge.getSrcAP().getOwner().isRCV() ||
671 edge.getTrgAP().getOwner().isRCV())
679 vectApA.sub(trgApA,srcApA);
680 vectApB.sub(srcApB,trgApB);
682 Point3d tr2 =
new Point3d();
689 if (vectApA.length() > vectApB.length())
702 tr2.sub(vectApA,vectApB);
707 for (IAtom atm : inFrag.atoms())
709 atm.getPoint3d().add(tr2);
710 if ((atm.getPoint3d().x != atm.getPoint3d().x) ||
711 (atm.getPoint3d().y != atm.getPoint3d().y) ||
712 (atm.getPoint3d().z != atm.getPoint3d().z))
714 String str =
"ERROR! NaN coordinated from "
715 +
"rototranslation of 3D fragment. "
716 +
"Check source code. Atm: "+atm;
722 Point3d pt =
new Point3d(ap.getDirectionVector());
724 if ((pt.x != pt.x ) || (pt.y != pt.y ) || (pt.z != pt.z ))
726 String str =
"ERROR! NaN coordinated from "
727 +
"rototranslation of 3D fragment's APs. "
728 +
"Check source code.";
731 ap.setDirectionVector(pt);
736 for (IAtom atm : inFrag.atoms())
738 Object prevPath = atm.getProperty(
743 idInVrx +
", " + prevPath.toString());
759 BondType bndTyp = edge.getBondType();
763 IBond bnd =
new Bond(mol.getAtom(idSrcAtmA), atmToBind,
768 ArrayList<AttachmentPoint> apsOnBond =
new ArrayList<>();
769 apsOnBond.add(edge.getSrcAP());
770 apsOnBond.add(edge.getTrgAP());
771 apsPerBond.put(bnd,apsOnBond);
776 edge.getSrcAP().getAPClass());
778 ArrayList<Ring> rings = graph.getRingsInvolvingVertex(inVtx);
784 rings.get(0).getBondType());
790 edge.getSrcAP().getAPClass().getBondType());
796 ArrayList<AttachmentPoint> apsOnThisFrag =
new ArrayList<>();
801 ap.setAtomPositionNumberInMol(ap.getAtomPositionNumber()
803 apsOnThisFrag.add(ap);
807 IAtom srcAtm = mol.getAtom(ap.getAtomPositionNumberInMol());
808 if (apsPerAtom.containsKey(srcAtm))
810 apsPerAtom.get(srcAtm).add(ap);
814 ArrayList<AttachmentPoint> apsOnThisAtm =
815 new ArrayList<AttachmentPoint>();
816 apsOnThisAtm.add(ap);
817 apsPerAtom.put(srcAtm,apsOnThisAtm);
821 apsPerVertexId.put(idInVrx, apsOnThisFrag);
824 for (
Edge nextEdge : graph.getEdgesWithSrc(inVtx))
827 ArrayList<AttachmentPoint> apOnThisEdge =
828 new ArrayList<AttachmentPoint>();
829 apOnThisEdge.add(nextEdge.getSrcAP());
830 apOnThisEdge.add(nextEdge.getTrgAP());
831 apsPerEdge.put(nextEdge,apOnThisEdge);
836 Point3d trgNextApA =
new Point3d(
837 nextEdge.getSrcAP().getDirectionVector());
840 nextEdge.getSrcAP().getAtomPositionNumber())));
844 nextEdge.getSrcAP().getAtomPositionNumberInMol(),
845 srcNextApA, trgNextApA, nextEdge, removeUsedRCAs,
847 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
852 removeUsedRCAs, rebuild,
853 apsPerVertexId,apsPerEdge,apsPerAtom,apsPerBond);
865 Point3d c =
new Point3d(0,0,0);
866 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.