Skip to content

Accond #251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dptb/tests/**/*.traj
dptb/tests/**/out*/*
examples/_*
*.dat
*log*
*log.*
dptb/tests/data/**/out*/config_*.json
bandstructure.npy
dptb/tests/data/hBN/data/set.0/xdat2.traj
Expand Down
81 changes: 81 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
cmake_minimum_required(VERSION 3.17...3.26)

option(BUILD_FORTRAN "Build Fortran extensions" OFF)
option(USE_INTEL "Use Intel compilers" ON)
option(USE_OPENMP "Use OpenMP" ON)

set(CMAKE_Fortran_FLAGS "-fpp -O3 -xHost -qopenmp -ipo -heap-arrays 32 -unroll -fma -align")
set(CMAKE_C_FLAGS "-O3 -xHost -ipo -fma -align")


if(BUILD_FORTRAN)
if(USE_INTEL)
set(CMAKE_C_COMPILER "icx")
set(CMAKE_Fortran_COMPILER "ifx")
else()
# 使用默认的编译器
endif()

project(${SKBUILD_PROJECT_NAME} LANGUAGES C Fortran)

# 设置编译器标志
#set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -O3 -fPIC")

if(USE_OPENMP)
find_package(OpenMP REQUIRED)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}")
endif()

# Search for packages and commands
find_package(Python COMPONENTS Interpreter Development.Module NumPy REQUIRED)

#------------------------------ Compiler options ------------------------------#
# Detect compiler vendor
if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
set(VENDOR "gnu")
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Intel")
set(VENDOR "intel")
else()
message(FATAL_ERROR "Unsupported Fortran compiler ${CMAKE_Fortran_COMPILER}")
endif()

#----------------------------- Fortran extension ------------------------------#
# Define the fortranobject
execute_process(
COMMAND "${Python_EXECUTABLE}" -c
"import numpy.f2py; print(numpy.f2py.get_include())"
OUTPUT_VARIABLE F2PY_INCLUDE_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE)
add_library(fortranobject OBJECT "${F2PY_INCLUDE_DIR}/fortranobject.c")
target_link_libraries(fortranobject PUBLIC Python::NumPy)
target_include_directories(fortranobject PUBLIC "${F2PY_INCLUDE_DIR}")
set_property(TARGET fortranobject PROPERTY POSITION_INDEPENDENT_CODE ON)

# Set the Fortran source file path
set(FORTRAN_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/dptb/postprocess/fortran/ac_cond.f90")

# Generate the interface
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ac_condmodule.c"
DEPENDS "${FORTRAN_SOURCE}"
COMMAND "${Python_EXECUTABLE}" -m numpy.f2py "${FORTRAN_SOURCE}"
-m ac_cond --lower
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
VERBATIM
)

# Define the python module
python_add_library(ac_cond MODULE
"${CMAKE_CURRENT_BINARY_DIR}/ac_condmodule.c"
"${FORTRAN_SOURCE}"
WITH_SOABI)
target_link_libraries(ac_cond PRIVATE fortranobject)
if(OpenMP_Fortran_FOUND)
target_link_libraries(ac_cond PRIVATE OpenMP::OpenMP_Fortran)
endif()

install(TARGETS ac_cond DESTINATION ./dptb/postprocess/fortran)
else()
project(${SKBUILD_PROJECT_NAME})
message(STATUS "Fortran extensions are disabled")
endif()
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ RUN apt-get update > /dev/null && \
git \
tini \
g++ \
cmake \
> /dev/null && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
Expand Down
1 change: 1 addition & 0 deletions Dockerfile.main
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ RUN apt-get update > /dev/null && \
git \
tini \
g++ \
cmake \
> /dev/null && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
Installing **DeePTB** is straightforward. We recommend using a virtual environment for dependency management.

