Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,36 @@ These affect the DREIDING parameterization stage.
| `--rules <FILE>` | path | none | Custom typing rules (TOML file). |
| `--params <FILE>` | path | none | Custom force field parameters (TOML file). |

### MPSim Compatibility

| Flag | Type | Default | Meaning |
| --------- | ---- | ------- | --------------------------------------------- |
| `--mpsim` | flag | off | Emit input for the legacy MPSim EM/MM engine. |

`--mpsim` adapts the output to MPSim's DREIDING conventions:

- **Atom types** — the hydrogen-bond hydrogen type `H_HB` is renamed to `H___A`.
This is a pure naming change; parameter lookup and H-bond terms are unaffected.
- **Protein termini** — both chain termini are forced into their neutral,
uncharged protonation state, independent of pH: the N-terminus becomes `–NH₂`
(the extra `H3` is removed) and the C-terminus becomes `–COOH` (the `HOXT`
proton is built onto `OXT`). The matching neutral terminal charge sets are
applied, so each terminal residue's backbone carries no net formal charge.
Nucleic-acid 5′/3′ termini are untouched.

Because the neutral terminal charges live in the force-field (hybrid) charge
path, `--mpsim` selects `--charge hybrid` automatically when `--charge` is left
unset. An explicit `--charge` value is respected — the terminal _topology_ is
still normalized, but the charges come from the method you chose.

```bash
# Protein → MPSim-ready BGF in one step (hybrid charges, neutral termini, H___A)
dforge bio -i protein.pdb -o protein.bgf --mpsim
```

For `dforge chem`, `--mpsim` only applies the `H_HB → H___A` rename (small
molecules have no protein termini).

---

## Command: `dforge chem`
Expand Down
20 changes: 20 additions & 0 deletions src/bin/dforge/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,20 @@ pub struct QeqSolverOptions {
pub damping: DampingStrategy,
}

/// MPSim compatibility options shared by bio and chem commands.
#[derive(Args)]
#[command(next_help_heading = "MPSim Compatibility")]
pub struct MpsimOptions {
/// Emit input for the legacy MPSim EM/MM engine.
///
/// Renames the DREIDING `H_HB` hydrogen type to MPSim's `H___A` and, for
/// protein systems, forces neutral N/C termini (–NH₂ / –COOH) in both
/// topology and charge, independent of pH. For `bio`, this selects the
/// hybrid charge method unless `--charge` is set explicitly.
#[arg(long = "mpsim")]
pub enabled: bool,
}

/// Potential function options shared by bio and chem commands.
#[derive(Args)]
#[command(next_help_heading = "Potential Functions")]
Expand Down Expand Up @@ -199,6 +213,9 @@ pub struct BioArgs {

#[command(flatten)]
pub potential: PotentialOptions,

#[command(flatten)]
pub mpsim: MpsimOptions,
}

#[derive(Args)]
Expand Down Expand Up @@ -322,6 +339,9 @@ pub struct ChemArgs {

#[command(flatten)]
pub potential: PotentialOptions,

#[command(flatten)]
pub mpsim: MpsimOptions,
}

#[derive(Clone, Copy, ValueEnum)]
Expand Down
13 changes: 11 additions & 2 deletions src/bin/dforge/commands/bio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,13 @@ pub fn run_bio(args: BioArgs, ctx: DisplayContext) -> Result<()> {
}

progress.step("Running DREIDING parameterization");
let forge_config =
build_bio_forge_config(&args.charge, &args.hybrid, &args.qeq, &args.potential)?;
let forge_config = build_bio_forge_config(
&args.charge,
&args.hybrid,
&args.qeq,
&args.potential,
&args.mpsim,
)?;
let forged = forge(&system, &forge_config).context("Parameterization failed")?;

let param_substeps = build_param_substeps(&args);
Expand Down Expand Up @@ -226,6 +231,10 @@ fn build_param_substeps(args: &BioArgs) -> Vec<String> {

steps.push("Compute H-bond pairs".to_string());

if args.mpsim.enabled {
steps.push("Apply MPSim adapter (H___A, neutral N/C termini)".to_string());
}

steps
}

Expand Down
7 changes: 6 additions & 1 deletion src/bin/dforge/commands/chem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ pub fn run_chem(args: ChemArgs, ctx: DisplayContext) -> Result<()> {
}

progress.step("Running DREIDING parameterization");
let forge_config = build_chem_forge_config(&args.charge, &args.qeq, &args.potential)?;
let forge_config =
build_chem_forge_config(&args.charge, &args.qeq, &args.potential, &args.mpsim)?;
let forged = forge(&system, &forge_config).context("Parameterization failed")?;

