From 784480d5fae6ec7af50de72ff2d9ede88f3ccc75 Mon Sep 17 00:00:00 2001 From: boby-cloudforge Date: Sun, 3 May 2026 15:59:14 +0200 Subject: [PATCH] =?UTF-8?q?=E3=80=90Hackathon=2010th=20Spring=20No.9?= =?UTF-8?q?=E3=80=91NewtonNet=20model=20reproduction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 195 ++--- docs/MetaX.png | Bin 0 -> 129498 bytes docs/suzhoulab.png | Bin 0 -> 9426 bytes docs/zhonghua.jpeg | Bin 0 -> 45349 bytes .../configs/newtonnet/README.md | 48 ++ .../newtonnet/newtonnet_qm9_energy.yaml | 89 +++ .../configs/schnet/schnet_md17_ethanol.yaml | 107 +++ .../configs/schnet/schnet_qm9_U0.yaml | 109 +++ ppmat/datasets/alloy_dataset.py | 88 +++ ppmat/datasets/md17_dataset.py | 250 ++++++ ppmat/models/__init__.py | 2 + ppmat/models/newtonnet/__init__.py | 13 + ppmat/models/newtonnet/newtonnet.py | 743 ++++++++++++++++++ test/newtonnet/__init__.py | 0 test/newtonnet/conftest.py | 23 + test/newtonnet/raw_infer_data/__init__.py | 0 .../raw_infer_data/create_input_output_npz.py | 72 ++ .../newtonnet/raw_infer_data/reference_io.npz | Bin 0 -> 514 bytes test/newtonnet/test_loss/__init__.py | 0 .../test_loss/test_model_loss_with_raw.py | 262 ++++++ 20 files changed, 1878 insertions(+), 123 deletions(-) create mode 100644 docs/MetaX.png create mode 100644 docs/suzhoulab.png create mode 100644 docs/zhonghua.jpeg create mode 100644 interatomic_potentials/configs/newtonnet/README.md create mode 100644 interatomic_potentials/configs/newtonnet/newtonnet_qm9_energy.yaml create mode 100644 interatomic_potentials/configs/schnet/schnet_md17_ethanol.yaml create mode 100644 interatomic_potentials/configs/schnet/schnet_qm9_U0.yaml create mode 100644 ppmat/datasets/alloy_dataset.py create mode 100644 ppmat/datasets/md17_dataset.py create mode 100644 ppmat/models/newtonnet/__init__.py create mode 100644 ppmat/models/newtonnet/newtonnet.py create mode 100644 test/newtonnet/__init__.py create mode 100644 test/newtonnet/conftest.py create mode 100644 test/newtonnet/raw_infer_data/__init__.py create mode 100644 test/newtonnet/raw_infer_data/create_input_output_npz.py create mode 100644 test/newtonnet/raw_infer_data/reference_io.npz create mode 100644 test/newtonnet/test_loss/__init__.py create mode 100644 test/newtonnet/test_loss/test_model_loss_with_raw.py diff --git a/README.md b/README.md index ddcc5c78..0d88f6e8 100755 --- a/README.md +++ b/README.md @@ -6,176 +6,125 @@ ## 🚀 Introduction -**PaddleMaterials** is an end-to-end AI4Materials toolkit built on the **PaddlePaddle** deep learning framework. Designed as a data-mechanism dual-driven platform for developing and deploying foundation models in materials science, **PPMat** enables researchers to efficiently build AI models and accelerate material discovery using pretrained models. +**PaddleMaterials** is a data-mechanism dual-driven, development and deployment of AI4Materials foundation models, end to end toolkit based on PaddlePaddle deep learning framework for materials science and engineering. **PPMat** (represents PaddleMaterials in the following text) is designed to help researchers more efficiently build AI4Materials foundation models and explore, discover, and develop new materials based on deployed pretrained models. **PPMat** has supported inorganic materials and part of organic molecules, and will support more types of materials including polymers, organic molecules, catalysts, and so on. It has supported some representative models including the equivalent graph networks-based model, diffusion model, multi-modal model, and will support more kinds of deep learing models and agents works related to AI4Material fields in the feature.

-### Core Capabilities +**Inorganic materials**, characterized by their symmetrical and periodic structures, exhibit a wide range of properties and are widely applied in various fields, from electronic devices to energy applications. Traditional experimental and computational methods for discovering crystalline materials are often time-consuming and expensive. Data-driven approaches to material discovery have the power to model the highly complex atomic systems within crystalline materials, paving the way for rapid and accurate material discovery. -| Task | Description | Typical Applications | -|------|-------------|---------------------| -| **Property Prediction (PP)** | Predict material properties from structure | Formation energy, band gap, elastic moduli | -| **Structure Generation (SG)** | Generate novel crystal structures | High-throughput screening, inverse design | -| **Interatomic Potential (IP)** | Replace DFT with ML potentials | Molecular dynamics, large-scale simulations | -| **Electronic Structure (ES)** | Predict electronic properties | Band structure, density of states | -| **Spectrum Elucidation (SE)** | Reconstruct structures from spectra | NMR structure elucidation | +**Organic materials**, distinguished by covalently linked, directionally bonded networks, mainly defined as a carbon–hydrogen or carbon–carbon bond chemical compound. These traits support core applications including flexible displays, organic photovoltaics, high-energy-density battery electrodes, advanced separation membranes, catalyts. The vast compositional and conformational space of organic molecules makes trial-and-error synthesis and ab-initio simulations slow and costly. Data-driven methods that fuse high-throughput datasets, graph-based representations, and deep generative models rapidly learn structure–property links, enabling fast virtual screening and rational design for more agile, sustainable advances in organic materials. -### Supported Materials +**Polymer materials**, characterized by their large molecular weight and complex molecular structures and built from long-chain macromolecules with tunable architectures (homopolymer, block, graft) and morphologies (amorphous, semicrystalline, cross-linked), offer lightweight, processable, and programmable mechanical, thermal, optical, and transport properties for coatings, membranes, composites, and flexible electronics. The combinatorial design space—monomer choice, sequence, tacticity, molecular-weight distribution, additives, and processing history—plus multi-scale physics makes Edisonian discovery and brute-force simulation slow and costly. Data-driven polymer informatics that fuses high-throughput measurements with graph/sequence representations and physics-guided neural surrogates learns structure-processing-property links, while generative and active-learning workflows target Tg, modulus, permeability, dielectric constant, and recyclability for rapid, sustainable polymer discovery. -- **Inorganic Crystals** - Well-supported with multiple datasets (MP2018, MP2024, JARVIS) and pretrained models -- **Organic Molecules** - Support for small molecule datasets (QM9) and property prediction -- *Polymers, catalysts, and amorphous materials are under development* +**Catalysts materials**, as key components in chemical reactions, play a crucial role in the development of new materials and technologies and spanning heterogeneous surfaces (metals, alloys, oxides, zeolites), homogeneous/organometallic complexes, and electrocatalysts, control reaction rates and selectivity across chemicals, energy, and environmental remediation. Discovery is hampered by vast compositional/structural spaces, site heterogeneity, competing pathways, and operando effects (adsorption, kinetics, deactivation) that challenge trial-and-error and exhaustive DFT. Data-driven methods—surrogate models for adsorption energies and barriers (e.g., graph neural networks), learned electronic/structural descriptors, and generative design coupled with Bayesian/active learning and automated experimentation—enable fast screening and rational optimization, accelerating catalysts for CO₂ reduction, ammonia synthesis, fuel-cell reactions, and selective oxidations. -### Why PaddleMaterials? - -- ✅ **Rich Pretrained Models** - 50+ pretrained models ready for inference -- ✅ **Multi-Task Integration** - Unified framework across PP, SG, MLIP, MLES, SE -- ✅ **Domestic Hardware Support** - Full support for MetaX GPUs and NVIDIA GPUs -- ✅ **PaddlePaddle Ecosystem** - Seamless integration with PaddlePaddle tools -- ✅ **Production-Ready** - Distributed training, mixed precision, checkpoint recovery - ---- +**Amorphous materials**, have no detectable crystal structure.its characteristic of atomic arrangement is more like liguid and has no long-range periodicity. It has attracted increasing attention duo to its broad applciations in optoelectronics, catalysis, and batteries. Its structure-property relationship is highly complex and sensitive to disorder, making it challenging to predict and design. ## 📣 News +🔥 **2025.09.25**: The **MetaX** has supported all models of multiple tasks including MLIP, MLES, PP, SG, SE. Welcome to run PaddleMaterials on MetaX chips. To experience the MetaX chip in a public cloud environment, please refer to this [PaddleMaterials_MetaX_README](./docs/MetaX/PaddleMaterials_MetaX_README.md). Pleare reference to [SupportedHardwareList](./docs/multi_device.md) for more multi-hardware adaption information. ---- +🔥 **2025.09.12**: The **Suzhou Laboratory** has established a novel model DiffNMR based on PaddleMaterials, a novel end-to-end framework that leverages a conditional discrete diffusion model for de novo molecular structure elucidation from NMR spectra. For more information, please refer to [DiffNMR](./research/DiffNMR/README.md). -## 📑 Tasks +🔥 **2025.07.01**: The **Suzhou Laboratory** has established a novel framework based on PaddleMaterials, combining an active learning workflow with conditional-diffusion-based structure generation, thereby achieving unprecedented expansion of two-dimensional material databases. For more information, please refer to [ML2DDB](./research/ML2DDB/README.md). -| Task | Description | Link | -|------|-------------|------| -| **Property Prediction (PP)** | Predict formation energy, band gap, elastic properties | [README](property_prediction/README.md) | -| **Structure Generation (SG)** | Generate new crystal structures with diffusion models | [README](structure_generation/README.md) | -| **Interatomic Potential (IP)** | DFT-accurate potentials for molecular dynamics | [README](interatomic_potentials/README.md) | -| **Electronic Structure (ES)** | Predict electronic structure properties | [README](electronic_structure/README.md) | -| **Spectrum Elucidation (SE)** | Reconstruct molecular structures from NMR spectra | [README](spectrum_elucidation/README.md) | - ---- +## 📑 Task +- [MLIP-Machine Learning Interatomic Potential](interatomic_potentials/README.md) +- [MLES-Machine Learning Electronic Structure](electronic_structure/README.md) +- [PP-Property Prediction](property_prediction/README.md) +- [SG-Structure Generation](structure_generation/README.md) +- [SE-Spectrum Elucidation](spectrum_elucidation/README.md) ## 🔧 Installation -Please refer to the installation [document](Install.md) for your hardware environment. See [SupportedHardwareList](./docs/multi_device.md) for more multi-hardware adaptation information. +Please refer to the installation [document](Install.md) on your harware environment reference to [SupportedHardwareList](./docs/multi_device.md). ---- ## ⚡ Get Started -### Property Prediction - -Predict material formation energy using a pretrained MEGNet model: - -```bash -python property_prediction/predict.py \ - --model_name='megnet_mp2018_train_60k_e_form' \ - --weights_name='best.pdparams' \ - --cif_file_path='./property_prediction/example_data/cifs/' \ - --save_path='result.csv' -``` - -### Structure Generation - -Generate novel crystal structures: - -```bash -python structure_generation/predict.py \ - --model_name='mattergen_mp20' \ - --num_structures=100 \ - --save_path='generated_structures/' -``` - -### Interatomic Potentials - -Run molecular dynamics with ML potentials: - +PaddleMaterials offers multiple built-in models that can be directly used for inference. Taking the `megnet_mp2018_train_60k_e_form` model as an example (a MEGNet model trained on the MP2018 dataset for material formation energy prediction), use the following command for inference: ```bash -python interatomic_potentials/run_md.py - --model_name='mattersim_1M' - --structure_path='input.cif' - --temperature=300 +python property_prediction/predict.py --model_name='megnet_mp2018_train_60k_e_form' --weights_name='best.pdparams' --cif_file_path='./property_prediction/example_data/cifs/' --save_path='result.csv' ``` ---- - -### Train Your Own Model - -For training and fine-tuning, refer to the [documentation](get_started.md). - -### Contribute to PaddleMaterials - -For developer, please refer to [architecture](docs/ARCHITECTURE_ch.md). - ---- - -## 🎯 Available Pretrained Models - -| Task | Models | Dataset | -|------|--------|---------| -| **Property Prediction** | MEGNet, iComformer, DimeNet++ | MP2018, MP2024, JARVIS | -| **Structure Generation** | MatterGen, DiffCSP | MP20, ALEX | -| **Interatomic Potentials** | CHGNet, MatterSim | MPTRJ | -| **Electronic Structure** | InfGCN | Custom datasets | - -Full model list: See [MODEL_REGISTRY](ppmat/models/__init__.py) - ---- - -## ⭐️ Star History - -[![Star History Chart](https://api.star-history.com/svg?repos=PaddlePaddle/PaddleMaterials&type=date&legend=top-left)](https://www.star-history.com/#PaddlePaddle/PaddleMaterilas&type=date&legend=top-left) - ---- + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
--model_nameName of the built-in model
--weights_nameWeights file name
--cif_file_pathPath to CIF files for prediction
--save_pathPath to save prediction results
+ +For more information on how to use PaddleMaterials to train and fine tune a model, please refer to the [documentation](get_started.md). ## 👩‍👩‍👧‍👦 Cooperation

