Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ __pycache__/
.fake
/result
/result-*
/crates/rustiq-core/examples/data/
22 changes: 21 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/rustiq-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ periodic_table.workspace = true
rayon.workspace = true
relative-path.workspace = true
tokio = { workspace = true, features = ["fs", "io-util"], optional = true }
serde_json.workspace = true
serde_json = { workspace = true, features = ["float_roundtrip"] }
serde.workspace = true
sha2 = "0.11.0"
delegate.workspace = true
Expand All @@ -47,6 +47,7 @@ smallvec = "1"
tempfile.workspace = true
bytesize.workspace = true
sysinfo.workspace = true
zip = { version = "8", default-features = false, features = ["deflate-flate2-zlib-rs"] }

[dev-dependencies]
approx.workspace = true
Expand Down
24 changes: 24 additions & 0 deletions crates/rustiq-core/examples/calculate_from_rustiq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! Restore a calculation and its AO ERI from a single `.rustiq` archive.
//! Create the default archive with `cargo run -p rustiq-core --example write_rustiq`,
//! then run this example with `cargo run -p rustiq-core --example calculate_from_rustiq`.
#[allow(dead_code)]
mod common;

use rustiq_core::{calculation::CalculationExecution, persistence::RustiQData};

fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = common::data_path("h2.rustiq")?;
let data = RustiQData::open(&input)?;
let prepared = data.prepare_calculation()?;
let result = prepared.execute()?;
println!("Retained AO ERI values: {}", result.hf.ao_eri().len());

println!(
"HF energy: {:.12} Eh",
result.hf.summary().scf.electronic_energy
);
if let Some(mp2) = result.mp2 {
println!("MP2 correlation energy: {:.12} Eh", mp2.correlation_energy);
}
Ok(())
}
26 changes: 26 additions & 0 deletions crates/rustiq-core/examples/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use std::fs::File;
use std::path::PathBuf;

use rustiq_core::{basis::BasisFile, molecules::geometry::Geometry};

pub fn h2_inputs() -> Result<(Geometry, BasisFile), Box<dyn std::error::Error>> {
let geometry_path = workspace_path("samples/h2/molecule.xyz")?.canonicalize()?;
let basis_path = workspace_path("tests/data/sto-3g.json")?.canonicalize()?;
let geometry = Geometry::from_file(File::open(geometry_path)?)?;
let basis = BasisFile::from_reader(File::open(basis_path)?)?;
Ok((geometry, basis))
}

pub fn workspace_path(path: &str) -> Result<PathBuf, Box<dyn std::error::Error>> {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.canonicalize()?;
Ok(root.join(path))
}

#[allow(dead_code)]
pub fn data_path(filename: &str) -> Result<PathBuf, Box<dyn std::error::Error>> {
let directory = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples/data");
std::fs::create_dir_all(&directory)?;
Ok(directory.canonicalize()?.join(filename))
}
24 changes: 24 additions & 0 deletions crates/rustiq-core/examples/copy_rustiq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! Read h2.rustiq, run HF and MP2, then write the retained AO ERI to h2-copy.rustiq.
mod common;

use rustiq_core::{calculation::CalculationBuilder, config::Mp2Config, persistence::RustiQData};

fn main() -> Result<(), Box<dyn std::error::Error>> {
let (geometry, basis) = common::h2_inputs()?;
let prepared = CalculationBuilder::new(&geometry, &basis)
.with_mp2(Mp2Config::default())
.prepare()?;
let input = common::data_path("h2.rustiq")?;
let mut data = RustiQData::open(input)?;
let eri = data.take_compatible_eri(&prepared)?;
let result = prepared.execute_with_eri(eri)?;
let mut output = RustiQData::from_calculation(&prepared)?;
let output_path = common::data_path("h2-copy.rustiq")?;
output.write_with_eri(&output_path, result.hf.ao_eri())?;
println!(
"HF energy: {:.12} Eh",
result.hf.summary().scf.electronic_energy
);
println!("Wrote {}", output_path.display());
Ok(())
}
23 changes: 23 additions & 0 deletions crates/rustiq-core/examples/hf_calculation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//! Run HF and MP2 directly from the H2 sample inputs.
mod common;

use rustiq_core::{
calculation::{CalculationBuilder, CalculationExecution},
config::Mp2Config,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
let (geometry, basis) = common::h2_inputs()?;
let prepared = CalculationBuilder::new(&geometry, &basis)
.with_mp2(Mp2Config::default())
.prepare()?;
let result = prepared.execute()?;
println!(
"HF energy: {:.12} Eh",
result.hf.summary().scf.electronic_energy
);
if let Some(mp2) = result.mp2 {
println!("MP2 correlation energy: {:.12} Eh", mp2.correlation_energy);
}
Ok(())
}
15 changes: 15 additions & 0 deletions crates/rustiq-core/examples/read_rustiq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! Run HF using the AO ERI stored in h2.rustiq.
mod common;

use rustiq_core::{calculation::CalculationBuilder, persistence::RustiQData};

fn main() -> Result<(), Box<dyn std::error::Error>> {
let (geometry, basis) = common::h2_inputs()?;
let prepared = CalculationBuilder::new(&geometry, &basis).prepare()?;
let input = common::data_path("h2.rustiq")?;
let mut data = RustiQData::open(input)?;
let eri = data.take_compatible_eri(&prepared)?;
let hf = prepared.run_hf_with_eri(eri)?;
println!("HF energy: {:.12} Eh", hf.summary().scf.electronic_energy);
Ok(())
}
15 changes: 15 additions & 0 deletions crates/rustiq-core/examples/write_rustiq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! Run HF and write its retained AO ERI to h2.rustiq.
mod common;

