1import sys
2import argparse
3
4import CDPL.Chem as Chem
5import CDPL.ConfGen as ConfGen
6
7
8# generates a low-energy 3D structure of the argument molecule using
9# the provided initialized ConfGen.StructureGenerator instance
10def gen3DStructure(mol: Chem.Molecule, struct_gen: ConfGen.StructureGenerator) -> int:
11 # prepare the molecule for 3D structure generation
12 ConfGen.prepareForConformerGeneration(mol)
13
14 # generate the 3D structure
15 status = struct_gen.generate(mol)
16
17 # if successful, store the generated conformer ensemble as
18 # per atom 3D coordinates arrays (= the way conformers are represented in CDPKit)
19 if status == ConfGen.ReturnCode.SUCCESS:
20 struct_gen.setCoordinates(mol)
21
22 # return status code
23 return status
24
25def parseArgs() -> argparse.Namespace:
26 parser = argparse.ArgumentParser(description='Generates conformer ensembles for the given input molecules.')
27
28 parser.add_argument('-i',
29 dest='in_file',
30 required=True,
31 metavar='<file>',
32 help='Molecule input file')
33 parser.add_argument('-o',
34 dest='out_file',
35 required=True,
36 metavar='<file>',
37 help='Conformer ensemble output file')
38 parser.add_argument('-t',
39 dest='max_time',
40 required=False,
41 metavar='<int>',
42 type=int,
43 default=3600,
44 help='Max. allowed molecule processing time (default: 3600 sec)')
45 parser.add_argument('-q',
46 dest='quiet',
47 required=False,
48 action='store_true',
49 default=False,
50 help='Disable progress output (default: false)')
51
52 return parser.parse_args()
53
54def main() -> None:
55 args = parseArgs()
56
57 # create reader for input molecules (format specified by file extension)
58 reader = Chem.MoleculeReader(args.in_file)
59
60 # create writer for the generated 3D structures (format specified by file extension)
61 writer = Chem.MolecularGraphWriter(args.out_file)
62
63 # export only a single 3D structure (in case of multi-conf. input molecules)
64 Chem.setMultiConfExportParameter(writer, False)
65
66 # create and initialize an instance of the class ConfGen.StructureGenerator which will
67 # perform the actual 3D structure generation work
68 struct_gen = ConfGen.StructureGenerator()
69
70 struct_gen.settings.timeout = args.max_time * 1000 # apply the -t argument
71
72 # dictionary mapping status codes to human readable strings
73 status_to_str = { ConfGen.ReturnCode.UNINITIALIZED : 'uninitialized',
74 ConfGen.ReturnCode.TIMEOUT : 'max. processing time exceeded',
75 ConfGen.ReturnCode.ABORTED : 'aborted',
76 ConfGen.ReturnCode.FORCEFIELD_SETUP_FAILED : 'force field setup failed',
77 ConfGen.ReturnCode.FORCEFIELD_MINIMIZATION_FAILED : 'force field structure refinement failed',
78 ConfGen.ReturnCode.FRAGMENT_LIBRARY_NOT_SET : 'fragment library not available',
79 ConfGen.ReturnCode.FRAGMENT_CONF_GEN_FAILED : 'fragment conformer generation failed',
80 ConfGen.ReturnCode.FRAGMENT_CONF_GEN_TIMEOUT : 'fragment conformer generation timeout',
81 ConfGen.ReturnCode.FRAGMENT_ALREADY_PROCESSED : 'fragment already processed',
82 ConfGen.ReturnCode.TORSION_DRIVING_FAILED : 'torsion driving failed',
83 ConfGen.ReturnCode.CONF_GEN_FAILED : 'conformer generation failed' }
84
85 # create an instance of the default implementation of the Chem.Molecule interface
86 mol = Chem.BasicMolecule()
87 i = 1
88
89 # read and process molecules one after the other until the end of input has been reached
90 try:
91 while reader.read(mol):
92 # compose a simple molecule identifier
93 mol_id = Chem.getName(mol).strip()
94
95 if mol_id == '':
96 mol_id = '#' + str(i) # fallback if name is empty
97 else:
98 mol_id = '\'%s\' (#%s)' % (mol_id, str(i))
99
100 if not args.quiet:
101 print('- Generating 3D structure of molecule %s...' % mol_id)
102
103 try:
104 # generate 3D structure of the read molecule
105 status = gen3DStructure(mol, struct_gen)
106
107 # check for severe error reported by status code
108 if status != ConfGen.ReturnCode.SUCCESS:
109 if args.quiet:
110 print('Error: 3D structure generation for molecule %s failed: %s' % (mol_id, status_to_str[status]))
111 else:
112 print(' -> 3D structure generation failed: %s' % status_to_str[status])
113 else:
114 # enforce the output of 3D coordinates in case of MDL file formats
115 Chem.setMDLDimensionality(mol, 3)
116
117 # output the generated 3D structure
118 if not writer.write(mol):
119 sys.exit('Error: writing 3D structure of molecule %s failed' % mol_id)
120
121 except Exception as e:
122 sys.exit('Error: 3D structure generation or output for molecule %s failed: %s' % (mol_id, str(e)))
123
124 i += 1
125
126 except Exception as e: # handle exception raised in case of severe read errors
127 sys.exit('Error: reading molecule failed: ' + str(e))
128
129 writer.close()
130 sys.exit(0)
131
132if __name__ == '__main__':
133 main()