Skip to content

Commit 135d4c1

Browse files
authored
Merge pull request #52 from ahxbcn/develop
Update run_abacus_calculation
2 parents c7262e1 + b29cc33 commit 135d4c1

7 files changed

Lines changed: 345 additions & 47 deletions

File tree

README.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ conda activate abacus-agent
2020
```
2121
2. Install necessary dependencies:
2222
```bash
23-
pip install mcp google-adk litellm bohr-agent-sdk pymatgen abacustest==0.4.24
23+
pip install mcp google-adk litellm bohr-agent-sdk pymatgen abacustest
2424
```
2525
3. Install ABACUS-agent-tools:
2626
```bash
@@ -60,9 +60,13 @@ Note: When running `abacusagent`, it will automatically check if the file exists
6060
"_comments": {
6161
"ABACUS_WORK_PATH": "The working directory for AbacusAgent, where all temporary files will be stored.",
6262
"ABACUS_SUBMIT_TYPE": "The type of submission for ABACUS, can be local or bohrium.",
63+
"ABACUSAGENT_TRANSPORT": "The transport protocol for AbacusAgent, can be 'sse' or 'streamable-http'.",
6364
"ABACUSAGENT_HOST": "The host address for the AbacusAgent server.",
6465
"ABACUSAGENT_PORT": "The port number for the AbacusAgent server.",
6566
"ABACUSAGENT_MODEL": "The model to use for AbacusAgent, can be 'fastmcp', 'test', or 'dp'.",
67+
"LLM_MODEL": "The model name for the LLM to use. Like: openai/qwen-turbo, deepseek/deepseek-chat",
68+
"LLM_API_KEY": "The API key for the LLM service.",
69+
"LLM_BASE_URL": "The base URL for the LLM service, if applicable.",
6670
"BOHRIUM_USERNAME": "The username for Bohrium.",
6771
"BOHRIUM_PASSWORD": "The password for Bohrium.",
6872
"BOHRIUM_PROJECT_ID": "The project ID for Bohrium.",
@@ -71,7 +75,10 @@ Note: When running `abacusagent`, it will automatically check if the file exists
7175
"BOHRIUM_ABACUS_COMMAND": "The command to run Abacus on Bohrium",
7276
"ABACUS_COMMAND": "The command to execute Abacus on local machine.",
7377
"ABACUS_PP_PATH": "The path to the pseudopotential library for Abacus.",
74-
"ABACUS_ORB_PATH": "The path to the orbital library for Abacus.",
78+
"ABACUS_ORB_PATH": "The path to the orbital library for ABACUS_PP_PATH",
79+
"ABACUS_SOC_PP_PATH": "The path to the SOC pseudopotential library for Abacus.",
80+
"ABACUS_SOC_ORB_PATH": "The path to the orbital library for ABACUS_SOC_PP_PATH.",
81+
"PYATB_COMMAND": "The command to execute PYATB on local machine.",
7582
"_comments": "This dictionary contains the default environment variables for AbacusAgent."
7683
}
7784
}
@@ -86,13 +93,17 @@ INFO: Application startup complete.
8693
INFO: Uvicorn running on http://localhost:50001 (Press CTRL+C to quit)
8794
```
8895
#### Preparing Google ADK Agent
89-
Organize your agent files in the following structure:
96+
You can use the following command to create files needed by a new agent:
9097
```
91-
name_of_your_agent/
98+
abacusagent --create
99+
```
100+
Then a directory containing all necessary files will be generated:
101+
```
102+
abacus-agent/
92103
├── __init__.py
93104
└── agent.py
94105
```
95-
See example files in `examples\my_agent` to prepare `__init__.py` and `agent.py`.
106+
Then you can edit the `agent.py` file to customize the agent.
96107
#### Starting Google ADK
97108
```bash
98109
>>> adk web
@@ -146,3 +157,6 @@ Functions of ABACUS Agent tools are in active development. Currently, the follow
146157
- Charge density difference
147158
- Using Birch-Murganhan equation to fit equation of state for cubic crystals
148159

160+
Besides, a wrapper function which accepts a structure file and some key parameters to do ABACUS calculation is also provided.
161+
162+
You can use `abacusagent --screen-modules` to hide tool function in some modules. The `--matmaster` option will only allow the wrapper function to be loaded.