use rustiq_core::calculation::CalculationBuilder;

fn main() -> Result<(), Box<dyn std::error::Error>> {
let (geometry, basis) = common::h2_inputs()?;
let prepared = CalculationBuilder::new(&geometry, &basis).prepare()?;
let hf = prepared.run_hf()?;
let mut data = rustiq_core::persistence::RustiQData::from_calculation(&prepared)?;
let output = common::data_path("h2.rustiq")?;
data.write_with_eri(&output, hf.ao_eri())?;
println!("Wrote {}", output.display());
Ok(())
}
82 changes: 82 additions & 0 deletions crates/rustiq-core/src/basis/gaussian/basis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,88 @@ pub struct NormalizedPrimitive {
}

impl Basis {
/// Rebuilds the resolved AO basis stored in portable calculation context.
/// Its normalized primitive coefficients are copied verbatim. Resolved AO
/// snapshots retain effective components, not the original shell grouping;
/// integral evaluation only needs the centers alongside those components.
pub(crate) fn from_calculation_context(
context: &crate::persistence::CalculationContext,
) -> Self {
let mut shells = Vec::new();
let mut shell_ids = Vec::new();
let mut angular_momenta = Vec::new();
let mut angular_components = Vec::new();
let mut normalized_components = Vec::new();

for ao in context.basis() {
let components: Vec<_> = ao.components().collect();
let first = components
.first()
.expect("validated portable AO has at least one component");
let shell_id = shells.len();
let center = ao.center();
shells.push(Shell {
alpha: nalgebra::DVector::zeros(0),
contr: Vec::new(),
origin: Point3::new(center[0], center[1], center[2]),
max_ln_coeff: nalgebra::DVector::zeros(0),
});
shell_ids.push(shell_id);
let first_angular_momentum = first.angular_momentum();
angular_momenta.push(Vector3::new(
first_angular_momentum[0],
first_angular_momentum[1],
first_angular_momentum[2],
));
angular_components.push(
components
.iter()
.map(|component| {
let angular_momentum = component.angular_momentum();
(
Vector3::new(
angular_momentum[0],
angular_momentum[1],
angular_momentum[2],
),
1.0,
)
})
.collect(),
);
normalized_components.push(
components
.iter()
.map(|component| NormalizedComponent {
angular_momentum: {
let angular_momentum = component.angular_momentum();
Vector3::new(
angular_momentum[0],
angular_momentum[1],
angular_momentum[2],
)
},
primitives: component
.primitives()
.map(|(exponent, coefficient)| NormalizedPrimitive {
exponent,
coefficient,
})
.collect(),
})
.collect(),
);
}

Self {
shells,
shell_ids,
angular_momenta,
angular_components,
normalized_components,
}
}

pub(crate) fn new(shells: Vec<Shell>) -> Self {
let mut shell_ids = Vec::new();
let mut angular_momenta = Vec::new();
Expand Down
11 changes: 9 additions & 2 deletions crates/rustiq-core/src/calculation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ pub use setup_error::HfSetupError;
mod solution;
use crate::hf::scf_result::ScfOutcome;
pub use solution::{CalculationExecutionError, Converged, HfOutcome, HfSolution, Unconverged};
mod artifact_reuse;
mod builder;
mod execution;
mod prepared_calculation;
Expand All @@ -101,8 +102,8 @@ pub use crate::{
};
pub use builder::CalculationBuilder;
pub use execution::{
CalculationEvent, CalculationExecution, CalculationResult, EriCacheAction, EriCacheEvent,
HfCalculationResult, Mp2MemoryPlan,
ArtifactReuseDecision, ArtifactReuseEvent, CalculationEvent, CalculationExecution,
CalculationResult, EriCacheAction, EriCacheEvent, HfCalculationResult, Mp2MemoryPlan,
};
pub use prepared_calculation::PreparedCalculation;
pub use request::CalculationRequest;
Expand Down Expand Up @@ -155,6 +156,8 @@ pub enum CalculationError {
Numerical(#[from] NumericalError),
#[error(transparent)]
Diis(#[from] DiisError),
#[error(transparent)]
Artifact(#[from] crate::persistence::ArtifactError),
#[error("{error}")]
Mp2 {
#[source]
Expand Down Expand Up @@ -222,17 +225,20 @@ impl<'a> HfCalculation<'a> {
config,
integrals,
eri_cache,
None,
progress,
|_| {},
)
}

#[allow(clippy::too_many_arguments)]
pub(crate) fn new_with_progress_and_cache(
molecule: &'a Molecule,
basis: &'a Basis,
config: &HfConfig,
integrals: &IntegralConfig,
eri_cache: Option<&'a EriCache>,
supplied_eri: Option<crate::eri::CompactEri>,
mut progress: impl FnMut(ScfSetupStep),
mut cache_event: impl FnMut(EriCacheEvent),
) -> Result<Self, CalculationError> {
Expand All @@ -251,6 +257,7 @@ impl<'a> HfCalculation<'a> {
&config.orthogonalization,
integrals,
eri_cache,
supplied_eri,
&mut progress,
&mut cache_event,
)
Expand Down
Loading
Loading