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.
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/D4CMPP2.egg-info/PKG-INFO +45 -4
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/D4CMPP2.egg-info/SOURCES.txt +18 -0
- d4cmpp2-1.0.0/D4CMPP2.egg-info/entry_points.txt +2 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/MANIFEST.in +1 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/PKG-INFO +45 -4
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/README.md +44 -3
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/__init__.py +6 -6
- d4cmpp2-1.0.0/__main__.py +5 -0
- d4cmpp2-1.0.0/_main.py +7 -0
- d4cmpp2-1.0.0/cli.py +7 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/AGENTS.md +4 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/README.md +22 -0
- d4cmpp2-1.0.0/examples/integration/README.md +34 -0
- d4cmpp2-1.0.0/examples/integration/common.py +93 -0
- d4cmpp2-1.0.0/examples/integration/run_all.py +84 -0
- d4cmpp2-1.0.0/examples/integration/solvent_analyzer.py +85 -0
- d4cmpp2-1.0.0/examples/integration/transfer_learning.py +111 -0
- d4cmpp2-1.0.0/exceptions.py +7 -0
- d4cmpp2-1.0.0/grid_search.py +7 -0
- d4cmpp2-1.0.0/optimize.py +7 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/pyproject.toml +3 -2
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/Dataset/GraphDataset.py +30 -4
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/Dataset/ISAGraphDataset.py +8 -2
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/MolDataManager.py +49 -6
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/contracts.py +10 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/PostProcessor.py +29 -4
- d4cmpp2-1.0.0/src/api/__init__.py +1 -0
- d4cmpp2-0.4.0/cli.py → d4cmpp2-1.0.0/src/api/command.py +1 -1
- d4cmpp2-0.4.0/exceptions.py → d4cmpp2-1.0.0/src/api/errors.py +1 -1
- d4cmpp2-0.4.0/grid_search.py → d4cmpp2-1.0.0/src/api/legacy_grid_search.py +1 -1
- d4cmpp2-0.4.0/optimize.py → d4cmpp2-1.0.0/src/api/optimization.py +1 -1
- d4cmpp2-0.4.0/_main.py → d4cmpp2-1.0.0/src/api/training.py +169 -156
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/argparser.py +20 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/checkpointing.py +1 -1
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/config_validation.py +17 -1
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/data_quality.py +6 -1
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/graph_cache.py +11 -3
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/module_loader.py +1 -1
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/run_manifest.py +1 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_cli_packaging.py +10 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_config_validation.py +10 -1
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_custom_network.py +11 -3
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_examples_syntax.py +4 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_failure_contracts.py +2 -2
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_public_contracts.py +51 -10
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_pyg_data_contract.py +45 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_scaler_alignment.py +1 -1
- d4cmpp2-1.0.0/tests/test_solvent_analyzer_end_to_end.py +54 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_dataset_contract_matrix.py +44 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_graph_cache_integrity.py +16 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_leaderboard.py +1 -1
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_errors_logging.py +1 -1
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t6_ci_contract.py +11 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t7_cycle_audit.py +1 -1
- d4cmpp2-0.4.0/D4CMPP2.egg-info/entry_points.txt +0 -2
- d4cmpp2-0.4.0/__main__.py +0 -5
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/D4CMPP2.egg-info/dependency_links.txt +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/D4CMPP2.egg-info/requires.txt +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/D4CMPP2.egg-info/top_level.txt +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/LICENSE +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/AGENTS.md +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/Aqsoldb.csv +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/BradleyMP.csv +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/Lipophilicity.csv +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/README.md +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/optical.csv +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/_Data/test.csv +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/ISA/segment.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/assets/tiny_numeric.csv +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/cli/README.md +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/custom_network.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/experiments/01_compare.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/experiments/02_optimize.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/experiments/03_legacy_grid_search.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/extensions/01_callbacks.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/extensions/02_custom_network_training.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/extensions/03_numeric_inputs.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/inference/01_prediction.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/inference/02_csv_prediction.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/inference/03_uncertainty_ensemble.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/inference/04_isa_interpretation.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/01_basic_cpu.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/02_solvent.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/03_multitarget.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/04_splitting_reproducibility.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/05_isa.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/06_saved_model_modes.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/examples/training/07_model_families.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/network_refer.yaml +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/AFP_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/AFPwithSolv_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/DMPNN_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/DMPNNwithSolv_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/GAT_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/GATwithSolv_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/GCN_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/GCNwithSolv_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/GC_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/ISATPM_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/ISATPN_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/ISAT_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/MPNN_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/MPNNwithSolv_model.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/base.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/registry.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/AFP.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/BiDropout.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/DMPNN.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/GAT.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/GC.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/GCN.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/ISAT.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/Linear.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/MPNN.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/SolventLayer.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/distGCN.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/networks/src/pyg_hetero.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/setup.cfg +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/ISAAnalyzer.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/ISAPNAnalyzer.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/ISAwSAnalyzer.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/MolAnalyzer.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/core.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/factory.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/interpretation.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/Analyzer/results.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/Dataset/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/GraphGenerator/ISAGraphGenerator.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/GraphGenerator/MolGraphGenerator.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/GraphGenerator/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/ISADataManager.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/DataManager/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/NetworkManager/ISANetworkManager.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/NetworkManager/NetworkManager.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/NetworkManager/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/TrainManager/ISATrainManager.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/TrainManager/TrainManager.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/TrainManager/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/TrainManager/callbacks.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/PATH.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/__init__.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/config_resolution.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/csv_validation.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/featureizer.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/functional_group.csv +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/leaderboard.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/metrics.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/output.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/reproducibility.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/scaler.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/sculptor.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/splitting.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/supportfile_saver.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/tools.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/src/utils/transfer_learning.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_csv_data_manager_validation.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_csv_validation.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_data_fixture.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_example_model_compatibility.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_failure_behavior.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_gcn_end_to_end.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_graph_alignment.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_heavy_smoke.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_network_abc.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_network_persistence.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_optimize.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_path_utils.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_pyg_dmpnn_afp.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_pyg_gcn.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_pyg_isa_models.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_pyg_mpnn_gat.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_runtime_environment.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_state_dict_contract.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_checkpoint_policy.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_data_quality.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_grid_search.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_registry_smoke_matrix.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_reproducibility.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_run_manifest.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_scaffold_split.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t3_transfer_learning.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t4_analyzer_core.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_callbacks.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_config_resolution.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_import_discovery.py +0 -0
- {d4cmpp2-0.4.0 → d4cmpp2-1.0.0}/tests/test_t5_manager_contracts.py +0 -0
- {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.
|
|
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
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: D4CMPP2
|
|
3
|
-
Version: 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
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
4
|
-
|
|
5
|
-
|
|
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.
|
|
2
|
-
|
|
3
|
-
from D4CMPP2.
|
|
4
|
-
from D4CMPP2.
|
|
5
|
-
from D4CMPP2.
|
|
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
|
+
|
d4cmpp2-1.0.0/_main.py
ADDED
d4cmpp2-1.0.0/cli.py
ADDED
|
@@ -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()
|