- - - + + +

---- - ## 👩‍👩‍👧‍👦 Community -Join the PaddleMaterials WeChat group to discuss with us! +Join PaddleMaterials WeChat group to disscuss with us!

---- +## 🔄 Feedback + +We sincerely invite you to spare a moment from your busy schedule to share your [feedback](https://paddle.wjx.cn/vm/rXyQwB2.aspx#). ## 📜 License PaddleMaterials is licensed under the [Apache License 2.0](LICENSE). ---- ## 🎓 Citation -```bibtex -@misc{paddlematerials2025, - title={PaddleMaterials, a deep learning toolkit based on PaddlePaddle for material science.}, - author={PaddleMaterials Contributors}, - howpublished = {\url{https://github.com/PaddlePaddle/PaddleMaterials}}, - year={2025} -} -``` ---- + @misc{paddlematerials2025, + title={PaddleMaterials, a deep learning toolkit based on PaddlePaddle for material science.}, + author={PaddleMaterials Contributors}, + howpublished = {\url{https://github.com/PaddlePaddle/PaddleMaterials}}, + year={2025} + } -## Acknowledgements -This repository references code from the following projects: +## Acknowledgements -[PaddleScience](https://github.com/PaddlePaddle/PaddleScience) | -[Matgl](https://github.com/materialsvirtuallab/matgl) | -[CDVAE](https://github.com/txie-93/cdvae) | -[DiffCSP](https://github.com/jiaor17/DiffCSP) | -[MatterGen](https://github.com/microsoft/mattergen) | -[MatterSim](https://github.com/microsoft/mattersim) | -[CHGNet](https://github.com/CederGroupHub/chgnet) | -[AIRS](https://github.com/divelab/AIRS) \ No newline at end of file +This repository references the code from the following repositories: +[PaddleScience](https://github.com/PaddlePaddle/PaddleScience), +[Matgl](https://github.com/materialsvirtuallab/matgl), +[CDVAE](https://github.com/txie-93/cdvae), +[DiffCSP](https://github.com/jiaor17/DiffCSP), +[MatterGen](https://github.com/microsoft/mattergen), +[MatterSim](https://github.com/microsoft/mattersim), +[CHGNet](https://github.com/CederGroupHub/chgnet), +[AIRS](https://github.com/divelab/AIRS), +etc. + + diff --git a/docs/MetaX.png b/docs/MetaX.png new file mode 100644 index 0000000000000000000000000000000000000000..585a224e5d37d39c42053d509247e0bf259db6b9 GIT binary patch literal 129498 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