src/abacusagent/modules/submodules/dos.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ def plot_pdos_species(shifted_energy, orbitals, output_dir, nspin, dpi):
334334
plt.plot(shifted_energy, -pdos_data[1::2], label=f'{species_name} ' + r'$\downarrow$', linestyle='--', linewidth=1.0)
335335

336336
plt.axvline(x=0, color='black', linestyle=':', linewidth=1.0)
337-
plt.xlabel('Energy/eV', fontsize=10)
338-
plt.ylabel(r'States/ev${^{-1}}$', fontsize=10)
337+
plt.xlabel('Energy (eV)', fontsize=10)
338+
plt.ylabel(r"States ($eV^{-1}$)", fontsize=10)
339339
plt.xlim(max(min(shifted_energy), -20), min(20, max(shifted_energy)))
340340
if nspin == 1:
341341
plt.ylim(bottom=0)
@@ -382,7 +382,7 @@ def plot_pdos_species_shell(shifted_energy, orbitals, output_dir, nspin, dpi):
382382

383383
ax.axvline(x=0, color='black', linestyle=':', linewidth=1.0)
384384
ax.set_title(f'PDOS for {species}', fontsize=12, pad=10)
385-
ax.set_ylabel(r'States/ev${^{-1}}$', fontsize=10)
385+
ax.set_ylabel(r"States ($eV^{-1}$)", fontsize=10)
386386
ax.set_xlim(max(min(shifted_energy), -20), min(20, max(shifted_energy)))
387387
#if nspin == 1:
388388
# ax.set_ylim(bottom=0)
@@ -391,7 +391,7 @@ def plot_pdos_species_shell(shifted_energy, orbitals, output_dir, nspin, dpi):
391391

392392
#ax.set_ylim(bottom=0)
393393

394-
axes[-1].set_xlabel('Energy/eV', fontsize=10)
394+
axes[-1].set_xlabel('Energy (eV)', fontsize=10)
395395

