All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.actelion.research.chem.chemicalspaces.ptree.search.SynthonPharmTreeGenerator Maven / Gradle / Ivy

There is a newer version: 2024.11.2
Show newest version
package com.actelion.research.chem.chemicalspaces.ptree.search;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.actelion.research.chem.Canonizer;
import com.actelion.research.chem.IDCodeParser;
import com.actelion.research.chem.Molecule;
import com.actelion.research.chem.SSSearcher;
import com.actelion.research.chem.StereoMolecule;
import com.actelion.research.chem.chemicalspaces.ptree.PharmTreeSynthonReactionHelper;
import com.actelion.research.chem.chemicalspaces.ptree.synthon.PharmTreeSynthon;
import com.actelion.research.chem.chemicalspaces.ptree.synthon.PharmTreeSynthonLibrary;
import com.actelion.research.chem.chemicalspaces.synthon.SynthonReactor;
import com.actelion.research.chem.descriptor.pharmacophoretree.FeatureCalculator;
import com.actelion.research.chem.descriptor.pharmacophoretree.PharmacophoreNode;
import com.actelion.research.chem.descriptor.pharmacophoretree.PharmacophoreTree;
import com.actelion.research.chem.descriptor.pharmacophoretree.PharmacophoreTreeGenerator;
import com.actelion.research.chem.phesa.pharmacophore.PharmacophoreCalculator;

/**
 * Generates PharmacophoreTrees (PharmTrees) for building blocks (or fragments) that are part of virtual chemical space.
 * Building blocks are represented as synthon structures, containing reactive linkers (R1,R2,R3,R4). 
 * In order to make the searches in the virtual chemical space using PharmTrees more efficient, atoms that will be part 
 * of the same ring (formed by the reaction), are merged into one node. Thereby, also the number of linkers required
 * to make the ring formation is reduced
 * @author Joel Wahl
 *
 */


public class SynthonPharmTreeGenerator {
	private PharmTreeSynthonLibrary synthonLib;
	private List genericSynthons;
	private PharmTreeSynthonReactionHelper rxnHelper;

	public SynthonPharmTreeGenerator(PharmTreeSynthonLibrary synthonLib) {
		this.synthonLib = synthonLib;
		this.genericSynthons = synthonLib.getGenericReactants();
		this.rxnHelper = synthonLib.getReactionHelper();
		furtherProcessGenericSynthons();
	}
	
