Skip to content
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

Translated Meta-GGA on-top functionals and MC23 functional added for the MCPDFT #93

Merged
merged 17 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from 10 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
33 changes: 33 additions & 0 deletions examples/mcpdft/03-metaGGA_functionals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env/python
from pyscf import gto, scf, mcpdft

mol = gto.M (
atom = 'O 0 0 0; O 0 0 1.2',
basis = 'ccpvdz',
spin = 2)

mf = scf.RHF (mol).run ()

# The translation of Meta-GGAs and hybrid-Meta-GGAs [ChemRxiv. 2024; doi:10.26434/chemrxiv-2024-5hc8g-v2]

# Translated-Meta-GGA
mc = mcpdft.CASCI(mf, 'tM06L', 6, 8).run ()

# Hybrid-Translated-Meta-GGA
tM06L0 = 't' + mcpdft.hyb('M06L',0.25, hyb_type='average')
mc = mcpdft.CASCI(mf, tM06L0, 6, 8).run ()

# MC23: meta-hybrid on-top functional [ChemRxiv. 2024; doi:10.26434/chemrxiv-2024-5hc8g-v2]
# To calculate the MC23 energies, you can define functional as 'tMC23'.

# Note: It's 'fully-translated' version 'ftMC23' is not defined as of now.

# State-Specific
mc = mcpdft.CASCI(mf, 'tMC23', 6, 8)
mc.kernel()

# State-average
nroots=2
mc = mcpdft.CASCI(mf, 'tMC23', 6, 8)
mc.fcisolver.nroots=nroots
mc.kernel()[0]
4 changes: 2 additions & 2 deletions pyscf/mcpdft/_libxc.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
from pyscf.dft.libxc import XC_ALIAS, XC_CODES, XC_KEYS
from pyscf.dft.libxc import hybrid_coeff, rsh_coeff
from pyscf.dft2.libxc import XC_ALIAS, XC_CODES, XC_KEYS
from pyscf.dft2.libxc import hybrid_coeff, rsh_coeff
from pyscf import lib

XC_ALIAS_KEYS = set (XC_ALIAS.keys ())
Expand Down
149 changes: 131 additions & 18 deletions pyscf/mcpdft/otfnal.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,110 @@
from scipy import linalg
from pyscf import lib, dft
from pyscf.lib import logger
from pyscf.dft2 import libxc
from pyscf.dft.gen_grid import Grids
from pyscf.dft.numint import _NumInt, NumInt
from pyscf.mcpdft import pdft_veff, tfnal_derivs, _libxc, _dms, pdft_feff, pdft_eff
from pyscf.mcpdft.otpd import get_ontop_pair_density
from pyscf import __config__

# Points to the libxc of the dft2 module
dft.numint.libxc = libxc
dft.numint.LibXCMixin.libxc = libxc
JangidBhavnesh marked this conversation as resolved.
Show resolved Hide resolved

FT_R0 = getattr(__config__, 'mcpdft_otfnal_ftransfnal_R0', 0.9)
FT_R1 = getattr(__config__, 'mcpdft_otfnal_ftransfnal_R1', 1.15)
FT_A = getattr(__config__, 'mcpdft_otfnal_ftransfnal_A', -475.60656009)
FT_B = getattr(__config__, 'mcpdft_otfnal_ftransfnal_B', -379.47331922)
FT_C = getattr(__config__, 'mcpdft_otfnal_ftransfnal_C', -85.38149682)

OT_HYB_ALIAS = {'PBE0' : '0.25*HF + 0.75*PBE, 0.25*HF + 0.75*PBE'}
OT_HYB_ALIAS = {'PBE0' : '0.25*HF + 0.75*PBE, 0.25*HF + 0.75*PBE',
'MC23' : 'mc23'} # Note: mc23 is hybrid Meta-GGA OT Functional.

REG_OT_FUNCTIONALS={}

