Skip to content

Create directories for model hamiltonians in tests directory#261

Open
JaeHyeokLee98 wants to merge 3 commits intoskmin-lab:masterfrom
JaeHyeokLee98:pytest_SAC
Open

Create directories for model hamiltonians in tests directory#261
JaeHyeokLee98 wants to merge 3 commits intoskmin-lab:masterfrom
JaeHyeokLee98:pytest_SAC

Conversation

@JaeHyeokLee98
Copy link
Copy Markdown
Contributor

Previously, only Shin-Metiu model is tested with pytest.

I'm going to add SAC model also for pytest

Create Shin-Metiu directory
Move files related to Shin-Metiu modeln in tests to Shin-Metiu directory
Create SAC directory
…-Metiu

Copy mqc_runner.py, pytest.ini, test_mqc_cases.py
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @JaeHyeokLee98, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request establishes a foundational testing framework for the Shin-Metiu model within the project. It introduces a dedicated runner for various multi-quantum coherence simulations and populates the test suite with extensive reference data. This setup is a prerequisite for expanding test coverage to other models, such as the SAC model, in future development.

Highlights

  • New MQC Runner Module: A new Python module, mqc_runner.py, has been added to define a structured way to build and execute various Multi-Quantum Coherence (MQC) simulations for the Shin-Metiu model. This includes methods like BOMD, Eh, SH, SHXF, EhXF, and CT, with configurable parameters for hop rescaling, rejection, and width schemes.
  • Pytest Configuration for MQC Methods: A pytest.ini file has been introduced to define custom markers for different MQC methods within the Shin-Metiu model. This will help in organizing and selectively running tests for specific simulation types.
  • Comprehensive Reference Data for Shin-Metiu Model: A large set of reference output files has been added under tests/Shin-Metiu/reference/ for various MQC methods and their configurations. These files cover molecular coordinates, energy data, Born-Oppenheimer coefficients, coherence, population, non-adiabatic coupling matrix elements, surface hopping probabilities, running states, and simulation logs, providing a robust baseline for regression testing.
Changelog
  • tests/Shin-Metiu/mqc_runner.py
    • Added a new module to define MQCArgs dataclass and functions (build_mqc, run_case) for configuring and running Shin-Metiu model simulations across various MQC methods.
  • tests/Shin-Metiu/pytest.ini
    • Added pytest configuration to define custom markers for different MQC simulation types (mqc, bomd, eh, sh, shxf, ehxf, ct) for the Shin-Metiu Model.
  • tests/Shin-Metiu/reference/
    • Added numerous reference output files (including .xyz, MDENERGY, BOCOEF, BOCOH, BOPOP, NACME, SHPROB, SHSTATE, and run.log) for BOMD, CT (two trajectories), Eh, EhXF (with various rescale/reject and width options), SH (with various rescale/reject options), and SHXF (with various rescale/reject and width options) simulations under the Shin-Metiu model. These files serve as ground truth for validating simulation results.
Activity
  • The pull request description indicates that this change is a preparatory step to extend pytest coverage to the SAC model, as currently only the Shin-Metiu model has pytest tests.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a test runner and extensive reference data for the Shin-Metiu model, which is a great step towards improving test coverage. The overall structure is good. My review of the new test runner script, mqc_runner.py, focuses on several areas for improvement to enhance code quality, readability, and maintainability. I've suggested using Enums to avoid magic numbers, refactoring a long conditional block to reduce duplication, and avoiding modification of global state and the current working directory. I also pointed out a minor typo in the pytest configuration and some import styling that could follow PEP 8.

def build_mqc(args: MQCArgs, nsteps: int = 10):

# Define initial conditions for the Shin-Metiu model
data["X1"] = 1836 # au
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The function build_mqc modifies the global data dictionary imported from misc. Modifying global state can lead to unexpected side effects and makes the code harder to understand, debug, and test. It would be better to avoid this. Perhaps this value can be configured in a more explicit way, for example by passing it as an argument or loading it from a configuration file within the model that uses it.

from dataclasses import dataclass
from contextlib import redirect_stdout, redirect_stderr
from pathlib import Path
import os, copy
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to PEP 8 style guidelines, it's recommended to have one import per line. This improves code readability.

Suggested change
import os, copy
import os
import copy

import random

from molecule import Molecule
import qm, mqc
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to PEP 8 style guidelines, it's recommended to have one import per line. This improves code readability.

Suggested change
import qm, mqc
import qm
import mqc

Comment on lines +12 to +17
@dataclass(frozen=True)
class MQCArgs:
md: int = 3 # the MQC method (0: BOMD, 1: Eh, 2: SH, 3: SHXF, 4: EhXF, 5: CT)
rescale: int = 3 # the hop rescale option (0: energy, 1: velocity, 2: momentum, 3: augment)
reject: int = 1 # the hop reject option (0: keep, 1: reverse)
width: int = 0 # the width scheme in XF (0: frozen Gaussian as 0.1 Bohr, 1: TD)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The MQCArgs class uses integers to represent different configuration options (e.g., md, rescale). This use of 'magic numbers' can make the code harder to read and maintain. It's better to use Enums to define these options, which makes the code more self-documenting and robust.

Example:

from enum import IntEnum

