1import sys
2import argparse
3
4import CDPL.Chem as Chem
5import CDPL.Pharm as Pharm
6
7
8# generates the pharmacophore of the argument molecule using
9# atom coordinates of the specified conformation
10def genPharmacophore(mol: Chem.Molecule, conf_idx: int) -> Pharm.Pharmacophore:
11 if conf_idx < 1: # for a new molecule
12 Pharm.prepareForPharmacophoreGeneration(mol) # first call utility function preparing the molecule for pharmacophore generation
13
14 ph4_gen = Pharm.DefaultPharmacophoreGenerator() # create an instance of the pharmacophore generator default implementation
15 ph4 = Pharm.BasicPharmacophore() # create an instance of the default implementation of the Pharm.Pharmacophore interface
16 ph4_name = Chem.getName(mol) # use the name of the input molecule as pharmacophore name
17
18 if conf_idx >= 0: # if mol is a multi-conf. molecule use atom 3D coordinates of the specified conf.
19 ph4_gen.setAtom3DCoordinatesFunction(Chem.AtomConformer3DCoordinatesFunctor(conf_idx))
20 ph4_name += '#' + str(conf_idx) # and append conformer index to the pharmacophore name
21
22 ph4_gen.generate(mol, ph4) # generate the pharmacophore
23 Pharm.setName(ph4, ph4_name) # set the pharmacophore name
24
25 return ph4
26
27def parseArgs() -> argparse.Namespace:
28 parser = argparse.ArgumentParser(description='Generates pharmacophores of the given input molecules.')
29
30 parser.add_argument('-i',
31 dest='in_file',
32 required=True,
33 metavar='<file>',
34 help='Molecule input file')
35 parser.add_argument('-o',
36 dest='out_file',
37 required=True,
38 metavar='<file>',
39 help='Pharmacophore output file')
40 parser.add_argument('-q',
41 dest='quiet',
42 required=False,
43 action='store_true',
44 default=False,
45 help='Disable progress output (default: false)')
46
47 return parser.parse_args()
48
49def main() -> None:
50 args = parseArgs()
51
52 # create reader for input molecules (format specified by file extension)
53 reader = Chem.MoleculeReader(args.in_file)
54
55 # create writer for the generated pharmacophores (format specified by file extension)
56 writer = Pharm.FeatureContainerWriter(args.out_file)
57
58 # create an instance of the default implementation of the Chem.Molecule interface
59 mol = Chem.BasicMolecule()
60 i = 1
61
62 # read and process molecules one after the other until the end of input has been reached
63 try:
64 while reader.read(mol):
65 # compose a simple molecule identifier
66 mol_id = Chem.getName(mol).strip()
67
68 if mol_id == '':
69 mol_id = '#' + str(i) # fallback if name is empty
70 else:
71 mol_id = '\'%s\' (#%s)' % (mol_id, str(i))
72
73 if not args.quiet:
74 print('- Generating pharmacophore of molecule %s...' % mol_id)
75
76 num_confs = Chem.getNumConformations(mol)
77 start_conf_idx = 0
78
79 if num_confs == 0: # test if molecule has conformations
80 start_conf_idx = -1 # if not, make sure conformer loop body gets executed
81
82 try:
83 for conf_idx in range(start_conf_idx, num_confs): # for each conformer
84 ph4 = genPharmacophore(mol, conf_idx) # generate pharmacophore
85
86 if not args.quiet:
87 print(' -> Generated %s features: %s' % (str(ph4.numFeatures), Pharm.generateFeatureTypeHistogramString(ph4)))
88
89 if not writer.write(ph4): # output pharmacophore
90 sys.exit('Error: writing generated pharmacophore %s failed' % mol_id)
91
92 except Exception as e:
93 sys.exit('Error: pharmacophore generation or output for molecule %s failed: %s' % (mol_id, str(e)))
94
95 i += 1
96
97 except Exception as e: # handle exception raised in case of severe read errors
98 sys.exit('Error: reading molecule failed: ' + str(e))
99
100 writer.close()
101 sys.exit(0)
102
103if __name__ == '__main__':
104 main()