D4CMPP2 0.4.0__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/D4CMPP2.egg-info/PKG-INFO +45 -4
  2. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/D4CMPP2.egg-info/SOURCES.txt +18 -0
  3. d4cmpp2-1.0.0/D4CMPP2.egg-info/entry_points.txt +2 -0
  4. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/MANIFEST.in +1 -0
  5. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/PKG-INFO +45 -4
  6. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/README.md +44 -3
  7. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/__init__.py +6 -6
  8. d4cmpp2-1.0.0/__main__.py +5 -0
  9. d4cmpp2-1.0.0/_main.py +7 -0
  10. d4cmpp2-1.0.0/cli.py +7 -0
  11. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/AGENTS.md +4 -0
  12. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/README.md +22 -0
  13. d4cmpp2-1.0.0/examples/integration/README.md +34 -0
  14. d4cmpp2-1.0.0/examples/integration/common.py +93 -0
  15. d4cmpp2-1.0.0/examples/integration/run_all.py +84 -0
  16. d4cmpp2-1.0.0/examples/integration/solvent_analyzer.py +85 -0
  17. d4cmpp2-1.0.0/examples/integration/transfer_learning.py +111 -0
  18. d4cmpp2-1.0.0/exceptions.py +7 -0
  19. d4cmpp2-1.0.0/grid_search.py +7 -0
  20. d4cmpp2-1.0.0/optimize.py +7 -0
  21. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/pyproject.toml +3 -2
  22. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/Dataset/GraphDataset.py +30 -4
  23. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/Dataset/ISAGraphDataset.py +8 -2
  24. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/MolDataManager.py +49 -6
  25. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/contracts.py +10 -0
  26. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/PostProcessor.py +29 -4
  27. d4cmpp2-1.0.0/src/api/__init__.py +1 -0
  28. d4cmpp2-0.4.0/cli.py → d4cmpp2-1.0.0/src/api/command.py +1 -1
  29. d4cmpp2-0.4.0/exceptions.py → d4cmpp2-1.0.0/src/api/errors.py +1 -1
  30. d4cmpp2-0.4.0/grid_search.py → d4cmpp2-1.0.0/src/api/legacy_grid_search.py +1 -1
  31. d4cmpp2-0.4.0/optimize.py → d4cmpp2-1.0.0/src/api/optimization.py +1 -1
  32. d4cmpp2-0.4.0/_main.py → d4cmpp2-1.0.0/src/api/training.py +169 -156
  33. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/argparser.py +20 -0
  34. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/checkpointing.py +1 -1
  35. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/config_validation.py +17 -1
  36. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/data_quality.py +6 -1
  37. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/graph_cache.py +11 -3
  38. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/module_loader.py +1 -1
  39. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/run_manifest.py +1 -0
  40. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_cli_packaging.py +10 -0
  41. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_config_validation.py +10 -1
  42. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_custom_network.py +11 -3
  43. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_examples_syntax.py +4 -0
  44. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_failure_contracts.py +2 -2
  45. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_public_contracts.py +51 -10
  46. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_pyg_data_contract.py +45 -0
  47. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_scaler_alignment.py +1 -1
  48. d4cmpp2-1.0.0/tests/test_solvent_analyzer_end_to_end.py +54 -0
  49. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_dataset_contract_matrix.py +44 -0
  50. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_graph_cache_integrity.py +16 -0
  51. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_leaderboard.py +1 -1
  52. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_errors_logging.py +1 -1
  53. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t6_ci_contract.py +11 -0
  54. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t7_cycle_audit.py +1 -1
  55. d4cmpp2-0.4.0/D4CMPP2.egg-info/entry_points.txt +0 -2
  56. d4cmpp2-0.4.0/__main__.py +0 -5
  57. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/D4CMPP2.egg-info/dependency_links.txt +0 -0
  58. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/D4CMPP2.egg-info/requires.txt +0 -0
  59. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/D4CMPP2.egg-info/top_level.txt +0 -0
  60. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/LICENSE +0 -0
  61. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/AGENTS.md +0 -0
  62. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/Aqsoldb.csv +0 -0
  63. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/BradleyMP.csv +0 -0
  64. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/Lipophilicity.csv +0 -0
  65. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/README.md +0 -0
  66. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/__init__.py +0 -0
  67. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/optical.csv +0 -0
  68. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/test.csv +0 -0
  69. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/ISA/segment.py +0 -0
  70. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/assets/tiny_numeric.csv +0 -0
  71. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/cli/README.md +0 -0
  72. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/custom_network.py +0 -0
  73. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/experiments/01_compare.py +0 -0
  74. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/experiments/02_optimize.py +0 -0
  75. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/experiments/03_legacy_grid_search.py +0 -0
  76. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/extensions/01_callbacks.py +0 -0
  77. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/extensions/02_custom_network_training.py +0 -0
  78. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/extensions/03_numeric_inputs.py +0 -0
  79. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/inference/01_prediction.py +0 -0
  80. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/inference/02_csv_prediction.py +0 -0
  81. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/inference/03_uncertainty_ensemble.py +0 -0
  82. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/inference/04_isa_interpretation.py +0 -0
  83. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/01_basic_cpu.py +0 -0
  84. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/02_solvent.py +0 -0
  85. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/03_multitarget.py +0 -0
  86. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/04_splitting_reproducibility.py +0 -0
  87. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/05_isa.py +0 -0
  88. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/06_saved_model_modes.py +0 -0
  89. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/07_model_families.py +0 -0
  90. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/network_refer.yaml +0 -0
  91. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/AFP_model.py +0 -0
  92. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/AFPwithSolv_model.py +0 -0
  93. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/DMPNN_model.py +0 -0
  94. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/DMPNNwithSolv_model.py +0 -0
  95. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/GAT_model.py +0 -0
  96. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/GATwithSolv_model.py +0 -0
  97. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/GCN_model.py +0 -0
  98. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/GCNwithSolv_model.py +0 -0
  99. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/GC_model.py +0 -0
  100. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/ISATPM_model.py +0 -0
  101. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/ISATPN_model.py +0 -0
  102. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/ISAT_model.py +0 -0
  103. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/MPNN_model.py +0 -0
  104. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/MPNNwithSolv_model.py +0 -0
  105. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/__init__.py +0 -0
  106. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/base.py +0 -0
  107. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/registry.py +0 -0
  108. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/AFP.py +0 -0
  109. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/BiDropout.py +0 -0
  110. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/DMPNN.py +0 -0
  111. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/GAT.py +0 -0
  112. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/GC.py +0 -0
  113. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/GCN.py +0 -0
  114. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/ISAT.py +0 -0
  115. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/Linear.py +0 -0
  116. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/MPNN.py +0 -0
  117. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/SolventLayer.py +0 -0
  118. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/__init__.py +0 -0
  119. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/distGCN.py +0 -0
  120. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/pyg_hetero.py +0 -0
  121. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/setup.cfg +0 -0
  122. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/ISAAnalyzer.py +0 -0
  123. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/ISAPNAnalyzer.py +0 -0
  124. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/ISAwSAnalyzer.py +0 -0
  125. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/MolAnalyzer.py +0 -0
  126. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/__init__.py +0 -0
  127. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/core.py +0 -0
  128. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/factory.py +0 -0
  129. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/interpretation.py +0 -0
  130. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/results.py +0 -0
  131. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/Dataset/__init__.py +0 -0
  132. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/GraphGenerator/ISAGraphGenerator.py +0 -0
  133. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/GraphGenerator/MolGraphGenerator.py +0 -0
  134. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/GraphGenerator/__init__.py +0 -0
  135. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/ISADataManager.py +0 -0
  136. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/__init__.py +0 -0
  137. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/NetworkManager/ISANetworkManager.py +0 -0
  138. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/NetworkManager/NetworkManager.py +0 -0
  139. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/NetworkManager/__init__.py +0 -0
  140. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/TrainManager/ISATrainManager.py +0 -0
  141. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/TrainManager/TrainManager.py +0 -0
  142. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/TrainManager/__init__.py +0 -0
  143. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/TrainManager/callbacks.py +0 -0
  144. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/__init__.py +0 -0
  145. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/PATH.py +0 -0
  146. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/__init__.py +0 -0
  147. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/config_resolution.py +0 -0
  148. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/csv_validation.py +0 -0
  149. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/featureizer.py +0 -0
  150. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/functional_group.csv +0 -0
  151. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/leaderboard.py +0 -0
  152. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/metrics.py +0 -0
  153. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/output.py +0 -0
  154. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/reproducibility.py +0 -0
  155. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/scaler.py +0 -0
  156. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/sculptor.py +0 -0
  157. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/splitting.py +0 -0
  158. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/supportfile_saver.py +0 -0
  159. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/tools.py +0 -0
  160. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/transfer_learning.py +0 -0
  161. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_csv_data_manager_validation.py +0 -0
  162. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_csv_validation.py +0 -0
  163. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_data_fixture.py +0 -0
  164. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_example_model_compatibility.py +0 -0
  165. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_failure_behavior.py +0 -0
  166. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_gcn_end_to_end.py +0 -0
  167. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_graph_alignment.py +0 -0
  168. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_heavy_smoke.py +0 -0
  169. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_network_abc.py +0 -0
  170. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_network_persistence.py +0 -0
  171. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_optimize.py +0 -0
  172. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_path_utils.py +0 -0
  173. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_pyg_dmpnn_afp.py +0 -0
  174. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_pyg_gcn.py +0 -0
  175. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_pyg_isa_models.py +0 -0
  176. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_pyg_mpnn_gat.py +0 -0
  177. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_runtime_environment.py +0 -0
  178. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_state_dict_contract.py +0 -0
  179. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_checkpoint_policy.py +0 -0
  180. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_data_quality.py +0 -0
  181. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_grid_search.py +0 -0
  182. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_registry_smoke_matrix.py +0 -0
  183. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_reproducibility.py +0 -0
  184. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_run_manifest.py +0 -0
  185. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_scaffold_split.py +0 -0
  186. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_transfer_learning.py +0 -0
  187. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t4_analyzer_core.py +0 -0
  188. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_callbacks.py +0 -0
  189. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_config_resolution.py +0 -0
  190. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_import_discovery.py +0 -0
  191. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_manager_contracts.py +0 -0
  192. {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_verbose_output.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: D4CMPP2
3
- Version: 0.4.0
3
+ Version: 1.0.0
4
4
  Summary: PyTorch Geometric molecular property prediction models
5
5
  License-Expression: MIT
6
6
  Requires-Python: <3.13,>=3.10
@@ -25,9 +25,24 @@ Dynamic: license-file
25
25
 
26
26
  # D4CMPP2
27
27
 
28
- D4CMPP2 is a PyTorch Geometric package for molecular-property regression. It
29
- supports ordinary molecular graphs, compound/solvent pairs, and interpretable
30
- ISA models through one training and inference API.
28
+ D4CMPP2 is the next-generation implementation of the D4CMPP framework. It is based on the original [D4CMPP](https://github.com/ACCA-KU/DeepMPP) project and was extensively redeveloped with OpenAI Codex through an AI-assisted, test-driven engineering workflow.
29
+
30
+ The package provides a unified PyTorch Geometric framework for molecular property prediction, supporting ordinary molecular graphs, compound–solvent pairs, and interpretable ISA models.
31
+
32
+ Key advantages of D4CMPP2 include:
33
+
34
+ - **Unified model interface** — Train general molecular, solvent-aware, and ISA-based models through a consistent Python API and command-line interface.
35
+ - **Multiple graph neural network architectures** — Use GCN, MPNN, DMPNN, AttentiveFP, GAT, graph-contribution, and ISA model families within the same workflow.
36
+ - **Interpretable molecular predictions** — Analyze fragment- and atom-level contributions with ISA models while preserving alignment between molecular structures and attribution scores.
37
+ - **Reliable data handling** — Detect invalid SMILES, missing columns, non-numeric targets, misaligned inputs, incompatible graph caches, and invalid dataset splits before they silently affect training.
38
+ - **Efficient repeated experiments** — Reuse fingerprinted graph caches and optionally skip previously completed data-quality and per-graph cache checks.
39
+ - **Transfer learning and training resumption** — Initialize compatible model parameters from existing models or resume complete optimizer and scheduler states from checkpoints.
40
+ - **Reproducible experimentation** — Control random seeds, deterministic execution, dataset splitting, and run metadata across CPU and CUDA environments.
41
+ - **Multi-target and multi-input support** — Train on multiple target properties, compound–solvent pairs, and additional numeric features without changing the overall workflow.
42
+ - **Saved-model analysis** — Reload trained models through `Analyzer` for single or batch prediction while retaining invalid and duplicate input rows.
43
+ - **Experiment tracking and optimization** — Record run manifests, compare completed experiments, and perform grid or Bayesian hyperparameter optimization.
44
+ - **Backward compatibility** — Preserve established D4CMPP APIs, model assets, configuration conventions, and legacy loading paths where practical.
45
+ - **Deployment-oriented validation** — Test source execution, packaged distributions, CLI entry points, model persistence, Analyzer workflows, and CPU-based end-to-end training.
31
46
 
32
47
  ## Requirements and installation
33
48
 
@@ -240,6 +255,32 @@ The cache policies are:
240
255
 
241
256
  DGL caches are preserved but never loaded.
242
257
 
258
+ Data preparation reports when CSV validation and graph-cache loading start and
259
+ finish, so a large cache no longer looks stalled before graph generation. Full
260
+ per-graph tensor validation remains the default. After a cache has already been
261
+ verified and the same data is trained repeatedly, it can be skipped explicitly:
262
+
263
+ ```python
264
+ train(
265
+ data="data.csv",
266
+ target=["target"],
267
+ network="GCN",
268
+ data_quality_report=False,
269
+ validate_graph_cache=False,
270
+ )
271
+ ```
272
+
273
+ `data_quality_report=False` skips the slower canonical-SMILES duplicate,
274
+ split-overlap, and issue report after that dataset has already been reviewed.
275
+ Required CSV columns, numeric values, split labels, row alignment, and nonempty
276
+ targets are still checked. `validate_graph_cache=False` still checks the cache
277
+ recipe, ordered SMILES, and graph count; it only skips tensor shape, dtype,
278
+ finite-value, and edge-alignment checks inside each cached graph. Newly generated
279
+ graphs are always validated before saving.
280
+
281
+ The CLI equivalents are `--skip-data-quality-report` and
282
+ `--skip-graph-cache-validation`.
283
+
243
284
  ## Prediction and analysis
244
285
 
245
286
  ```python
@@ -84,6 +84,12 @@ pyproject.toml
84
84
  ./src/TrainManager/TrainManager.py
85
85
  ./src/TrainManager/__init__.py
86
86
  ./src/TrainManager/callbacks.py
87
+ ./src/api/__init__.py
88
+ ./src/api/command.py
89
+ ./src/api/errors.py
90
+ ./src/api/legacy_grid_search.py
91
+ ./src/api/optimization.py
92
+ ./src/api/training.py
87
93
  ./src/utils/PATH.py
88
94
  ./src/utils/__init__.py
89
95
  ./src/utils/argparser.py
@@ -137,6 +143,11 @@ examples/inference/01_prediction.py
137
143
  examples/inference/02_csv_prediction.py
138
144
  examples/inference/03_uncertainty_ensemble.py
139
145
  examples/inference/04_isa_interpretation.py
146
+ examples/integration/README.md
147
+ examples/integration/common.py
148
+ examples/integration/run_all.py
149
+ examples/integration/solvent_analyzer.py
150
+ examples/integration/transfer_learning.py
140
151
  examples/training/01_basic_cpu.py
141
152
  examples/training/02_solvent.py
142
153
  examples/training/03_multitarget.py
@@ -202,6 +213,12 @@ src/TrainManager/ISATrainManager.py
202
213
  src/TrainManager/TrainManager.py
203
214
  src/TrainManager/__init__.py
204
215
  src/TrainManager/callbacks.py
216
+ src/api/__init__.py
217
+ src/api/command.py
218
+ src/api/errors.py
219
+ src/api/legacy_grid_search.py
220
+ src/api/optimization.py
221
+ src/api/training.py
205
222
  src/utils/PATH.py
206
223
  src/utils/__init__.py
207
224
  src/utils/argparser.py
@@ -250,6 +267,7 @@ tests/test_pyg_isa_models.py
250
267
  tests/test_pyg_mpnn_gat.py
251
268
  tests/test_runtime_environment.py
252
269
  tests/test_scaler_alignment.py
270
+ tests/test_solvent_analyzer_end_to_end.py
253
271
  tests/test_state_dict_contract.py
254
272
  tests/test_t3_checkpoint_policy.py
255
273
  tests/test_t3_data_quality.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ d4cmpp2 = D4CMPP2.src.api.command:main
@@ -8,3 +8,4 @@ recursive-include examples/inference *.py
8
8
  recursive-include examples/experiments *.py
9
9
  recursive-include examples/extensions *.py
10
10
  recursive-include examples/cli *.md
11
+ recursive-include examples/integration *.py *.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: D4CMPP2
3
- Version: 0.4.0
3
+ Version: 1.0.0
4
4
  Summary: PyTorch Geometric molecular property prediction models
5
5
  License-Expression: MIT
6
6
  Requires-Python: <3.13,>=3.10
@@ -25,9 +25,24 @@ Dynamic: license-file
25
25
 
26
26
  # D4CMPP2
27
27
 
28
- D4CMPP2 is a PyTorch Geometric package for molecular-property regression. It
29
- supports ordinary molecular graphs, compound/solvent pairs, and interpretable
30
- ISA models through one training and inference API.
28
+ D4CMPP2 is the next-generation implementation of the D4CMPP framework. It is based on the original [D4CMPP](https://github.com/ACCA-KU/DeepMPP) project and was extensively redeveloped with OpenAI Codex through an AI-assisted, test-driven engineering workflow.
29
+
30
+ The package provides a unified PyTorch Geometric framework for molecular property prediction, supporting ordinary molecular graphs, compound–solvent pairs, and interpretable ISA models.
31
+
32
+ Key advantages of D4CMPP2 include:
33
+
34
+ - **Unified model interface** — Train general molecular, solvent-aware, and ISA-based models through a consistent Python API and command-line interface.
35
+ - **Multiple graph neural network architectures** — Use GCN, MPNN, DMPNN, AttentiveFP, GAT, graph-contribution, and ISA model families within the same workflow.
36
+ - **Interpretable molecular predictions** — Analyze fragment- and atom-level contributions with ISA models while preserving alignment between molecular structures and attribution scores.
37
+ - **Reliable data handling** — Detect invalid SMILES, missing columns, non-numeric targets, misaligned inputs, incompatible graph caches, and invalid dataset splits before they silently affect training.
38
+ - **Efficient repeated experiments** — Reuse fingerprinted graph caches and optionally skip previously completed data-quality and per-graph cache checks.
39
+ - **Transfer learning and training resumption** — Initialize compatible model parameters from existing models or resume complete optimizer and scheduler states from checkpoints.
40
+ - **Reproducible experimentation** — Control random seeds, deterministic execution, dataset splitting, and run metadata across CPU and CUDA environments.
41
+ - **Multi-target and multi-input support** — Train on multiple target properties, compound–solvent pairs, and additional numeric features without changing the overall workflow.
42
+ - **Saved-model analysis** — Reload trained models through `Analyzer` for single or batch prediction while retaining invalid and duplicate input rows.
43
+ - **Experiment tracking and optimization** — Record run manifests, compare completed experiments, and perform grid or Bayesian hyperparameter optimization.
44
+ - **Backward compatibility** — Preserve established D4CMPP APIs, model assets, configuration conventions, and legacy loading paths where practical.
45
+ - **Deployment-oriented validation** — Test source execution, packaged distributions, CLI entry points, model persistence, Analyzer workflows, and CPU-based end-to-end training.
31
46
 
32
47
  ## Requirements and installation
33
48
 
@@ -240,6 +255,32 @@ The cache policies are:
240
255
 
241
256
  DGL caches are preserved but never loaded.
242
257
 
258
+ Data preparation reports when CSV validation and graph-cache loading start and
259
+ finish, so a large cache no longer looks stalled before graph generation. Full
260
+ per-graph tensor validation remains the default. After a cache has already been
261
+ verified and the same data is trained repeatedly, it can be skipped explicitly:
262
+
263
+ ```python
264
+ train(
265
+ data="data.csv",
266
+ target=["target"],
267
+ network="GCN",
268
+ data_quality_report=False,
269
+ validate_graph_cache=False,
270
+ )
271
+ ```
272
+
273
+ `data_quality_report=False` skips the slower canonical-SMILES duplicate,
274
+ split-overlap, and issue report after that dataset has already been reviewed.
275
+ Required CSV columns, numeric values, split labels, row alignment, and nonempty
276
+ targets are still checked. `validate_graph_cache=False` still checks the cache
277
+ recipe, ordered SMILES, and graph count; it only skips tensor shape, dtype,
278
+ finite-value, and edge-alignment checks inside each cached graph. Newly generated
279
+ graphs are always validated before saving.
280
+
281
+ The CLI equivalents are `--skip-data-quality-report` and
282
+ `--skip-graph-cache-validation`.
283
+
243
284
  ## Prediction and analysis
244
285
 
245
286
  ```python
@@ -1,8 +1,23 @@
1
1
  # D4CMPP2
2
2
 
3
- D4CMPP2 is a PyTorch Geometric package for molecular-property regression. It
4
- supports ordinary molecular graphs, compound/solvent pairs, and interpretable
5
- ISA models through one training and inference API.
3
+ D4CMPP2 is the next-generation implementation of the D4CMPP framework. It is based on the original [D4CMPP](https://github.com/ACCA-KU/DeepMPP) project and was extensively redeveloped with OpenAI Codex through an AI-assisted, test-driven engineering workflow.
4
+
5
+ The package provides a unified PyTorch Geometric framework for molecular property prediction, supporting ordinary molecular graphs, compound–solvent pairs, and interpretable ISA models.
6
+
7
+ Key advantages of D4CMPP2 include:
8
+
9
+ - **Unified model interface** — Train general molecular, solvent-aware, and ISA-based models through a consistent Python API and command-line interface.
10
+ - **Multiple graph neural network architectures** — Use GCN, MPNN, DMPNN, AttentiveFP, GAT, graph-contribution, and ISA model families within the same workflow.
11
+ - **Interpretable molecular predictions** — Analyze fragment- and atom-level contributions with ISA models while preserving alignment between molecular structures and attribution scores.
12
+ - **Reliable data handling** — Detect invalid SMILES, missing columns, non-numeric targets, misaligned inputs, incompatible graph caches, and invalid dataset splits before they silently affect training.
13
+ - **Efficient repeated experiments** — Reuse fingerprinted graph caches and optionally skip previously completed data-quality and per-graph cache checks.
14
+ - **Transfer learning and training resumption** — Initialize compatible model parameters from existing models or resume complete optimizer and scheduler states from checkpoints.
15
+ - **Reproducible experimentation** — Control random seeds, deterministic execution, dataset splitting, and run metadata across CPU and CUDA environments.
16
+ - **Multi-target and multi-input support** — Train on multiple target properties, compound–solvent pairs, and additional numeric features without changing the overall workflow.
17
+ - **Saved-model analysis** — Reload trained models through `Analyzer` for single or batch prediction while retaining invalid and duplicate input rows.
18
+ - **Experiment tracking and optimization** — Record run manifests, compare completed experiments, and perform grid or Bayesian hyperparameter optimization.
19
+ - **Backward compatibility** — Preserve established D4CMPP APIs, model assets, configuration conventions, and legacy loading paths where practical.
20
+ - **Deployment-oriented validation** — Test source execution, packaged distributions, CLI entry points, model persistence, Analyzer workflows, and CPU-based end-to-end training.
6
21
 
7
22
  ## Requirements and installation
8
23
 
@@ -215,6 +230,32 @@ The cache policies are:
215
230
 
216
231
  DGL caches are preserved but never loaded.
217
232
 
233
+ Data preparation reports when CSV validation and graph-cache loading start and
234
+ finish, so a large cache no longer looks stalled before graph generation. Full
235
+ per-graph tensor validation remains the default. After a cache has already been
236
+ verified and the same data is trained repeatedly, it can be skipped explicitly:
237
+
238
+ ```python
239
+ train(
240
+ data="data.csv",
241
+ target=["target"],
242
+ network="GCN",
243
+ data_quality_report=False,
244
+ validate_graph_cache=False,
245
+ )
246
+ ```
247
+
248
+ `data_quality_report=False` skips the slower canonical-SMILES duplicate,
249
+ split-overlap, and issue report after that dataset has already been reviewed.
250
+ Required CSV columns, numeric values, split labels, row alignment, and nonempty
251
+ targets are still checked. `validate_graph_cache=False` still checks the cache
252
+ recipe, ordered SMILES, and graph count; it only skips tensor shape, dtype,
253
+ finite-value, and edge-alignment checks inside each cached graph. Newly generated
254
+ graphs are always validated before saving.
255
+
256
+ The CLI equivalents are `--skip-data-quality-report` and
257
+ `--skip-graph-cache-validation`.
258
+
218
259
  ## Prediction and analysis
219
260
 
220
261
  ```python
@@ -1,8 +1,8 @@
1
- __version__ = "0.4.0"
2
-
3
- from D4CMPP2._main import train as train
4
- from D4CMPP2.grid_search import grid_search as grid_search
5
- from D4CMPP2.optimize import optimize as optimize
1
+ __version__ = "1.0.0"
2
+
3
+ from D4CMPP2.src.api.training import train as train
4
+ from D4CMPP2.src.api.legacy_grid_search import grid_search as grid_search
5
+ from D4CMPP2.src.api.optimization import optimize as optimize
6
6
  from D4CMPP2.src.utils.leaderboard import compare_experiments as compare_experiments
7
7
  from D4CMPP2.src.Analyzer import Analyzer as Analyzer
8
8
  from D4CMPP2.src.utils.sculptor import Segmentator as Segmentator
@@ -13,4 +13,4 @@ from D4CMPP2.networks import (
13
13
  MolecularNetwork as MolecularNetwork,
14
14
  register_network as register_network,
15
15
  )
16
-
16
+
@@ -0,0 +1,5 @@
1
+ from D4CMPP2.src.api.command import main
2
+
3
+
4
+ if __name__ == "__main__":
5
+ main()
d4cmpp2-1.0.0/_main.py ADDED
@@ -0,0 +1,7 @@
1
+ """Compatibility alias for :mod:`D4CMPP2.src.api.training`."""
2
+
3
+ from importlib import import_module as _import_module
4
+ import sys as _sys
5
+
6
+
7
+ _sys.modules[__name__] = _import_module("D4CMPP2.src.api.training")
d4cmpp2-1.0.0/cli.py ADDED
@@ -0,0 +1,7 @@
1
+ """Compatibility alias for :mod:`D4CMPP2.src.api.command`."""
2
+
3
+ from importlib import import_module as _import_module
4
+ import sys as _sys
5
+
6
+
7
+ _sys.modules[__name__] = _import_module("D4CMPP2.src.api.command")
@@ -27,3 +27,7 @@ fixture를 제공한다.
27
27
  - 2026-07-20: 학습, 모델 변형, 저장 모델 모드, inference, 불확실성, ISA 해석,
28
28
  실험 비교·최적화, callback, custom network 및 CLI를 기능별 Python 예제로
29
29
  분리하고 `examples/README.md`에 실행 비용과 산출물 경계를 기록했다.
30
+ - 2026-07-21: `integration/`에 solvent 5종 train-save-Analyzer와
31
+ general/solvent/ISA transfer-save-Analyzer public workflow를 추가했다.
32
+ `run_all.py`는 각 workflow를 임시 cwd subprocess로 격리하고 선택적 artifact
33
+ 보존, 실행 시간 요약과 실패 exit status를 제공한다.
@@ -43,6 +43,7 @@ target 이름을 자신의 데이터에 맞게 바꾼다.
43
43
  | callback | `extensions/01_callbacks.py` | 학습 loop를 바꾸지 않는 관찰자 |
44
44
  | custom network | `custom_network.py`, `extensions/02_custom_network_training.py` | 등록·학습·재로딩 가능한 사용자 모델 |
45
45
  | numeric input | `extensions/03_numeric_inputs.py` | named numeric batch key와 predefined split |
46
+ | heavy 통합 실행 | `integration/run_all.py` | solvent Analyzer와 계열별 transfer를 실제 학습·저장·재로딩으로 일괄 검증 |
46
47
  | CLI | `cli/README.md` | 설치, 학습, resume/load/transfer 명령 |
47
48
  | ISA segmentation | `ISA/segment.py` | 학습 전 fragmentation 규칙 확인 |
48
49
 
@@ -79,3 +80,24 @@ target 이름을 자신의 데이터에 맞게 바꾼다.
79
80
  ISA 학습, scaffold split, grid search와 Bayesian optimization은 데이터 크기와
80
81
  trial 수에 따라 오래 걸린다. 최적화 예제의 기본 trial/grid는 설명을 위해 작게
81
82
  설정했지만 각 trial은 완전한 학습·저장 작업이다.
83
+
84
+ ## Heavy integration runner
85
+
86
+ 단위 테스트가 manager, 저장, Analyzer 경계를 우회하는 문제를 막기 위해 실제
87
+ public API만 사용하는 무거운 workflow는 `integration/`에 둔다. 다음 한 명령은
88
+ 각 workflow를 별도 subprocess와 임시 작업 폴더에서 실행하고 성공/실패 및
89
+ 소요 시간을 요약한다. 기본 산출물은 종료 시 자동 제거된다.
90
+
91
+ ```sh
92
+ python examples/integration/run_all.py
93
+ ```
94
+
95
+ 모델, `transfer_report.json`, manifest를 직접 확인하려면 보존 경로를 지정한다.
96
+
97
+ ```sh
98
+ python examples/integration/run_all.py --keep-output integration-output
99
+ ```
100
+
101
+ 세부 workflow와 선택 실행 방법은 `integration/README.md`를 참고한다.
102
+ 개별 실행 파일은 `integration/solvent_analyzer.py`와
103
+ `integration/transfer_learning.py`다.
@@ -0,0 +1,34 @@
1
+ # Heavy integration examples
2
+
3
+ These examples execute real public workflows rather than mocking training or
4
+ calling networks directly. They are intentionally excluded from the fast test
5
+ layer because they train and reload multiple models on CPU.
6
+
7
+ Run everything with self-cleaning temporary outputs:
8
+
9
+ ```sh
10
+ python examples/integration/run_all.py
11
+ ```
12
+
13
+ Keep generated models, transfer reports, and manifests for inspection:
14
+
15
+ ```sh
16
+ python examples/integration/run_all.py --keep-output integration-output
17
+ ```
18
+
19
+ Run one workflow:
20
+
21
+ ```sh
22
+ python examples/integration/run_all.py --only transfer-learning
23
+ ```
24
+
25
+ The workflows are:
26
+
27
+ - `solvent-analyzer`: all five solvent models, from one-epoch public training
28
+ through saved artifacts and row-preserving Analyzer prediction.
29
+ - `transfer-learning`: representative GCN, GCNwS, and ISAT source/target runs;
30
+ compatible backbone loading, resized-head reporting, saved-model reload, and
31
+ Analyzer prediction.
32
+
33
+ The data is generated locally, no download is performed, and CPU is used by
34
+ default. The command exits nonzero if any workflow fails.
@@ -0,0 +1,93 @@
1
+ """Shared helpers for isolated public-API integration examples."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import contextlib
6
+ import os
7
+ import sys
8
+ import tempfile
9
+ from pathlib import Path
10
+
11
+
12
+ PACKAGE_ROOT = Path(__file__).resolve().parents[2]
13
+ if str(PACKAGE_ROOT.parent) not in sys.path:
14
+ sys.path.insert(0, str(PACKAGE_ROOT.parent))
15
+
16
+
17
+ @contextlib.contextmanager
18
+ def workflow_workspace(name: str, output_root: str | None):
19
+ """Run in an explicit output folder or a self-cleaning temporary folder."""
20
+
21
+ original = Path.cwd()
22
+ if output_root is None:
23
+ with tempfile.TemporaryDirectory(prefix=f"d4cmpp2-{name}-") as temporary:
24
+ root = Path(temporary).resolve()
25
+ os.chdir(root)
26
+ try:
27
+ yield root
28
+ finally:
29
+ os.chdir(original)
30
+ return
31
+
32
+ root = Path(output_root).resolve()
33
+ root.mkdir(parents=True, exist_ok=True)
34
+ os.chdir(root)
35
+ try:
36
+ yield root
37
+ finally:
38
+ os.chdir(original)
39
+
40
+
41
+ def write_tiny_dataset(root: Path) -> Path:
42
+ """Write one small predefined-split dataset shared by all workflows."""
43
+
44
+ path = root / "tiny_integration.csv"
45
+ path.write_text(
46
+ "\n".join(
47
+ (
48
+ "compound,solvent,target_a,target_b,set",
49
+ "CC,O,1.0,12.0,train",
50
+ "CCC,CO,2.0,11.0,train",
51
+ "CCO,O,3.0,10.0,train",
52
+ "CCN,CO,4.0,9.0,train",
53
+ "c1ccccc1,O,5.0,8.0,train",
54
+ "CCCl,CCO,6.0,7.0,train",
55
+ "CCBr,O,7.0,6.0,train",
56
+ "CC(=O)O,CO,8.0,5.0,train",
57
+ "C1CCCCC1,O,9.0,4.0,val",
58
+ "COC,CCO,10.0,3.0,val",
59
+ "CN,O,11.0,2.0,test",
60
+ "CC(C)O,CO,12.0,1.0,test",
61
+ )
62
+ )
63
+ + "\n",
64
+ encoding="utf-8",
65
+ )
66
+ return path
67
+
68
+
69
+ def base_train_kwargs(root: Path, data_path: Path) -> dict:
70
+ """Return small deterministic settings while using only public train options."""
71
+
72
+ model_dir = root / "models"
73
+ graph_dir = root / "graphs"
74
+ model_dir.mkdir(exist_ok=True)
75
+ graph_dir.mkdir(exist_ok=True)
76
+ return {
77
+ "data": str(data_path),
78
+ "device": "cpu",
79
+ "max_epoch": 1,
80
+ "batch_size": 4,
81
+ "hidden_dim": 8,
82
+ "conv_layers": 1,
83
+ "linear_layers": 1,
84
+ "dropout": 0.0,
85
+ "random_seed": 42,
86
+ "num_workers": 0,
87
+ "MODEL_DIR": str(model_dir),
88
+ "GRAPH_DIR": str(graph_dir),
89
+ "NET_DIR": str(PACKAGE_ROOT / "networks"),
90
+ "NET_REFER": str(PACKAGE_ROOT / "network_refer.yaml"),
91
+ "save_prediction": False,
92
+ "verbose": False,
93
+ }
@@ -0,0 +1,84 @@
1
+ """Run every heavy integration example in an isolated subprocess."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import subprocess
7
+ import sys
8
+ import tempfile
9
+ import time
10
+ from pathlib import Path
11
+
12
+
13
+ HERE = Path(__file__).resolve().parent
14
+ WORKFLOWS = (
15
+ ("solvent-analyzer", HERE / "solvent_analyzer.py"),
16
+ ("transfer-learning", HERE / "transfer_learning.py"),
17
+ )
18
+
19
+
20
+ def run_all(base: Path, selected: set[str]) -> int:
21
+ """Run selected workflows and return a process-compatible status code."""
22
+
23
+ summary = []
24
+ for name, script in WORKFLOWS:
25
+ if selected and name not in selected:
26
+ continue
27
+ output_root = base / name
28
+ working_directory = base / f".{name}-cwd"
29
+ output_root.mkdir(parents=True, exist_ok=True)
30
+ working_directory.mkdir(parents=True, exist_ok=True)
31
+ command = [
32
+ sys.executable,
33
+ str(script),
34
+ "--output-root",
35
+ str(output_root),
36
+ ]
37
+ print(f"\n=== Running {name} ===", flush=True)
38
+ started = time.monotonic()
39
+ completed = subprocess.run(command, cwd=working_directory, check=False)
40
+ elapsed = time.monotonic() - started
41
+ summary.append((name, completed.returncode, elapsed, output_root))
42
+
43
+ print("\n=== Integration summary ===")
44
+ for name, returncode, elapsed, output_root in summary:
45
+ status = "PASS" if returncode == 0 else "FAIL"
46
+ print(f"{status:4} {name:20} {elapsed:7.2f}s {output_root}")
47
+ failures = [name for name, returncode, _, _ in summary if returncode != 0]
48
+ if failures:
49
+ print(f"Failed workflows: {failures}", file=sys.stderr)
50
+ return 1
51
+ return 0
52
+
53
+
54
+ def main() -> None:
55
+ names = {name for name, _ in WORKFLOWS}
56
+ parser = argparse.ArgumentParser()
57
+ parser.add_argument(
58
+ "--only",
59
+ action="append",
60
+ choices=sorted(names),
61
+ default=[],
62
+ help="Run only this workflow; repeat the option to select more than one.",
63
+ )
64
+ parser.add_argument(
65
+ "--keep-output",
66
+ type=Path,
67
+ help="Keep generated models and reports under this directory.",
68
+ )
69
+ args = parser.parse_args()
70
+
71
+ if args.keep_output is not None:
72
+ base = args.keep_output.resolve()
73
+ base.mkdir(parents=True, exist_ok=True)
74
+ raise SystemExit(run_all(base, set(args.only)))
75
+
76
+ with tempfile.TemporaryDirectory(prefix="d4cmpp2-integration-") as temporary:
77
+ base = Path(temporary).resolve()
78
+ status = run_all(base, set(args.only))
79
+ print(f"Temporary outputs removed from {base}")
80
+ raise SystemExit(status)
81
+
82
+
83
+ if __name__ == "__main__":
84
+ main()
@@ -0,0 +1,85 @@
1
+ """Train, save, reload, and predict with every solvent-aware model.
2
+
3
+ Run directly with temporary outputs::
4
+
5
+ python examples/integration/solvent_analyzer.py
6
+
7
+ Keep artifacts for inspection::
8
+
9
+ python examples/integration/solvent_analyzer.py --output-root integration-output/solvent
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import argparse
15
+ import json
16
+ import math
17
+
18
+ from common import base_train_kwargs, workflow_workspace, write_tiny_dataset
19
+
20
+
21
+ NETWORK_IDS = ("GCNwS", "MPNNwS", "DMPNNwS", "AFPwS", "GATwS")
22
+
23
+
24
+ def run(output_root: str | None = None) -> dict:
25
+ """Execute the five-model public train-to-Analyzer workflow."""
26
+
27
+ from D4CMPP2 import Analyzer, train
28
+ from rdkit import rdBase
29
+
30
+ results = {}
31
+ with workflow_workspace("solvent-analyzer", output_root) as root:
32
+ data_path = write_tiny_dataset(root)
33
+ common = base_train_kwargs(root, data_path)
34
+ for network_id in NETWORK_IDS:
35
+ model_path = root / f"saved-{network_id}"
36
+ trained_path = train(
37
+ **common,
38
+ network=network_id,
39
+ target=["target_a"],
40
+ molecule_columns=["compound", "solvent"],
41
+ MODEL_PATH=str(model_path),
42
+ )
43
+ required = ("network.py", "config.yaml", "final.pth", "scaler.pkl")
44
+ missing = [name for name in required if not (model_path / name).is_file()]
45
+ if missing:
46
+ raise RuntimeError(
47
+ f"{network_id} completed training but is missing artifacts {missing}."
48
+ )
49
+ analyzer = Analyzer(trained_path, save_result=False, device="cpu")
50
+ # Invalid input is intentional here. Keep the Analyzer's structured
51
+ # error result while suppressing RDKit's expected parser diagnostics.
52
+ with rdBase.BlockLogs():
53
+ rows = analyzer.predict_rows(
54
+ compound=["CC", "CC", "not-a-smiles"],
55
+ solvent=["O", "O", "O"],
56
+ )
57
+ statuses = [row.status for row in rows]
58
+ if statuses != ["ok", "ok", "invalid"]:
59
+ raise RuntimeError(
60
+ f"{network_id} returned unexpected row statuses {statuses}."
61
+ )
62
+ first = float(rows[0].prediction[0])
63
+ duplicate = float(rows[1].prediction[0])
64
+ if not math.isfinite(first) or abs(first - duplicate) > 1e-6:
65
+ raise RuntimeError(
66
+ f"{network_id} returned inconsistent duplicate predictions "
67
+ f"{first} and {duplicate}."
68
+ )
69
+ results[network_id] = {
70
+ "model_path": str(model_path),
71
+ "prediction": first,
72
+ "invalid_error": rows[2].error,
73
+ }
74
+ return results
75
+
76
+
77
+ def main() -> None:
78
+ parser = argparse.ArgumentParser()
79
+ parser.add_argument("--output-root")
80
+ args = parser.parse_args()
81
+ print(json.dumps(run(args.output_root), indent=2, sort_keys=True))
82
+
83
+
84
+ if __name__ == "__main__":
85
+ main()