Skip to content

Commit

Permalink
python interface for nfold way
Browse files Browse the repository at this point in the history
  • Loading branch information
seshasaibehara committed Aug 16, 2024
1 parent 9d768f0 commit bb7eb24
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 0 deletions.
16 changes: 16 additions & 0 deletions python/src/clexmonte_monte_calculator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ CASM::clexmonte::BaseMonteCalculator *make_SemiGrandCanonicalCalculator();
/// \brief Returns a clexmonte::BaseMonteCalculator* owning a
/// CanonicalCalculator
CASM::clexmonte::BaseMonteCalculator *make_CanonicalCalculator();

/// \brief Returns a clexmonte::BaseMonteCalculator* owning a
/// NfoldCalculator
CASM::clexmonte::BaseMonteCalculator *make_NfoldCalculator();
}

/// CASM - Python binding code
Expand Down Expand Up @@ -86,6 +90,15 @@ std::shared_ptr<clexmonte::MonteCalculator> make_shared_CanonicalCalculator(
lib);
}

std::shared_ptr<clexmonte::MonteCalculator> make_shared_NfoldCalculator(
jsonParser const &params, std::shared_ptr<system_type> system) {
std::shared_ptr<RuntimeLibrary> lib = nullptr;
return clexmonte::make_monte_calculator(
params, system,
std::unique_ptr<clexmonte::BaseMonteCalculator>(make_NfoldCalculator()),
lib);
}

std::shared_ptr<clexmonte::StateData> make_state_data(
std::shared_ptr<system_type> system, state_type &state,
monte::OccLocation *occ_location) {
Expand All @@ -105,6 +118,9 @@ std::shared_ptr<clexmonte::MonteCalculator> make_monte_calculator(
return make_shared_SemiGrandCanonicalCalculator(_params, system);
} else if (method == "canonical") {
return make_shared_CanonicalCalculator(_params, system);
} else if (method == "nfold") {
return make_shared_NfoldCalculator(_params, system);

} else {
std::stringstream msg;
msg << "Error in make_monte_calculator: method='" << method
Expand Down
186 changes: 186 additions & 0 deletions python/tests/nfold/test_NfoldCalculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import numpy as np
import pytest

import libcasm.clexmonte as clexmonte
import libcasm.monte as monte
import libcasm.xtal as xtal


def test_constructors_1(Clex_ZrO_Occ_System):
system = Clex_ZrO_Occ_System

calculator = clexmonte.MonteCalculator(
method="nfold",
system=system,
)
assert isinstance(calculator, clexmonte.MonteCalculator)
with pytest.raises(Exception):
assert isinstance(calculator.potential, clexmonte.MontePotential)
with pytest.raises(Exception):
assert isinstance(calculator.state_data, clexmonte.StateData)

state = clexmonte.MonteCarloState(
configuration=system.make_default_configuration(
transformation_matrix_to_super=np.eye(3, dtype="int") * 2,
),
conditions={
"temperature": 300.0,
"param_chem_pot": [0.0],
},
)
calculator.set_state_and_potential(state=state)
assert isinstance(calculator.potential, clexmonte.MontePotential)
assert isinstance(calculator.state_data, clexmonte.StateData)

state_data = clexmonte.StateData(
system=system,
state=state,
occ_location=None,
)
assert isinstance(state_data, clexmonte.StateData)

potential = clexmonte.MontePotential(calculator=calculator, state=state)
assert isinstance(potential, clexmonte.MontePotential)


def test_run_fixture_1(Clex_ZrO_Occ_System, tmp_path):
"""A single run, using a fixture"""
system = Clex_ZrO_Occ_System
output_dir = tmp_path / "output"
summary_file = output_dir / "summary.json"

# construct a semi-grand canonical MonteCalculator
calculator = clexmonte.MonteCalculator(
method="nfold",
system=system,
)

# construct default sampling fixture parameters
thermo = calculator.make_default_sampling_fixture_params(
label="thermo",
output_dir=str(output_dir),
)
print(xtal.pretty_json(thermo.to_dict()))

# construct the initial state (default configuration)
initial_state, motif, motif_id = clexmonte.make_initial_state(
calculator=calculator,
conditions={
"temperature": 300.0,
"param_chem_pot": [-1.0],
},
min_volume=1000,
)

# Run
sampling_fixture = calculator.run_fixture(
state=initial_state,
sampling_fixture_params=thermo,
)
assert isinstance(sampling_fixture, clexmonte.SamplingFixture)

pytest.helpers.validate_summary_file(summary_file=summary_file, expected_size=1)


def test_run_fixture_2(Clex_ZrO_Occ_System, tmp_path):
"""A single run, using a fixture, for a range of param_chem_pot"""
system = Clex_ZrO_Occ_System

output_dir = tmp_path / "output"
summary_file = output_dir / "summary.json"

# construct a semi-grand canonical MonteCalculator
calculator = clexmonte.MonteCalculator(
method="nfold",
system=system,
)

# construct default sampling fixture parameters
thermo = calculator.make_default_sampling_fixture_params(
label="thermo",
output_dir=str(output_dir),
)

# set lower convergence level for potential_energy
thermo.converge(quantity="potential_energy", abs=2e-3)

# set lower convergence level for param_composition("a")
thermo.converge(quantity="param_composition", abs=2e-3, component_name=["a"])

# construct the initial state (default configuration)
state, motif, motif_id = clexmonte.make_initial_state(
calculator=calculator,
conditions={
"temperature": 300.0,
"param_chem_pot": [-1.0],
},
min_volume=1000,
)

# Run several, w/ dependent runs
x_list = np.arange(-4.0, 0.01, step=0.5)
for x in x_list:
state.conditions.vector_values["param_chem_pot"] = [x]
sampling_fixture = calculator.run_fixture(
state=state,
sampling_fixture_params=thermo,
)
assert isinstance(sampling_fixture, clexmonte.SamplingFixture)

pytest.helpers.validate_summary_file(
summary_file=summary_file, expected_size=len(x_list)
)


def test_run_1(Clex_ZrO_Occ_System, tmp_path):
"""A single run, using RunManager"""
system = Clex_ZrO_Occ_System

output_dir = tmp_path / "output"
summary_file = output_dir / "summary.json"

# construct a semi-grand canonical MonteCalculator
calculator = clexmonte.MonteCalculator(
method="nfold",
system=system,
)

# construct default sampling fixture parameters
thermo = calculator.make_default_sampling_fixture_params(
label="thermo",
output_dir=str(output_dir),
)

# construct RunManager
run_manager = clexmonte.RunManager(
engine=monte.RandomNumberEngine(),
sampling_fixture_params=[thermo],
global_cutoff=True,
)

# construct the initial state (default configuration)
state, motif, motif_id = clexmonte.make_initial_state(
calculator=calculator,
conditions={
"temperature": 300.0,
"param_chem_pot": [-1.0],
},
min_volume=1000,
)

# Run several, w/ dependent runs
x_list = np.arange(-4.0, 0.01, step=0.5)
for x in x_list:
state.conditions.vector_values["param_chem_pot"] = [x]
run_manager = calculator.run(
state=state,
run_manager=run_manager,
)
assert isinstance(run_manager, clexmonte.RunManager)
assert "thermo" in run_manager.sampling_fixture_labels
sampling_fixture = run_manager.sampling_fixture("thermo")
assert isinstance(sampling_fixture, clexmonte.SamplingFixture)

pytest.helpers.validate_summary_file(
summary_file=summary_file, expected_size=len(x_list)
)

0 comments on commit bb7eb24

Please sign in to comment.