diff --git a/.claude/agents/mpk-documenter.md b/.claude/agents/mpk-documenter.md index 7413268..ae9640e 100644 --- a/.claude/agents/mpk-documenter.md +++ b/.claude/agents/mpk-documenter.md @@ -27,7 +27,9 @@ You **maintain** molpack's documentation. You do **NOT** invent API behavior — | Python docs | `docs/python/` (the site's "Python" nav section) | Python users | | CONTRIBUTING | `CONTRIBUTING.md` | Contributors | | README | `README.md` (CLI keyword table, format table, quick-start) | Discovery | -| Changelog | `CHANGELOG.md` | Users tracking releases | + +Release history lives in git tags / GitHub Releases — no hand-written +`CHANGELOG.md`. **Sync triggers.** When one of these changes, the listed doc must change too: @@ -38,7 +40,6 @@ You **maintain** molpack's documentation. You do **NOT** invent API behavior — | New file format | README format table; `docs/getting_started.md` | | Public type added / renamed | rustdoc on the type; Python docs if mirrored | | Feature flag added | `Cargo.toml` comment; README install section; CONTRIBUTING test commands | -| User-visible bug fix | `CHANGELOG.md` | **Rustdoc style.** Every public item gets a one-line summary plus, for non-trivial items, an example. Examples must compile (`cargo test --doc`). Cross-link via `` [`Item`] `` syntax, never bare names. Use `# Examples`, `# Errors`, `# Panics` sections per Rust API guidelines. diff --git a/.claude/skills/mpk-docs/SKILL.md b/.claude/skills/mpk-docs/SKILL.md index 8235788..dd590c2 100644 --- a/.claude/skills/mpk-docs/SKILL.md +++ b/.claude/skills/mpk-docs/SKILL.md @@ -1,6 +1,6 @@ --- name: mpk-docs -description: Audit or update docs — rustdoc, docs/ (incl. docs/python/), README, CONTRIBUTING, CHANGELOG. Writes docs when asked. +description: Audit or update docs — rustdoc, docs/ (incl. docs/python/), README, CONTRIBUTING. Writes docs when asked. argument-hint: "'>" user-invocable: true --- diff --git a/.claude/skills/mpk-fix/SKILL.md b/.claude/skills/mpk-fix/SKILL.md index f638b5b..ead2aba 100644 --- a/.claude/skills/mpk-fix/SKILL.md +++ b/.claude/skills/mpk-fix/SKILL.md @@ -16,7 +16,7 @@ Read CLAUDE.md for molpack conventions. 3. **Diagnose** in place — read the suspect code path. Do not modify code yet. 4. **Smallest fix.** Edit only what is necessary to flip the test GREEN. Resist the urge to refactor adjacent code, rename variables, or "clean up" while you're there — open a separate `/mpk-refactor` if cleanup is warranted. 5. **Run impacted tier.** If the fix touches a hot-path file, run the relevant criterion bench. If it touches `restraint.rs`, `objective.rs`, `packer.rs`, `gencan/`, `initial.rs`, `relaxer.rs`, or `movebad.rs`, run `examples_batch`. -6. **Changelog.** Update `CHANGELOG.md` if the bug was user-visible. +6. **History.** No `CHANGELOG.md` — release notes come from git tags / GitHub Releases. ## Output diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 235aad8..daa715c 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -20,7 +20,7 @@ on: # Pin sibling molrs to the same version as Cargo.toml / python/pyproject.toml. env: - MOLRS_GIT_REF: v0.9.3 + MOLRS_GIT_REF: v0.12.0 jobs: bench: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd4553b..ebae617 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ on: # Pin sibling molrs to the same version as Cargo.toml / python/pyproject.toml [tool.tox]. # Bump together when raising molcrafts-molrs / molcrafts-molpy. env: - MOLRS_GIT_REF: v0.9.3 + MOLRS_GIT_REF: v0.12.0 # Lint: same as prek commit-stage hooks in .pre-commit-config.yaml. # Tests: same commands as prek pre-push hooks (no scripts/). @@ -71,7 +71,7 @@ jobs: - name: Cache test data uses: actions/cache@v5 with: - path: molrs/molrs-core/target/tests-data + path: molrs/tests-data key: ${{ runner.os }}-test-data-${{ hashFiles('molrs/scripts/fetch-test-data.sh') }} - name: Fetch test data run: bash scripts/fetch-test-data.sh diff --git a/.github/workflows/publish-crate.yml b/.github/workflows/publish-crate.yml index 32b74d0..22c8c86 100644 --- a/.github/workflows/publish-crate.yml +++ b/.github/workflows/publish-crate.yml @@ -11,7 +11,7 @@ permissions: # Keep in lockstep with ci.yml / Cargo.toml molrs pin. env: - MOLRS_GIT_REF: v0.9.3 + MOLRS_GIT_REF: v0.12.0 jobs: ci: diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 6e93c72..9e9e2f7 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -12,7 +12,7 @@ permissions: # Keep in lockstep with ci.yml / Cargo.toml molrs pin. env: - MOLRS_GIT_REF: v0.9.3 + MOLRS_GIT_REF: v0.12.0 # Build matrix produces one wheel per OS per supported Python (3.12, 3.13), # matching `requires-python = ">=3.12"` in pyproject.toml. Linux + macOS only; diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index e3d32a3..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,111 +0,0 @@ -# Changelog - -All notable changes to `molcrafts-molpack` are documented here. - -The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). -This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -### Fixed - -- Python tests construct `molrs.Frame.from_dict` with both `"blocks"` and - `"meta"` (required by molrs 0.9.x). - -### Changed - -- Pinned runtime deps to `molcrafts-molrs==0.9.3` and `molcrafts-molpy==0.9.3`; - CI checks out `MolCrafts/molrs@v0.9.3` for path builds. -- Python tests via `tox -c python -e py` (config in `python/pyproject.toml` - `[tool.tox]`; isolated non-editable wheel; no `scripts/`). Git hooks use - **prek**; pre-push mirrors CI. - -### Changed (earlier) - -- Updated the Rust integration for molrs's chemical-perception reorganization: - torsion relaxers now use `molrs::perceive::rotatable` after the removal of the - compatibility `molrs::chem` module. -- Aligned the force-field relaxer documentation and regression coverage with - molrs's generic MMFF94 pipeline (`typify` → typed frame → - `intramolecular_pairs` → `ForceField::to_potentials`) and the renamed - `MMFF94Typifier` API. -- Updated nonbonded force-field coverage for molrs's explicit `coul/cut` - contract: force fields now provide their Coulomb constant and dielectric - instead of relying on kernel-owned physical defaults. -- Updated post-pack relaxation references to molpy's `LAMMPSEngine` API. - -## [0.1.1] - 2026-07-08 - -### Changed -- Bumped the `molcrafts-molrs` dependency (Rust crate + `molrs-ffi` FFI layer and - the Python runtime pins) from 0.6.0 to 0.7.0, and the Python runtime - `molcrafts-molpy` pin from 0.6.0 to 0.7.0. No molpack API change — a - dependency-tracking release against the unified molrs/molpy 0.7.0 line. -- Docs build now pins the shared `molcrafts-zensical-theme` at 0.1.1. - -## [0.1.0] - 2026-07-04 - -Inaugural release of `molcrafts-molpack`. - -### Added -- Three-phase packing algorithm (per-type init → geometric pre-fit → main loop with `movebad` heuristic) -- GENCAN quasi-Newton optimizer with bound constraints -- 14 concrete `*Restraint` types covering Packmol kinds 2–15, each with an analytic `f` energy and a matching `fg` gradient (verified by finite-difference unit tests) -- `Region` trait with `And` / `Or` / `Not` combinators and `RegionRestraint` lift -- `Handler` trait with built-ins: `NullHandler`, `ProgressHandler`, `EarlyStopHandler`, `XYZHandler` -- `Relaxer` trait with `TorsionMcRelaxer` built-in -- `ForceFieldRelaxer` (feature `ff`): a `Relaxer` that relaxes a flexible - molecule's internal geometry during packing by energy-minimizing it under a - caller-supplied molrs force-field `Potential` (via molrs's L-BFGS optimizer), - accepting the relaxed conformer only when it does not worsen the packer - objective. The `ff` feature enables `molrs/ff` and re-exports the `Potential` - trait at the crate root. -- Per-axis periodic boundary conditions via `InsideBoxRestraint::new(min, max, [bool; 3])` -- `pbc` keyword in `.inp` scripts and `Molpack::with_periodic_box` -- `.inp` parser now covers 12 restraint forms — `inside`/`outside` for `box`, `cube`, `sphere`, `ellipsoid`, and `cylinder`, plus `over`/`below plane` and `over`/`below xygauss` (with positive-axis / non-zero-axis input validation) -- Public extension surface re-exported at the crate root: `Objective`, `Constraints`, `EvalMode`, `EvalOutput` -- Optional `rayon` feature for parallel objective evaluation -- Optional `cli` feature gating the `molpack` binary -- Python bindings via PyO3 + maturin (`molcrafts-molpack` on PyPI) -- `PackResult.frame` returns a topology-complete `molrs.Frame`: each target's source-frame topology (bonds/angles/dihedrals/impropers) is replayed onto the packed coordinates with indices offset per copy, `id`/`mol_id` regenerated, and `frame.box` stamped from the periodic box — adopt into molpy with `molpy.Frame.from_dict(...)`. Falls back to a coordinates-only `atoms` block for `.inp` script packing. -- Profile-distribution restraint family (`ProfileRestraint`): composes a reaction - coordinate (planar / radial / cylindrical) with a target distribution - (`gaussian`, `erf`, `tanh`, `exponential`, or a `tabulated` density/histogram via - monotone-cubic interpolation + Boltzmann inversion), each with an analytic - Jacobian. Exposed as the `.inp` `profile` keyword and lowered through - `Script::lower` + `StructurePlan::apply`. -- Python restraint extensibility: user code can subclass the restraint base in - pure Python and have it driven through the Rust optimizer (parallel-unsafe - restraints are serialized automatically); see - `python/examples/pack_profile_monolayer.py` and the - `profile_monolayer_extensibility.md` write-up. -- Five canonical Packmol workloads as runnable examples (mixture, bilayer, spherical, interface, solvprotein), plus the `mt_scaling` measurement harness (parallel speed-up-vs-size sweep) -- Criterion regression benchmark suite (`cargo bench --benches`, no `io` feature - required — each synthesizes its own geometry in-process): the fused - pair/objective kernel (`compute_f` / `compute_fg`), objective dispatch - (`via_inherent` vs `via_dyn`), one `run_iteration` step, restraint evaluation - (`InsideBox` / `InsideSphere` `f`/`fg`), and a tiny end-to-end `Molpack::pack` - mixture. Each uses `sample_size(10)` + ~500 ms measurement so the whole run is - cheap; `.github/workflows/bench.yml` tracks their history on canonical pushes - via `benchmark-action/github-action-benchmark`. -- Rustdoc chapters: `getting_started`, `concepts`, `architecture`, `extending` - -### Fixed -- `OutsideEllipsoidRestraint` (Packmol kind 9): `f` now multiplies the squared - penalty by `scale2`, matching `fg`'s gradient and the documented "quadratic - penalty group" convention. The previous transcription left `f` and `fg` - 100× out of phase at the default `scale2 = 0.01`, causing the optimizer to - see a gradient much flatter than the function value reported. -- `movebad` worst-atom selection uses `f64::total_cmp` instead of `partial_cmp().unwrap()`, removing a NaN-triggered panic path. -- `initial` cell-grid sizing clamps total cell count (atom-count aware, hard ceiling) so a degenerate fallback box can no longer trigger an out-of-memory allocation. - -### Changed -- Parallel objective gradient uses a half-stencil scheme with parallel projection (under the `rayon` feature), halving redundant pair evaluations on the hot path. -- Restraint code split from a single `src/restraint.rs` into the `src/restraint/` module (`geometric/`, `profile/`) as the type count grew. -- Relaxer Monte-Carlo loop reuses a single trial buffer (`mem::swap` on accept) instead of cloning per step. -- `self_avoidance_penalty` evaluates the cheap distance gate before the exclusion-set hash probe. -- CI runs the test suites plus the Packmol regression (on non-PR events); formatting and lint (`fmt`, `clippy`, `ruff`, `ty`) are enforced by pre-commit hooks. -- Depends on the unified `molcrafts-molrs` 0.6.0 crate: `core` is always-on and re-exported at the crate root, while `io` and `ff` are feature-gated modules that forward to `molrs/io` and `molrs/ff`. - -[0.1.1]: https://github.com/MolCrafts/molpack/compare/v0.1.0...v0.1.1 -[0.1.0]: https://github.com/MolCrafts/molpack/releases/tag/v0.1.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f4c785e..80e66a5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,10 +22,11 @@ workspace/ The root `Cargo.toml` uses a path dependency on `../molrs/molrs`. With the sibling layout above everything resolves automatically. -**Version pins:** path molrs / PyPI `molcrafts-molrs` / `molcrafts-molpy` are -fixed at **0.9.3** (see `Cargo.toml`, `python/pyproject.toml` `[tool.tox]`, and -`MOLRS_GIT_REF` in `.github/workflows/ci.yml`). Keep the sibling molrs clone -on that version line (`git checkout v0.9.3` or the matching release branch). +**Version pins:** path molrs / PyPI `molcrafts-molrs` / `molcrafts-molpy` track +the **0.12.*** minor line (see `Cargo.toml`, `python/pyproject.toml` `[tool.tox]`, +and `MOLRS_GIT_REF` in `.github/workflows/ci.yml`). Patch may differ; only +major.minor must match. Keep the sibling molrs clone on that minor line +(`git checkout v0.12.x` or the matching release branch). **First-time setup:** diff --git a/Cargo.toml b/Cargo.toml index 0ae7860..e6ede93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "molcrafts-molpack" -version = "0.1.2" +version = "0.2.0" edition = "2024" rust-version = "1.91" authors = ["MolCrafts"] @@ -28,7 +28,7 @@ bench = false # Library-required. The merged `molcrafts-molrs` crate exposes its former member # crates as feature-gated modules: `core` is always on (re-exported at the crate # root), while `io` and `ff` are opt-in via the molpack features below. -molrs = { path = "../molrs/molrs", version = "0.9.3", package = "molcrafts-molrs", default-features = false } +molrs = { path = "../molrs/molrs", version = "0.12.0", package = "molcrafts-molrs", default-features = false } rand = "0.10" ndarray = "0.17" log = "0.4" diff --git a/README.md b/README.md index e60f92d..dc57651 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ let report = Molpack::new().pack_with_report(&[target], 200)?; import molrs from molpack import InsideBoxRestraint, Molpack, Target -frame = molrs.read_pdb("water.pdb") +frame = molrs.io.read_pdb("water.pdb") water = ( Target(frame, count=100) diff --git a/docs/getting_started.md b/docs/getting_started.md index 0f06c91..dc9b904 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -20,7 +20,7 @@ type plus PDB/XYZ I/O. ```python import molrs - frame = molrs.read_pdb("water.pdb") + frame = molrs.io.read_pdb("water.pdb") ``` === "In-memory (no file)" @@ -37,7 +37,8 @@ type plus PDB/XYZ I/O. "z": np.zeros(3), "element": ["O", "H", "H"], } - } + }, + "meta": {}, }) ``` @@ -90,8 +91,8 @@ For a frame-only return, use `Molpack().pack([water], max_loops=200)`. ```python import molrs -molrs.write_pdb(packed, "water_box.pdb") -# or: molrs.write_xyz(packed, "water_box.xyz") +molrs.io.write_pdb("water_box.pdb", packed) +# or: molrs.io.write_xyz("water_box.xyz", packed) ``` ## Where next diff --git a/docs/install.md b/docs/install.md index e499d90..d5fd911 100644 --- a/docs/install.md +++ b/docs/install.md @@ -37,7 +37,7 @@ Optional features (crate defaults to none enabled): ```toml # Cargo.toml — common combinations -molcrafts-molpack = { version = "0.1", features = ["io", "rayon"] } +molcrafts-molpack = { version = "0.2", features = ["io", "rayon"] } ``` ## Python binding diff --git a/docs/python/api-reference.md b/docs/python/api-reference.md index eeadf40..ddf16cd 100644 --- a/docs/python/api-reference.md +++ b/docs/python/api-reference.md @@ -334,7 +334,7 @@ Raises `ImportError` if `molcrafts-molpy` is not installed. ### `load_script(path, *, read_frame=None) -> ScriptJob` Parse and lower a Packmol-compatible `.inp` script. Template files are -read on the Python side (defaulting to `molrs.read_pdb` / `read_xyz` by +read on the Python side (defaulting to `molrs.io.read_pdb` / `read_xyz` by extension), so the wheel stays free of `molrs-io`. Pass `read_frame` — a callable `(path, filetype) -> molrs.Frame` — to plug in another loader (mdtraj, ASE, …). diff --git a/docs/python/examples.md b/docs/python/examples.md index ff4c0d9..902c25d 100644 --- a/docs/python/examples.md +++ b/docs/python/examples.md @@ -20,7 +20,7 @@ pip install molcrafts-molpack ``` `pack_water_cube.py` builds its frame in memory with `molrs.Frame.from_dict` -(no PDB file); the others load PDB files via `molrs.read_pdb`. +(no PDB file); the others load PDB files via `molrs.io.read_pdb`. ## Running @@ -41,8 +41,8 @@ The `pack_mixture.py` example reproduces Packmol's classic `mixture.inp`: import molrs from molpack import InsideBoxRestraint, Molpack, Target -water_frame = molrs.read_pdb("water.pdb") -urea_frame = molrs.read_pdb("urea.pdb") +water_frame = molrs.io.read_pdb("water.pdb") +urea_frame = molrs.io.read_pdb("urea.pdb") box = InsideBoxRestraint([0, 0, 0], [40, 40, 40]) @@ -69,7 +69,8 @@ frame = molrs.Frame.from_dict({ "z": np.zeros(3), "element": ["O", "H", "H"], } - } + }, + "meta": {}, }) water = Target(frame, count=100).with_name("water").with_restraint( diff --git a/docs/python/getting-started.md b/docs/python/getting-started.md index d2e5e40..b2b1c41 100644 --- a/docs/python/getting-started.md +++ b/docs/python/getting-started.md @@ -4,13 +4,13 @@ A minimal end-to-end pack: 100 water molecules inside a 40 Å cube. ## 1. Load a molecule -Use `molrs.read_pdb` to load a template PDB file — the returned +Use `molrs.io.read_pdb` to load a template PDB file — the returned `Frame` can be passed directly to `Target`: ```python import molrs -frame = molrs.read_pdb("water.pdb") +frame = molrs.io.read_pdb("water.pdb") ``` No PDB file? Build a `molrs.Frame` from arrays with `Frame.from_dict`: @@ -27,7 +27,8 @@ frame = molrs.Frame.from_dict({ "z": np.zeros(3), "element": ["O", "H", "H"], } - } + }, + "meta": {}, }) ``` @@ -96,7 +97,7 @@ output. Hand the returned frame to a writer: ```python import molrs -molrs.write_xyz("packed.xyz", frame) +molrs.io.write_xyz("packed.xyz", frame) ``` Or use `pack_with_report()` and write `result.frame` if you also need @@ -108,7 +109,7 @@ the diagnostic fields. import molrs from molpack import InsideBoxRestraint, Molpack, Target -frame = molrs.read_pdb("water.pdb") +frame = molrs.io.read_pdb("water.pdb") water = ( Target(frame, count=100) diff --git a/docs/python/guide/packer.md b/docs/python/guide/packer.md index 323b70a..27a01a0 100644 --- a/docs/python/guide/packer.md +++ b/docs/python/guide/packer.md @@ -130,7 +130,7 @@ if not result.converged: ``` `PackResult.frame` is the same Frame returned by `pack()`. Pass it to a -writer of your choice (e.g. `molrs.write_pdb`). molpack does **not** +writer of your choice (e.g. `molrs.io.write_pdb`). molpack does **not** provide writers. ## Reproducibility diff --git a/docs/python/guide/targets.md b/docs/python/guide/targets.md index a1eb5aa..35003ef 100644 --- a/docs/python/guide/targets.md +++ b/docs/python/guide/targets.md @@ -18,9 +18,9 @@ target = Target(frame, count) | Source | Element column | |--------|---------------| - | `molrs.read_pdb(path)` | `"symbol"` | - | `molrs.read_xyz(path)` | `"element"` | - | `molrs.Frame.from_dict({"blocks": {"atoms": {...}}})` | `"element"` | + | `molrs.io.read_pdb(path)` | `"symbol"` | + | `molrs.io.read_xyz(path)` | `"element"` | + | `molrs.Frame.from_dict({"blocks": {"atoms": {...}}, "meta": {}})` | `"element"` | | `molpy.Frame` | `"element"` | - `count` — number of copies to produce. @@ -45,7 +45,8 @@ frame = molrs.Frame.from_dict({ "z": np.zeros(3), "element": ["O", "H", "H"], } - } + }, + "meta": {}, }) water = Target(frame, count=100).with_name("water") ``` diff --git a/docs/python/index.md b/docs/python/index.md index 8c671ce..d12b6b2 100644 --- a/docs/python/index.md +++ b/docs/python/index.md @@ -13,7 +13,7 @@ reference output. import molrs from molpack import InsideBoxRestraint, Molpack, Target -frame = molrs.read_pdb("water.pdb") +frame = molrs.io.read_pdb("water.pdb") water = ( Target(frame, count=100) diff --git a/docs/python/installation.md b/docs/python/installation.md index 664300a..1f9d9ac 100644 --- a/docs/python/installation.md +++ b/docs/python/installation.md @@ -29,7 +29,7 @@ pip install molcrafts-molpack import molrs from molpack import InsideBoxRestraint, Molpack, Target -frame = molrs.read_pdb("water.pdb") +frame = molrs.io.read_pdb("water.pdb") water = ( Target(frame, count=100) .with_name("water") @@ -61,7 +61,8 @@ import molrs from molpack import Target frame = molrs.Frame.from_dict({ - "blocks": {"atoms": {"x": [0.0], "y": [0.0], "z": [0.0], "element": ["O"]}} + "blocks": {"atoms": {"x": [0.0], "y": [0.0], "z": [0.0], "element": ["O"]}}, + "meta": {}, }) target = Target(frame, count=1).with_name("mol") print(target) # Target(natoms=1, count=1, name=Some("mol")) diff --git a/python/Cargo.toml b/python/Cargo.toml index eab7e1c..cf8e859 100644 --- a/python/Cargo.toml +++ b/python/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "molpack-python" -version = "0.1.2" +version = "0.2.0" edition = "2024" rust-version = "1.91" authors = ["MolCrafts"] @@ -17,17 +17,17 @@ crate-type = ["cdylib"] pyo3 = { version = "0.29", features = ["extension-module"] } numpy = "0.29" ndarray = "0.17" -molpack = { path = "..", package = "molcrafts-molpack", version = "0.1.2" } +molpack = { path = "..", package = "molcrafts-molpack", version = "0.2.0" } # Same crate (and version) molpack links, so frame types unify across the wheel. # The merged `molcrafts-molrs` crate exposes core at its root with default # features off (matching molpack's dependency), so the wheel stays io/ff-free. -molrs = { path = "../../molrs/molrs", package = "molcrafts-molrs", version = "0.9.3", default-features = false } +molrs = { path = "../../molrs/molrs", package = "molcrafts-molrs", version = "0.12.0", default-features = false } # Stable FFI handle layer. molpack resolves molrs/molpy Python objects to # `molrs_ffi::{FrameRef, ForceFieldRef}` capsules (zero-copy) instead of dict -# marshalling — see `src/interop.rs`. Pinned to the same 0.9.3 molrs-python +# marshalling — see `src/interop.rs`. Pinned to the same 0.12.0 molrs-python # links, so the handle types and the `molrs::Frame` they lend share one layout # (path+version managed manually, per project convention). -molrs-ffi = { path = "../../molrs/molrs-ffi", package = "molcrafts-molrs-ffi", version = "0.9.3" } +molrs-ffi = { path = "../../molrs/molrs-ffi", package = "molcrafts-molrs-ffi", version = "0.12.0" } # Direct rayon dep so the binding can introspect/configure the global pool # (`num_threads`, `init_thread_pool`); shares the same process-global pool # molpack's parallel evaluator runs on. Gated behind the `rayon` feature. diff --git a/python/examples/_common.py b/python/examples/_common.py index a8bb071..5850532 100644 --- a/python/examples/_common.py +++ b/python/examples/_common.py @@ -1,7 +1,7 @@ """Shared helpers for the molpack Python examples. Provides a minimal PDB loader for cases where ``molrs`` is unavailable. -When ``molrs`` is installed, prefer ``molrs.read_pdb(path)`` directly — +When ``molrs`` is installed, prefer ``molrs.io.read_pdb(path)`` directly — the returned ``Frame`` can be passed straight to ``molpack.Target(frame, count)``. """ diff --git a/python/examples/pack_bilayer.py b/python/examples/pack_bilayer.py index 2b75804..1082d8e 100644 --- a/python/examples/pack_bilayer.py +++ b/python/examples/pack_bilayer.py @@ -19,8 +19,8 @@ def main() -> None: - water_frame = molrs.read_pdb(str(DATA / "water.pdb")) - lipid_frame = molrs.read_pdb(str(DATA / "palmitoil.pdb")) + water_frame = molrs.io.read_pdb(str(DATA / "water.pdb")) + lipid_frame = molrs.io.read_pdb(str(DATA / "palmitoil.pdb")) water_low = ( molpack.Target(water_frame, count=50) diff --git a/python/examples/pack_interface.py b/python/examples/pack_interface.py index f7a513a..cb89da9 100644 --- a/python/examples/pack_interface.py +++ b/python/examples/pack_interface.py @@ -19,9 +19,9 @@ def main() -> None: - water_frame = molrs.read_pdb(str(DATA / "water.pdb")) - chlor_frame = molrs.read_pdb(str(DATA / "chloroform.pdb")) - t3_frame = molrs.read_pdb(str(DATA / "t3.pdb")) + water_frame = molrs.io.read_pdb(str(DATA / "water.pdb")) + chlor_frame = molrs.io.read_pdb(str(DATA / "chloroform.pdb")) + t3_frame = molrs.io.read_pdb(str(DATA / "t3.pdb")) water = ( molpack.Target(water_frame, count=100) diff --git a/python/examples/pack_mixture.py b/python/examples/pack_mixture.py index 5b5e0a0..ec223b9 100644 --- a/python/examples/pack_mixture.py +++ b/python/examples/pack_mixture.py @@ -18,8 +18,8 @@ def main() -> None: - water_frame = molrs.read_pdb(str(DATA / "water.pdb")) - urea_frame = molrs.read_pdb(str(DATA / "urea.pdb")) + water_frame = molrs.io.read_pdb(str(DATA / "water.pdb")) + urea_frame = molrs.io.read_pdb(str(DATA / "urea.pdb")) box = molpack.InsideBoxRestraint([0.0, 0.0, 0.0], [40.0, 40.0, 40.0]) diff --git a/python/examples/pack_solvprotein.py b/python/examples/pack_solvprotein.py index c29fe53..54eee0e 100644 --- a/python/examples/pack_solvprotein.py +++ b/python/examples/pack_solvprotein.py @@ -20,10 +20,10 @@ def main() -> None: - protein_frame = molrs.read_pdb(str(DATA / "protein.pdb")) - water_frame = molrs.read_pdb(str(DATA / "water.pdb")) - sodium_frame = molrs.read_pdb(str(DATA / "sodium.pdb")) - chloride_frame = molrs.read_pdb(str(DATA / "chloride.pdb")) + protein_frame = molrs.io.read_pdb(str(DATA / "protein.pdb")) + water_frame = molrs.io.read_pdb(str(DATA / "water.pdb")) + sodium_frame = molrs.io.read_pdb(str(DATA / "sodium.pdb")) + chloride_frame = molrs.io.read_pdb(str(DATA / "chloride.pdb")) sphere = molpack.InsideSphereRestraint([0.0, 0.0, 0.0], 50.0) diff --git a/python/examples/pack_spherical.py b/python/examples/pack_spherical.py index cbfc785..604f891 100644 --- a/python/examples/pack_spherical.py +++ b/python/examples/pack_spherical.py @@ -21,8 +21,8 @@ def main() -> None: - water_frame = molrs.read_pdb(str(DATA / "water.pdb")) - lipid_frame = molrs.read_pdb(str(DATA / "palmitoil.pdb")) + water_frame = molrs.io.read_pdb(str(DATA / "water.pdb")) + lipid_frame = molrs.io.read_pdb(str(DATA / "palmitoil.pdb")) # 1. Inner water sphere (r = 13). water_inner = ( diff --git a/python/pyproject.toml b/python/pyproject.toml index 25964d9..96c0e6b 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -4,17 +4,17 @@ build-backend = "maturin" [project] name = "molcrafts-molpack" -version = "0.1.2" +version = "0.2.0" description = "Python bindings for molpack molecular packing (Packmol port)" requires-python = ">=3.12" readme = "README.md" license = "BSD-3-Clause" -# Exact pins — keep in lockstep with Cargo.toml, [tool.tox], and CI MOLRS_GIT_REF. +# Minor-line pins — same major.minor as molrs/molpy; patch may drift. dependencies = [ "numpy>=2.0", "typer>=0.12", - "molcrafts-molrs==0.9.3", - "molcrafts-molpy==0.9.3", + "molcrafts-molrs>=0.12.0,<0.13", + "molcrafts-molpy>=0.12.0,<0.13", ] # Installable "extra" carrying the docs-build deps. Unlike the [dependency-groups] @@ -24,8 +24,8 @@ dependencies = [ # That is the build command a Cloudflare Pages Git-integration build should use. [project.optional-dependencies] doc = [ - "zensical>=0.0.51", - "molcrafts-zensical-theme>=0.2.3", + "zensical>=0.0.53", + "molcrafts-zensical-theme>=0.2.5", ] # PEP 735 dependency groups — the single source of truth for dev-time @@ -38,7 +38,7 @@ typecheck = [ "ty", "typer>=0.12", "numpy>=2.0", - "molcrafts-molrs==0.9.3", + "molcrafts-molrs>=0.12.0,<0.13", # `ty check` walks tests/ which imports pytest. "pytest", ] @@ -46,8 +46,8 @@ test = [ "pytest", "typer>=0.12", "numpy>=2.0", - "molcrafts-molrs==0.9.3", - "molcrafts-molpy==0.9.3", + "molcrafts-molrs>=0.12.0,<0.13", + "molcrafts-molpy>=0.12.0,<0.13", ] dev = [ {include-group = "typecheck"}, @@ -61,9 +61,9 @@ dev = [ # Documentation build: `zensical build` reads zensical.toml (docs → site). # Theme: `theme.name = "molcrafts"` (molcrafts-zensical-theme on PyPI). doc = [ - "zensical>=0.0.51", + "zensical>=0.0.53", # The molcrafts docs theme (zensical.toml sets `theme.name = "molcrafts"`). - "molcrafts-zensical-theme>=0.2.3", + "molcrafts-zensical-theme>=0.2.5", ] [project.scripts] @@ -124,7 +124,7 @@ extra-paths = ["examples"] # Isolated binding tests — prek pre-push + CI call: `tox -c python -e py` # Non-editable only: sibling molrs path install + maturin wheel + pytest. -# Requires ../../molrs at workspace version 0.9.3 (CI: MolCrafts/molrs@v0.9.3). +# Requires ../../molrs at workspace version 0.12.0 (CI: MolCrafts/molrs@v0.12.0). [tool.tox] requires = ["tox>=4.23"] env_list = ["py"] @@ -138,7 +138,7 @@ deps = [ "pytest", "numpy>=2.0", "typer>=0.12", - "molcrafts-molpy==0.9.3", + "molcrafts-molpy>=0.12.0,<0.13", ] pass_env = [ "HOME", @@ -153,11 +153,12 @@ pass_env = [ ] allowlist_externals = ["maturin"] # toxinidir is python/ when config lives here; sibling molrs is ../.. /molrs. +# Minor-line only: 0.12.* (patch may differ). commands_pre = [ [ "{envpython}", "-c", - "import tomllib; from pathlib import Path; p=Path('{toxinidir}')/'..'/'..'/'molrs'/'Cargo.toml'; v=tomllib.loads(p.read_text())['workspace']['package']['version']; assert v=='0.9.3', f'sibling molrs {{v}} != 0.9.3'", + "import tomllib; from pathlib import Path; p=Path('{toxinidir}')/'..'/'..'/'molrs'/'Cargo.toml'; v=tomllib.loads(p.read_text())['workspace']['package']['version']; assert tuple(map(int, v.split('.')[:2]))==(0,12), f'sibling molrs {{v}} not on 0.12.*'", ], [ "{envpython}", @@ -169,7 +170,7 @@ commands_pre = [ [ "{envpython}", "-c", - "import importlib.metadata as m; v=m.version('molcrafts-molrs'); assert v=='0.9.3', v", + "import importlib.metadata as m; v=m.version('molcrafts-molrs'); assert tuple(map(int, v.split('.')[:2]))==(0,12), v", ], ["maturin", "build", "--release", "-o", "{env_tmp_dir}/wheels"], [ diff --git a/python/python/molpack/cli.py b/python/python/molpack/cli.py index c4f7bc3..8134239 100644 --- a/python/python/molpack/cli.py +++ b/python/python/molpack/cli.py @@ -66,9 +66,9 @@ def _read_frame(path: Path) -> Any: suffix = path.suffix.lower() molrs = _require_molrs() if suffix == ".pdb": - return molrs.read_pdb(str(path)) + return molrs.io.read_pdb(str(path)) if suffix == ".xyz": - return molrs.read_xyz(str(path)) + return molrs.io.read_xyz(str(path)) raise typer.BadParameter(f"unsupported input extension '{suffix}' for {path}") @@ -89,9 +89,9 @@ def _write_result(path: Path, result: Any) -> None: path.parent.mkdir(parents=True, exist_ok=True) suffix = path.suffix.lower() if suffix == ".pdb": - molrs.write_pdb(str(path), frame) + molrs.io.write_pdb(str(path), frame) elif suffix == ".xyz": - molrs.write_xyz(str(path), frame) + molrs.io.write_xyz(str(path), frame) else: raise typer.BadParameter(f"unsupported output extension '{suffix}' for {path}") diff --git a/python/src/interop.rs b/python/src/interop.rs index 5582f62..8f3ed12 100644 --- a/python/src/interop.rs +++ b/python/src/interop.rs @@ -15,7 +15,7 @@ //! what molpack (built `ff`-only) sees across the extension boundary. use molrs::Frame; -use molrs::spatial::region::simbox::SimBox; +use molrs::spatial::simbox::SimBox; use molrs_ffi::{FfiError, FrameRef}; use ndarray::Array1; use pyo3::exceptions::{PyTypeError, PyValueError}; diff --git a/python/src/script.rs b/python/src/script.rs index 2a775d2..f978137 100644 --- a/python/src/script.rs +++ b/python/src/script.rs @@ -7,7 +7,7 @@ //! //! The loader does **not** touch molecule files in Rust. Each //! ``structure``'s template is read on the Python side, defaulting to -//! :mod:`molrs` (``molrs.read_pdb`` / ``read_xyz``) but pluggable via the +//! :mod:`molrs` (``molrs.io.read_pdb`` / ``read_xyz``) but pluggable via the //! ``read_frame`` argument. This keeps the PyO3 wheel free of //! ``molrs-io`` and lets users plug in their own loader (mdtraj, ASE, …) as //! long as it returns a ``molrs.Frame`` / ``molpy.Frame``. @@ -179,9 +179,9 @@ fn default_molrs_loader(py: Python<'_>) -> PyResult> { def _loader(path, filetype): fmt = (filetype or '').lower() or path.rsplit('.', 1)[-1].lower() if fmt == 'pdb': - return molrs.read_pdb(path) + return molrs.io.read_pdb(path) if fmt == 'xyz': - return molrs.read_xyz(path) + return molrs.io.read_xyz(path) raise ValueError( f"default loader handles .pdb / .xyz only - pass read_frame=... for {fmt!r}" ) diff --git a/python/tests/test_integration.py b/python/tests/test_integration.py index 5d5b9d2..ff80d18 100644 --- a/python/tests/test_integration.py +++ b/python/tests/test_integration.py @@ -20,12 +20,12 @@ @pytest.fixture(scope="module") def water_frame(): - return molrs.read_pdb(str(DATA_ROOT / "pack_mixture" / "water.pdb")) + return molrs.io.read_pdb(str(DATA_ROOT / "pack_mixture" / "water.pdb")) @pytest.fixture(scope="module") def urea_frame(): - return molrs.read_pdb(str(DATA_ROOT / "pack_mixture" / "urea.pdb")) + return molrs.io.read_pdb(str(DATA_ROOT / "pack_mixture" / "urea.pdb")) def _packer() -> molpack.Molpack: diff --git a/src/assemble.rs b/src/assemble.rs index b42ad2d..ff13a3e 100644 --- a/src/assemble.rs +++ b/src/assemble.rs @@ -63,8 +63,8 @@ fn topology_frame(targets: &[Target], positions: &[[F; 3]]) -> molrs::Frame { let mut topo_parts: Vec)>> = TOPOLOGY.iter().map(|_| Vec::new()).collect(); let (mut xs, mut ys, mut zs) = (Vec::new(), Vec::new(), Vec::new()); - let mut ids: Vec = Vec::new(); - let mut mol_ids: Vec = Vec::new(); + let mut ids: Vec = Vec::new(); + let mut mol_ids: Vec = Vec::new(); let mut atom_base: usize = 0; let mut mol_base: usize = 0; @@ -82,9 +82,9 @@ fn topology_frame(targets: &[Target], positions: &[[F; 3]]) -> molrs::Frame { zs.push(p[2]); } cursor += span; - ids.extend((atom_base + 1..=atom_base + span).map(|i| i as I)); + ids.extend((atom_base + 1..=atom_base + span).map(|i| i as U)); for copy in 0..count { - mol_ids.extend(std::iter::repeat_n((mol_base + copy + 1) as I, n)); + mol_ids.extend(std::iter::repeat_n((mol_base + copy + 1) as U, n)); } for (slot, (key, dtype)) in carried.iter().enumerate() { @@ -120,8 +120,8 @@ fn topology_frame(targets: &[Target], positions: &[[F; 3]]) -> molrs::Frame { } let mut atoms = Block::new(); - insert_int(&mut atoms, "id", ids); - insert_int(&mut atoms, "mol_id", mol_ids); + insert_uint(&mut atoms, "id", ids); + insert_uint(&mut atoms, "mol_id", mol_ids); insert_float(&mut atoms, "x", xs); insert_float(&mut atoms, "y", ys); insert_float(&mut atoms, "z", zs); @@ -146,7 +146,7 @@ fn topology_frame(targets: &[Target], positions: &[[F; 3]]) -> molrs::Frame { .expect("topology column insert"); } let nrows = table.nrows().unwrap_or(0); - insert_int(&mut table, "id", (1..=nrows as I).collect()); + insert_uint(&mut table, "id", (1..=nrows as U).collect()); frame.insert(*block, table); } @@ -157,22 +157,22 @@ fn topology_frame(targets: &[Target], positions: &[[F; 3]]) -> molrs::Frame { fn coords_only_frame(targets: &[Target], positions: &[[F; 3]]) -> molrs::Frame { let n = positions.len(); let mut elements: Vec = Vec::with_capacity(n); - let mut mol_ids: Vec = Vec::with_capacity(n); + let mut mol_ids: Vec = Vec::with_capacity(n); let mut mol = 0usize; for target in targets { for _ in 0..target.count { mol += 1; elements.extend(target.elements.iter().cloned()); - mol_ids.extend(std::iter::repeat_n(mol as I, target.elements.len())); + mol_ids.extend(std::iter::repeat_n(mol as U, target.elements.len())); } } let mut atoms = Block::new(); - insert_int(&mut atoms, "id", (1..=n as I).collect()); + insert_uint(&mut atoms, "id", (1..=n as U).collect()); insert_float(&mut atoms, "x", positions.iter().map(|p| p[0]).collect()); insert_float(&mut atoms, "y", positions.iter().map(|p| p[1]).collect()); insert_float(&mut atoms, "z", positions.iter().map(|p| p[2]).collect()); - insert_int(&mut atoms, "mol_id", mol_ids); + insert_uint(&mut atoms, "mol_id", mol_ids); atoms .insert("element", Array1::from_vec(elements).into_dyn()) .expect("element insert"); @@ -207,10 +207,10 @@ fn insert_float(block: &mut Block, key: &str, values: Vec) { .expect("float column insert"); } -fn insert_int(block: &mut Block, key: &str, values: Vec) { +fn insert_uint(block: &mut Block, key: &str, values: Vec) { block .insert(key, Array1::from_vec(values).into_dyn()) - .expect("int column insert"); + .expect("uint column insert"); } /// Repeat `arr` `count` times along axis 0 (numpy `tile`). @@ -298,11 +298,11 @@ fn offset_index_column(tiled: Column, atom_base: usize, n: usize, rows: usize) - mod tests { use super::*; - fn col_int(frame: &molrs::Frame, block: &str, key: &str) -> Vec { + fn col_uint(frame: &molrs::Frame, block: &str, key: &str) -> Vec { frame .get(block) .unwrap() - .get_int(key) + .get_uint(key) .unwrap() .iter() .copied() @@ -341,10 +341,10 @@ mod tests { } let mut bonds = Block::new(); bonds - .insert("atomi", Array1::from_vec(vec![0 as I]).into_dyn()) + .insert("atomi", Array1::from_vec(vec![0 as U]).into_dyn()) .unwrap(); bonds - .insert("atomj", Array1::from_vec(vec![1 as I]).into_dyn()) + .insert("atomj", Array1::from_vec(vec![1 as U]).into_dyn()) .unwrap(); let mut frame = molrs::Frame::new(); frame.insert("atoms", atoms); @@ -379,11 +379,11 @@ mod tests { let target = Target::new(diatomic(), 3); let frame = assemble_frame(&[target], &positions(6)); - assert_eq!(col_int(&frame, "bonds", "atomi"), [0, 2, 4]); - assert_eq!(col_int(&frame, "bonds", "atomj"), [1, 3, 5]); - assert_eq!(col_int(&frame, "bonds", "id"), [1, 2, 3]); - assert_eq!(col_int(&frame, "atoms", "id"), [1, 2, 3, 4, 5, 6]); - assert_eq!(col_int(&frame, "atoms", "mol_id"), [1, 1, 2, 2, 3, 3]); + assert_eq!(col_uint(&frame, "bonds", "atomi"), [0, 2, 4]); + assert_eq!(col_uint(&frame, "bonds", "atomj"), [1, 3, 5]); + assert_eq!(col_uint(&frame, "bonds", "id"), [1, 2, 3]); + assert_eq!(col_uint(&frame, "atoms", "id"), [1, 2, 3, 4, 5, 6]); + assert_eq!(col_uint(&frame, "atoms", "mol_id"), [1, 1, 2, 2, 3, 3]); assert_eq!( col_str(&frame, "atoms", "type"), ["A", "B", "A", "B", "A", "B"] @@ -415,9 +415,9 @@ mod tests { col_str(&frame, "atoms", "type"), ["A", "B", "A", "B", "", ""] ); - assert_eq!(col_int(&frame, "atoms", "mol_id"), [1, 1, 2, 2, 3, 4]); + assert_eq!(col_uint(&frame, "atoms", "mol_id"), [1, 1, 2, 2, 3, 4]); // Bonds belong only to the two diatomics. - assert_eq!(col_int(&frame, "bonds", "atomi"), [0, 2]); + assert_eq!(col_uint(&frame, "bonds", "atomi"), [0, 2]); } #[test] @@ -425,7 +425,7 @@ mod tests { let target = Target::from_coords(&[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]], &[1.5, 1.5], 2); let frame = assemble_frame(&[target], &positions(4)); - assert_eq!(col_int(&frame, "atoms", "id"), [1, 2, 3, 4]); + assert_eq!(col_uint(&frame, "atoms", "id"), [1, 2, 3, 4]); assert!(frame.get("bonds").is_none()); } } diff --git a/src/frame.rs b/src/frame.rs index e19d4ae..4a649d4 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -1,7 +1,7 @@ //! Helpers for converting between `molrs_core::Frame` and packing inputs. use molrs::store::block::Block; -use molrs::types::{F, I}; +use molrs::types::{F, U}; use ndarray::Array1; use std::str::FromStr; @@ -94,14 +94,14 @@ pub fn init_frame_constants(sys: &mut PackContext) { .collect(); let mol_ids = compute_mol_ids(sys); - let mol_id_int: Vec = mol_ids.iter().map(|&id| id as I).collect(); + let mol_id_u: Vec = mol_ids.iter().map(|&id| id as U).collect(); let mut atoms = Block::new(); atoms .insert("element", Array1::from_vec(elem_strs).into_dyn()) .expect("element insert"); atoms - .insert("mol_id", Array1::from_vec(mol_id_int).into_dyn()) + .insert("mol_id", Array1::from_vec(mol_id_u).into_dyn()) .expect("mol_id insert"); sys.frame.insert("atoms", atoms); @@ -158,7 +158,7 @@ pub fn context_to_frame(sys: &PackContext) -> molrs::Frame { .collect(); let mol_ids = compute_mol_ids(sys); - let mol_id_int: Vec = mol_ids.iter().map(|&id| id as I).collect(); + let mol_id_u: Vec = mol_ids.iter().map(|&id| id as U).collect(); let mut atoms = Block::new(); atoms @@ -174,7 +174,7 @@ pub fn context_to_frame(sys: &PackContext) -> molrs::Frame { .insert("element", Array1::from_vec(elem_strs).into_dyn()) .expect("element insert"); atoms - .insert("mol_id", Array1::from_vec(mol_id_int).into_dyn()) + .insert("mol_id", Array1::from_vec(mol_id_u).into_dyn()) .expect("mol_id insert"); let mut frame = molrs::Frame::new(); diff --git a/src/packer.rs b/src/packer.rs index 59d8385..e569d64 100644 --- a/src/packer.rs +++ b/src/packer.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use molrs::Element; -use molrs::spatial::region::simbox::SimBox; +use molrs::spatial::simbox::SimBox; use molrs::types::F; use ndarray::Array1; use rand::SeedableRng; diff --git a/src/relaxer/lbfgs.rs b/src/relaxer/lbfgs.rs index 7d85313..c83b1d8 100644 --- a/src/relaxer/lbfgs.rs +++ b/src/relaxer/lbfgs.rs @@ -26,12 +26,32 @@ use std::sync::Arc; use molrs::Frame; use molrs::ff::ForceField; use molrs::ff::potential::{Potential, intramolecular_pairs}; -use molrs::optimize::{LBFGS, LbfgsConfig}; +use molrs::optimize::LBFGS; use molrs::types::F; use rand::Rng; use super::{Relaxer, RelaxerRunner, recenter}; +/// L-BFGS knobs for the relaxer (defaults match molrs `LBFGS::with_defaults`). +#[derive(Clone, Copy, Debug)] +struct LbfgsConfig { + fmax: F, + max_steps: usize, + max_step: F, + memory: usize, +} + +impl Default for LbfgsConfig { + fn default() -> Self { + Self { + fmax: 0.05, + max_steps: 500, + max_step: 0.2, + memory: 8, + } + } +} + // ── LBFGSRelaxer ──────────────────────────────────────────────────────── /// Force-field energy-minimization relaxer. Stored on `Target` (immutable config). @@ -192,10 +212,17 @@ impl RelaxerRunner for LBFGSRelaxerRunner { // Flatten to molrs's `[x0,y0,z0, x1,y1,z1, …]` 3N layout and relax the // internal geometry under the force field. let mut flat: Vec = coords.iter().flat_map(|p| *p).collect(); - // `run` only errors on a non-3N buffer, which cannot happen here, but + // `minimize` only errors on a non-3N buffer, which cannot happen here, but // surface it rather than silently no-op'ing in case molrs grows new // error conditions (e.g. a non-finite energy). - let report = match LBFGS::new(&**potential, self.cfg).run(&mut flat) { + let report = match LBFGS::minimize( + &**potential, + &mut flat, + self.cfg.fmax, + self.cfg.max_steps, + self.cfg.max_step, + self.cfg.memory, + ) { Ok(report) => report, Err(e) => { log::debug!( diff --git a/src/restraint/geometric/bounded.rs b/src/restraint/geometric/bounded.rs index cf26f1d..504a1ac 100644 --- a/src/restraint/geometric/bounded.rs +++ b/src/restraint/geometric/bounded.rs @@ -109,7 +109,7 @@ impl InsideBoxRestraint { /// not currently carry per-axis periodicity). Off-axis cells /// (triclinic tilts) are not representable as an axis-aligned /// restraint — write a custom `impl AtomRestraint` for those. - pub fn from_simbox(simbox: &molrs::spatial::region::SimBox, periodic: [bool; 3]) -> Self { + pub fn from_simbox(simbox: &molrs::spatial::simbox::SimBox, periodic: [bool; 3]) -> Self { let origin = simbox.origin_view(); let lengths = simbox.lengths(); let o = [origin[0], origin[1], origin[2]]; diff --git a/src/script/io.rs b/src/script/io.rs index 151f1ff..12b9699 100644 --- a/src/script/io.rs +++ b/src/script/io.rs @@ -62,7 +62,7 @@ pub fn read_frame(path: &Path, filetype_hint: Option<&str>) -> Result