1 #!/bin/env python 2 # 3 # File: OpenFEGenerateLigandNetwork.py 4 # Author: Manish Sud <msud@san.rr.com> 5 # 6 # Copyright (C) 2026 Manish Sud. All rights reserved. 7 # 8 # The functionality available in this script is implemented using OpenFE, an 9 # open source package for alchemical free energy calculations. 10 # 11 # This file is part of MayaChemTools. 12 # 13 # MayaChemTools is free software; you can redistribute it and/or modify it under 14 # the terms of the GNU Lesser General Public License as published by the Free 15 # Software Foundation; either version 3 of the License, or (at your option) any 16 # later version. 17 # 18 # MayaChemTools is distributed in the hope that it will be useful, but without 19 # any warranty; without even the implied warranty of merchantability of fitness 20 # for a particular purpose. See the GNU Lesser General Public License for more 21 # details. 22 # 23 # You should have received a copy of the GNU Lesser General Public License 24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or 25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, 26 # Boston, MA, 02111-1307, USA. 27 # 28 29 from __future__ import print_function 30 31 import os 32 import sys 33 import time 34 import re 35 import logging 36 37 # OpenFE imports... 38 try: 39 import openfe 40 except ImportError as ErrMsg: 41 sys.stderr.write("\nFailed to import OpenFE related module/package: %s\n" % ErrMsg) 42 sys.stderr.write("Check/update your OpenFE environment and try again.\n\n") 43 sys.exit(1) 44 45 # RDKit imports... 46 try: 47 from rdkit import rdBase 48 except ImportError as ErrMsg: 49 sys.stderr.write("\nFailed to import RDKit module/package: %s\n" % ErrMsg) 50 sys.stderr.write("Check/update your RDKit environment and try again.\n\n") 51 sys.exit(1) 52 53 # MayaChemTools imports... 54 sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python")) 55 try: 56 from docopt import docopt 57 import MiscUtil 58 import OpenFEUtil 59 except ImportError as ErrMsg: 60 sys.stderr.write("\nFailed to import MayaChemTools module/package: %s\n" % ErrMsg) 61 sys.stderr.write("Check/update your MayaChemTools environment and try again.\n\n") 62 sys.exit(1) 63 64 ScriptName = os.path.basename(sys.argv[0]) 65 Options = {} 66 OptionsInfo = {} 67 68 69 def main(): 70 """Start execution of the script.""" 71 72 MiscUtil.PrintInfo( 73 "\n%s (OpenFE v%s; OpenMM v%s; RDKit v%s; MayaChemTools v%s; %s): Starting...\n" 74 % ( 75 ScriptName, 76 openfe.version("openfe"), 77 openfe.version("openmm"), 78 rdBase.rdkitVersion, 79 MiscUtil.GetMayaChemToolsVersion(), 80 time.asctime(), 81 ) 82 ) 83 84 (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime() 85 86 # Retrieve command line arguments and options... 87 RetrieveOptions() 88 89 # Process and validate command line arguments and options... 90 ProcessOptions() 91 92 # Perform actions required by the script... 93 GenerateLigandNetwork() 94 95 MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName) 96 MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime)) 97 98 99 def GenerateLigandNetwork(): 100 """Generate ligand network for molecules and write them out.""" 101 102 # Process ligand molecules... 103 Mols = ProcessLigandMolecules() 104 105 # Validate central ligand name for radial network... 106 ValidateRadialCentralLigandName(Mols) 107 108 # Initialize atom mappers... 109 Mappers = InitializeAtomMappers() 110 111 # Initialize atom scorer... 112 MapperScorer = InitializeAtomMapperScorer() 113 114 # Generate network... 115 GenerateNetwork(Mols, Mappers, MapperScorer) 116 117 118 def GenerateNetwork(Mols, Mappers, MapperScorer): 119 """Generate network and write it out.""" 120 121 NetworkName = OptionsInfo["Network"] 122 NetworkParams = OptionsInfo["NetworkParams"] 123 124 MiscUtil.PrintInfo("\nChanging directory to %s..." % OptionsInfo["OutfileDir"]) 125 os.chdir(OptionsInfo["OutfileDirPath"]) 126 127 MiscUtil.PrintInfo("\nGenerating ligand network (%s)..." % NetworkName) 128 129 LigandNetwork = OpenFEUtil.GenerateLigandNetwork(Mols, NetworkName, NetworkParams, Mappers, MapperScorer) 130 131 # Write out ligand network graphml and image files... 132 WriteLigandNetworkOutputFiles(LigandNetwork, NetworkName) 133 134 # Write out image files for edges... 135 WriteLigandNetworkEdgesOutputFiles(LigandNetwork, NetworkName) 136 137 138 def WriteLigandNetworkOutputFiles(LigandNetwork, NetworkName): 139 """Write ligand network output files.""" 140 141 GraphMLOutfile, ImageOutfile = SetupLigandNetworkOutputFilePaths(NetworkName) 142 143 # Write graphml file... 144 MiscUtil.PrintInfo("Writing %s..." % GraphMLOutfile) 145 OpenFEUtil.WriteLigandNetworkGraphMLFile(LigandNetwork, GraphMLOutfile) 146 147 # Write image file... 148 MiscUtil.PrintInfo("Writing %s..." % ImageOutfile) 149 OpenFEUtil.WriteLigandNetworkImageFile(LigandNetwork, ImageOutfile) 150 151 152 def WriteLigandNetworkEdgesOutputFiles(LigandNetwork, NetworkName): 153 """Write ligand network edges output files.""" 154 155 if not OptionsInfo["NetworkParams"]["OutputEdges"]: 156 return 157 158 NetworkEdges = [Edge for Edge in LigandNetwork.edges] 159 160 if len(NetworkEdges): 161 MiscUtil.PrintInfo( 162 "Writing %s edge output files <MolName1>_To_<MolName2>_*.png to %s subdirectory..." 163 % (len(NetworkEdges), OptionsInfo["EdgesOutfileDir"]) 164 ) 165 166 for Edge in NetworkEdges: 167 EdgeOutfile = SetupLigandNetworkEdgeOutputFilePath(Edge, NetworkName) 168 OpenFEUtil.WriteMappingImageFile(Edge, EdgeOutfile) 169 170 171 def SetupLigandNetworkOutputFilePaths(NetworkName): 172 """Setup ligand network output file paths.""" 173 174 NetworkOutfilePrefix = "%s_Network_%s_Mapper_%s" % (OptionsInfo["OutfilePrefix"], NetworkName, SetupMapperLabel()) 175 176 GraphMLOutfile = "%s.graphml" % NetworkOutfilePrefix 177 ImageOutfile = "%s.%s" % (NetworkOutfilePrefix, OptionsInfo["NetworkParams"]["OutputNetworkFormat"]) 178 179 return (GraphMLOutfile, ImageOutfile) 180 181 182 def SetupLigandNetworkEdgeOutputFilePath(Edge, NetworkName): 183 """Setup ligand network edge outfile file path.""" 184 185 EdgeOutfile = "%s_To_%s_Network_%s_Mapper_%s.png" % ( 186 Edge.componentA.name, 187 Edge.componentB.name, 188 NetworkName, 189 SetupMapperLabel(), 190 ) 191 EdgeOutfile = re.sub(" ", "_", EdgeOutfile) 192 193 EdgeOutfilePath = os.path.join(OptionsInfo["EdgesOutfileDir"], EdgeOutfile) 194 195 return EdgeOutfilePath 196 197 198 def SetupMapperLabel(): 199 """Setup mapper label.""" 200 201 return "_".join(OptionsInfo["MapperList"]) 202 203 204 def InitializeAtomMappers(): 205 """Initialize atom mappers..""" 206 207 MiscUtil.PrintInfo("\nInitializing atom mappers (%s)..." % " ".join(OptionsInfo["MapperList"])) 208 Mappers = OpenFEUtil.InitializeAtomMappers(OptionsInfo["MapperList"], OptionsInfo["MapperParams"]) 209 210 return Mappers 211 212 213 def InitializeAtomMapperScorer(): 214 """Initialize atom mapper scorer.""" 215 216 MiscUtil.PrintInfo("\nInitializing atom mapper scorer (%s)..." % OptionsInfo["MapperScorer"]) 217 MapperScorer = OpenFEUtil.InitializeAtomMapperScorer(OptionsInfo["MapperScorer"]) 218 219 return MapperScorer 220 221 222 def ProcessLigandMolecules(): 223 """Process ligand molecules.""" 224 225 MiscUtil.PrintInfo("\nProcessing file %s..." % OptionsInfo["Infile"]) 226 Mols, MolCount, ValidMolCount = OpenFEUtil.ReadAndValidateMolecules( 227 OptionsInfo["InfilePath"], **OptionsInfo["InfileParams"] 228 ) 229 230 MiscUtil.PrintInfo("\nTotal number of molecules: %d" % MolCount) 231 MiscUtil.PrintInfo("Number of valid molecules: %d" % ValidMolCount) 232 MiscUtil.PrintInfo("Number of ignored molecules: %d" % (MolCount - ValidMolCount)) 233 234 if ValidMolCount == 0: 235 MiscUtil.PrintInfo("") 236 MiscUtil.PrintError("No valid ligand molecules found in input file.\n") 237 238 return Mols 239 240 241 def ValidateRadialCentralLigandName(Mols): 242 """Validate central ligand name for radial network.""" 243 244 if not OptionsInfo["RadialNetworkStatus"]: 245 return 246 247 if not OpenFEUtil.IsMolNamePresent(Mols, OptionsInfo["NetworkParams"]["RadialCentralLigand"]): 248 MiscUtil.PrintError( 249 'The value specified, %s, for parameter name, radialCentralLigand, using option "-n, --networkParams" is not valid. Failed to find the specified molecule name in input file.' 250 % (OptionsInfo["NetworkParams"]["RadialCentralLigand"]) 251 ) 252 253 if OpenFEUtil.IsMolNamePresentMultipleTimes(Mols, OptionsInfo["NetworkParams"]["RadialCentralLigand"]): 254 MiscUtil.PrintError( 255 'The value specified, %s, for parameter name, radialCentralLigand, using option "-n, --networkParams" is not valid. Found multiple occurrences of the specified molecule name in input file.' 256 % (OptionsInfo["NetworkParams"]["RadialCentralLigand"]) 257 ) 258 259 260 def ProcessOutfilePrefixOption(): 261 """Process outfile prefix option.""" 262 263 OutfilePrefix = Options["--outfilePrefix"] 264 265 if re.match("^auto$", OutfilePrefix, re.I): 266 OutfilePrefix = OptionsInfo["InfileRoot"] 267 268 OptionsInfo["OutfilePrefix"] = OutfilePrefix 269 270 271 def ProcessOutfileDirOption(): 272 """Process outfile directory Option.""" 273 274 OutfileDir = Options["--outfileDir"] 275 OutfileDirPath = os.path.abspath(OutfileDir) 276 277 if not os.path.exists(OutfileDir): 278 MiscUtil.PrintInfo("\nCreating output directory %s..." % (OutfileDir)) 279 os.mkdir(OutfileDirPath) 280 281 OptionsInfo["OutfileDir"] = OutfileDir 282 OptionsInfo["OutfileDirPath"] = OutfileDirPath 283 284 # Setup edges output directory... 285 EdgesOutfileDir = "EdgeImages" 286 EdgesOutfileDirPath = os.path.join(OptionsInfo["OutfileDirPath"], EdgesOutfileDir) 287 if OptionsInfo["NetworkParams"]["OutputEdges"]: 288 if not os.path.exists(EdgesOutfileDirPath): 289 os.mkdir(EdgesOutfileDirPath) 290 291 OptionsInfo["EdgesOutfileDir"] = EdgesOutfileDir 292 OptionsInfo["EdgesOutfileDirPath"] = EdgesOutfileDirPath 293 294 295 def ConfigureLogging(): 296 """Configure logging.""" 297 298 OptionsInfo["LoggingLevel"] = Options["--loggingLevel"] 299 300 if re.match("^Warning$", OptionsInfo["LoggingLevel"], re.I): 301 LoggingLevel = logging.WARNING 302 else: 303 LoggingLevel = logging.INFO 304 305 logging.basicConfig(format="%(levelname)s: %(message)s", level=LoggingLevel) 306 307 308 def ProcessOptions(): 309 """Process and validate command line arguments and options.""" 310 311 MiscUtil.PrintInfo("Processing options...") 312 313 # Validate options... 314 ValidateOptions() 315 316 # Configure logging... 317 ConfigureLogging() 318 319 OptionsInfo["Infile"] = Options["--infile"] 320 OptionsInfo["InfilePath"] = os.path.abspath(OptionsInfo["Infile"]) 321 322 FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["Infile"]) 323 OptionsInfo["InfileRoot"] = FileName 324 325 OptionsInfo["LoggingLevel"] = Options["--loggingLevel"] 326 327 ParamsDefaultInfoOverride = {"RemoveHydrogens": False} 328 OptionsInfo["InfileParams"] = MiscUtil.ProcessOptionInfileParameters( 329 "--infileParams", 330 Options["--infileParams"], 331 InfileName=Options["--infile"], 332 ParamsDefaultInfo=ParamsDefaultInfoOverride, 333 ) 334 335 OptionsInfo["MapperList"] = OpenFEUtil.ProcessOptionOpenFEMapper("-m, --mapper", Options["--mapper"]) 336 OptionsInfo["MapperParams"] = OpenFEUtil.ProcessOptionOpenFEMapperParameters( 337 "-m, --mapperParams", Options["--mapperParams"] 338 ) 339 OptionsInfo["MapperScorer"] = Options["--mapperScorer"] 340 341 OptionsInfo["Network"] = OpenFEUtil.ProcessOptionOpenFENetwork("-n, --network", Options["--network"]) 342 OptionsInfo["RadialNetworkStatus"] = True if re.match("^Radial$", OptionsInfo["Network"], re.I) else False 343 OptionsInfo["NetworkParams"] = OpenFEUtil.ProcessOptionOpenFENetworkParameters( 344 "--networkParams", Options["--networkParams"], RadialNetworkStatus=OptionsInfo["RadialNetworkStatus"] 345 ) 346 347 ProcessOutfilePrefixOption() 348 ProcessOutfileDirOption() 349 350 OptionsInfo["Overwrite"] = Options["--overwrite"] 351 352 # Track top level working directory... 353 OptionsInfo["TopWorkingDir"] = os.getcwd() 354 355 356 def RetrieveOptions(): 357 """Retrieve command line arguments and options.""" 358 359 # Get options... 360 global Options 361 Options = docopt(_docoptUsage_) 362 363 # Set current working directory to the specified directory... 364 WorkingDir = Options["--workingdir"] 365 if WorkingDir: 366 os.chdir(WorkingDir) 367 368 # Handle examples option... 369 if "--examples" in Options and Options["--examples"]: 370 MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_)) 371 sys.exit(0) 372 373 374 def ValidateOptions(): 375 """Validate option values.""" 376 377 MiscUtil.ValidateOptionFilePath("-i, --infile", Options["--infile"]) 378 MiscUtil.ValidateOptionFileExt("-i, --infile", Options["--infile"], "sdf sd") 379 380 MiscUtil.ValidateOptionDirPath("-o, --outfileDir", Options["--outfileDir"]) 381 MiscUtil.ValidateOptionsOutputDirOverwrite( 382 "-o, --outfileDir", Options["--outfileDir"], "--overwrite", Options["--overwrite"] 383 ) 384 385 MiscUtil.ValidateOptionTextValue(" --loggingLevel", Options["--loggingLevel"], "Info Warning") 386 387 for Mapper in Options["--mapper"].split(","): 388 Mapper = Mapper.strip() 389 MiscUtil.ValidateOptionTextValue("-m, --mapper", Mapper, "LOMAP Kartograf") 390 391 MiscUtil.ValidateOptionTextValue("--mapperScorer", Options["--mapperScorer"], "LOMAP") 392 393 MiscUtil.ValidateOptionTextValue("-n, --network", Options["--network"], "LOMAP MinimalSpanning Radial") 394 395 396 # Setup a usage string for docopt... 397 _docoptUsage_ = """ 398 OpenFEGenerateLigandNetwork.py - Generate ligand network 399 400 Usage: 401 OpenFEGenerateLigandNetwork.py [--infileParams <Name,Value,...>] [--loggingLevel <Info or Warning>] 402 [--mapper <mapper1, mapper2,...>] [--mapperParams <Name,Value,..>] [--mapperScorer <LOMAP>] 403 [--network <text>] [--networkParams <Name,Value,..>] [--outfilePrefix <text>] 404 [--overwrite] [-w <dir>] -i <infile> -o <outifiledir> 405 OpenFEGenerateLigandNetwork.py -h | --help | -e | --examples 406 407 Description: 408 Generate a ligand network for molecules in an input file and write it out 409 as graphml and image files under the output directory. You may optionally 410 generate image files for all edges in a ligand network. 411 412 You must specify a valid input file containing 3D coordinates for all 413 molecules. In addition, the hydrogens must be present for all molecules 414 in the input file. 415 416 The supported input file format is: SD (.sdf, .sd) 417 418 The supported output file formats are: GraphML (.graphml), SVG (.svg), 419 PNG (.png), etc. 420 421 Possible output directories: 422 423 <OutfileDir> 424 <OutfileDir>/Edges 425 426 Possible outfile prefixe: 427 428 <OutfilePrefix> or <InfileRoot> 429 430 Possible output files: 431 432 <OutfilePrefix>_Network_<NetworkName>_Mapper_<MapperNames>.graphml 433 <OutfilePrefix>_Network_<NetworkName>_Mapper_<MapperNames>.<ImgExt> 434 435 Edges: 436 437 <MolName1>_To_<MolName2>_<NetworkName>_Mapper_<MapperNames>.png 438 ... ... ... 439 440 Options: 441 -e, --examples 442 Print examples. 443 -h, --help 444 Print this help message. 445 -i, --infile <infile> 446 Input file name. 447 --infileParams <Name,Value,...> [default: auto] 448 A comma delimited list of parameter name and value pairs for reading 449 molecules from files. The supported parameter names for different file 450 formats, along with their default values, are shown below: 451 452 SD: removeHydrogens,no,sanitize,yes,strictParsing,yes 453 454 --loggingLevel <Info or Warning> [default: Warning] 455 Logging level to configure the 'root logger' via logging.basicConfig() 456 function. The default logging level is changed from 'logging.INFO' to 457 'logging.WARNING'. Otherwise, OpenFE and its associated modules 458 may generate a lot of informational messages. 459 -m, --mapper <mapper1, mapper2> [default: LOMAP] 460 A comma delimited names of atom mappers to use for generating a ligand 461 network. Possible values: LOMAP [ Lead Optimization MAPer; Ref 176 ] or 462 Kartograf [ Ref 177 ]. You may specify multiple mappers for generating 463 mapping between two molecules. All specified mappers are employed to 464 identify the highest scoring edges for generating a ligand network. 465 --mapperParams <Name,Value,..> [default: auto] 466 A comma delimited list of parameter name and value pairs for atom 467 mappers used during the generation of a ligand network. 468 469 The supported parameter names along with their default values are 470 are shown below: 471 472 lomapTime, 20, [ Units: seconds ] 473 lomapThreeD, yes [ Possible values: yes or no ] 474 lomapMax3D, 1.0 [ Units: Angstrom ] 475 lomapElementChange, yes [ Possible values: yes or no] 476 lomapSeed, None [ Possible value: A string. An empty string causes 477 MCS search to start from scratch ] 478 lomapShift, no [ Possible values: yes or no] 479 480 kartografAtomMaxDistance, 0.95 [ Units: Angstrom ] 481 kartografAtomMapHydrogens, yes [ Possible values: yes or no ] 482 kartografMapHydrogensOnHydrogensOnly, No [ Possible values: yes or 483 no ] 484 kartografMapExactRingMatchesOnly, yes [ Possible values: yes or no ] 485 kartografAllowPartialFusedRings, yes [ Possible values: yes or no ] 486 487 A brief description of parameters is provided below: 488 489 lomapTime: Time out for MCS algorithm. 490 lomapThreeD: Use atom positions to prune symmetric mappings. 491 lomapMax3D: Forbid mapping between atoms with distance more than 492 specified value. 493 lomapElementChange: Allow mappings that change an atom element. 494 lomapSeed: An Empty SMARTS string causes MCS search to start from 495 scratch. 496 lomapShift: Keep pre-aligned atom positions for 3D position checks. 497 498 kartografAtomMaxDistance: Geometric criteria for two atoms 499 corresponding to maximum distance between them. 500 kartografAtomMapHydrogens: Map hydrogens. 501 kartografMapHydrogensOnHydrogensOnly: Map hydrogens only on 502 hydrogens. 503 kartografMapExactRingMatchesOnly: Map rings with only matching ring 504 size and bond orders. In addition, ring breaking is not 505 permitted. 506 kartografAllowPartialFusedRings: Allow mapping of partially fused 507 rings. 508 509 --mapperScorer <LOMAP> [default: LOMAP] 510 Atom mapper scorer to use for scoring edge mappings during generation 511 of a ligand network. Possible value: LOMAP. The atom scorer is not used 512 during the generation of MinimalSpanning network. 513 -n, --network <text> [default: MinimalSpanning] 514 Name of a ligand network to generate. Possible values: LOMAP, 515 MinimalSpanning or Radial. 516 --networkParams <Name,Value,..> [default: auto] 517 A comma delimited list of parameter name and value pairs for generating 518 a ligand network. 519 520 The supported parameter names along with their default values are 521 are shown below: 522 523 lomapDistanceCutoff, 0.4 524 lomapMaxPathLength, 6 525 lomapRequireCycleCovering, yes [ Possible values: yes or no ] 526 527 minimalSpanningProgress, no [ Possible values: yes or no ] 528 529 radialCentralLigand, None [ Possible values: Valid ligand name ] 530 531 outputEdges, no [ Possible values: yes or no ] 532 outputNetworkFormat, svg [ Possible values: Any valid format. ] 533 534 A brief description of parameters is provided below: 535 536 lomapDistanceCutoff: Maximum distance/dissimilarity between two 537 molecules for an edge to be accepted. 538 lomapMaxPathLength: Maximum distance between any two molecules in 539 the resulting network 540 lomapRequireCycleCovering: Add cycles into the network 541 542 minimalSpanningProgress: Show progress using tqdm. 543 544 radialCentralLigand: Name of central ligand. A valid ligand name 545 must be specified to generate a radial ligand network. 546 547 outputEdges: Generate PNG image files for all edges in a ligand 548 network. 549 outputNetworkFormat: Valid image file format for ligand network. 550 You must specify a valid format supported by Python module 551 Matplotlib. For example: PNG (.png), SVG (.svg), PDF (.pdf), 552 etc. In addition, the graphml file is always generated. 553 554 -o, --outfileDir <outfiledir> 555 Output directory. 556 --outfilePrefix <text> [default: auto] 557 Prefix for generating output files under output directory. 558 --overwrite 559 Overwrite existing files. 560 -w, --workingdir <dir> 561 Location of working directory which defaults to the current directory. 562 563 Examples: 564 To generate a minimal spanning ligand network for molecules in a SD file with 565 3D structures, employing LOMAP atom mapper to map egdes, and write out 566 network GraphML, SVG and edge image files to output directory, type: 567 568 % OpenFEGenerateLigandNetwork.py -i SampleTyk2Ligands.sdf 569 -o SampleTyk2LigandsMSTNetwork 570 571 To run the first example along with generating PNG image files for all edges, 572 type: 573 574 % OpenFEGenerateLigandNetwork.py -i SampleTyk2Ligands.sdf 575 -o SampleTyk2LigandsMSTNetwork --networkParams "outputEdges, yes" 576 577 To run the first example employing Kartograf atom mapper to map edges, 578 and write out various output files under to directory, type: 579 580 % OpenFEGenerateLigandNetwork.py -i SampleTyk2Ligands.sdf 581 -o SampleTyk2LigandsMSTNetwork -m Kartograf 582 583 To run the first example for generating a radial ligand network centered 584 around the ligand lig_ejm_31, and write out various output files to output 585 directory, type: 586 587 % OpenFEGenerateLigandNetwork.py -i SampleTyk2Ligands.sdf 588 -o SampleTyk2LigandsRadialNetwork -n Radial --networkParams 589 "RadialCentralLigand,lig_ejm_31" 590 591 To run the previous example along with generating PNG image files for all edges, 592 type: 593 594 % OpenFEGenerateLigandNetwork.py -i SampleTyk2Ligands.sdf 595 -o SampleTyk2LigandsRadialNetwork -n Radial --networkParams 596 "RadialCentralLigand,lig_ejm_31,outputEdges, yes" 597 598 To run the first example by specifying explicit values for various parameters 599 and write out various output files to output directory, type: 600 601 % OpenFEGenerateLigandNetwork.py -i SampleTyk2Ligands.sdf 602 -o SampleTyk2LigandsLOMAPNetwork 603 --loggingLevel Warning -m LOMAP --mapperParams "lomapTime, 20, 604 lomapThreeD, yes, lomapElementChange, yes, lomapElementChange, yes, 605 lomapSeed, None, lomapShift, no" -n LOMAP --networkParams 606 "lomapDistanceCutoff, 0.4, lomapMaxPathLength, 6, 607 lomapRequireCycleCovering, yes, outputEdges, yes" 608 609 Author: 610 Manish Sud(msud@san.rr.com) 611 612 See also: 613 OpenFECalculateAbsoluteHydrationFreeEnergy.py, 614 OpenFECalculateRelativeBindingFreeEnergy.py, 615 OpenFECalculateRelativeHydrationFreeEnergy.py, 616 OpenFECalculatePartialCharges.py 617 618 Copyright: 619 Copyright (C) 2026 Manish Sud. All rights reserved. 620 621 The functionality available in this script is implemented using OpenFE, an 622 open source molecuar for alchemical free energy calculations. 623 624 This file is part of MayaChemTools. 625 626 MayaChemTools is free software; you can redistribute it and/or modify it under 627 the terms of the GNU Lesser General Public License as published by the Free 628 Software Foundation; either version 3 of the License, or (at your option) any 629 later version. 630 631 """ 632 633 if __name__ == "__main__": 634 main()