use crate::prelude::*;
#[derive(Debug, Clone, Copy)]
pub struct LibXCDerivativeFlags {
pub do_exc: bool,
pub do_vxc: bool,
pub do_fxc: bool,
pub do_kxc: bool,
pub do_lxc: bool,
}
impl Default for LibXCDerivativeFlags {
fn default() -> Self {
Self { do_exc: true, do_vxc: true, do_fxc: false, do_kxc: false, do_lxc: false }
}
}
impl From<usize> for LibXCDerivativeFlags {
fn from(level: usize) -> Self {
match level {
0 => Self { do_exc: true, do_vxc: false, do_fxc: false, do_kxc: false, do_lxc: false },
1 => Self { do_exc: true, do_vxc: true, do_fxc: false, do_kxc: false, do_lxc: false },
2 => Self { do_exc: true, do_vxc: true, do_fxc: true, do_kxc: false, do_lxc: false },
3 => Self { do_exc: true, do_vxc: true, do_fxc: true, do_kxc: true, do_lxc: false },
4 => Self { do_exc: true, do_vxc: true, do_fxc: true, do_kxc: true, do_lxc: true },
_ => panic!("invalid derivative level {level}"),
}
}
}
#[rustfmt::skip]
pub const LDA_OUTPUT_LABELS: [&str; 5] = [
"zk", "vrho", "v2rho2", "v3rho3", "v4rho4", ];
const LDA_EXC_END: usize = 1;
const LDA_VXC_END: usize = 2;
const LDA_FXC_END: usize = 3;
const LDA_KXC_END: usize = 4;
const LDA_LXC_END: usize = 5;
#[rustfmt::skip]
pub const GGA_OUTPUT_LABELS: [&str; 15] = [
"zk", "vrho", "vsigma", "v2rho2", "v2rhosigma", "v2sigma2", "v3rho3", "v3rho2sigma", "v3rhosigma2", "v3sigma3", "v4rho4", "v4rho3sigma", "v4rho2sigma2", "v4rhosigma3", "v4sigma4", ];
const GGA_EXC_END: usize = 1;
const GGA_VXC_END: usize = 3;
const GGA_FXC_END: usize = 6;
const GGA_KXC_END: usize = 10;
const GGA_LXC_END: usize = 15;
#[rustfmt::skip]
pub const MGGA_OUTPUT_LABELS: [&str; 70] = [
"zk", "vrho", "vsigma", "vlapl", "vtau", "v2rho2", "v2rhosigma", "v2rholapl", "v2rhotau", "v2sigma2", "v2sigmalapl", "v2sigmatau", "v2lapl2", "v2lapltau", "v2tau2",
"v3rho3", "v3rho2sigma", "v3rho2lapl", "v3rho2tau", "v3rhosigma2", "v3rhosigmalapl", "v3rhosigmatau", "v3rholapl2", "v3rholapltau",
"v3rhotau2", "v3sigma3", "v3sigma2lapl", "v3sigma2tau",
"v3sigmalapl2", "v3sigmalapltau", "v3sigmatau2", "v3lapl3",
"v3lapl2tau", "v3lapltau2", "v3tau3",
"v4rho4", "v4rho3sigma", "v4rho3lapl", "v4rho3tau", "v4rho2sigma2", "v4rho2sigmalapl", "v4rho2sigmatau", "v4rho2lapl2", "v4rho2lapltau",
"v4rho2tau2", "v4rhosigma3", "v4rhosigma2lapl", "v4rhosigma2tau",
"v4rhosigmalapl2", "v4rhosigmalapltau", "v4rhosigmatau2",
"v4rholapl3", "v4rholapl2tau", "v4rholapltau2", "v4rhotau3",
"v4sigma4", "v4sigma3lapl", "v4sigma3tau", "v4sigma2lapl2",
"v4sigma2lapltau", "v4sigma2tau2", "v4sigmalapl3", "v4sigmalapl2tau",
"v4sigmalapltau2", "v4sigmatau3", "v4lapl4", "v4lapl3tau",
"v4lapl2tau2", "v4lapltau3", "v4tau4",
];
const MGGA_EXC_END: usize = 1;
const MGGA_VXC_END: usize = 5;
const MGGA_FXC_END: usize = 15;
const MGGA_KXC_END: usize = 35;
const MGGA_LXC_END: usize = 70;
pub fn get_dim(dim: &ffi::xc_dimensions, label: &str) -> i32 {
match label {
"zk" => dim.zk,
"vrho" => dim.vrho,
"vsigma" => dim.vsigma,
"vlapl" => dim.vlapl,
"vtau" => dim.vtau,
"v2rho2" => dim.v2rho2,
"v2rhosigma" => dim.v2rhosigma,
"v2rholapl" => dim.v2rholapl,
"v2rhotau" => dim.v2rhotau,
"v2sigma2" => dim.v2sigma2,
"v2sigmalapl" => dim.v2sigmalapl,
"v2sigmatau" => dim.v2sigmatau,
"v2lapl2" => dim.v2lapl2,
"v2lapltau" => dim.v2lapltau,
"v2tau2" => dim.v2tau2,
"v3rho3" => dim.v3rho3,
"v3rho2sigma" => dim.v3rho2sigma,
"v3rho2lapl" => dim.v3rho2lapl,
"v3rho2tau" => dim.v3rho2tau,
"v3rhosigma2" => dim.v3rhosigma2,
"v3rhosigmalapl" => dim.v3rhosigmalapl,
"v3rhosigmatau" => dim.v3rhosigmatau,
"v3rholapl2" => dim.v3rholapl2,
"v3rholapltau" => dim.v3rholapltau,
"v3rhotau2" => dim.v3rhotau2,
"v3sigma3" => dim.v3sigma3,
"v3sigma2lapl" => dim.v3sigma2lapl,
"v3sigma2tau" => dim.v3sigma2tau,
"v3sigmalapl2" => dim.v3sigmalapl2,
"v3sigmalapltau" => dim.v3sigmalapltau,
"v3sigmatau2" => dim.v3sigmatau2,
"v3lapl3" => dim.v3lapl3,
"v3lapl2tau" => dim.v3lapl2tau,
"v3lapltau2" => dim.v3lapltau2,
"v3tau3" => dim.v3tau3,
"v4rho4" => dim.v4rho4,
"v4rho3sigma" => dim.v4rho3sigma,
"v4rho3lapl" => dim.v4rho3lapl,
"v4rho3tau" => dim.v4rho3tau,
"v4rho2sigma2" => dim.v4rho2sigma2,
"v4rho2sigmalapl" => dim.v4rho2sigmalapl,
"v4rho2sigmatau" => dim.v4rho2sigmatau,
"v4rho2lapl2" => dim.v4rho2lapl2,
"v4rho2lapltau" => dim.v4rho2lapltau,
"v4rho2tau2" => dim.v4rho2tau2,
"v4rhosigma3" => dim.v4rhosigma3,
"v4rhosigma2lapl" => dim.v4rhosigma2lapl,
"v4rhosigma2tau" => dim.v4rhosigma2tau,
"v4rhosigmalapl2" => dim.v4rhosigmalapl2,
"v4rhosigmalapltau" => dim.v4rhosigmalapltau,
"v4rhosigmatau2" => dim.v4rhosigmatau2,
"v4rholapl3" => dim.v4rholapl3,
"v4rholapl2tau" => dim.v4rholapl2tau,
"v4rholapltau2" => dim.v4rholapltau2,
"v4rhotau3" => dim.v4rhotau3,
"v4sigma4" => dim.v4sigma4,
"v4sigma3lapl" => dim.v4sigma3lapl,
"v4sigma3tau" => dim.v4sigma3tau,
"v4sigma2lapl2" => dim.v4sigma2lapl2,
"v4sigma2lapltau" => dim.v4sigma2lapltau,
"v4sigma2tau2" => dim.v4sigma2tau2,
"v4sigmalapl3" => dim.v4sigmalapl3,
"v4sigmalapl2tau" => dim.v4sigmalapl2tau,
"v4sigmalapltau2" => dim.v4sigmalapltau2,
"v4sigmatau3" => dim.v4sigmatau3,
"v4lapl4" => dim.v4lapl4,
"v4lapl3tau" => dim.v4lapl3tau,
"v4lapl2tau2" => dim.v4lapl2tau2,
"v4lapltau3" => dim.v4lapltau3,
"v4tau4" => dim.v4tau4,
_ => 0,
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn check_arrays(
layout: &mut LibXCOutputLayout,
labels: &[&'static str],
start: usize,
end: usize,
dim: &ffi::xc_dimensions,
required: bool,
needs_lapl: bool,
needs_tau: bool,
) {
for &label in &labels[start..end] {
let label_required = required
&& !(!needs_lapl && label.contains("lapl"))
&& !(!needs_tau && label.contains("tau"));
if label_required {
layout.push(label, get_dim(dim, label));
}
}
}
#[derive(Debug, Clone)]
pub struct LibXCOutputLayout {
pub total_size: usize,
pub npoints: usize,
components: Vec<(&'static str, usize, usize)>, }
impl LibXCOutputLayout {
fn new(npoints: usize) -> Self {
Self { total_size: 0, npoints, components: Vec::new() }
}
fn push(&mut self, name: &'static str, n_comp: i32) {
if n_comp == 0 {
return;
}
let size = self.npoints * (n_comp as usize);
let offset = self.total_size;
self.components.push((name, offset, size));
self.total_size += size;
}
pub fn get(&self, name: &str) -> Option<Range<usize>> {
for &(n, offset, size) in &self.components {
if n == name {
return Some(offset..offset + size);
}
}
None
}
pub fn component_names(&self) -> impl Iterator<Item = &str> {
self.components.iter().map(|&(n, _, _)| n)
}
pub fn component_size(&self, name: &str) -> Option<usize> {
for &(n, _, size) in &self.components {
if n == name {
return Some(size);
}
}
None
}
pub fn component_dim(&self, name: &str) -> Option<usize> {
for &(n, _, size) in &self.components {
if n == name {
return Some(size / self.npoints);
}
}
None
}
}
impl core::fmt::Display for LibXCOutputLayout {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(
f,
"LibXCOutputLayout (total_size={}, npoints={}):",
self.total_size, self.npoints
)?;
for &(name, offset, size) in &self.components {
writeln!(
f,
" {name}: [{offset}..{}], size={size}, dim={}",
offset + size,
size / self.npoints
)?;
}
Ok(())
}
}
impl LibXCFunctional {
#[rustfmt::skip]
pub fn lda_output_layout(
&self,
npoints: usize,
flags: LibXCDerivativeFlags,
) -> LibXCOutputLayout {
let dim = self.dim();
let mut layout = LibXCOutputLayout::new(npoints);
check_arrays(&mut layout, &LDA_OUTPUT_LABELS, 0, LDA_EXC_END, dim, flags.do_exc, false, false);
check_arrays(&mut layout, &LDA_OUTPUT_LABELS, LDA_EXC_END, LDA_VXC_END, dim, flags.do_vxc, false, false);
check_arrays(&mut layout, &LDA_OUTPUT_LABELS, LDA_VXC_END, LDA_FXC_END, dim, flags.do_fxc, false, false);
check_arrays(&mut layout, &LDA_OUTPUT_LABELS, LDA_FXC_END, LDA_KXC_END, dim, flags.do_kxc, false, false);
check_arrays(&mut layout, &LDA_OUTPUT_LABELS, LDA_KXC_END, LDA_LXC_END, dim, flags.do_lxc, false, false);
layout
}
#[rustfmt::skip]
pub fn gga_output_layout(
&self,
npoints: usize,
flags: LibXCDerivativeFlags,
) -> LibXCOutputLayout {
let dim = self.dim();
let mut layout = LibXCOutputLayout::new(npoints);
check_arrays(&mut layout, &GGA_OUTPUT_LABELS, 0, GGA_EXC_END, dim, flags.do_exc, false, false);
check_arrays(&mut layout, &GGA_OUTPUT_LABELS, GGA_EXC_END, GGA_VXC_END, dim, flags.do_vxc, false, false);
check_arrays(&mut layout, &GGA_OUTPUT_LABELS, GGA_VXC_END, GGA_FXC_END, dim, flags.do_fxc, false, false);
check_arrays(&mut layout, &GGA_OUTPUT_LABELS, GGA_FXC_END, GGA_KXC_END, dim, flags.do_kxc, false, false);
check_arrays(&mut layout, &GGA_OUTPUT_LABELS, GGA_KXC_END, GGA_LXC_END, dim, flags.do_lxc, false, false);
layout
}
#[rustfmt::skip]
pub fn mgga_output_layout(
&self,
npoints: usize,
flags: LibXCDerivativeFlags,
) -> LibXCOutputLayout {
let dim = self.dim();
let needs_lapl = self.needs_laplacian();
let needs_tau = self.needs_tau();
let mut layout = LibXCOutputLayout::new(npoints);
check_arrays(&mut layout, &MGGA_OUTPUT_LABELS, 0, MGGA_EXC_END, dim, flags.do_exc, needs_lapl, needs_tau);
check_arrays(&mut layout, &MGGA_OUTPUT_LABELS, MGGA_EXC_END, MGGA_VXC_END, dim, flags.do_vxc, needs_lapl, needs_tau);
check_arrays(&mut layout, &MGGA_OUTPUT_LABELS, MGGA_VXC_END, MGGA_FXC_END, dim, flags.do_fxc, needs_lapl, needs_tau);
check_arrays(&mut layout, &MGGA_OUTPUT_LABELS, MGGA_FXC_END, MGGA_KXC_END, dim, flags.do_kxc, needs_lapl, needs_tau);
check_arrays(&mut layout, &MGGA_OUTPUT_LABELS, MGGA_KXC_END, MGGA_LXC_END, dim, flags.do_lxc, needs_lapl, needs_tau);
layout
}
pub fn output_layout(
&self,
npoints: usize,
flags: impl Into<LibXCDerivativeFlags>,
) -> LibXCOutputLayout {
use crate::prelude::libxc_enum_items::*;
let flags = flags.into();
match self.family() {
LDA | HybLDA => self.lda_output_layout(npoints, flags),
GGA | HybGGA => self.gga_output_layout(npoints, flags),
MGGA | HybMGGA => self.mgga_output_layout(npoints, flags),
OEP | LCA => unimplemented!("output layout for OEP/LCA is not recognized."),
}
}
pub(crate) fn validate_flags(
&self,
flags: impl Into<LibXCDerivativeFlags>,
) -> Result<(), LibXCError> {
let flags = flags.into();
for (flag, has_cap, name) in [
(flags.do_exc, self.has_exc(), "EXC"),
(flags.do_vxc, self.has_vxc(), "VXC"),
(flags.do_fxc, self.has_fxc(), "FXC"),
(flags.do_kxc, self.has_kxc(), "KXC"),
(flags.do_lxc, self.has_lxc(), "LXC"),
] {
if flag && !has_cap {
return Err(LibXCError::ComputeError(format!(
"functional '{}' does not have {name} capabilities",
self.identifier(),
)));
}
}
Ok(())
}
}
pub(crate) fn ptr_of(ptrs: &HashMap<&'static str, *mut f64>, key: &str) -> *mut f64 {
ptrs.get(key).copied().unwrap_or(std::ptr::null_mut())
}
pub(crate) unsafe fn xc_lda_call(
func_ptr: *mut ffi::xc_func_type,
npoints: usize,
rho_ptr: *const f64,
output_base: *mut f64,
layout: &LibXCOutputLayout,
) {
let ptr_for = |name: &str| -> *mut f64 {
match layout.get(name) {
Some(range) => output_base.add(range.start),
None => std::ptr::null_mut::<f64>(),
}
};
ffi::xc_lda(
func_ptr,
npoints,
rho_ptr,
ptr_for("zk"),
ptr_for("vrho"),
ptr_for("v2rho2"),
ptr_for("v3rho3"),
ptr_for("v4rho4"),
);
}
pub(crate) unsafe fn xc_lda_call_with_output(
func_ptr: *mut ffi::xc_func_type,
npoints: usize,
rho_ptr: *const f64,
ptrs: &HashMap<&'static str, *mut f64>,
) {
ffi::xc_lda(
func_ptr,
npoints,
rho_ptr,
ptr_of(ptrs, "zk"),
ptr_of(ptrs, "vrho"),
ptr_of(ptrs, "v2rho2"),
ptr_of(ptrs, "v3rho3"),
ptr_of(ptrs, "v4rho4"),
);
}
pub(crate) unsafe fn xc_gga_call(
func_ptr: *mut ffi::xc_func_type,
npoints: usize,
rho_ptr: *const f64,
sigma_ptr: *const f64,
output_base: *mut f64,
layout: &LibXCOutputLayout,
) {
let ptr_for = |name: &str| -> *mut f64 {
match layout.get(name) {
Some(range) => output_base.add(range.start),
None => std::ptr::null_mut::<f64>(),
}
};
ffi::xc_gga(
func_ptr,
npoints,
rho_ptr,
sigma_ptr as *mut f64,
ptr_for("zk"),
ptr_for("vrho"),
ptr_for("vsigma"),
ptr_for("v2rho2"),
ptr_for("v2rhosigma"),
ptr_for("v2sigma2"),
ptr_for("v3rho3"),
ptr_for("v3rho2sigma"),
ptr_for("v3rhosigma2"),
ptr_for("v3sigma3"),
ptr_for("v4rho4"),
ptr_for("v4rho3sigma"),
ptr_for("v4rho2sigma2"),
ptr_for("v4rhosigma3"),
ptr_for("v4sigma4"),
);
}
pub(crate) unsafe fn xc_gga_call_with_output(
func_ptr: *mut ffi::xc_func_type,
npoints: usize,
rho_ptr: *const f64,
sigma_ptr: *const f64,
ptrs: &HashMap<&'static str, *mut f64>,
) {
ffi::xc_gga(
func_ptr,
npoints,
rho_ptr,
sigma_ptr as *mut f64,
ptr_of(ptrs, "zk"),
ptr_of(ptrs, "vrho"),
ptr_of(ptrs, "vsigma"),
ptr_of(ptrs, "v2rho2"),
ptr_of(ptrs, "v2rhosigma"),
ptr_of(ptrs, "v2sigma2"),
ptr_of(ptrs, "v3rho3"),
ptr_of(ptrs, "v3rho2sigma"),
ptr_of(ptrs, "v3rhosigma2"),
ptr_of(ptrs, "v3sigma3"),
ptr_of(ptrs, "v4rho4"),
ptr_of(ptrs, "v4rho3sigma"),
ptr_of(ptrs, "v4rho2sigma2"),
ptr_of(ptrs, "v4rhosigma3"),
ptr_of(ptrs, "v4sigma4"),
);
}
#[allow(clippy::too_many_arguments)]
pub(crate) unsafe fn xc_mgga_call(
func_ptr: *mut ffi::xc_func_type,
npoints: usize,
rho_ptr: *const f64,
sigma_ptr: *const f64,
lapl_ptr: *const f64,
tau_ptr: *const f64,
output_base: *mut f64,
layout: &LibXCOutputLayout,
) {
let ptr_for = |name: &str| -> *mut f64 {
match layout.get(name) {
Some(range) => output_base.add(range.start),
None => std::ptr::null_mut::<f64>(),
}
};
ffi::xc_mgga(
func_ptr,
npoints,
rho_ptr,
sigma_ptr as *mut f64,
lapl_ptr as *mut f64,
tau_ptr as *mut f64,
ptr_for("zk"),
ptr_for("vrho"),
ptr_for("vsigma"),
ptr_for("vlapl"),
ptr_for("vtau"),
ptr_for("v2rho2"),
ptr_for("v2rhosigma"),
ptr_for("v2rholapl"),
ptr_for("v2rhotau"),
ptr_for("v2sigma2"),
ptr_for("v2sigmalapl"),
ptr_for("v2sigmatau"),
ptr_for("v2lapl2"),
ptr_for("v2lapltau"),
ptr_for("v2tau2"),
ptr_for("v3rho3"),
ptr_for("v3rho2sigma"),
ptr_for("v3rho2lapl"),
ptr_for("v3rho2tau"),
ptr_for("v3rhosigma2"),
ptr_for("v3rhosigmalapl"),
ptr_for("v3rhosigmatau"),
ptr_for("v3rholapl2"),
ptr_for("v3rholapltau"),
ptr_for("v3rhotau2"),
ptr_for("v3sigma3"),
ptr_for("v3sigma2lapl"),
ptr_for("v3sigma2tau"),
ptr_for("v3sigmalapl2"),
ptr_for("v3sigmalapltau"),
ptr_for("v3sigmatau2"),
ptr_for("v3lapl3"),
ptr_for("v3lapl2tau"),
ptr_for("v3lapltau2"),
ptr_for("v3tau3"),
ptr_for("v4rho4"),
ptr_for("v4rho3sigma"),
ptr_for("v4rho3lapl"),
ptr_for("v4rho3tau"),
ptr_for("v4rho2sigma2"),
ptr_for("v4rho2sigmalapl"),
ptr_for("v4rho2sigmatau"),
ptr_for("v4rho2lapl2"),
ptr_for("v4rho2lapltau"),
ptr_for("v4rho2tau2"),
ptr_for("v4rhosigma3"),
ptr_for("v4rhosigma2lapl"),
ptr_for("v4rhosigma2tau"),
ptr_for("v4rhosigmalapl2"),
ptr_for("v4rhosigmalapltau"),
ptr_for("v4rhosigmatau2"),
ptr_for("v4rholapl3"),
ptr_for("v4rholapl2tau"),
ptr_for("v4rholapltau2"),
ptr_for("v4rhotau3"),
ptr_for("v4sigma4"),
ptr_for("v4sigma3lapl"),
ptr_for("v4sigma3tau"),
ptr_for("v4sigma2lapl2"),
ptr_for("v4sigma2lapltau"),
ptr_for("v4sigma2tau2"),
ptr_for("v4sigmalapl3"),
ptr_for("v4sigmalapl2tau"),
ptr_for("v4sigmalapltau2"),
ptr_for("v4sigmatau3"),
ptr_for("v4lapl4"),
ptr_for("v4lapl3tau"),
ptr_for("v4lapl2tau2"),
ptr_for("v4lapltau3"),
ptr_for("v4tau4"),
);
}
#[allow(clippy::too_many_arguments)]
pub(crate) unsafe fn xc_mgga_call_with_output(
func_ptr: *mut ffi::xc_func_type,
npoints: usize,
rho_ptr: *const f64,
sigma_ptr: *const f64,
lapl_ptr: *const f64,
tau_ptr: *const f64,
ptrs: &HashMap<&'static str, *mut f64>,
) {
ffi::xc_mgga(
func_ptr,
npoints,
rho_ptr,
sigma_ptr as *mut f64,
lapl_ptr as *mut f64,
tau_ptr as *mut f64,
ptr_of(ptrs, "zk"),
ptr_of(ptrs, "vrho"),
ptr_of(ptrs, "vsigma"),
ptr_of(ptrs, "vlapl"),
ptr_of(ptrs, "vtau"),
ptr_of(ptrs, "v2rho2"),
ptr_of(ptrs, "v2rhosigma"),
ptr_of(ptrs, "v2rholapl"),
ptr_of(ptrs, "v2rhotau"),
ptr_of(ptrs, "v2sigma2"),
ptr_of(ptrs, "v2sigmalapl"),
ptr_of(ptrs, "v2sigmatau"),
ptr_of(ptrs, "v2lapl2"),
ptr_of(ptrs, "v2lapltau"),
ptr_of(ptrs, "v2tau2"),
ptr_of(ptrs, "v3rho3"),
ptr_of(ptrs, "v3rho2sigma"),
ptr_of(ptrs, "v3rho2lapl"),
ptr_of(ptrs, "v3rho2tau"),
ptr_of(ptrs, "v3rhosigma2"),
ptr_of(ptrs, "v3rhosigmalapl"),
ptr_of(ptrs, "v3rhosigmatau"),
ptr_of(ptrs, "v3rholapl2"),
ptr_of(ptrs, "v3rholapltau"),
ptr_of(ptrs, "v3rhotau2"),
ptr_of(ptrs, "v3sigma3"),
ptr_of(ptrs, "v3sigma2lapl"),
ptr_of(ptrs, "v3sigma2tau"),
ptr_of(ptrs, "v3sigmalapl2"),
ptr_of(ptrs, "v3sigmalapltau"),
ptr_of(ptrs, "v3sigmatau2"),
ptr_of(ptrs, "v3lapl3"),
ptr_of(ptrs, "v3lapl2tau"),
ptr_of(ptrs, "v3lapltau2"),
ptr_of(ptrs, "v3tau3"),
ptr_of(ptrs, "v4rho4"),
ptr_of(ptrs, "v4rho3sigma"),
ptr_of(ptrs, "v4rho3lapl"),
ptr_of(ptrs, "v4rho3tau"),
ptr_of(ptrs, "v4rho2sigma2"),
ptr_of(ptrs, "v4rho2sigmalapl"),
ptr_of(ptrs, "v4rho2sigmatau"),
ptr_of(ptrs, "v4rho2lapl2"),
ptr_of(ptrs, "v4rho2lapltau"),
ptr_of(ptrs, "v4rho2tau2"),
ptr_of(ptrs, "v4rhosigma3"),
ptr_of(ptrs, "v4rhosigma2lapl"),
ptr_of(ptrs, "v4rhosigma2tau"),
ptr_of(ptrs, "v4rhosigmalapl2"),
ptr_of(ptrs, "v4rhosigmalapltau"),
ptr_of(ptrs, "v4rhosigmatau2"),
ptr_of(ptrs, "v4rholapl3"),
ptr_of(ptrs, "v4rholapl2tau"),
ptr_of(ptrs, "v4rholapltau2"),
ptr_of(ptrs, "v4rhotau3"),
ptr_of(ptrs, "v4sigma4"),
ptr_of(ptrs, "v4sigma3lapl"),
ptr_of(ptrs, "v4sigma3tau"),
ptr_of(ptrs, "v4sigma2lapl2"),
ptr_of(ptrs, "v4sigma2lapltau"),
ptr_of(ptrs, "v4sigma2tau2"),
ptr_of(ptrs, "v4sigmalapl3"),
ptr_of(ptrs, "v4sigmalapl2tau"),
ptr_of(ptrs, "v4sigmalapltau2"),
ptr_of(ptrs, "v4sigmatau3"),
ptr_of(ptrs, "v4lapl4"),
ptr_of(ptrs, "v4lapl3tau"),
ptr_of(ptrs, "v4lapl2tau2"),
ptr_of(ptrs, "v4lapltau3"),
ptr_of(ptrs, "v4tau4"),
);
}