	public void processBuildingBlocks() {
		Map> ringReactantIndeces = rxnHelper.getRingReactantIndeces();
		Map> ringWithLinks = rxnHelper.getRingWithLinks();
		StereoMolecule genericProduct = rxnHelper.getGenericProduct();
		Map> reactantsWithLinkers = rxnHelper.getReactantsWithLinkers().entrySet().stream()
			    .collect(Collectors.toMap(e -> e.getKey(), e -> new ArrayList(e.getValue()))); //deep copy of map, since it will be modified later
		
		Set linkersToDelete = new HashSet();
		for(int ring : ringReactantIndeces.keySet()) {
			int nLinkers = ringReactantIndeces.get(ring).size()-1; 
			//number of linkers actually needed to describe ring closure reaction is equal to number of reactants that are involved in forming the ring minus 1
			int toDelete = ringWithLinks.get(ring).size()-nLinkers; // number of links that can be removed 
			Iterator iterator = ringWithLinks.get(ring).iterator();
			for(int i=0;i v.remove(Integer.valueOf(del)));		
			}
		}
		for(int i=0;i synthonList = synthonLib.getSynthons().get(i);
			for(int bb=0;bb nodesToBeDeleted = new ArrayList();
				for(PharmacophoreNode node : bbTree.getNodes()) {
					if(node.isLinkNode()) {
						if(linkersToDelete.contains(node.getFunctionalities()[0]))
							nodesToBeDeleted.add(node);
					}
				}
				nodesToBeDeleted.forEach(e -> {
					bbTree.removeNode(e);
				});
				
				synthonList.get(bb).setPharmacophoreTree(bbTree);

			}	
		}
		
		
	}
	
	
	
	public PharmacophoreTree calculatePTree(StereoMolecule bb, StereoMolecule genericProduct, int synthonID,
			Map> ringReactantIndeces, Map> reactantsWithLinkers) {
		

		FeatureCalculator calculator = new FeatureCalculator(genericProduct);
		calculator.calculate();
		int[][] productAtomFunctionalities = calculator.getAtomFunctionalities();
		double[] productAtomVolumes = PharmacophoreTreeGenerator.getAtomVolumes(genericProduct);
		
		List ringFunctionalities = new ArrayList();
		List> ringVolumes = new ArrayList>();
		
		for(Set ring : rxnHelper.getFormedRings()) {
			int[] func = new int[PharmacophoreCalculator.LIPO_ID+1];
			List volumes = new ArrayList();
			for(int ringAtom : ring) {
				int[] atomFunc = productAtomFunctionalities[ringAtom];
				IntStream.range(0,func.length).forEach(e -> func[e]+=atomFunc[e]);
				volumes.add(productAtomVolumes[ringAtom]);
			}
			ringFunctionalities.add(func);
			ringVolumes.add(volumes);
		}
		//from this info, the node properties of the ring nodes representing rings formed
		//in the reaction are fully defined. Now we need to map them to the correct ring indeces
		// and process the building blocks accordingly
		//one building block involved in the ring formation should bear the full ring node, 
		//the others are dummy nodes

		int[] reactantToBBMap = new int[0];
		Map> rings = new HashMap>(); //formed rings are indiced
		if(rxnHelper.getFormedRings().size()>0) {
			SSSearcher searcher = new SSSearcher();
			searcher.setFragment(genericSynthons.get(synthonID));
			searcher.setMolecule(bb);
			searcher.findFragmentInMolecule();
			ArrayList matches = searcher.getMatchList();
			if(matches.size()!=1) {
				System.err.println("could not match generic reactant to building block");
				System.err.println(genericSynthons.get(synthonID).getIDCode());
				System.err.println(bb.getIDCode());
				return null;
			}
			else {
				reactantToBBMap = matches.get(0);

			}
					
			for(int a=0;a=SynthonReactor.CONNECTOR_OFFSET)
					continue;
				for(int i=0;i());
								rings.get(ringIndex).add(a);
							}
								
							
						}
					}
				}
			}
							
		}
		
		Map> atomToNodes = new HashMap>();
		PharmacophoreTree bbTree = PharmacophoreTreeGenerator.generate(bb, atomToNodes,rings.values().stream().collect(Collectors.toList()));

		Map ringMainReactants = new HashMap();
		//for every formed ring in the reaction, one reactant has all the features assigned to it, whereas the remaining ones have zero nodes
		// the main reactant should be the one with the highest number of linkers
		for(int ring : ringReactantIndeces.keySet()) {
			Set reactants = ringReactantIndeces.get(ring);
			Iterator iterator = reactants.iterator();
			int maxLinkers = 0;
			int mainReactant = -1;
			while(iterator.hasNext()) {
				int reactant = iterator.next();
				if(reactantsWithLinkers.get(reactant).size()>maxLinkers) {
					maxLinkers = reactantsWithLinkers.get(reactant).size();
					mainReactant = reactant;
				}
			}
			ringMainReactants.put(ring,mainReactant);
		}
		
		// for the nodes that represent groups of atoms that will be part of a newly formed ring, do the following:
		// if the building block is considered the main reactant for this ring formation, all ring functionalities/volumes
		// are assigned to it
		for(PharmacophoreNode node : bbTree.getNodes()) {
			if(node.isLinkNode())
				continue;
			else {
				
			boolean nodeProcessed = false;
			for(int index=0;index formedRing = rxnHelper.getFormedRings().get(l);
							if(formedRing.contains(productIndex)) {
								nodeProcessed = true;
								int ringIndex = l;
								int mainReactantSynthonID = ringMainReactants.get(ringIndex);
								
								if(synthonID==mainReactantSynthonID) {
									int dummyAtomsToAdd = formedRing.size()-node.getAtoms().size();
									for(int da=0;da weights = new ArrayList();
									IntStream.range(0, node.getAtoms().size()).forEach(e -> weights.add(1.0));
									node.setFunctionalities(ringFunctionalities.get(l));
									node.setVolumes(ringVolumes.get(l));
								}
								else {
									node.setFunctionalities(new int[PharmacophoreCalculator.LIPO_ID+1]);
									node.setVolumes(new ArrayList());
									node.setWeights(new ArrayList());
									node.setAtoms(new ArrayList());
									node.setRole(PharmacophoreNode.ZERO_NODE);
								}
								node.calculate();
								
						}
						}
					}
				}
			}
			}
		}

		return bbTree;
		
	}
	
	/**
	 * only keep parts of synthons responsible for ring formation
	 * if one synthon is involved in the formation of more than one ring, it is split into different, disconnected
	 * fragments so that atoms that are not involved in ring formation are omitted
	 * @param genericSynthons
	 * @param rxnHelper
	 */
	private void furtherProcessGenericSynthons() {
		List newGenericSynthons = new ArrayList<>();
		Map> ringWithLinks = rxnHelper.getRingWithLinks();
		Map> reactantsWithRings = new HashMap>();
		Map> ringsWithReactants = rxnHelper.getRingReactantIndeces();
		for(int s=0;s());
			for(Map.Entry> entry : ringsWithReactants.entrySet()) {
				if (entry.getValue().contains(s)) {
					reactantsWithRings.get(s).add(entry.getKey());
				}
			}
			StereoMolecule ringFormationSynthon = new StereoMolecule();
			StereoMolecule mol = genericSynthons.get(s);
			if(reactantsWithRings.get(s).size()==0)
				ringFormationSynthon.addMolecule(mol);
			else {
				PharmTreeSynthon synthon = new PharmTreeSynthon(mol);
				List allConnectorAtoms = new ArrayList<>(synthon.getConnectorLabels().values());
				List usedConnectorAtoms = new ArrayList<>();
				for(int ring : reactantsWithRings.get(s)) {
					synthon = new PharmTreeSynthon(mol);
					List connectorAtomsToKeep = new ArrayList<>();
					
					
					for(Map.Entry entry : synthon.getConnectorLabels().entrySet()) {
						int linkerNo = synthon.getLinkerNoFromConnectorLabel(entry.getKey());
						Set ringLinks = ringWithLinks.get(ring);
							if(ringLinks.contains(linkerNo)) {
								connectorAtomsToKeep.add(entry.getValue());
							}
						
					}
					usedConnectorAtoms.addAll(connectorAtomsToKeep);
					ringFormationSynthon.addMolecule(synthon.cutConnectorPaths(synthon.getStructure(), connectorAtomsToKeep));
				}
				for(int connAtom: allConnectorAtoms) {
					if(!usedConnectorAtoms.contains(connAtom)) {
						List atomPath = Arrays.asList(connAtom, mol.getConnAtom(connAtom, 0));
						ringFormationSynthon.addMolecule(synthon.cutConnectorPaths(synthon.getStructure(), atomPath));
					}
				}
			}
			ringFormationSynthon.ensureHelperArrays(Molecule.cHelperParities);
			newGenericSynthons.add(new Canonizer(ringFormationSynthon).getCanMolecule());
		
	
		}

		genericSynthons.clear();
		for(StereoMolecule gs : newGenericSynthons) {
			gs.ensureHelperArrays(Molecule.cHelperParities);
			genericSynthons.add(gs);

		}
		rxnHelper = new PharmTreeSynthonReactionHelper(genericSynthons);


		
	}
	


	

	
	

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy