5.1. Single low-energy 3D structures

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

Download source file