let param_substeps = build_param_substeps(&args);
Expand Down Expand Up @@ -122,6 +123,10 @@ fn build_param_substeps(args: &ChemArgs) -> Vec<String> {
steps.push("Apply custom parameters".to_string());
}

if args.mpsim.enabled {
steps.push("Apply MPSim adapter (H___A type naming)".to_string());
}

steps
}

Expand Down
18 changes: 15 additions & 3 deletions src/bin/dforge/config/forge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,41 @@ use std::path::Path;

use anyhow::{Context, Result};

use dreid_forge::ForgeConfig;
use dreid_forge::{ForgeConfig, MpsimConfig};

use crate::cli::{ChargeOptions, HybridChargeOptions, PotentialOptions, QeqSolverOptions};
use crate::cli::{
ChargeOptions, HybridChargeOptions, MpsimOptions, PotentialOptions, QeqSolverOptions,
};
use crate::util::convert::{build_bio_charge_method, build_chem_charge_method};

pub fn build_bio_forge_config(
charge: &ChargeOptions,
hybrid: &HybridChargeOptions,
qeq: &QeqSolverOptions,
potential: &PotentialOptions,
mpsim: &MpsimOptions,
) -> Result<ForgeConfig> {
let rules = load_optional_file(&potential.rules, "typing rules")?;
let params = load_optional_file(&potential.params, "force field parameters")?;

Ok(ForgeConfig {
rules,
params,
charge_method: build_bio_charge_method(charge, hybrid, qeq),
// MPSim's neutral termini need force-field charges to be meaningful, so
// default to the hybrid method when the user left --charge unset.
charge_method: build_bio_charge_method(charge, hybrid, qeq, mpsim.enabled),
bond_potential: potential.bond_potential.into(),
angle_potential: potential.angle_potential.into(),
vdw_potential: potential.vdw_potential.into(),
mpsim: build_mpsim_config(mpsim),
})
}

pub fn build_chem_forge_config(
charge: &ChargeOptions,
qeq: &QeqSolverOptions,
potential: &PotentialOptions,
mpsim: &MpsimOptions,
) -> Result<ForgeConfig> {
let rules = load_optional_file(&potential.rules, "typing rules")?;
let params = load_optional_file(&potential.params, "force field parameters")?;
Expand All @@ -42,9 +49,14 @@ pub fn build_chem_forge_config(
bond_potential: potential.bond_potential.into(),
angle_potential: potential.angle_potential.into(),
vdw_potential: potential.vdw_potential.into(),
mpsim: build_mpsim_config(mpsim),
Comment thread
TKanX marked this conversation as resolved.
})
}

fn build_mpsim_config(mpsim: &MpsimOptions) -> Option<MpsimConfig> {
mpsim.enabled.then(MpsimConfig::default)
}

fn load_optional_file(
path: &Option<std::path::PathBuf>,
description: &str,
Expand Down
4 changes: 2 additions & 2 deletions src/bin/dforge/display/tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fn print_type_distribution(out: &mut impl Write, forged: &ForgedSystem) {
(name, count)
})
.collect();
sorted.sort_by(|a, b| b.1.cmp(&a.1));
sorted.sort_by_key(|(_, count)| std::cmp::Reverse(*count));

print_distribution_table(out, "Atom Type Distribution", &sorted, total);
}
Expand All @@ -80,7 +80,7 @@ fn print_element_distribution(out: &mut impl Write, system: &System) {
.into_iter()
.map(|(e, c)| (format!("{:?}", e), c))
.collect();
sorted.sort_by(|a, b| b.1.cmp(&a.1));
sorted.sort_by_key(|(_, count)| std::cmp::Reverse(*count));

print_distribution_table(out, "Element Distribution", &sorted, total);
}
Expand Down
12 changes: 11 additions & 1 deletion src/bin/dforge/util/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,18 @@ pub fn build_bio_charge_method(
charge: &cli::ChargeOptions,
hybrid: &cli::HybridChargeOptions,
qeq: &cli::QeqSolverOptions,
mpsim: bool,
) -> LibChargeMethod {
match charge.method {
// MPSim's neutral-termini charges only exist in the hybrid (force-field)
// path. When --mpsim is set and no charge method was chosen, default to
// hybrid so the requested neutral termini are actually assigned.
let method = if mpsim && matches!(charge.method, cli::ChargeMethod::None) {
cli::ChargeMethod::Hybrid
} else {
charge.method
};

match method {
cli::ChargeMethod::None => LibChargeMethod::None,
cli::ChargeMethod::Qeq => LibChargeMethod::Qeq(QeqConfig {
total_charge: charge.total_charge,
Expand Down
Loading
Loading