# ALIAS for the preset on-top functional
OT_PRESET={
# Reparametrized-M06L: rep-M06L
# MC23 = { '0.2952*HF + (1-0.2952)*rep-M06L, 0.2952*HF + (1-0.2952)*rep-M06L'}}
# XC_ID_MGGA_C_M06_L = 233
# XC_ID_MGGA_X_M06_L = 203
'MC23':{
'xc_base':'M06L',
'ext_params':{203: np.array([3.352197, 6.332929e-01, -9.469553e-01, 2.030835e-01,
2.503819, 8.085354e-01, -3.619144, -5.572321e-01,
-4.506606, 9.614774e-01, 6.977048, -1.309337, -2.426371,
-7.896540e-03, 1.364510e-02, -1.714252e-06, -4.698672e-05, 0.0]),
233: np.array([0.06, 0.0031, 0.00515088, 0.00304966, 2.427648, 3.707473,
-7.943377, -2.521466, 2.658691, 2.932276, -8.832841e-01,
-1.895247, -2.899644, -5.068570e-01, -2.712838, 9.416102e-02,
-3.485860e-03, -5.811240e-04, 6.668814e-04, 0.0, 2.669169e-01,
-7.563289e-02, 7.036292e-02, 3.493904e-04, 6.360837e-04, 0.0, 1e-10])},
'hyb':(0.2952,0,0),
'facs':(0.7048,0.7048)}
}

def register_otfnal(xc_code, preset):
'''
This function registers the new on-top functional if it hasn't been
registered previously.
Args:
xc_code: str
The name of the on-top functional to be registered.
preset: dict
The dictionary containing the information about the on-top functional
to be registered.
xc_base: str
The name of the underylying KS-functional in the libxc library.
ext_params: dict, with LibXC exchange and correlation functional integer ID as key, and
an array-like object containing the functional parameters as value.
hyb: tuple
The hybrid functional parameters.
facs: tuple
The mixing factors.
kwargs: dict
The additional keyword arguments.
'''
libxc_register_code = xc_code.lower ()
libxc_base_code = preset['xc_base']
ext_params = preset['ext_params']
hyb = preset.get('hyb', None)
facs = preset.get('facs', None)
libxc.register_custom_functional_(libxc_register_code, libxc_base_code,
ext_params=ext_params, hyb=hyb, facs=facs)
REG_OT_FUNCTIONALS[xc_code.upper()] = {'hyb_x':preset.get('hyb',[0])[0],
'hyb_c':preset.get('hyb',[0])[0]}

def unregister_otfnal(xc_code):
'''
This function unregisters the on-top functional if it has been registered
previously.
Args:
xc_code: str
The name of the on-top functional to be unregistered.
'''
try:
if xc_code.upper() in REG_OT_FUNCTIONALS:
libxc_unregister_code = xc_code.lower()
libxc.unregister_custom_functional_(libxc_unregister_code)
del REG_OT_FUNCTIONALS[xc_code.upper()]

except Exception as e:
raise RuntimeError(f"Failed to unregister functional '{xc_code}': {e}") from e

def _get_regsitered_ot_functional(xc_code, mol):
JangidBhavnesh marked this conversation as resolved.
Show resolved Hide resolved
'''
This function returns the on-top functional if it has been registered
previously.
Args:
xc_code: str
The name of the on-top functional to be registered.
'''
if (xc_code.upper() not in REG_OT_FUNCTIONALS) and (xc_code.upper() in OT_PRESET):
preset = OT_PRESET[xc_code.upper()]
register_otfnal(xc_code, preset)
logger.info(mol, 'Registered the on-top functional: %s', xc_code)
return xc_code.upper()

def energy_ot (ot, casdm1s, casdm2, mo_coeff, ncore, max_memory=2000, hermi=1):
'''Compute the on-top energy - the last term in
Expand Down Expand Up @@ -253,11 +344,23 @@ def get_ratio (self, Pi, rho_avg):

def get_rho_translated (self, Pi, rho, _fn_deriv=0):
r''' Compute the "translated" alpha and beta densities:
For the unrestricted case,
rho = [rho^a, rho^b]
Here:
rho^a will have dim of 1,4 or 6 depends on the functional. For MGGA,
rho^a = [rho_u,grad_xu, grad_yu, grad_zu, laplacian_u, tau_u]
Similar for rho_b.

The translation is done as follows:

rho_t^a = (rho/2) * (1 + zeta)
rho_t^b = (rho/2) * (1 - zeta)
rho'_t^a = (rho'/2) * (1 + zeta)
rho'_t^b = (rho'/2) * (1 - zeta)
laplacian_t^a = (laplacian/2) * (1 + zeta)
laplacian_t^b = (laplacian/2) * (1 - zeta)
tau_t^a = (tau/2) * (1 + zeta)
JangidBhavnesh marked this conversation as resolved.
Show resolved Hide resolved
tau_t^b = (tau/2) * (1 - zeta)

See "get_zeta" for the meaning of "zeta"

Expand All @@ -278,7 +381,8 @@ def get_rho_translated (self, Pi, rho, _fn_deriv=0):

Returns:
rho_t : ndarray of shape (2,*,ngrids)
Translated spin density (and derivatives)
Translated spin density (and derivatives) in case of LDA or GGAs
Translated spin density, derivatives, and kinetic energy density in case of MGGA
'''

# For nonzero charge & pair density, set alpha dens = beta dens
Expand Down Expand Up @@ -736,8 +840,14 @@ def get_transfnal (mol, otxc):
'On-top pair-density functional names other than "translated" (t) or '
'"fully-translated (ft).'
)
# Try to register the functional with libxc, if not already done
xc_base = _get_regsitered_ot_functional (xc_base, mol)

xc_base = OT_HYB_ALIAS.get (xc_base.upper (), xc_base)
if ',' not in xc_base and _libxc.is_hybrid_or_rsh (xc_base):

if ',' not in xc_base and \
(xc_base.upper() not in REG_OT_FUNCTIONALS) and \
(_libxc.is_hybrid_or_rsh (xc_base)):
raise NotImplementedError (
'Aliased or built-in translated hybrid or range-separated '
'functionals\nother than those listed in otfnal.OT_HYB_ALIAS. '
Expand All @@ -749,8 +859,6 @@ def get_transfnal (mol, otxc):
ks.xc = xc_base
return fnal_class (ks)



class colle_salvetti_corr (otfnal):


Expand Down Expand Up @@ -801,19 +909,24 @@ def _hybrid_2c_coeff (ni, xc_code, spin=0):
exchange and correlation components of the hybrid coefficent
separately '''

hyb_tot = _NumInt.hybrid_coeff (ni, xc_code, spin=spin)
if hyb_tot == 0: return [0, 0]

# For exchange-only functionals, hyb_c = hyb_x
x_code, c_code = _libxc.split_x_c_comma (xc_code)
x_code = x_code + ','
c_code = ',' + c_code

# All factors of 'HF' are summed by default. Therefore just run the same
# code for the exchange and correlation parts of the string separately
hyb_x = _NumInt.hybrid_coeff(ni, x_code, spin=spin) if len (x_code) else 0
hyb_c = _NumInt.hybrid_coeff(ni, c_code, spin=spin) if len (c_code) else 0
return [hyb_x, hyb_c]
if xc_code.upper() in REG_OT_FUNCTIONALS:
hyb_x = REG_OT_FUNCTIONALS[xc_code.upper ()].get('hyb_x', 0)
hyb_c = REG_OT_FUNCTIONALS[xc_code.upper ()].get('hyb_c', 0)
return [hyb_x, hyb_c]
else:
hyb_tot = _NumInt.hybrid_coeff (ni, xc_code, spin=spin)
if hyb_tot == 0: return [0, 0]

# For exchange-only functionals, hyb_c = hyb_x
x_code, c_code = _libxc.split_x_c_comma (xc_code)
x_code = x_code + ','
c_code = ',' + c_code

# All factors of 'HF' are summed by default. Therefore just run the same
# code for the exchange and correlation parts of the string separately
hyb_x = _NumInt.hybrid_coeff(ni, x_code, spin=spin) if len (x_code) else 0
hyb_c = _NumInt.hybrid_coeff(ni, c_code, spin=spin) if len (c_code) else 0
return [hyb_x, hyb_c]

def make_scaled_fnal (xc_code, hyb_x = 0, hyb_c = 0, fnal_x = None,
fnal_c = None):
Expand Down
Loading