396396
plt.tight_layout()
397397
pdos_pic_file = os.path.join(output_dir, 'PDOS.png')
@@ -460,13 +460,13 @@ def plot_pdos_species_orbital(shifted_energy, orbitals, output_dir, nspin, label
460460
ax.set_xlim(max(min(shifted_energy), -20), min(20, max(shifted_energy)))
461461
if nspin == 1:
462462
ax.set_ylim(bottom=0)
463-
ax.set_ylabel(r'States/ev${^{-1}}$', fontsize=10)
463+
ax.set_ylabel(r"States ($eV^{-1}$)", fontsize=10)
464464
ax.legend(fontsize=8, ncol=nspin)
465465
ax.grid(alpha=0.3)
466466

467467
subplot_count += 1
468468

469-
axes[-1].set_xlabel('Energy/eV', fontsize=10)
469+
axes[-1].set_xlabel('Energy (eV)', fontsize=10)
470470

471471
plt.tight_layout()
472472
pdos_pic_file = os.path.join(output_dir, 'PDOS.png')
@@ -500,8 +500,8 @@ def plot_dos(file_path: List[Path],
500500
plt.plot(energy, dos, linestyle='-', label='spin up')
501501
plt.plot(energy, -dos_dn, linestyle='--', label='spin down')
502502
plt.axvline(x=0, color='k', linestyle='--', alpha=0.5)
503-
plt.xlabel('Energy/eV')
504-
plt.ylabel(r'States/ev${^{-1}}$')
503+
plt.xlabel('Energy (eV)')
504+
plt.ylabel(r'States ($eV^{-1}$)')
505505
plt.title('Density of States')
506506
plt.grid(True, alpha=0.3)
507507
plt.xlim(x_min, x_max)

src/abacusagent/modules/submodules/eos.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import os
22
from pathlib import Path
33
from typing import Literal, Optional, TypedDict, Dict, Any, List
4+
import copy
45
import numpy as np
56
import matplotlib.pyplot as plt
67
from abacustest.lib_prepare.abacus import AbacusStru, ReadInput, WriteInput
78
from abacustest.lib_model.comm_eos import eos_fit
89
from abacustest.lib_model.comm import check_abacus_inputs
910

1011
from abacusagent.init_mcp import mcp
11-
from abacusagent.modules.abacus import abacus_modify_input, abacus_modify_stru, abacus_collect_data
12-
from abacusagent.modules.util.comm import run_abacus, link_abacusjob, generate_work_path
12+
from abacusagent.modules.util.comm import run_abacus, link_abacusjob, generate_work_path, collect_metrics
1313

1414
def is_cubic(cell: List[List[float]]) -> bool:
1515
"""
@@ -76,7 +76,8 @@ def abacus_eos(
7676
raise ValueError("The structure is not cubic. Implemented EOS calculation requires a cubic structure.")
7777

7878
# Generated lattice parameters for EOS calculation
79-
original_cell_param = input_stru.get_cell()[0][0] # Assuming cubic structure, take one cell parameter
79+
original_cell = input_stru.get_cell()
80+
original_cell_param = np.linalg.norm(original_cell[0])
8081
if stru_scale_type == 'percentage':
8182
scales = [1 + i * scale_stepsize for i in range(-stru_scale_number, stru_scale_number + 1)]
8283
elif stru_scale_type == 'angstrom':
@@ -86,9 +87,11 @@ def abacus_eos(
8687

8788
scaled_lat_params = [original_cell_param * scale for scale in scales]
8889

89-
output = abacus_modify_input(abacus_inputs_dir, extra_input={'calculation': 'scf'})
90+
input_params['calculation'] = 'scf'
91+
WriteInput(input_params, os.path.join(abacus_inputs_dir, "INPUT"))
9092

9193
scale_cell_job_dirs = []
94+
stru = copy.deepcopy(input_stru)
9295
for i in range(len(scales)):
9396
dir_name = Path(os.path.join(work_path, f"scale_cell_{i}")).absolute()
9497
os.makedirs(dir_name, exist_ok=True)
@@ -103,13 +106,14 @@ def abacus_eos(
103106
)
104107

105108
new_cell = (np.array(input_stru.get_cell()) * scales[i]).tolist()
106-
output = abacus_modify_stru(dir_name, cell=new_cell, coord_change_type='scale')
109+
stru.set_cell(new_cell, bohr=False, change_coord=True)
110+
stru.write(os.path.join(dir_name, input_stru_file))
107111

108112
run_abacus(scale_cell_job_dirs)
109113

110114
energies = []
111115
for i, job_dir in enumerate(scale_cell_job_dirs):
112-
metrics = abacus_collect_data(job_dir)['collected_metrics']
116+
metrics = collect_metrics(job_dir)
113117
if metrics['normal_end'] is not True or metrics['converge'] is not True:
114118
raise RuntimeError(f"Job {i} did not end normally or did not converge. Please check the job directory: {job_dir}")
115119
energies.append(metrics['energy'])
@@ -139,9 +143,8 @@ def abacus_eos(
139143
)
140144
optimal_lat_param = V0 ** (1.0 / 3)
141145
optimal_cell = (np.array(input_stru.get_cell()) * optimal_lat_param / original_cell_param).tolist()
142-
output = abacus_modify_stru(new_abacus_inputs_dir,
143-
cell = optimal_cell,
144-
coord_change_type = 'scale')
146+
stru.set_cell(optimal_cell, bohr=False, change_coord=True)
147+
stru.write(os.path.join(new_abacus_inputs_dir, input_stru_file))
145148

146149
return {
147150
"eos_work_path": work_path.absolute(),

src/abacusagent/modules/submodules/md.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
from abacustest.lib_prepare.abacus import ReadInput, WriteInput, AbacusStru
99

1010
from abacusagent.init_mcp import mcp
11-
from abacusagent.modules.util.comm import generate_work_path, link_abacusjob, run_abacus
12-
from abacusagent.modules.abacus import abacus_collect_data
11+
from abacusagent.modules.util.comm import generate_work_path, link_abacusjob, run_abacus, collect_metrics
1312

1413

1514
def get_last_md_stru(md_stru_outputdir: Path) -> Path:
@@ -181,7 +180,7 @@ def abacus_run_md(
181180

182181
run_abacus(work_path)
183182

184-
metrics = abacus_collect_data(work_path)['collected_metrics']
183+
metrics = collect_metrics(work_path)
185184
suffix = input_params.get('suffix', 'ABACUS')
186185
md_traj_file, traj_frame_nums = convert_md_dump_to_ase_traj(Path(os.path.join(work_path, f'OUT.{suffix}/MD_dump')).absolute())
187186
return {'md_work_path': work_path,

0 commit comments

Comments
 (0)