### Requirements
- Cmake 3.17 or later.
- Python 3.8 or later.
- Torch 1.13.0 or later ([PyTorch Installation](https://pytorch.org/get-started/locally)).
- ifermi (optional, for 3D fermi-surface plotting).
Expand All @@ -45,6 +46,20 @@ Installing **DeePTB** is straightforward. We recommend using a virtual environme
pip install .
```

### Install optical response module
1. Ensure you have the intel MKL library installed.

2. Clone the repository:
```bash
git clone https://github.com/deepmodeling/DeePTB.git
```
3. Navigate to the root directory and install DeePTB:
```bash
cd DeePTB
BUILD_FORTRAN=ON pip install .
```
Note: by default, the optical response module is not installed. To install it, you need to set the `BUILD_FORTRAN=ON` flag. By default we set the CMakeList.txt to use the intel compiler with openmp enabled. If you want to use other compilers, you need to modify the CMakeList.txt file.

## Usage
For a comprehensive guide and usage tutorials, visit [our documentation website](https://deeptb.readthedocs.io/en/latest/).

Expand Down
11 changes: 9 additions & 2 deletions dptb/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import importlib.metadata
try:
import importlib.metadata as importlib_metadata
except ImportError:
# for Python 3.7
import importlib_metadata

__version__ = importlib.metadata.version("dptb")
try:
__version__ = importlib_metadata.version("dptb")
except importlib_metadata.PackageNotFoundError:
__version__ = "unknown"
20 changes: 20 additions & 0 deletions dptb/entrypoints/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from dptb.utils.tools import j_loader
from dptb.utils.tools import j_must_have
from dptb.postprocess.write_ham import write_ham
from dptb.postprocess.optical.optical_cond import AcCond
import torch
import h5py

Expand Down Expand Up @@ -85,6 +86,25 @@ def run(
emin=jdata["task_options"].get("emin", None),
emax=jdata["task_options"].get("emax", None))
log.info(msg='band calculation successfully completed.')
elif task == 'ac_cond':
accondcal = AcCond(model=model, results_path=results_path, use_gui=use_gui)

accondcal.get_accond(struct=struct_file,
AtomicData_options=jdata['AtomicData_options'],
emax=jdata['task_options'].get('emax'),
num_omega=jdata['task_options'].get('num_omega',1000),
mesh_grid=jdata['task_options'].get('mesh_grid',[1,1,1]),
nk_per_loop=jdata['task_options'].get('nk_per_loop',None),
delta=jdata['task_options'].get('delta',0.03),
e_fermi=jdata['task_options'].get('e_fermi',0),
valence_e=jdata['task_options'].get('valence_e',None),
gap_corr=jdata['task_options'].get('gap_corr',0),
T=jdata['task_options'].get('T',300),
direction=jdata['task_options'].get('direction','xx'),
g_s=jdata['task_options'].get('g_s',2)
)
accondcal.accond_plot()
log.info(msg='ac optical conductivity calculation successfully completed.')

elif task=='write_block':
task = torch.load(init_model, map_location="cpu")["task"]
Expand Down
130 changes: 130 additions & 0 deletions dptb/nn/hr2dhk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#from hr2dhk import Hr2dHk
import torch
from dptb.utils.constants import h_all_types, anglrMId, atomic_num_dict, atomic_num_dict_r
from typing import Tuple, Union, Dict
from dptb.data.transforms import OrbitalMapper
from dptb.data import AtomicDataDict
import re
from dptb.utils.tools import float2comlex

class Hr2dHk(torch.nn.Module):
def __init__(
self,
basis: Dict[str, Union[str, list]]=None,
idp: Union[OrbitalMapper, None]=None,
edge_field: str = AtomicDataDict.EDGE_FEATURES_KEY,
node_field: str = AtomicDataDict.NODE_FEATURES_KEY,
out_field: str = 'dHdk',
overlap: bool = False,
dtype: Union[str, torch.dtype] = torch.float32,
device: Union[str, torch.device] = torch.device("cpu"),
):
super(Hr2dHk, self).__init__()

if isinstance(dtype, str):
dtype = getattr(torch, dtype)
self.dtype = dtype
self.device = device
self.overlap = overlap
self.ctype = float2comlex(dtype)

if basis is not None:
self.idp = OrbitalMapper(basis, method="e3tb", device=self.device)
if idp is not None:
assert idp == self.idp, "The basis of idp and basis should be the same."
else:
assert idp is not None, "Either basis or idp should be provided."
assert idp.method == "e3tb", "The method of idp should be e3tb."
self.idp = idp

self.basis = self.idp.basis
self.idp.get_orbpair_maps()
self.idp.get_orbpair_soc_maps()

self.edge_field = edge_field
self.node_field = node_field
self.out_field = out_field

def forward(self, data: AtomicDataDict.Type, direction = 'xyz') -> AtomicDataDict.Type:
dir2ind = {'x':0, 'y':1, 'z':2}

uniq_direcs = list(set(direction))
assert len(uniq_direcs) > 0, "direction should be provided."
orbpair_hopping = data[self.edge_field]
orbpair_onsite = data.get(self.node_field)

bondwise_dh = {}
for idirec in uniq_direcs:
assert idirec in dir2ind, "direction should be x, y or z."
bondwise_dh[idirec] = torch.zeros((len(orbpair_hopping), self.idp.full_basis_norb, self.idp.full_basis_norb), dtype=self.dtype, device=self.device)

dr_ang = data[AtomicDataDict.EDGE_VECTORS_KEY]
onsite_block = torch.zeros((len(data[AtomicDataDict.ATOM_TYPE_KEY]), self.idp.full_basis_norb, self.idp.full_basis_norb,), dtype=self.dtype, device=self.device)

ist = 0
for i,iorb in enumerate(self.idp.full_basis):
jst = 0
li = anglrMId[re.findall(r"[a-zA-Z]+", iorb)[0]]
for j,jorb in enumerate(self.idp.full_basis):
orbpair = iorb + "-" + jorb
lj = anglrMId[re.findall(r"[a-zA-Z]+", jorb)[0]]

# constructing hopping blocks
if iorb == jorb:
factor = 0.5
else:
factor = 1.0

if i <= j:
# note: we didnot consider the factor 1.0j here. we will multiply it later.
# -1j * R_ij * H_ij(R_ij) * exp(-i2pi k.R_ij)
for idirec in uniq_direcs:
bondwise_dh[idirec][:,ist:ist+2*li+1,jst:jst+2*lj+1] = factor * ( -1 * dr_ang[:,[dir2ind[idirec]]] * orbpair_hopping[:,self.idp.orbpair_maps[orbpair]]).reshape(-1, 2*li+1, 2*lj+1)
if self.overlap:
raise NotImplementedError("Overlap is not implemented for dHk yet.")
else:
if i <= j:
onsite_block[:,ist:ist+2*li+1,jst:jst+2*lj+1] = factor * orbpair_onsite[:,self.idp.orbpair_maps[orbpair]].reshape(-1, 2*li+1, 2*lj+1)
jst += 2*lj+1
ist += 2*li+1
self.onsite_block = onsite_block
self.bondwise_dh = bondwise_dh

# R2K procedure can be done for all kpoint at once.
all_norb = self.idp.atom_norb[data[AtomicDataDict.ATOM_TYPE_KEY]].sum()


dHdk = {}
for idirec in uniq_direcs:
dHdk[idirec] = torch.zeros(data[AtomicDataDict.KPOINT_KEY][0].shape[0], all_norb, all_norb, dtype=self.ctype, device=self.device)

atom_id_to_indices = {}
ist = 0
for i, oblock in enumerate(onsite_block):
mask = self.idp.mask_to_basis[data[AtomicDataDict.ATOM_TYPE_KEY].flatten()[i]]
masked_oblock = oblock[mask][:,mask]
for idirec in uniq_direcs:
dHdk[idirec][:,ist:ist+masked_oblock.shape[0],ist:ist+masked_oblock.shape[1]] = masked_oblock.squeeze(0)
atom_id_to_indices[i] = slice(ist, ist+masked_oblock.shape[0])
ist += masked_oblock.shape[0]

for i in range (len(bondwise_dh[uniq_direcs[0]])):
iatom = data[AtomicDataDict.EDGE_INDEX_KEY][0][i]
jatom = data[AtomicDataDict.EDGE_INDEX_KEY][1][i]
iatom_indices = atom_id_to_indices[int(iatom)]
jatom_indices = atom_id_to_indices[int(jatom)]
imask = self.idp.mask_to_basis[data[AtomicDataDict.ATOM_TYPE_KEY].flatten()[iatom]]
jmask = self.idp.mask_to_basis[data[AtomicDataDict.ATOM_TYPE_KEY].flatten()[jatom]]


for idirec in uniq_direcs:
hblock = bondwise_dh[idirec][i]
masked_hblock = hblock[imask][:,jmask]
dHdk[idirec][:,iatom_indices,jatom_indices] += 1.0j *masked_hblock.squeeze(0).type_as(dHdk[idirec]) * \
torch.exp(-1j * 2 * torch.pi * (data[AtomicDataDict.KPOINT_KEY][0] @ data[AtomicDataDict.EDGE_CELL_SHIFT_KEY][i])).reshape(-1,1,1)

for idirec in uniq_direcs:
dHdk[idirec] = dHdk[idirec] + dHdk[idirec].conj().transpose(1,2)

return dHdk

4 changes: 4 additions & 0 deletions dptb/plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .train_logger import Logger
from .base_plugin import Plugin, PluginUser
from .monitor import Monitor
from .saver import Saver
Loading