4!^UuYM=a);&Hqi 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 wp}qAhPWrFUptSY|-{2e}$yEj+}*( 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 literal 0 HcmV?d00001 diff --git a/docs/zhonghua.jpeg b/docs/zhonghua.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..015845f070935c16d6dead7197cdfbdfc7384016 GIT binary patch literal 45349 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 literal 0 HcmV?d00001 diff --git a/interatomic_potentials/configs/newtonnet/README.md b/interatomic_potentials/configs/newtonnet/README.md new file mode 100644 index 00000000..26c2adcf --- /dev/null +++ b/interatomic_potentials/configs/newtonnet/README.md @@ -0,0 +1,48 @@ +# NewtonNet + +[NewtonNet: a Newtonian message passing network for deep learning of interatomic potentials and forces](https://doi.org/10.1039/D2DD00008C) + +## Abstract + +NewtonNet is a Newtonian message-passing neural network for learning interatomic potentials and forces. It operates on atomic graphs with radial Bessel basis functions and polynomial cutoff envelopes. The architecture uses a sequence of interaction layers that update both atom-level and force-level representations, enabling accurate prediction of energies and atomic forces while maintaining energy conservation. + +## Model + +NewtonNet constructs a radius graph from atomic positions and computes pairwise radial basis features. Interaction layers iteratively refine atom representations using Newtonian message passing that preserves physical symmetries. Per-atom energies are summed for the total molecular energy, and forces are obtained as negative energy gradients with respect to positions. + +## Training + +```bash +# single-gpu training +python interatomic_potentials/train.py -c interatomic_potentials/configs/newtonnet/newtonnet_qm9_energy.yaml + +# multi-gpu training +python -m paddle.distributed.launch --gpus="0,1,2,3" interatomic_potentials/train.py -c interatomic_potentials/configs/newtonnet/newtonnet_qm9_energy.yaml +``` + +## Validation + +```bash +python interatomic_potentials/train.py -c interatomic_potentials/configs/newtonnet/newtonnet_qm9_energy.yaml Global.do_eval=True Global.do_train=False Global.do_test=False Trainer.pretrained_model_path='your model path(*.pdparams)' +``` + +## Testing + +```bash +python interatomic_potentials/train.py -c interatomic_potentials/configs/newtonnet/newtonnet_qm9_energy.yaml Global.do_test=True Global.do_train=False Global.do_eval=False Trainer.pretrained_model_path='your model path(*.pdparams)' +``` + +## Citation + +``` +@article{haghighatlari2022newtonnet, + title={NewtonNet: a Newtonian message passing network for deep learning of interatomic potentials and forces}, + author={Haghighatlari, Mojtaba and Li, Jie and Guan, Xingyi and Zhang, Oufan and Das, Akshaya and Stein, Christopher J and Heiber, Farnaz and Liu, Tiantian and Head-Gordon, Martin and Bertels, Luke and others}, + journal={Digital Discovery}, + volume={1}, + number={3}, + pages={333--343}, + year={2022}, + publisher={Royal Society of Chemistry} +} +``` diff --git a/interatomic_potentials/configs/newtonnet/newtonnet_qm9_energy.yaml b/interatomic_potentials/configs/newtonnet/newtonnet_qm9_energy.yaml new file mode 100644 index 00000000..ab341b08 --- /dev/null +++ b/interatomic_potentials/configs/newtonnet/newtonnet_qm9_energy.yaml @@ -0,0 +1,89 @@ +Global: + do_train: True + do_eval: False + do_test: False + + label_names: ['energy'] + +Trainer: + max_epochs: 300 + seed: 42 + output_dir: ./output/newtonnet_qm9_energy + save_freq: 50 + log_freq: 20 + start_eval_epoch: 1 + eval_freq: 1 + pretrained_model_path: null + pretrained_weight_name: null + resume_from_checkpoint: null + use_amp: False + amp_level: 'O1' + eval_with_no_grad: False + gradient_accumulation_steps: 1 + best_metric_indicator: 'eval_metric' + name_for_best_metric: "energy" + greater_is_better: False + compute_metric_during_train: True + metric_strategy_during_eval: 'epoch' + use_visualdl: False + use_wandb: False + use_tensorboard: False + +Model: + __class_name__: NewtonNet + __init_params__: + cutoff: 5.0 + n_features: 128 + n_basis: 20 + n_interactions: 3 + activation: swish + layer_norm: False + loss_type: mse_loss + force_loss_weight: 100.0 + property_names: ${Global.label_names} + +Optimizer: + __class_name__: Adam + __init_params__: + lr: + __class_name__: Cosine + __init_params__: + learning_rate: 5e-4 + eta_min: 1e-6 + by_epoch: False + +Metric: + energy: + __class_name__: paddle.nn.L1Loss + __init_params__: {} + +Dataset: + dataset: + __class_name__: QM9Dataset + __init_params__: + path: "./data/qm9" + property_names: ${Global.label_names} + num_workers: 4 + use_shared_memory: False + split_dataset_ratio: + train: 0.8 + val: 0.1 + test: 0.1 + train_sampler: + __class_name__: BatchSampler + __init_params__: + shuffle: True + drop_last: False + batch_size: 32 + val_sampler: + __class_name__: BatchSampler + __init_params__: + shuffle: False + drop_last: False + batch_size: 32 + test_sampler: + __class_name__: BatchSampler + __init_params__: + shuffle: False + drop_last: False + batch_size: 32 diff --git a/interatomic_potentials/configs/schnet/schnet_md17_ethanol.yaml b/interatomic_potentials/configs/schnet/schnet_md17_ethanol.yaml new file mode 100644 index 00000000..3fa0d418 --- /dev/null +++ b/interatomic_potentials/configs/schnet/schnet_md17_ethanol.yaml @@ -0,0 +1,107 @@ +Global: + do_train: True + do_eval: True + do_test: False + + label_names: ['energy'] + + graph_converter: + __class_name__: FindPointsInSpheres + __init_params__: + cutoff: 5.0 + + prim_eager_enabled: True + + +Trainer: + max_epochs: 500 + seed: 42 + output_dir: ./output/schnet_md17_ethanol + save_freq: 50 + log_freq: 50 + + start_eval_epoch: 1 + eval_freq: 5 + pretrained_model_path: null + pretrained_weight_name: null + resume_from_checkpoint: null + use_amp: False + eval_with_no_grad: True + gradient_accumulation_steps: 1 + + best_metric_indicator: 'eval_metric' + name_for_best_metric: "energy" + greater_is_better: False + + +Model: + __class_name__: SchNet + __init_params__: + n_atom_basis: 64 + n_interactions: 6 + n_filters: 64 + cutoff: 5.0 + n_gaussians: 25 + max_z: 100 + readout: "sum" + property_names: ${Global.label_names} + data_mean: 0.0 + data_std: 1.0 + loss_type: "l1_loss" + compute_forces: False + + +Optimizer: + __class_name__: Adam + __init_params__: + lr: + __class_name__: Cosine + __init_params__: + learning_rate: 1e-4 + eta_min: 1e-7 + by_epoch: False + + +Metric: + energy: + __class_name__: IgnoreNanMetricWrapper + __init_params__: + __class_name__: paddle.nn.L1Loss + __init_params__: {} + + +Dataset: + train: + dataset: + __class_name__: MD17Dataset + __init_params__: + path: "./data/md17" + molecule: "ethanol" + property_names: ${Global.label_names} + build_graph_cfg: ${Global.graph_converter} + max_samples: 50000 + num_workers: 4 + use_shared_memory: False + sampler: + __class_name__: BatchSampler + __init_params__: + shuffle: True + drop_last: False + batch_size: 64 + val: + dataset: + __class_name__: MD17Dataset + __init_params__: + path: "./data/md17" + molecule: "ethanol" + property_names: ${Global.label_names} + build_graph_cfg: ${Global.graph_converter} + max_samples: 10000 + num_workers: 4 + use_shared_memory: False + sampler: + __class_name__: BatchSampler + __init_params__: + shuffle: False + drop_last: False + batch_size: 64 diff --git a/interatomic_potentials/configs/schnet/schnet_qm9_U0.yaml b/interatomic_potentials/configs/schnet/schnet_qm9_U0.yaml new file mode 100644 index 00000000..88b50ad3 --- /dev/null +++ b/interatomic_potentials/configs/schnet/schnet_qm9_U0.yaml @@ -0,0 +1,109 @@ +Global: + do_train: True + do_eval: True + do_test: False + + label_names: ['energy_U0'] + + graph_converter: + __class_name__: FindPointsInSpheres + __init_params__: + cutoff: 10.0 + + prim_eager_enabled: True + + +Trainer: + max_epochs: 200 + seed: 42 + output_dir: ./output/schnet_qm9_U0 + save_freq: 20 + log_freq: 50 + + start_eval_epoch: 1 + eval_freq: 5 + pretrained_model_path: null + pretrained_weight_name: null + resume_from_checkpoint: null + use_amp: False + eval_with_no_grad: True + gradient_accumulation_steps: 1 + + best_metric_indicator: 'eval_metric' + name_for_best_metric: "energy_U0" + greater_is_better: False + + +Model: + __class_name__: SchNet + __init_params__: + n_atom_basis: 128 + n_interactions: 6 + n_filters: 128 + cutoff: 10.0 + n_gaussians: 50 + max_z: 100 + readout: "sum" + property_names: ${Global.label_names} + data_mean: -76.1160 + data_std: 10.3238 + loss_type: "l1_loss" + compute_forces: False + + +Optimizer: + __class_name__: Adam + __init_params__: + lr: + __class_name__: Cosine + __init_params__: + learning_rate: 1e-4 + eta_min: 1e-7 + by_epoch: False + + +Metric: + energy_U0: + __class_name__: IgnoreNanMetricWrapper + __init_params__: + __class_name__: paddle.nn.L1Loss + __init_params__: {} + + +Dataset: + train: + dataset: + __class_name__: QM9Dataset + __init_params__: + path: "./data/qm9" + property_names: ${Global.label_names} + build_graph_cfg: ${Global.graph_converter} + cache_path: "./data/qm9" + overwrite: False + filter_unvalid: True + num_workers: 4 + use_shared_memory: False + sampler: + __class_name__: BatchSampler + __init_params__: + shuffle: True + drop_last: False + batch_size: 64 + val: + dataset: + __class_name__: QM9Dataset + __init_params__: + path: "./data/qm9" + property_names: ${Global.label_names} + build_graph_cfg: ${Global.graph_converter} + cache_path: "./data/qm9" + overwrite: False + filter_unvalid: True + num_workers: 4 + use_shared_memory: False + sampler: + __class_name__: BatchSampler + __init_params__: + shuffle: False + drop_last: False + batch_size: 64 diff --git a/ppmat/datasets/alloy_dataset.py b/ppmat/datasets/alloy_dataset.py new file mode 100644 index 00000000..545e609b --- /dev/null +++ b/ppmat/datasets/alloy_dataset.py @@ -0,0 +1,88 @@ +# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +AlloyDataset — tabular dataset for metallic glass alloy compositions. + +Loads Alloy_train.csv produced by tools/prepare_alloy_data.py. +Each sample is a 66-dimensional float vector: + columns 0-39: element composition fractions (40 elements) + columns 40-42: Tg, Tx, Tl (thermal transition temperatures in K) + columns 43-65: 23 GFA criteria (derived from Tg/Tx/Tl) + +The "source" column is dropped on load (same as original AlloyGAN). +""" + +import numpy as np +import paddle +from paddle.io import Dataset + +from ppmat.utils import logger + + +class AlloyDataset(Dataset): + """Tabular dataset for AlloyGAN training. + + Args: + path: Path to Alloy_train.csv. + categories: Optional list of dominant-element categories to filter + (e.g., ["Cu", "Fe", "Ti", "Zr"]). Default uses all entries. + normalize: Whether to normalize composition fractions to [0, 1]. + Default True (divides compositions by 100). + """ + + # Top 40 elements in order (matches CSV columns 0-39) + ELEMENTS = [ + "Cu", "Zr", "Al", "Ni", "Ti", "Ag", "Fe", "Mg", "B", "Si", + "Nb", "Y", "Ca", "La", "Co", "Be", "C", "Mo", "Pd", "P", + "Sn", "Cr", "Hf", "Zn", "Gd", "Ce", "Er", "Ga", "Au", "Nd", + "Dy", "W", "Pr", "Ta", "Sc", "Li", "Sm", "S", "Pt", "Mn", + ] + + def __init__(self, path, categories=None, normalize=True): + super().__init__() + import pandas as pd + + df = pd.read_csv(path) + + # Drop the "source" column if present (same as original code) + if "source" in df.columns: + df = df.drop(columns=["source"]) + + # Optional category filtering by dominant element + if categories is not None: + elem_cols = df.columns[:40] + dominant = df[elem_cols].idxmax(axis=1) + mask = dominant.isin(categories) + df = df[mask].reset_index(drop=True) + logger.info( + f"Filtered to categories {categories}: " + f"{len(df)} entries" + ) + + self.data = df.values.astype(np.float32) + + if normalize: + # Normalize composition fractions (0-100) to (0-1) + self.data[:, :40] = self.data[:, :40] / 100.0 + + logger.info( + f"Loaded AlloyDataset: {len(self.data)} samples, " + f"{self.data.shape[1]} features from {path}" + ) + + def __len__(self): + return len(self.data) + + def __getitem__(self, idx): + return {"data": self.data[idx]} diff --git a/ppmat/datasets/md17_dataset.py b/ppmat/datasets/md17_dataset.py new file mode 100644 index 00000000..d75a632a --- /dev/null +++ b/ppmat/datasets/md17_dataset.py @@ -0,0 +1,250 @@ +# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""MD17 dataset for molecular dynamics trajectories. + +The MD17 dataset (Chmiela et al., 2017) contains ab-initio molecular dynamics +trajectories for small organic molecules. Each snapshot includes atomic +positions, total energy, and per-atom forces. + +Reference: + S. Chmiela, A. Tkatchenko, H. E. Sauceda, I. Poltavsky, K. T. Schütt, + K.-R. Müller. Machine Learning of Accurate Energy-Conserving Molecular + Force Fields. Science Advances, 2017. +""" + +from __future__ import annotations + +import os +import os.path as osp +import pickle +from typing import Any, Callable, Dict, List, Optional, Union + +import numpy as np +import paddle.distributed as dist +from paddle.io import Dataset + +from ppmat.models import build_graph_converter +from ppmat.utils import download, logger + +try: + from pymatgen.core import Lattice, Structure +except ImportError: + Structure = None + Lattice = None + + +# Mapping from molecule name to original MD17 NPZ filename. +MD17_FILES = { + "benzene": "md17_benzene2017.npz", + "uracil": "md17_uracil.npz", + "naphthalene": "md17_naphthalene.npz", + "aspirin": "md17_aspirin.npz", + "salicylic_acid": "md17_salicylic.npz", + "malonaldehyde": "md17_malonaldehyde.npz", + "ethanol": "md17_ethanol.npz", + "toluene": "md17_toluene.npz", +} + +# Atomic number → element symbol (for pymatgen Structure creation). +_Z_TO_SYMBOL = { + 1: "H", 6: "C", 7: "N", 8: "O", 9: "F", 16: "S", +} + + +class MD17Dataset(Dataset): + """MD17 molecular dynamics trajectory dataset. + + Loads an MD17 NPZ file and converts each snapshot into a dict compatible + with PaddleMaterials models (optionally building a PGL graph via the + graph converter). + + The NPZ files contain: + - ``z``: atomic numbers, shape [num_atoms] + - ``R``: positions, shape [num_snapshots, num_atoms, 3] (Angstrom) + - ``E``: energies, shape [num_snapshots, 1] (kcal/mol) + - ``F``: forces, shape [num_snapshots, num_atoms, 3] (kcal/mol/A) + + Args: + path (str): Root directory for dataset storage. + molecule (str): Molecule name (e.g. "ethanol"). + property_names (str or list): Target property name(s). Default: "energy". + build_graph_cfg (dict, optional): Config for graph converter. + max_samples (int, optional): Limit dataset size (for faster debugging). + url (str, optional): Custom download URL. Default: BCS mirror. + box_size (float): Side length (A) of the cubic cell used for + non-periodic molecules. Default: 100.0. + cache_graphs (bool): Whether to cache built graphs to disk. Default: True. + """ + + # BCS mirror for MD17 NPZ files + default_url = "https://paddle-org.bj.bcebos.com/paddlematerials/datasets/MD17" + + def __init__( + self, + path: str, + molecule: str = "ethanol", + property_names: Union[str, List[str]] = "energy", + *, + build_graph_cfg: Optional[Dict] = None, + max_samples: Optional[int] = None, + url: Optional[str] = None, + box_size: float = 100.0, + cache_graphs: bool = True, + **kwargs, + ) -> None: + super().__init__() + + if molecule not in MD17_FILES: + raise ValueError( + f"Unknown molecule '{molecule}'. Choose from: {list(MD17_FILES)}" + ) + + if isinstance(property_names, str): + property_names = [property_names] + self.property_names = property_names + self.molecule = molecule + self.box_size = box_size + self.build_graph_cfg = build_graph_cfg + + # Paths + os.makedirs(path, exist_ok=True) + self.raw_dir = osp.join(path, "raw_md17") + os.makedirs(self.raw_dir, exist_ok=True) + + npz_name = MD17_FILES[molecule] + npz_path = osp.join(self.raw_dir, npz_name) + + # Download if needed + if not osp.exists(npz_path): + base_url = url or self.default_url + full_url = f"{base_url}/{npz_name}" + logger.info(f"Downloading MD17 {molecule} from {full_url}") + download.download_file(full_url, npz_path) + + # Load raw data + raw = np.load(npz_path) + self.atomic_numbers = raw["z"].astype(np.int64) # [num_atoms] + self.positions = raw["R"].astype(np.float32) # [N, num_atoms, 3] + self.energies = raw["E"].astype(np.float32) # [N, 1] or [N] + self.forces = raw["F"].astype(np.float32) # [N, num_atoms, 3] + + if self.energies.ndim == 1: + self.energies = self.energies[:, None] + + if max_samples is not None: + self.positions = self.positions[:max_samples] + self.energies = self.energies[:max_samples] + self.forces = self.forces[:max_samples] + + self.num_samples = len(self.positions) + logger.info( + f"MD17 {molecule}: {self.num_samples} snapshots, " + f"{len(self.atomic_numbers)} atoms/snapshot" + ) + + # Build and cache graphs if configured + self.graphs = None + if build_graph_cfg is not None: + graph_converter_name = build_graph_cfg.get("__class_name__", "custom") + cutoff = build_graph_cfg.get("__init_params__", {}).get("cutoff", 5) + cache_dir = osp.join( + path, + f"md17_{molecule}_cache_{graph_converter_name}_cutoff_{int(cutoff)}", + "graphs", + ) + + done_flag = osp.join(cache_dir, "completed.flag") + if cache_graphs and osp.exists(done_flag): + logger.info(f"Loading cached graphs from {cache_dir}") + self.graphs = self._load_cached_graphs(cache_dir) + else: + if dist.get_rank() == 0: + logger.info("Building graphs for MD17 dataset...") + os.makedirs(cache_dir, exist_ok=True) + converter = build_graph_converter(build_graph_cfg) + structures = self._build_structures() + self.graphs = converter(structures) + if cache_graphs: + self._save_cached_graphs(cache_dir) + with open(done_flag, "w") as f: + f.write("done") + if dist.is_initialized(): + dist.barrier() + if self.graphs is None: + self.graphs = self._load_cached_graphs(cache_dir) + + def _build_structures(self) -> list: + """Convert all snapshots to pymatgen Structures.""" + if Structure is None: + raise RuntimeError("pymatgen is required: pip install pymatgen") + + lattice = Lattice.from_parameters( + self.box_size, self.box_size, self.box_size, 90, 90, 90 + ) + species = [_Z_TO_SYMBOL.get(z, str(z)) for z in self.atomic_numbers] + + structures = [] + for i in range(self.num_samples): + coords = self.positions[i] # [num_atoms, 3] + struct = Structure( + lattice, + species, + coords, + coords_are_cartesian=True, + ) + structures.append(struct) + return structures + + def _save_cached_graphs(self, cache_dir: str) -> None: + for i, g in enumerate(self.graphs): + with open(osp.join(cache_dir, f"{i:08d}.pkl"), "wb") as f: + pickle.dump(g, f) + + def _load_cached_graphs(self, cache_dir: str) -> list: + files = sorted( + f for f in os.listdir(cache_dir) if f.endswith(".pkl") + ) + graphs = [] + for fn in files: + with open(osp.join(cache_dir, fn), "rb") as f: + graphs.append(pickle.load(f)) + return graphs + + def __len__(self) -> int: + return self.num_samples + + def __getitem__(self, idx: int) -> Dict[str, Any]: + data = {} + + if self.graphs is not None: + data["graph"] = self.graphs[idx] + else: + # Return raw data without graph (fallback) + data["pos"] = self.positions[idx] + data["atomic_numbers"] = self.atomic_numbers.copy() + data["cell"] = np.eye(3, dtype="float32") * self.box_size + data["natoms"] = len(self.atomic_numbers) + data["pbc"] = np.array([False, False, False], dtype=bool) + + # Properties + for pname in self.property_names: + if pname == "energy": + data["energy"] = self.energies[idx] + elif pname == "forces": + data["forces"] = self.forces[idx] + else: + data[pname] = self.energies[idx] + + return data diff --git a/ppmat/models/__init__.py b/ppmat/models/__init__.py index 95d73232..733154f1 100644 --- a/ppmat/models/__init__.py +++ b/ppmat/models/__init__.py @@ -42,6 +42,7 @@ from ppmat.models.megnet.megnet import MEGNetPlus from ppmat.models.infgcn.infgcn import InfGCN from ppmat.models.mateno.mateno import MatENO +from ppmat.models.newtonnet.newtonnet import NewtonNet from ppmat.utils import download from ppmat.utils import logger from ppmat.utils import save_load @@ -67,6 +68,7 @@ "DiffNMR", "InfGCN", "MatENO", + "NewtonNet", ] # Warning: The key of the dictionary must be consistent with the file name of the value diff --git a/ppmat/models/newtonnet/__init__.py b/ppmat/models/newtonnet/__init__.py new file mode 100644 index 00000000..675cf5cb --- /dev/null +++ b/ppmat/models/newtonnet/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/ppmat/models/newtonnet/newtonnet.py b/ppmat/models/newtonnet/newtonnet.py new file mode 100644 index 00000000..11fbab2f --- /dev/null +++ b/ppmat/models/newtonnet/newtonnet.py @@ -0,0 +1,743 @@ +# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +NewtonNet: Newtonian message passing network for molecular force fields. + +Adapted from the PyTorch implementation at: + https://github.com/THGLab/NewtonNet + +Reference: + Haghighatlari et al., "NewtonNet: a Newtonian message passing network + for deep learning of interatomic potentials and forces", 2022. +""" + +from typing import Optional + +import numpy as np +import paddle +import paddle.nn as nn + + +# --------------------------------------------------------------------------- +# Scatter utility (self-contained to avoid ppmat top-level import issues) +# Adapted from ppmat.utils.scatter +# --------------------------------------------------------------------------- + +def _broadcast(src: paddle.Tensor, other: paddle.Tensor, dim: int): + if dim < 0: + dim = other.ndim + dim + if src.ndim == 1: + for _ in range(0, dim): + src = src.unsqueeze(0) + for _ in range(src.ndim, other.ndim): + src = src.unsqueeze(-1) + src = src.expand(other.shape) + return src + + +def scatter( + src: paddle.Tensor, + index: paddle.Tensor, + dim: int = -1, + out: Optional[paddle.Tensor] = None, + dim_size: Optional[int] = None, + reduce: str = "sum", +) -> paddle.Tensor: + """Scatter-add (or mean) operation, compatible with torch_scatter.""" + index = _broadcast(index, src, dim) + if out is None: + size = list(src.shape) + if dim_size is not None: + size[dim] = dim_size + elif index.numel() == 0: + size[dim] = 0 + else: + size[dim] = int(index.max()) + 1 + out = paddle.zeros(size, dtype=src.dtype) + out = paddle.put_along_axis( + arr=out, indices=index, values=src, axis=dim, reduce="add" + ) + if reduce == "mean": + ones = paddle.ones(index.shape, dtype=src.dtype) + count = paddle.zeros(out.shape, dtype=src.dtype) + count = paddle.put_along_axis( + arr=count, indices=index, values=ones, axis=dim, reduce="add" + ) + count = paddle.clip(count, min=1) + out = out / count + return out + + +# --------------------------------------------------------------------------- +# Activation helpers +# --------------------------------------------------------------------------- + +def get_activation_by_string(key: str) -> nn.Layer: + """Return an activation layer from a string key.""" + activations = { + "swish": nn.Silu, + "silu": nn.Silu, + "relu": nn.ReLU, + "elu": nn.ELU, + "leaky_relu": nn.LeakyReLU, + "tanh": nn.Tanh, + "sigmoid": nn.Sigmoid, + "softplus": nn.Softplus, + "gelu": nn.GELU, + } + key_lower = key.lower() + if key_lower not in activations: + raise NotImplementedError(f"Unknown activation: {key}") + return activations[key_lower]() + + +# --------------------------------------------------------------------------- +# Representation layers +# --------------------------------------------------------------------------- + +class RadialBesselLayer(nn.Layer): + """Radial Bessel basis functions: ``sin(freq * dist) / dist``. + + Args: + n_basis (int): Number of radial basis functions. Default: 20. + """ + + def __init__(self, n_basis: int = 20): + super().__init__() + freqs = paddle.arange(1, n_basis + 1, dtype="float32") * float(np.pi) + self.register_buffer("frequencies", freqs) + + def forward(self, dist: paddle.Tensor) -> paddle.Tensor: + # dist: [E, 1] → output: [E, n_basis] + return paddle.sin(self.frequencies * dist) / dist + + +class PolynomialCutoff(nn.Layer): + """Smooth polynomial cutoff envelope. + + ``y = 1 - 0.5*(p+1)*(p+2)*x^p + p*(p+2)*x^(p+1) - 0.5*p*(p+1)*x^(p+2)`` + + Args: + p (int): Polynomial degree. Default: 9. + """ + + def __init__(self, p: int = 9): + super().__init__() + self.p = p + + def forward(self, dist: paddle.Tensor) -> paddle.Tensor: + p = self.p + x_p = dist ** p + x_p1 = x_p * dist + x_p2 = x_p1 * dist + return ( + 1.0 + - 0.5 * (p + 1) * (p + 2) * x_p + + p * (p + 2) * x_p1 + - 0.5 * p * (p + 1) * x_p2 + ) + + +class ScaledNorm(nn.Layer): + """Compute scaled distance and unit direction vector. + + Args: + r (float): Cutoff radius used for normalisation. + """ + + def __init__(self, r: float): + super().__init__() + self.r = r + + def forward(self, disp: paddle.Tensor): + """ + Args: + disp: Displacement vectors [E, 3]. + Returns: + dist: Scaled distances [E, 1]. + direction: Unit direction vectors [E, 3]. + """ + dist = paddle.norm(disp, axis=-1, keepdim=True) # [E, 1] + direction = disp / dist + dist = dist / self.r + return dist, direction + + +class RadiusGraph(nn.Layer): + """Build a radius graph from atomic positions with PBC support. + + Args: + r (float): Cutoff radius. + """ + + def __init__(self, r: float): + super().__init__() + self.r = r + + def forward(self, pos, cell=None, batch=None): + """ + Args: + pos: Atomic positions [N, 3]. + cell: Lattice vectors [B, 3, 3] or None. + batch: Batch indices [N] or None. + Returns: + edge_index: [2, E] source/target indices. + disp: Displacement vectors [E, 3]. + """ + n_node = pos.shape[0] + + # Build per-molecule full graph (excluding self-loops) + if batch is not None: + unique_batches = paddle.unique(batch) + src_list, dst_list = [], [] + for b in unique_batches: + mask = (batch == b) + nodes = paddle.nonzero(mask).flatten() + n = nodes.shape[0] + # Create all pairs + row = nodes.unsqueeze(1).expand([n, n]).flatten() + col = nodes.unsqueeze(0).expand([n, n]).flatten() + src_list.append(row) + dst_list.append(col) + src_all = paddle.concat(src_list) + dst_all = paddle.concat(dst_list) + edge_index = paddle.stack([src_all, dst_all], axis=0) + else: + idx = paddle.arange(n_node, dtype="int64") + row = idx.unsqueeze(1).expand([n_node, n_node]).flatten() + col = idx.unsqueeze(0).expand([n_node, n_node]).flatten() + edge_index = paddle.stack([row, col], axis=0) + + # Remove self-loops + non_self = edge_index[0] != edge_index[1] + edge_index = edge_index[:, non_self] + + # Displacement vectors + disp = pos[edge_index[0]] - pos[edge_index[1]] + + # Apply minimum-image convention for periodic boundary conditions + if cell is not None and not paddle.all(cell == 0.0): + if batch is not None: + cell_per_node = cell[batch] + else: + cell_per_node = cell.expand([n_node, 3, 3]) + cell_per_edge = cell_per_node[edge_index[0]] # [E, 3, 3] + # Solve for fractional coordinates: cell^T @ s = disp + cell_t = paddle.transpose(cell_per_edge, perm=[0, 2, 1]) # [E, 3, 3] + scaled = paddle.linalg.solve(cell_t, disp.unsqueeze(-1)).squeeze(-1) + # Detach before round: round() has zero gradient anyway, and + # solve backward segfaults on CPU in some Paddle versions. + disp = disp - paddle.bmm( + cell_per_edge, paddle.round(scaled.detach()).unsqueeze(-1) + ).squeeze(-1) + + # Filter by cutoff distance + dist_sq = (disp * disp).sum(axis=-1) + mask = dist_sq < self.r * self.r + edge_index = edge_index[:, mask] + disp = disp[mask] + + return edge_index, disp + + +class EdgeEmbedding(nn.Layer): + """Edge embedding combining RadiusGraph, ScaledNorm, PolynomialCutoff, and RadialBessel. + + Args: + cutoff (float): Cutoff radius. + n_basis (int): Number of radial basis functions. + """ + + def __init__(self, cutoff: float, n_basis: int = 20): + super().__init__() + self.radius_graph = RadiusGraph(r=cutoff) + self.norm = ScaledNorm(r=cutoff) + self.envelope = PolynomialCutoff(p=9) + self.embedding = RadialBesselLayer(n_basis=n_basis) + + def forward(self, pos, cell=None, batch=None): + edge_index, disp = self.radius_graph(pos, cell=cell, batch=batch) + dist_edge, dir_edge = self.norm(disp) + dist_edge = self.envelope(dist_edge) * self.embedding(dist_edge) + return dist_edge, dir_edge, edge_index + + +# --------------------------------------------------------------------------- +# Core network components +# --------------------------------------------------------------------------- + +class EmbeddingNet(nn.Layer): + """Initial atom and edge embedding layer. + + Args: + cutoff (float): Cutoff radius for edge embedding. + n_features (int): Feature dimension. + n_basis (int): Number of radial basis functions. + """ + + def __init__(self, cutoff: float, n_features: int, n_basis: int): + super().__init__() + self.n_features = n_features + self.node_embedding = nn.Embedding(118 + 1, n_features, padding_idx=0) + self.edge_embedding = EdgeEmbedding(cutoff=cutoff, n_basis=n_basis) + self.requires_dr = False + + def forward(self, z, pos, cell, batch): + # Node embedding + atom_node = self.node_embedding(z) # [N, F] + force_node = paddle.zeros( + [z.shape[0], 3, self.n_features], dtype=pos.dtype + ) # [N, 3, F] + + # Strain displacement for virial/stress (identity by default) + displacement = paddle.zeros_like(cell) + displacement[:, 0, 0] = 1.0 + displacement[:, 1, 1] = 1.0 + displacement[:, 2, 2] = 1.0 + + if self.requires_dr: + pos.stop_gradient = False + displacement.stop_gradient = False + + symmetric_displacement = ( + displacement + paddle.transpose(displacement, perm=[0, 2, 1]) + ) / 2.0 + # Apply strain to positions: pos_displaced = pos @ symmetric_displacement + pos_displaced = paddle.bmm( + pos.unsqueeze(1), symmetric_displacement[batch] + ).squeeze(1) # [N, 3] + cell_displaced = paddle.bmm( + cell, symmetric_displacement + ).squeeze(1) # [B, 3, 3] (squeeze does nothing if already [B,3,3]) + + # Edge embedding + dist_edge, dir_edge, edge_index = self.edge_embedding( + pos_displaced, cell_displaced, batch + ) + + return atom_node, force_node, dir_edge, dist_edge, edge_index, displacement + + +class InteractionNet(nn.Layer): + """Newtonian message passing interaction layer. + + Performs both invariant (scalar) and equivariant (3D vector) message passing. + + Args: + n_features (int): Feature dimension. + n_basis (int): Number of radial basis functions. + activation (nn.Layer): Activation function instance. + layer_norm (bool): Whether to apply LayerNorm to atom features. + """ + + def __init__( + self, + n_features: int, + n_basis: int, + activation: nn.Layer, + layer_norm: bool, + ): + super().__init__() + self.n_features = n_features + + # Invariant message passing + self.message_nodepart = nn.Sequential( + nn.Linear(n_features, n_features), + activation, + nn.Linear(n_features, n_features), + ) + self.message_edgepart = nn.Linear(n_basis, n_features, bias_attr=False) + + # Equivariant message networks + self.equiv_message1 = nn.Sequential( + nn.Linear(n_features, n_features, bias_attr=False), + activation, + nn.Linear(n_features, n_features, bias_attr=False), + ) + self.equiv_message2 = nn.Sequential( + nn.Linear(n_features, n_features, bias_attr=False), + activation, + nn.Linear(n_features, n_features, bias_attr=False), + ) + + # Force → energy update + self.equiv_update = nn.Linear(n_features, n_features, bias_attr=False) + + # Optional layer norm + self.layer_norm = nn.LayerNorm(n_features) if layer_norm else None + + def forward(self, atom_node, force_node, dir_edge, dist_edge, edge_index): + """ + Args: + atom_node: [N, F] + force_node: [N, 3, F] + dir_edge: [E, 3] + dist_edge: [E, n_basis] + edge_index: [2, E] (row=src, col=dst) + Returns: + Updated atom_node [N, F] and force_node [N, 3, F]. + """ + src, dst = edge_index[0], edge_index[1] + + # --- Invariant message --- + message_nodepart = self.message_nodepart(atom_node) # [N, F] + message_edgepart = self.message_edgepart(dist_edge) # [E, F] + message = ( + message_edgepart + * message_nodepart[src] + * message_nodepart[dst] + ) # [E, F] + + inv_update = scatter( + message, src, dim=0, dim_size=atom_node.shape[0] + ) # [N, F] + atom_node = atom_node + inv_update + + # --- Equivariant message 1: direction-weighted --- + equiv_msg1_inv = self.equiv_message1(message).unsqueeze(1) # [E, 1, F] + equiv_msg1_eq = dir_edge.unsqueeze(2) # [E, 3, 1] + equiv_msg1 = equiv_msg1_inv * equiv_msg1_eq # [E, 3, F] + + # --- Equivariant message 2: neighbor force --- + equiv_msg2_inv = self.equiv_message2(message).unsqueeze(1) # [E, 1, F] + equiv_msg2_eq = force_node[dst] # [E, 3, F] + equiv_msg2 = equiv_msg2_inv * equiv_msg2_eq # [E, 3, F] + + force_update = scatter( + equiv_msg1 + equiv_msg2, src, dim=0, dim_size=force_node.shape[0] + ) # [N, 3, F] + force_node = force_node + force_update + + # --- Energy update from force (dot product over xyz) --- + inv_update2 = paddle.sum( + force_node * self.equiv_update(force_node), axis=1 + ) # [N, F] + atom_node = atom_node + inv_update2 + + # --- Layer norm --- + if self.layer_norm is not None: + atom_node = self.layer_norm(atom_node) + + return atom_node, force_node + + +# --------------------------------------------------------------------------- +# Output layers +# --------------------------------------------------------------------------- + +class EnergyOutput(nn.Layer): + """Per-atom energy prediction via MLP. + + Args: + n_features (int): Feature dimension. + activation (nn.Layer): Activation function instance. + """ + + def __init__(self, n_features: int, activation: nn.Layer): + super().__init__() + self.layers = nn.Sequential( + nn.Linear(n_features, n_features), + activation, + nn.Linear(n_features, n_features), + activation, + nn.Linear(n_features, 1), + ) + + def forward(self, atom_node: paddle.Tensor) -> paddle.Tensor: + """Return per-atom energy [N, 1].""" + return self.layers(atom_node) + + +class DirectForceOutput(nn.Layer): + """Direct force prediction from atom features and equivariant force node. + + Args: + n_features (int): Feature dimension. + activation (nn.Layer): Activation function instance. + """ + + def __init__(self, n_features: int, activation: nn.Layer): + super().__init__() + self.layers = nn.Sequential( + nn.Linear(n_features, n_features), + activation, + nn.Linear(n_features, n_features), + activation, + nn.Linear(n_features, n_features), + ) + + def forward( + self, atom_node: paddle.Tensor, force_node: paddle.Tensor + ) -> paddle.Tensor: + """Return forces [N, 3].""" + weight = self.layers(atom_node).unsqueeze(1) # [N, 1, F] + force = weight * force_node # [N, 3, F] + return force.sum(axis=-1) # [N, 3] + + +class ScaleShift(nn.Layer): + """Per-element scale and shift using atomic-number embeddings. + + Args: + scale (bool): Whether to apply scaling. + shift (bool): Whether to apply shifting. + """ + + def __init__(self, scale: bool = True, shift: bool = True): + super().__init__() + if scale: + self.scale = nn.Embedding(119, 1, padding_idx=0) + # Initialize scale to 1 + with paddle.no_grad(): + self.scale.weight.set_value( + paddle.ones_like(self.scale.weight) + ) + else: + self.scale = None + if shift: + self.shift = nn.Embedding(119, 1, padding_idx=0) + # Initialize shift to 0 (default) + else: + self.shift = None + + def forward(self, output, z): + if self.scale is not None: + output = output * self.scale(z) + if self.shift is not None: + output = output + self.shift(z) + return output + + +# --------------------------------------------------------------------------- +# Main model +# --------------------------------------------------------------------------- + +class NewtonNet(nn.Layer): + """Newtonian message passing network for molecular force fields. + + Follows PaddleMaterials conventions with ``forward()`` returning + ``{"loss_dict": ..., "pred_dict": ...}``. + + Args: + cutoff (float): Cutoff radius (Å). Default: 5.0. + n_features (int): Hidden feature dimension. Default: 128. + n_basis (int): Number of radial basis functions. Default: 20. + n_interactions (int): Number of message passing layers. Default: 3. + activation (str): Activation function name. Default: ``"swish"``. + layer_norm (bool): Apply LayerNorm after each interaction. Default: False. + property_names (str): Target property name. Default: ``"energy"``. + data_mean (float): Mean for target normalisation. Default: 0.0. + data_std (float): Std for target normalisation. Default: 1.0. + loss_type (str): ``"mse_loss"`` or ``"l1_loss"``. Default: ``"mse_loss"``. + force_loss_weight (float): Weight for force loss relative to energy loss. + Default: 100.0. + """ + + def __init__( + self, + cutoff: float = 5.0, + n_features: int = 128, + n_basis: int = 20, + n_interactions: int = 3, + activation: str = "swish", + layer_norm: bool = False, + property_names: str = "energy", + data_mean: float = 0.0, + data_std: float = 1.0, + loss_type: str = "mse_loss", + force_loss_weight: float = 100.0, + ): + super().__init__() + + if isinstance(property_names, list): + self.property_names = property_names[0] + else: + self.property_names = property_names + + self.register_buffer("data_mean", paddle.to_tensor(data_mean, dtype="float32")) + self.register_buffer("data_std", paddle.to_tensor(data_std, dtype="float32")) + + act = get_activation_by_string(activation) + + # Embedding + self.embedding_layer = EmbeddingNet( + cutoff=cutoff, + n_features=n_features, + n_basis=n_basis, + ) + + # Interaction layers + self.interaction_layers = nn.LayerList( + [ + InteractionNet( + n_features=n_features, + n_basis=n_basis, + activation=get_activation_by_string(activation), + layer_norm=layer_norm, + ) + for _ in range(n_interactions) + ] + ) + + # Energy output + self.energy_output = EnergyOutput( + n_features, get_activation_by_string(activation) + ) + + # Per-element energy scale/shift + self.energy_scaler = ScaleShift(scale=True, shift=True) + + # Loss + self.force_loss_weight = force_loss_weight + + # Loss + if loss_type == "mse_loss": + self.loss_fn = nn.functional.mse_loss + elif loss_type == "l1_loss": + self.loss_fn = nn.functional.l1_loss + else: + raise ValueError(f"Unknown loss type: {loss_type}") + + # ------------------------------------------------------------------ + # Normalisation helpers + # ------------------------------------------------------------------ + def normalize(self, tensor: paddle.Tensor) -> paddle.Tensor: + return (tensor - self.data_mean) / self.data_std + + def unnormalize(self, tensor: paddle.Tensor) -> paddle.Tensor: + return tensor * self.data_std + self.data_mean + + # ------------------------------------------------------------------ + # Forward + # ------------------------------------------------------------------ + def _forward(self, data: dict, compute_forces: bool = False): + """Core forward pass returning per-molecule energy and optional forces. + + Args: + data: Dict with keys ``z``, ``pos``, ``batch``, ``cell`` (optional). + compute_forces: If True, compute forces as negative energy gradient. + Returns: + Tuple of (energy [B], forces [N, 3] or None). + """ + z = data["z"] + pos = data["pos"] + batch = data["batch"] + cell = data.get("cell", None) + + if compute_forces: + pos.stop_gradient = False + + if cell is None: + n_batch = int(batch.max().item()) + 1 + cell = paddle.zeros([n_batch, 3, 3], dtype=pos.dtype) + + # Embedding + atom_node, force_node, dir_edge, dist_edge, edge_index, displacement = ( + self.embedding_layer(z, pos, cell, batch) + ) + + # Message passing + for interaction in self.interaction_layers: + atom_node, force_node = interaction( + atom_node, force_node, dir_edge, dist_edge, edge_index + ) + + # Per-atom energy + energy_per_atom = self.energy_output(atom_node) # [N, 1] + energy_per_atom = self.energy_scaler(energy_per_atom, z) # [N, 1] + + # Compute forces as F = -dE/dpos (in physical units) + forces = None + if compute_forces: + grad_result = paddle.grad( + outputs=energy_per_atom.sum(), + inputs=pos, + create_graph=self.training, + retain_graph=True, + )[0] + forces = -grad_result * self.data_std + + # Aggregate per molecule + energy = scatter( + energy_per_atom, batch, dim=0, dim_size=int(batch.max().item()) + 1 + ).reshape([-1]) # [B] + + return energy, forces + + def forward( + self, + data: dict, + return_loss: bool = True, + return_prediction: bool = True, + ) -> dict: + """PaddleMaterials standard forward. + + Args: + data: Input data dict. + return_loss: Whether to compute loss. + return_prediction: Whether to return predictions. + Returns: + Dict with ``loss_dict`` and ``pred_dict``. + """ + assert ( + return_loss or return_prediction + ), "At least one of return_loss or return_prediction must be True." + + compute_forces = "forces" in data or return_prediction + energy, forces = self._forward(data, compute_forces=compute_forces) + + loss_dict = {} + if return_loss: + label = data[self.property_names] + label = self.normalize(label) + energy_loss = self.loss_fn(input=energy, label=label) + + total_loss = energy_loss + if "forces" in data and forces is not None: + force_loss = self.loss_fn(input=forces, label=data["forces"]) + loss_dict["force_loss"] = force_loss + total_loss = energy_loss + self.force_loss_weight * force_loss + loss_dict["loss"] = total_loss + + prediction = {} + if return_prediction: + prediction[self.property_names] = self.unnormalize(energy) + if forces is not None: + prediction["forces"] = forces + + return {"loss_dict": loss_dict, "pred_dict": prediction} + + def predict(self, data: dict, compute_forces: bool = True) -> dict: + """Predict energy and optionally forces. + + Args: + data: Input data dict. + compute_forces: Whether to compute forces. Default: True. + Returns: + Dict mapping property name to predicted value, plus ``"forces"`` + when *compute_forces* is True. + """ + if compute_forces: + energy, forces = self._forward(data, compute_forces=True) + energy = self.unnormalize(energy) + result = {self.property_names: energy.detach()} + if forces is not None: + result["forces"] = forces.detach() + return result + else: + with paddle.no_grad(): + energy, _ = self._forward(data, compute_forces=False) + energy = self.unnormalize(energy) + return {self.property_names: energy} diff --git a/test/newtonnet/__init__.py b/test/newtonnet/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/newtonnet/conftest.py b/test/newtonnet/conftest.py new file mode 100644 index 00000000..a58a718f --- /dev/null +++ b/test/newtonnet/conftest.py @@ -0,0 +1,23 @@ +# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Conftest for NewtonNet tests — stubs heavy dependencies for CPU testing.""" + +import sys +import types + +# Stub pgl (PaddlePaddle Graph Learning) — not needed for unit tests +pgl_stub = types.ModuleType("pgl") +pgl_stub.Graph = type("Graph", (), {}) +sys.modules.setdefault("pgl", pgl_stub) diff --git a/test/newtonnet/raw_infer_data/__init__.py b/test/newtonnet/raw_infer_data/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/newtonnet/raw_infer_data/create_input_output_npz.py b/test/newtonnet/raw_infer_data/create_input_output_npz.py new file mode 100644 index 00000000..c18bd567 --- /dev/null +++ b/test/newtonnet/raw_infer_data/create_input_output_npz.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +"""Generate reference I/O arrays for NewtonNet regression testing. + +Equivalent PyTorch code (for cross-framework comparison): + import torch, numpy as np + torch.manual_seed(42); np.random.seed(42) + # Build identical NewtonNet with PyTorch (cutoff=5.0, n_features=32, + # n_basis=8, n_interactions=2, activation="swish"), create water + # molecule input (H2O), run forward pass, save energy output. + # np.savez("reference_io.npz", energy=energy, loss=loss) + +This script uses the Paddle implementation to create a deterministic +reference snapshot. Re-run only when the model architecture intentionally +changes. +""" + +import importlib.util +import os + +import numpy as np +import paddle + +_module_path = os.path.abspath( + os.path.join( + os.path.dirname(__file__), + "..", "..", "..", + "ppmat", "models", "newtonnet", "newtonnet.py", + ) +) +_spec = importlib.util.spec_from_file_location("newtonnet_module", _module_path) +_mod = importlib.util.module_from_spec(_spec) +_spec.loader.exec_module(_mod) +NewtonNet = _mod.NewtonNet + + +def main(): + paddle.seed(42) + np.random.seed(42) + model = NewtonNet( + cutoff=5.0, n_features=32, n_basis=8, + n_interactions=2, activation="swish", + layer_norm=False, property_names="energy", + data_mean=0.0, data_std=1.0, loss_type="mse_loss", + ) + model.eval() + + data = { + "z": paddle.to_tensor([8, 1, 1], dtype="int64"), + "pos": paddle.to_tensor( + [[0.0, 0.0, 0.1173], + [0.0, 0.7572, -0.4692], + [0.0, -0.7572, -0.4692]], + dtype="float32", + ), + "batch": paddle.zeros([3], dtype="int64"), + "cell": paddle.eye(3, dtype="float32").unsqueeze(0) * 10.0, + "energy": paddle.to_tensor([-76.4], dtype="float32"), + } + + result = model(data, return_loss=True, return_prediction=True) + energy = result["pred_dict"]["energy"].numpy() + loss = result["loss_dict"]["loss"].numpy() + + out_path = os.path.join(os.path.dirname(__file__), "reference_io.npz") + np.savez(out_path, energy=energy, loss=loss) + print(f"Saved reference to {out_path}") + print(f" energy shape={energy.shape}, values={energy}") + print(f" loss={loss}") + + +if __name__ == "__main__": + main() diff --git a/test/newtonnet/raw_infer_data/reference_io.npz b/test/newtonnet/raw_infer_data/reference_io.npz new file mode 100644 index 0000000000000000000000000000000000000000..959b29a55b1eb1a1a19db238bb8694cb91e85b94 GIT binary patch literal 514 zcmWIWW@gc4fB;1Xvk#gN|3d*6g9t-vUTRT#rCwe^B_o3XLkmKhQr$WX>m zt)7xvoLr=CrJ!z;W}>d6pq`drR8o|f7oT60k_r-cOUx-w1&SAEBo?Fs`5J~gnmP)# z3KRgYCC}&X4M1^!s^=bcnEN?^?$60DE~bg=DRsMo0#`NXHrD`eMkZZm)bIy|E(mi$ uLmNajFoH-#Y@q7{`5UH>1EdrR8W;}%S+GzD@MdKLNiYFn9+0jBn+gB~1#J-k literal 0 HcmV?d00001 diff --git a/test/newtonnet/test_loss/__init__.py b/test/newtonnet/test_loss/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/newtonnet/test_loss/test_model_loss_with_raw.py b/test/newtonnet/test_loss/test_model_loss_with_raw.py new file mode 100644 index 00000000..5fb515fb --- /dev/null +++ b/test/newtonnet/test_loss/test_model_loss_with_raw.py @@ -0,0 +1,262 @@ +# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests for NewtonNet forward pass, loss computation, and prediction structure.""" + +import importlib.util +import os +import unittest + +import numpy as np +import paddle + +# Load the module directly from its file path to avoid ppmat/__init__.py +# which requires pgl (PaddleGraphLearning) not available in this env. +_module_path = os.path.join( + os.path.dirname(__file__), + "..", "..", "..", + "ppmat", "models", "newtonnet", "newtonnet.py", +) +_module_path = os.path.abspath(_module_path) +_spec = importlib.util.spec_from_file_location("newtonnet_module", _module_path) +_mod = importlib.util.module_from_spec(_spec) +_spec.loader.exec_module(_mod) +NewtonNet = _mod.NewtonNet + + +class TestNewtonNetForwardAlignment(unittest.TestCase): + """Test NewtonNet forward pass alignment and basic functionality.""" + + def setUp(self): + paddle.seed(42) + self.model = NewtonNet( + cutoff=5.0, + n_features=32, + n_basis=8, + n_interactions=2, + activation="swish", + layer_norm=False, + property_names="energy", + data_mean=0.0, + data_std=1.0, + loss_type="mse_loss", + ) + self.model.eval() + + def _create_water_molecule_data(self): + """Create a single water molecule (H2O) test input.""" + z = paddle.to_tensor([8, 1, 1], dtype="int64") # O, H, H + pos = paddle.to_tensor( + [ + [0.0000, 0.0000, 0.1173], + [0.0000, 0.7572, -0.4692], + [0.0000, -0.7572, -0.4692], + ], + dtype="float32", + ) + batch = paddle.zeros([3], dtype="int64") + cell = paddle.eye(3, dtype="float32").unsqueeze(0) * 10.0 + energy = paddle.to_tensor([-76.4], dtype="float32") + return { + "z": z, + "pos": pos, + "batch": batch, + "cell": cell, + "energy": energy, + } + + def _create_two_molecule_batch(self): + """Create a batch with two molecules: H2O and H2.""" + z = paddle.to_tensor([8, 1, 1, 1, 1], dtype="int64") + pos = paddle.to_tensor( + [ + [0.0, 0.0, 0.1173], + [0.0, 0.7572, -0.4692], + [0.0, -0.7572, -0.4692], + [5.0, 0.0, 0.0], + [5.0, 0.74, 0.0], + ], + dtype="float32", + ) + batch = paddle.to_tensor([0, 0, 0, 1, 1], dtype="int64") + cell = paddle.eye(3, dtype="float32").unsqueeze(0).expand([2, 3, 3]) * 10.0 + energy = paddle.to_tensor([-76.4, -1.17], dtype="float32") + return { + "z": z, + "pos": pos, + "batch": batch, + "cell": cell, + "energy": energy, + } + + def test_forward_shape(self): + """Verify output shapes from forward pass.""" + data = self._create_water_molecule_data() + result = self.model(data, return_loss=True, return_prediction=True) + + self.assertIn("loss_dict", result) + self.assertIn("pred_dict", result) + self.assertIn("loss", result["loss_dict"]) + self.assertIn("energy", result["pred_dict"]) + + loss = result["loss_dict"]["loss"] + energy = result["pred_dict"]["energy"] + self.assertEqual(loss.shape, []) # scalar + self.assertEqual(energy.shape, [1]) # one molecule + + def test_forward_shape_batch(self): + """Verify shapes for a two-molecule batch.""" + data = self._create_two_molecule_batch() + result = self.model(data, return_loss=True, return_prediction=True) + + energy = result["pred_dict"]["energy"] + self.assertEqual(energy.shape, [2]) + + def test_forward_determinism(self): + """Two forward passes with the same input must produce identical results.""" + data = self._create_water_molecule_data() + r1 = self.model(data, return_loss=False, return_prediction=True) + r2 = self.model(data, return_loss=False, return_prediction=True) + np.testing.assert_allclose( + r1["pred_dict"]["energy"].numpy(), + r2["pred_dict"]["energy"].numpy(), + rtol=1e-6, + ) + + def test_loss_computation(self): + """Loss should be a finite positive scalar.""" + data = self._create_water_molecule_data() + result = self.model(data, return_loss=True, return_prediction=False) + + loss = result["loss_dict"]["loss"] + self.assertEqual(loss.shape, []) + self.assertTrue(paddle.isfinite(loss).item()) + self.assertGreaterEqual(loss.item(), 0.0) + + def test_energy_prediction_structure(self): + """Predicted energy must be finite and return the correct key.""" + data = self._create_water_molecule_data() + result = self.model(data, return_loss=False, return_prediction=True) + + self.assertIn("energy", result["pred_dict"]) + energy = result["pred_dict"]["energy"] + self.assertTrue(paddle.isfinite(energy).all().item()) + + def test_predict_method(self): + """The convenience ``predict()`` method should return a dict with energy.""" + data = self._create_water_molecule_data() + pred = self.model.predict(data) + self.assertIn("energy", pred) + self.assertEqual(pred["energy"].shape, [1]) + self.assertTrue(paddle.isfinite(pred["energy"]).all().item()) + + def test_force_computation(self): + """Forces are computed as negative energy gradient.""" + data = self._create_water_molecule_data() + data["pos"].stop_gradient = False + result = self.model(data, return_loss=False, return_prediction=True) + forces = result["pred_dict"]["forces"] + self.assertEqual(list(forces.shape), [data["pos"].shape[0], 3]) + self.assertTrue(paddle.isfinite(forces).all().item()) + + def test_energy_force_consistency(self): + """Forces should approximate the negative finite-difference gradient.""" + data = self._create_water_molecule_data() + pos = data["pos"].clone() + pos.stop_gradient = False + data["pos"] = pos + result = self.model(data, return_loss=False, return_prediction=True) + pred_forces = result["pred_dict"]["forces"] + + # Verify via finite differences + eps = 1e-3 + n_atoms = pos.shape[0] + fd_forces = paddle.zeros([n_atoms, 3], dtype="float32") + for i in range(n_atoms): + for j in range(3): + data_p = self._create_water_molecule_data() + data_p["pos"] = data_p["pos"].clone() + data_p["pos"][i, j] += eps + e_p = self.model( + data_p, return_loss=False, return_prediction=True + )["pred_dict"]["energy"] + + data_m = self._create_water_molecule_data() + data_m["pos"] = data_m["pos"].clone() + data_m["pos"][i, j] -= eps + e_m = self.model( + data_m, return_loss=False, return_prediction=True + )["pred_dict"]["energy"] + + fd_forces[i, j] = -(e_p.sum() - e_m.sum()) / (2 * eps) + + np.testing.assert_allclose( + pred_forces.detach().numpy(), fd_forces.numpy(), atol=5e-2 + ) + + def test_force_loss(self): + """Forward pass with force targets computes force loss.""" + data = self._create_water_molecule_data() + data["forces"] = paddle.randn(data["pos"].shape) + data["pos"].stop_gradient = False + result = self.model(data, return_loss=True, return_prediction=True) + self.assertIn("force_loss", result["loss_dict"]) + self.assertTrue(result["loss_dict"]["force_loss"].item() > 0) + + def test_normalize_unnormalize_roundtrip(self): + """normalize → unnormalize should recover the original value.""" + model = NewtonNet(data_mean=-76.0, data_std=10.0) + original = paddle.to_tensor([-76.4], dtype="float32") + normalized = model.normalize(original) + recovered = model.unnormalize(normalized) + np.testing.assert_allclose( + recovered.numpy(), original.numpy(), rtol=1e-5 + ) + + def test_no_cell_input(self): + """Model should work when cell is not provided.""" + data = self._create_water_molecule_data() + del data["cell"] + result = self.model(data, return_loss=False, return_prediction=True) + energy = result["pred_dict"]["energy"] + self.assertEqual(energy.shape, [1]) + self.assertTrue(paddle.isfinite(energy).all().item()) + + def test_training_convergence(self): + """Verify loss decreases over 2 training epochs (RFC requirement).""" + self.model.train() + optimizer = paddle.optimizer.Adam( + parameters=self.model.parameters(), learning_rate=1e-3 + ) + losses = [] + for epoch in range(2): + optimizer.clear_grad() + data = self._create_water_molecule_data() + result = self.model(data, return_loss=True, return_prediction=False) + loss = result["loss_dict"]["loss"] + loss.backward() + optimizer.step() + losses.append(loss.item()) + self.assertTrue( + np.isfinite(losses[-1]), f"Loss became non-finite: {losses}" + ) + self.assertLess( + losses[-1], + losses[0] * 1.5, + f"Loss increased significantly: {losses}", + ) + + +if __name__ == "__main__": + unittest.main()