class MQCMethod(IntEnum):
    BOMD = 0
    EH = 1
    SH = 2
    SHXF = 3
    EHXF = 4
    CT = 5

class RescaleOption(IntEnum):
    ENERGY = 0
    VELOCITY = 1
    MOMENTUM = 2
    AUGMENT = 3

# ... and so on for other options.

@dataclass(frozen=True)
class MQCArgs:
    md: MQCMethod = MQCMethod.SHXF
    rescale: RescaleOption = RescaleOption.AUGMENT
    # ...

This would make comparisons in build_mqc like if args.md == MQCMethod.BOMD: much clearer.

Comment on lines +44 to +91
if args.md == 0: # BOMD
out_dir += "-BOMD"
md = mqc.BOMD(molecule=mol, nsteps=nsteps, dt=5.0, unit_dt="au", istate=1)

elif args.md == 1: # Eh
out_dir += "-Eh"
md = mqc.Eh(molecule=mol, nsteps=nsteps, dt=5.0, unit_dt="au", istate=1)

elif args.md == 2: # SH
out_dir += "-SH"
md = mqc.SH(molecule=mol, nsteps=nsteps, nesteps=1, dt=5.0, unit_dt="au", istate=1)
suffix, md.hop_rescale, md.hop_reject = MOMENTUM_JUMP_SCHEME[(args.rescale, args.reject)]
out_dir += suffix

elif args.md == 3: # SHXF
out_dir += "-SHXF"
if args.width == 0:
md = mqc.SHXF(molecule=mol, nsteps=nsteps, nesteps=1, dt=5.0, unit_dt="au", sigma=0.1, istate=1)
out_dir += "-FG"
elif args.width == 1:
md = mqc.SHXF(molecule=mol, nsteps=nsteps, nesteps=1, dt=5.0, unit_dt="au", l_td_sigma=True, istate=1)
out_dir += "-TD"
else:
raise ValueError(f"Invalid width={args.width} for SHXF")
suffix, md.hop_rescale, md.hop_reject = MOMENTUM_JUMP_SCHEME[(args.rescale, args.reject)]
out_dir += suffix

elif args.md == 4: # EhXF
out_dir += "-EhXF"
if args.width == 0:
md = mqc.EhXF(molecule=mol, nsteps=nsteps, nesteps=1, dt=5.0, unit_dt="au", sigma=0.1, istate=1)
out_dir += "-FG"
elif args.width == 1:
md = mqc.EhXF(molecule=mol, nsteps=nsteps, nesteps=1, dt=5.0, unit_dt="au", l_td_sigma=True, istate=1)
out_dir += "-TD"
else:
raise ValueError(f"Invalid width={args.width} for EhXF")
suffix, md.hop_rescale, md.hop_reject = MOMENTUM_JUMP_SCHEME[(args.rescale, args.reject)]
out_dir += suffix

elif args.md == 5: # CT
out_dir += "-CT"
mol1 = copy.deepcopy(mol)
mol1.pos[0, 0] = -1.9
md = mqc.CT(molecules=[mol, mol1], nsteps=nsteps, nesteps=1, dt=5.0, unit_dt="au", istates=[1, 1])

else:
raise ValueError(f"Invalid md={args.md}")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The build_mqc function contains a long if/elif/else chain that can be refactored for better readability and maintainability. There is significant code duplication, especially in the blocks for SHXF (lines 58-69) and EhXF (lines 71-82). This duplication can be reduced by extracting common logic into helper functions or using a more data-driven approach like a factory pattern.
For instance, the logic for handling args.width and setting hop parameters is identical for SHXF and EhXF. This could be extracted into a shared function.

Comment on lines +103 to +111
cwd = os.getcwd()
try:
random.seed(1000) # keep random numbers for SH tests

with open(log_path, "w") as f, redirect_stdout(f), redirect_stderr(f):
md.run(qm=qm, output_dir=str(out_dir))
#md.run(qm=qm, output_dir=out_dir)
finally:
os.chdir(cwd)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The run_case function changes the current working directory using os.chdir(). While the try...finally block correctly restores the original directory, changing the global state of the process (like the CWD) is generally discouraged. It can lead to subtle bugs, especially in a testing context where tests might be run in parallel. It's better to work with absolute paths or paths relative to a known base directory. The md.run function seems to accept an output_dir. If it can handle absolute paths, you could construct the absolute path for log_path and out_dir and pass those, avoiding the need to change the CWD.

bomd: Born-Oppenheimer MD
eh: Ehrenfest dynamics
sh: surface hopping
shxf: surface hopping basd on XF
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a typo in the description for the shxf marker. 'basd' should be 'based'.

    shxf: surface hopping based on XF

Comment on lines +32 to +34
# Define initial conditions for the Shin-Metiu model
data["X1"] = 1836 # au
geom = """
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Tully's models, the mass was originally set to 2000 a.u., so please change it. Also, please edit all comments accordingly, e.g. Shin-Metiu -> SAC in this case.

(3, 1): ("-a-", "augment", "reverse"),
}

def build_mqc(args: MQCArgs, nsteps: int = 50):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider reducing nsteps, let say, nsteps=10 by adjusting dt, etc., for faster pytest as in the Shin-Metiu pytest.


return qm_model, md, out_dir

def run_case(args: MQCArgs, nsteps: int = 50):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make nsteps consistent when you change nsteps above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants