Skip to content

Commit b89fa6d

Browse files
authored
Merge pull request #18 from zirenjin/master
fix convert() api and glob format
2 parents 2767008 + b904848 commit b89fa6d

11 files changed

Lines changed: 355 additions & 441 deletions

File tree

doc/dpa_adapt/README.md

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ model.fit(train_data="/data/qm9", aux_data="/data/spice2")
5454
## Data preparation
5555

5656
DPA-ADAPT trains on `deepmd/npy` data. Use `dpa-adapt data convert` (or the Python
57-
`auto_convert` helper) to route common inputs into the right conversion pipeline:
57+
`convert` helper) to route common inputs into the right conversion pipeline:
5858

5959
- **SMILES CSV**: a `.csv` file with a `SMILES`/`smiles` column. RDKit generates 3D
6060
conformers, or existing `.mol`/`.sdf`/`.xyz`/`.pdb` files can be supplied with
@@ -67,19 +67,19 @@ DPA-ADAPT trains on `deepmd/npy` data. Use `dpa-adapt data convert` (or the Pyth
6767
inputs.
6868

6969
```python
70-
from dpa_adapt import auto_convert
70+
from dpa_adapt import convert
7171

7272
# Structure file / trajectory → dpdata → deepmd/npy
73-
auto_convert("POSCAR", "./npy")
74-
auto_convert("OUTCAR", "./npy", fmt="vasp/outcar")
75-
auto_convert("traj.extxyz", "./npy", fmt="extxyz")
73+
convert("POSCAR", "./npy")
74+
convert("OUTCAR", "./npy", fmt="vasp/outcar")
75+
convert("traj.extxyz", "./npy", fmt="extxyz")
7676

7777
# Glob patterns: one match is converted as one system; multiple matches are batched.
78-
auto_convert("calcs/**/OUTCAR", "./npy_root", fmt="vasp/outcar")
78+
convert("calcs/**/OUTCAR", "./npy_root", fmt="vasp/outcar")
7979

8080
# CSV with a SMILES column → RDKit 3D conformers → deepmd/npy.
8181
# property_col names the input target column and output label name.
82-
auto_convert(
82+
convert(
8383
"molecules.csv",
8484
"./npy",
8585
fmt="smiles", # optional when a SMILES/smiles column is present
@@ -89,7 +89,7 @@ auto_convert(
8989
)
9090

9191
# CSV + pre-generated molecular structures: skip RDKit conformer generation.
92-
auto_convert(
92+
convert(
9393
"molecules.csv",
9494
"./npy",
9595
fmt="smiles",
@@ -103,7 +103,7 @@ auto_convert(
103103
# CSV: header required; defaults are formula_col="formula" and property_col="Property".
104104
# e.g. formula,Property
105105
# Ni0.65Gd0.15Fe0.10Co0.05Yb0.05O2H1,291.9
106-
auto_convert(
106+
convert(
107107
"compositions.csv",
108108
"./npy",
109109
fmt="formula",
@@ -134,10 +134,10 @@ dpa-adapt data convert --input "calcs/**/OUTCAR" --output ./npy_root --fmt vasp/
134134
Lower-level helpers:
135135

136136
```python
137-
from dpa_adapt import convert, batch_convert, attach_labels, check_data
137+
from dpa_adapt import convert, attach_labels, check_data
138138

139139
convert("OUTCAR", "./npy", fmt="vasp/outcar")
140-
batch_convert("calcs/**/OUTCAR", "./npy_root", fmt="vasp/outcar")
140+
convert("calcs/**/OUTCAR", "./npy_root", fmt="vasp/outcar")
141141
attach_labels(system, head="bandgap", values=np.array([1.0, 2.0, 3.0]))
142142
check_data("/data/system") # → list[Issue]
143143
```
@@ -216,11 +216,9 @@ from dpa_adapt import (
216216
extract_descriptors, # standalone descriptor extraction
217217
cross_validate, # leak-proof cross-validation
218218
train_test_split, # formula-grouped splitting
219-
auto_convert, # format-sniffing data conversion
219+
convert, # format-sniffing data conversion
220220
smiles_to_npy, # CSV+SMILES → deepmd/npy
221221
formula_to_npy, # composition formula CSV + POSCAR → deepmd/npy
222-
convert, # structure file → deepmd/npy
223-
batch_convert, # glob-based batch conversion
224222
check_data, # data sanity checks
225223
attach_labels, # inject label arrays
226224
load_dataset, # label-filtered data loading

doc/dpa_adapt/input_formats.md

Lines changed: 38 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
> **Optional short alias:** `dpaad`
77
> **Display name:** DPA-ADAPT — Atomistic DPA Adaptation for Property Tasks
88
9-
`dpa-adapt data convert` auto-detects the input type and routes it to the correct pipeline:
9+
`dpa-adapt data convert` and the Python `dpa_adapt.convert()` helper
10+
auto-detect the input type and route it to the correct pipeline:
1011
**SMILES table** → RDKit 3D conformer generation,
1112
**formula table** → random doping from a POSCAR template,
1213
**structure files** → dpdata (auto-detect or explicit `--fmt`).
@@ -45,19 +46,30 @@ dpaad data convert --input data.csv --output ./npy --fmt smiles \
4546
--split-seed 42 --conformer-seed 43
4647
```
4748

48-
## 2. Formula Tables (CSV + POSCAR Template)
49+
## 2. Formula Tables (CSV/TXT + POSCAR Template)
4950

50-
**Trigger:** `--fmt formula`. Reads a CSV of elemental composition formulas
51-
(e.g. `Ni0.65Gd0.15O2H1`) and a template POSCAR, then generates doped structures
52-
by randomly substituting atoms on the host-element sublattice.
51+
**Trigger:** `--fmt formula`. Reads a table of elemental composition formulas
52+
(e.g. `Ni0.65Gd0.15O2H1`) and a template POSCAR, then generates doped
53+
structures by randomly substituting atoms on the host-element sublattice.
54+
55+
Formula input supports two table styles:
56+
57+
- Headered CSV/TSV: comma- or tab-delimited with named columns, such as
58+
`formula,Property`.
59+
- Headered delimited text: comma, tab, semicolon, or pipe (`|`) delimiters
60+
with named columns.
61+
- Headerless delimited or whitespace rows: use integer column indices, such as
62+
`Ni0.65Gd0.15Fe0.10Co0.05Yb0.05O2H1 291.9` or
63+
`Ni0.65Gd0.15Fe0.10Co0.05Yb0.05O2H1|291.9`.
5364

5465
| Parameter | Default | Description |
5566
|-----------|---------|-------------|
5667
| `--poscar` | *(required)* | Template POSCAR file for the host lattice |
57-
| `--formula-col` | `formula` | Input CSV column name to read composition formulas from |
68+
| `--formula-col` | `formula` | Input table column to read composition formulas from; use a column name for headered files or a 0-based index for headerless whitespace files |
5869
| `--base-element` | auto | Host element to substitute. Inferred as the most frequent non-O/H element in the template if omitted. |
5970
| `--sets` | `1` | Number of random structures generated per formula row |
60-
| `--property-col` | `Property` | Input CSV column name to read target values from; also used as the output label name |
71+
| `--property-col` | `Property` | Input table column to read target values from; use a column name for headered files or a 0-based index for headerless whitespace files |
72+
| `--property-name` | value of `--property-col` | Output label name written as `set.*/{property_name}.npy` |
6173
| `--seed` | `42` | Random seed for selecting substituted host-atom sites |
6274

6375
```bash
@@ -68,6 +80,15 @@ dpa-adapt data convert --input compositions.csv --output ./npy --fmt formula \
6880
dpaad data convert --input compositions.csv --output ./npy --fmt formula \
6981
--poscar template.POSCAR --sets 3 \
7082
--formula-col formula --property-col bandgap
83+
84+
# Headerless whitespace-delimited TXT: formula in column 0, target in column 1
85+
dpa-adapt data convert --input 20260514.txt --output ./npy --fmt formula \
86+
--poscar template.POSCAR --formula-col 0 --property-col 1 \
87+
--property-name overpotential
88+
89+
# Headerless pipe-delimited TXT works the same way
90+
dpa-adapt data convert --input compositions.txt --output ./npy --fmt formula \
91+
--poscar template.POSCAR --formula-col 0 --property-col 1
7192
```
7293

7394
## 3. Structure Files via dpdata
@@ -155,46 +176,21 @@ dpaad data convert --input traj.extxyz --output ./npy --fmt extxyz
155176

156177
### Glob patterns
157178

158-
When `--input` contains wildcards (`*`, `?`, `[`):
179+
When `--input` contains wildcards (`*`, `?`, `[`), conversion uses mirrored
180+
batch output:
159181

160-
- **1 match** → treated as a single file (output directly into `--output`).
161-
- **N > 1 matches** → each match is converted into a numbered subdirectory
162-
`{output}/sys_{i:04d}/` (zero-indexed, sorted).
182+
- **1 or more matches** → each matched file is converted into an output
183+
directory that mirrors its path relative to the non-wildcard prefix.
163184
- **0 matches**`FileNotFoundError`.
185+
- A `manifest.json` is written into the output root, recording converted and
186+
skipped files.
164187

165188
```bash
166-
# Single match (only one OUTCAR found)
167-
dpa-adapt data convert --input "run*/OUTCAR" --output ./npy
168-
dpaad data convert --input "run*/OUTCAR" --output ./npy
169-
170-
# Multi-match: outputs sys_0000/, sys_0001/, …
189+
# Glob output mirrors the input tree under ./npy_root
171190
dpa-adapt data convert --input "calcs/**/OUTCAR" --output ./npy_root --fmt vasp/outcar
172191
dpaad data convert --input "calcs/**/OUTCAR" --output ./npy_root --fmt vasp/outcar
173192
```
174193

175-
## 4. Batch Mode
176-
177-
**Trigger:** `--input` with glob wildcards and N > 1 matches. Uses
178-
`batch_convert()` internally.
179-
180-
Key behaviors:
181-
182-
- Output directory tree mirrors the input tree structure (relative to the
183-
non-wildcard prefix of the glob pattern).
184-
- A `manifest.json` is written into the output root, recording every
185-
converted and skipped file.
186-
- When `--strict` is set, the first conversion error fails immediately.
187-
Without it (default), errors are skipped and logged.
188-
189-
```bash
190-
# Batch convert all OUTCAR files; each lands in a mirrored subdirectory
191-
dpa-adapt data convert --input "scan/**/OUTCAR" --output ./all_npy --fmt vasp/outcar
192-
dpaad data convert --input "scan/**/OUTCAR" --output ./all_npy --fmt vasp/outcar
193-
194-
# Strict mode — abort on first failure
195-
dpa-adapt data convert --input "scan/**/OUTCAR" --output ./all_npy --fmt vasp/outcar --strict
196-
dpaad data convert --input "scan/**/OUTCAR" --output ./all_npy --fmt vasp/outcar --strict
197-
198-
# Check the manifest
199-
cat ./all_npy/manifest.json
200-
```
194+
For example, `calcs/run1/OUTCAR` is written as `npy_root/run1/OUTCAR/`.
195+
When `--strict` is set, the first conversion error fails immediately. Without
196+
it, errors are skipped and logged in the manifest.

dpa_adapt/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
"MFTFineTuner",
1919
"SmilesDataResult",
2020
"attach_labels",
21-
"auto_convert",
22-
"batch_convert",
2321
"check_data",
2422
"convert",
2523
"cross_validate",
@@ -37,8 +35,6 @@
3735
"train_test_split": (".cv", "train_test_split"),
3836
"SmilesDataResult": (".data", "SmilesDataResult"),
3937
"attach_labels": (".data", "attach_labels"),
40-
"auto_convert": (".data", "auto_convert"),
41-
"batch_convert": (".data", "batch_convert"),
4238
"check_data": (".data", "check_data"),
4339
"convert": (".data", "convert"),
4440
"formula_to_npy": (".data", "formula_to_npy"),

dpa_adapt/cli.py

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -246,32 +246,13 @@ def _cmd_evaluate(args: argparse.Namespace) -> int:
246246
def _cmd_data_convert(args: argparse.Namespace) -> int:
247247

248248
type_map = _maybe_split_list(args.type_map)
249-
input_val = args.input
250249

251-
# Detect glob patterns — batch mode.
252-
if any(ch in input_val for ch in "*?["):
253-
from dpa_adapt import (
254-
batch_convert,
255-
)
256-
257-
outputs = batch_convert(
258-
glob_pattern=input_val,
259-
output_dir=args.output,
260-
fmt=args.fmt or "auto",
261-
type_map=type_map,
262-
validate=args.validate,
263-
strict=args.strict,
264-
)
265-
_LOG.info("Wrote %d deepmd/npy dirs under %s", len(outputs), args.output)
266-
return 0
267-
268-
# Single-file mode.
269-
from dpa_adapt.data.convert import (
270-
auto_convert,
250+
from dpa_adapt import (
251+
convert,
271252
)
272253

273-
result = auto_convert(
274-
input_path=input_val,
254+
result = convert(
255+
input_path=args.input,
275256
output_dir=args.output,
276257
fmt=args.fmt,
277258
type_map=type_map,
@@ -301,6 +282,9 @@ def _cmd_data_convert(args: argparse.Namespace) -> int:
301282
print(f"Failed rows : {len(result['failed_rows'])}")
302283
print(f"Skipped zero : {result['skipped_zero']}")
303284
print(f"Skipped overlap: {result['skipped_overlap']}")
285+
elif result["method"] == "batch_dpdata":
286+
print(f"Output dirs : {len(result['output_dirs'])}")
287+
print(f"Manifest : {result['manifest']}")
304288
else:
305289
_LOG.info("Wrote deepmd/npy → %s", result["output_dir"])
306290
return 0

dpa_adapt/data/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
"Issue",
1212
"SmilesDataResult",
1313
"attach_labels",
14-
"auto_convert",
15-
"batch_convert",
1614
"check_data",
1715
"convert",
1816
"formula_to_npy",
@@ -32,10 +30,8 @@
3230
"read_checkpoint_type_map": (".type_map", "read_checkpoint_type_map"),
3331
"read_data_type_map_union": (".type_map", "read_data_type_map_union"),
3432
"validate_type_map_subset": (".type_map", "validate_type_map_subset"),
35-
"auto_convert": (".convert", "auto_convert"),
3633
"convert": (".convert", "convert"),
3734
"attach_labels": (".convert", "attach_labels"),
38-
"batch_convert": (".convert", "batch_convert"),
3935
"formula_to_npy": (".formula", "formula_to_npy"),
4036
"check_data": (".validate", "check_data"),
4137
"Issue": (".validate", "Issue"),

0 commit comments

Comments
 (0)