            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestQuery failed')
        return lrc_omega.value

    @memoized_property
    def vv10_scale(self):
        vv10_scale = ce.data_double()
        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_XCINTPLAN,
            object=self.xc_int_plan_handle,
            attribute=ce.CuestXCIntPlanAttributes.CUEST_XCINTPLAN_VV10_SCALE,
            attributeValue=vv10_scale,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestQuery failed')
        return vv10_scale.value

    @memoized_property
    def vv10_c(self):
        vv10_c = ce.data_double()
        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_XCINTPLAN,
            object=self.xc_int_plan_handle,
            attribute=ce.CuestXCIntPlanAttributes.CUEST_XCINTPLAN_VV10_C,
            attributeValue=vv10_c,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestQuery failed')
        return vv10_c.value

    @memoized_property
    def vv10_b(self):
        vv10_b = ce.data_double()
        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_XCINTPLAN,
            object=self.xc_int_plan_handle,
            attribute=ce.CuestXCIntPlanAttributes.CUEST_XCINTPLAN_VV10_B,
            attributeValue=vv10_b,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestQuery failed')
        return vv10_b.value

    # => String Details <= #

    def __str__(self):
        return self.string


            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestQuery failed')
        return vv10_scale.value

    @memoized_property
    def vv10_c(self):
        vv10_c = ce.data_double()
        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_XCINTPLAN,
            object=self.xc_int_plan_handle,
            attribute=ce.CuestXCIntPlanAttributes.CUEST_XCINTPLAN_VV10_C,
            attributeValue=vv10_c,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestQuery failed')
        return vv10_c.value

    @memoized_property
    def vv10_b(self):
        vv10_b = ce.data_double()
        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_XCINTPLAN,
            object=self.xc_int_plan_handle,
            attribute=ce.CuestXCIntPlanAttributes.CUEST_XCINTPLAN_VV10_B,
            attributeValue=vv10_b,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestQuery failed')
        return vv10_b.value

    # => String Details <= #

    def __str__(self):
        return self.string

    @property
    def string(self):
        s = ''
        s += 'XCIntPlan:\n';
        if self.engine_description and self.engine_citation:
            s += '%-10s = %s\n' % ('engine', self.engine_description)
            s += '%-10s = %s\n' % ('citation', self.engine_citation)
        s += '%-10s = %s\n'     % ('XC brief', self.functional_description)
        s += '%-10s = %s\n'     % ('citation', self.functional_citation)
        s += '%-10s = %10s\n'   % ('functional', self.functional_name)
        s += '%-10s = %10.3f\n' % ('hf scale',   self.exchange_scale)
        s += '%-10s = %10.3f\n' % ('lrc scale',  self.lrc_exchange_scale)
        if self.lrc_exchange_scale != 0.0:
            s += '%-10s = %10.3f\n' % ('lrc omega', self.lrc_omega)


        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestQuery failed')
        return vv10_c.value

    @memoized_property
    def vv10_b(self):
        vv10_b = ce.data_double()
        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_XCINTPLAN,
            object=self.xc_int_plan_handle,
            attribute=ce.CuestXCIntPlanAttributes.CUEST_XCINTPLAN_VV10_B,
            attributeValue=vv10_b,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestQuery failed')
        return vv10_b.value

    # => String Details <= #

    def __str__(self):
        return self.string

    @property
    def string(self):
        s = ''
        s += 'XCIntPlan:\n';
        if self.engine_description and self.engine_citation:
            s += '%-10s = %s\n' % ('engine', self.engine_description)
            s += '%-10s = %s\n' % ('citation', self.engine_citation)
        s += '%-10s = %s\n'     % ('XC brief', self.functional_description)
        s += '%-10s = %s\n'     % ('citation', self.functional_citation)
        s += '%-10s = %10s\n'   % ('functional', self.functional_name)
        s += '%-10s = %10.3f\n' % ('hf scale',   self.exchange_scale)
        s += '%-10s = %10.3f\n' % ('lrc scale',  self.lrc_exchange_scale)
        if self.lrc_exchange_scale != 0.0:
            s += '%-10s = %10.3f\n' % ('lrc omega', self.lrc_omega)
        s += '%-10s = %10.3f\n' % ('vv10 scale', self.vv10_scale)
        if self.vv10_scale != 0.0:
            s += '%-10s = %10.3f\n' % ('vv10 b', self.vv10_b)
            s += '%-10s = %10.3f\n' % ('vv10 c', self.vv10_c)
        return s;


string

    @memoized_property
    def vv10_b(self):
        vv10_b = ce.data_double()
        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_XCINTPLAN,
            object=self.xc_int_plan_handle,
            attribute=ce.CuestXCIntPlanAttributes.CUEST_XCINTPLAN_VV10_B,
            attributeValue=vv10_b,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestQuery failed')
        return vv10_b.value

    # => String Details <= #

    def __str__(self):
        return self.string

    @property
    def string(self):
        s = ''
        s += 'XCIntPlan:\n';
        if self.engine_description and self.engine_citation:
            s += '%-10s = %s\n' % ('engine', self.engine_description)
            s += '%-10s = %s\n' % ('citation', self.engine_citation)
        s += '%-10s = %s\n'     % ('XC brief', self.functional_description)
        s += '%-10s = %s\n'     % ('citation', self.functional_citation)
        s += '%-10s = %10s\n'   % ('functional', self.functional_name)
        s += '%-10s = %10.3f\n' % ('hf scale',   self.exchange_scale)
        s += '%-10s = %10.3f\n' % ('lrc scale',  self.lrc_exchange_scale)
        if self.lrc_exchange_scale != 0.0:
            s += '%-10s = %10.3f\n' % ('lrc omega', self.lrc_omega)
        s += '%-10s = %10.3f\n' % ('vv10 scale', self.vv10_scale)
        if self.vv10_scale != 0.0:
            s += '%-10s = %10.3f\n' % ('vv10 b', self.vv10_b)
            s += '%-10s = %10.3f\n' % ('vv10 c', self.vv10_c)
        return s;


# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np

from .ao_basis import AOBasis

from .sad_atom_structure import SADAtomStructure

from .sad_overlap import SADOverlap

from .memoized_property import memoized_property

class SADGuessAtom(object):

    def __init__(
        self,
        primary : AOBasis,
        minao : AOBasis,
        structure : SADAtomStructure,
        ):

        self.primary = primary
        self.minao = minao
        self.structure = structure

        if self.primary.natom != 1: raise RuntimeError('primary.natom != 1')
        if self.minao.natom != 1: raise RuntimeError('minao.natom != 1')

        if [shell.L for shell in minao.shells[0]] != structure.Ls:
            raise RuntimeError('minao L structure is not correct for this atom. N = %d' % (structure.N))

        if not minao.is_pure:
            raise RuntimeError('minao is not pure')

        if minao.nao > primary.nao:
            raise RuntimeError('minao.nao > primary.nao')

    @memoized_property
    def Smm(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.minao,
            )

    @memoized_property
    def Smp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.primary,
            )

    @memoized_property
    def Spp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.primary,
            basis2=self.primary,
            )

    @memoized_property
    def Xm(self):
        s, U = np.linalg.eigh(self.Smm)
        X = np.einsum('pi,i->pi', U, s**(-0.5))
        return np.dot(X, U.T)

    @memoized_property
    def Xp(self):
        s, U = np.linalg.eigh(self.Spp)
        ind = s > 1.0E-12
        s = s[ind]
        U = U[:, ind]
        X = np.einsum('pi,i->ip', U, s**(-0.5))
        return X

    @memoized_property
    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)

    @memoized_property
    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)

    @memoized_property
    def C(self):
        return np.dot(self.P, self.Xp)

    @property
    def minao_health(self):
        return np.max(np.abs(self.Smm - np.eye(self.Smm.shape[0])))

    @property
    def overlap_health(self):
        return np.max(np.abs(self.s - 1.0))


SADGuessAtom

# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np

from .ao_basis import AOBasis

from .sad_atom_structure import SADAtomStructure

from .sad_overlap import SADOverlap

from .memoized_property import memoized_property

class SADGuessAtom(object):

    def __init__(
        self,
        primary : AOBasis,
        minao : AOBasis,
        structure : SADAtomStructure,
        ):

        self.primary = primary
        self.minao = minao
        self.structure = structure

        if self.primary.natom != 1: raise RuntimeError('primary.natom != 1')
        if self.minao.natom != 1: raise RuntimeError('minao.natom != 1')

        if [shell.L for shell in minao.shells[0]] != structure.Ls:
            raise RuntimeError('minao L structure is not correct for this atom. N = %d' % (structure.N))

        if not minao.is_pure:
            raise RuntimeError('minao is not pure')

        if minao.nao > primary.nao:
            raise RuntimeError('minao.nao > primary.nao')

    @memoized_property
    def Smm(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.minao,
            )

    @memoized_property
    def Smp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.primary,
            )

    @memoized_property
    def Spp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.primary,
            basis2=self.primary,
            )

    @memoized_property
    def Xm(self):
        s, U = np.linalg.eigh(self.Smm)
        X = np.einsum('pi,i->pi', U, s**(-0.5))
        return np.dot(X, U.T)

    @memoized_property
    def Xp(self):
        s, U = np.linalg.eigh(self.Spp)
        ind = s > 1.0E-12
        s = s[ind]
        U = U[:, ind]
        X = np.einsum('pi,i->ip', U, s**(-0.5))
        return X

    @memoized_property
    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)

    @memoized_property
    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)

    @memoized_property
    def C(self):
        return np.dot(self.P, self.Xp)

    @property
    def minao_health(self):
        return np.max(np.abs(self.Smm - np.eye(self.Smm.shape[0])))

    @property
    def overlap_health(self):
        return np.max(np.abs(self.s - 1.0))


# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np

from .ao_basis import AOBasis

from .sad_atom_structure import SADAtomStructure

from .sad_overlap import SADOverlap

from .memoized_property import memoized_property

class SADGuessAtom(object):

    def __init__(
        self,
        primary : AOBasis,
        minao : AOBasis,
        structure : SADAtomStructure,
        ):

        self.primary = primary
        self.minao = minao
        self.structure = structure

        if self.primary.natom != 1: raise RuntimeError('primary.natom != 1')
        if self.minao.natom != 1: raise RuntimeError('minao.natom != 1')

        if [shell.L for shell in minao.shells[0]] != structure.Ls:
            raise RuntimeError('minao L structure is not correct for this atom. N = %d' % (structure.N))

        if not minao.is_pure:
            raise RuntimeError('minao is not pure')

        if minao.nao > primary.nao:
            raise RuntimeError('minao.nao > primary.nao')

    @memoized_property
    def Smm(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.minao,
            )

    @memoized_property
    def Smp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.primary,
            )

    @memoized_property
    def Spp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.primary,
            basis2=self.primary,


Smm

        structure : SADAtomStructure,
        ):

        self.primary = primary
        self.minao = minao
        self.structure = structure

        if self.primary.natom != 1: raise RuntimeError('primary.natom != 1')
        if self.minao.natom != 1: raise RuntimeError('minao.natom != 1')

        if [shell.L for shell in minao.shells[0]] != structure.Ls:
            raise RuntimeError('minao L structure is not correct for this atom. N = %d' % (structure.N))

        if not minao.is_pure:
            raise RuntimeError('minao is not pure')

        if minao.nao > primary.nao:
            raise RuntimeError('minao.nao > primary.nao')

    @memoized_property
    def Smm(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.minao,
            )

    @memoized_property
    def Smp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.primary,
            )

    @memoized_property
    def Spp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.primary,
            basis2=self.primary,
            )

    @memoized_property
    def Xm(self):
        s, U = np.linalg.eigh(self.Smm)
        X = np.einsum('pi,i->pi', U, s**(-0.5))
        return np.dot(X, U.T)


Smp

        if self.primary.natom != 1: raise RuntimeError('primary.natom != 1')
        if self.minao.natom != 1: raise RuntimeError('minao.natom != 1')

        if [shell.L for shell in minao.shells[0]] != structure.Ls:
            raise RuntimeError('minao L structure is not correct for this atom. N = %d' % (structure.N))

        if not minao.is_pure:
            raise RuntimeError('minao is not pure')

        if minao.nao > primary.nao:
            raise RuntimeError('minao.nao > primary.nao')

    @memoized_property
    def Smm(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.minao,
            )

    @memoized_property
    def Smp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.primary,
            )

    @memoized_property
    def Spp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.primary,
            basis2=self.primary,
            )

    @memoized_property
    def Xm(self):
        s, U = np.linalg.eigh(self.Smm)
        X = np.einsum('pi,i->pi', U, s**(-0.5))
        return np.dot(X, U.T)

    @memoized_property
    def Xp(self):
        s, U = np.linalg.eigh(self.Spp)
        ind = s > 1.0E-12
        s = s[ind]
        U = U[:, ind]


Spp

            raise RuntimeError('minao is not pure')

        if minao.nao > primary.nao:
            raise RuntimeError('minao.nao > primary.nao')

    @memoized_property
    def Smm(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.minao,
            )

    @memoized_property
    def Smp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.primary,
            )

    @memoized_property
    def Spp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.primary,
            basis2=self.primary,
            )

    @memoized_property
    def Xm(self):
        s, U = np.linalg.eigh(self.Smm)
        X = np.einsum('pi,i->pi', U, s**(-0.5))
        return np.dot(X, U.T)

    @memoized_property
    def Xp(self):
        s, U = np.linalg.eigh(self.Spp)
        ind = s > 1.0E-12
        s = s[ind]
        U = U[:, ind]
        X = np.einsum('pi,i->ip', U, s**(-0.5))
        return X

    @memoized_property
    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)


Xm

        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.minao,
            )

    @memoized_property
    def Smp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.primary,
            )

    @memoized_property
    def Spp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.primary,
            basis2=self.primary,
            )

    @memoized_property
    def Xm(self):
        s, U = np.linalg.eigh(self.Smm)
        X = np.einsum('pi,i->pi', U, s**(-0.5))
        return np.dot(X, U.T)

    @memoized_property
    def Xp(self):
        s, U = np.linalg.eigh(self.Spp)
        ind = s > 1.0E-12
        s = s[ind]
        U = U[:, ind]
        X = np.einsum('pi,i->ip', U, s**(-0.5))
        return X

    @memoized_property
    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)

    @memoized_property
    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):


Xp

    def Smp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.minao,
            basis2=self.primary,
            )

    @memoized_property
    def Spp(self):
        return SADOverlap.compute_atomic_overlap(
            basis1=self.primary,
            basis2=self.primary,
            )

    @memoized_property
    def Xm(self):
        s, U = np.linalg.eigh(self.Smm)
        X = np.einsum('pi,i->pi', U, s**(-0.5))
        return np.dot(X, U.T)

    @memoized_property
    def Xp(self):
        s, U = np.linalg.eigh(self.Spp)
        ind = s > 1.0E-12
        s = s[ind]
        U = U[:, ind]
        X = np.einsum('pi,i->ip', U, s**(-0.5))
        return X

    @memoized_property
    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)

    @memoized_property
    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)


M

            basis1=self.primary,
            basis2=self.primary,
            )

    @memoized_property
    def Xm(self):
        s, U = np.linalg.eigh(self.Smm)
        X = np.einsum('pi,i->pi', U, s**(-0.5))
        return np.dot(X, U.T)

    @memoized_property
    def Xp(self):
        s, U = np.linalg.eigh(self.Spp)
        ind = s > 1.0E-12
        s = s[ind]
        U = U[:, ind]
        X = np.einsum('pi,i->ip', U, s**(-0.5))
        return X

    @memoized_property
    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)

    @memoized_property
    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)


U

    @memoized_property
    def Xm(self):
        s, U = np.linalg.eigh(self.Smm)
        X = np.einsum('pi,i->pi', U, s**(-0.5))
        return np.dot(X, U.T)

    @memoized_property
    def Xp(self):
        s, U = np.linalg.eigh(self.Spp)
        ind = s > 1.0E-12
        s = s[ind]
        U = U[:, ind]
        X = np.einsum('pi,i->ip', U, s**(-0.5))
        return X

    @memoized_property
    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)

    @memoized_property
    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)

    @memoized_property
    def C(self):
        return np.dot(self.P, self.Xp)


s

        return np.dot(X, U.T)

    @memoized_property
    def Xp(self):
        s, U = np.linalg.eigh(self.Spp)
        ind = s > 1.0E-12
        s = s[ind]
        U = U[:, ind]
        X = np.einsum('pi,i->ip', U, s**(-0.5))
        return X

    @memoized_property
    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)

    @memoized_property
    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)

    @memoized_property
    def C(self):
        return np.dot(self.P, self.Xp)

    @property
    def minao_health(self):
        return np.max(np.abs(self.Smm - np.eye(self.Smm.shape[0])))


V

        s, U = np.linalg.eigh(self.Spp)
        ind = s > 1.0E-12
        s = s[ind]
        U = U[:, ind]
        X = np.einsum('pi,i->ip', U, s**(-0.5))
        return X

    @memoized_property
    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)

    @memoized_property
    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)

    @memoized_property
    def C(self):
        return np.dot(self.P, self.Xp)

    @property
    def minao_health(self):
        return np.max(np.abs(self.Smm - np.eye(self.Smm.shape[0])))

    @property
    def overlap_health(self):
        return np.max(np.abs(self.s - 1.0))


UsV

        X = np.einsum('pi,i->ip', U, s**(-0.5))
        return X

    @memoized_property
    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)

    @memoized_property
    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)

    @memoized_property
    def C(self):
        return np.dot(self.P, self.Xp)

    @property
    def minao_health(self):
        return np.max(np.abs(self.Smm - np.eye(self.Smm.shape[0])))

    @property
    def overlap_health(self):
        return np.max(np.abs(self.s - 1.0))


P

    def M(self):
        return np.dot(np.dot(self.Xm, self.Smp), self.Xp.T)

    @memoized_property
    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)

    @memoized_property
    def C(self):
        return np.dot(self.P, self.Xp)

    @property
    def minao_health(self):
        return np.max(np.abs(self.Smm - np.eye(self.Smm.shape[0])))

    @property
    def overlap_health(self):
        return np.max(np.abs(self.s - 1.0))


C

    def U(self):
        return self.UsV[0]

    @memoized_property
    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)

    @memoized_property
    def C(self):
        return np.dot(self.P, self.Xp)

    @property
    def minao_health(self):
        return np.max(np.abs(self.Smm - np.eye(self.Smm.shape[0])))

    @property
    def overlap_health(self):
        return np.max(np.abs(self.s - 1.0))


    def s(self):
        return self.UsV[1]

    @memoized_property
    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)

    @memoized_property
    def C(self):
        return np.dot(self.P, self.Xp)

    @property
    def minao_health(self):
        return np.max(np.abs(self.Smm - np.eye(self.Smm.shape[0])))

    @property
    def overlap_health(self):
        return np.max(np.abs(self.s - 1.0))


    def V(self):
        return self.UsV[2]

    @memoized_property
    def UsV(self):
        return np.linalg.svd(self.M, full_matrices=False)

    @memoized_property
    def P(self):
        return np.dot(self.U, self.V)

    @memoized_property
    def C(self):
        return np.dot(self.P, self.Xp)

    @property
    def minao_health(self):
        return np.max(np.abs(self.Smm - np.eye(self.Smm.shape[0])))

    @property
    def overlap_health(self):
        return np.max(np.abs(self.s - 1.0))


# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np

class CuestWorkspaceDescriptor():

    _dtype = np.dtype([
        ("hostBufferSizeInBytes", np.uint64, ),
        ("deviceBufferSizeInBytes", np.uint64, ),
        ], align=True
        )

    def __init__(
        self,
        *,
        hostBufferSizeInBytes: np.uint64 = 0,
        deviceBufferSizeInBytes: np.uint64 = 0,
        ):

        self.struct = np.array(
            (hostBufferSizeInBytes, deviceBufferSizeInBytes),
            dtype=self._dtype,
            )

    def __str__(
        self,
        ):

        hostsize = self.struct['hostBufferSizeInBytes']
        devicesize = self.struct['deviceBufferSizeInBytes']
        return f'host buffer size = {hostsize} bytes, device buffer size = {devicesize} bytes'

    @property
    def pointer(self):
        return self.struct.ctypes.data


# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np

class CuestWorkspaceDescriptor():

    _dtype = np.dtype([
        ("hostBufferSizeInBytes", np.uint64, ),
        ("deviceBufferSizeInBytes", np.uint64, ),
        ], align=True
        )

    def __init__(
        self,
        *,
        hostBufferSizeInBytes: np.uint64 = 0,
        deviceBufferSizeInBytes: np.uint64 = 0,
        ):

        self.struct = np.array(
            (hostBufferSizeInBytes, deviceBufferSizeInBytes),
            dtype=self._dtype,
            )

    def __str__(
        self,
        ):

        hostsize = self.struct['hostBufferSizeInBytes']
        devicesize = self.struct['deviceBufferSizeInBytes']
        return f'host buffer size = {hostsize} bytes, device buffer size = {devicesize} bytes'

    @property
    def pointer(self):
        return self.struct.ctypes.data


class CuestWorkspaceDescriptor():

    _dtype = np.dtype([
        ("hostBufferSizeInBytes", np.uint64, ),
        ("deviceBufferSizeInBytes", np.uint64, ),
        ], align=True
        )

    def __init__(
        self,
        *,
        hostBufferSizeInBytes: np.uint64 = 0,
        deviceBufferSizeInBytes: np.uint64 = 0,
        ):

        self.struct = np.array(
            (hostBufferSizeInBytes, deviceBufferSizeInBytes),
            dtype=self._dtype,
            )

    def __str__(
        self,
        ):

        hostsize = self.struct['hostBufferSizeInBytes']
        devicesize = self.struct['deviceBufferSizeInBytes']
        return f'host buffer size = {hostsize} bytes, device buffer size = {devicesize} bytes'

    @property
    def pointer(self):
        return self.struct.ctypes.data


pointer

        self,
        *,
        hostBufferSizeInBytes: np.uint64 = 0,
        deviceBufferSizeInBytes: np.uint64 = 0,
        ):

        self.struct = np.array(
            (hostBufferSizeInBytes, deviceBufferSizeInBytes),
            dtype=self._dtype,
            )

    def __str__(
        self,
        ):

        hostsize = self.struct['hostBufferSizeInBytes']
        devicesize = self.struct['deviceBufferSizeInBytes']
        return f'host buffer size = {hostsize} bytes, device buffer size = {devicesize} bytes'

    @property
    def pointer(self):
        return self.struct.ctypes.data


# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_handle import CuestHandle
from .cuest_oe_int_plan import CuestOEIntPlan

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace
from .cuest_parameters import CuestParameters

import numpy as np

class CuestOEIntCompute(object):

    @staticmethod
    def overlap(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Sptr,
        ):

        Sptr2 = ce.Pointer()
        Sptr2.value = np.intp(Sptr)

        # => Workspace query <= #

        overlap_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_OVERLAPCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestOverlapComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outSMatrix=Sptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestOverlapCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            outSMatrix=Sptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapCompute failed')
        del overlap_compute_parameters

    @staticmethod
    def kinetic(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Tptr,
        ):

        Tptr2 = ce.Pointer()
        Tptr2.value = np.intp(Tptr)

        # => Workspace query <= #

        kinetic_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_KINETICCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestKineticComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outTMatrix=Tptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestKineticCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            outTMatrix=Tptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticCompute failed')
        del kinetic_compute_parameters

    @staticmethod
    def potential(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        ncharge,
        xyz,
        q,
        Vptr,
        ):

        Vptr2 = ce.Pointer()
        Vptr2.value = np.intp(Vptr)

        xyz2 = ce.Pointer()
        xyz2.value = np.intp(xyz)

        q2 = ce.Pointer()
        q2.value = np.intp(q)

        # => Workspace query <= #

        potential_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_POTENTIALCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPotentialComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            outVMatrix=Vptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPotentialCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            outVMatrix=Vptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialCompute failed')
        del potential_compute_parameters

    @staticmethod
    def overlap_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Gptr,
        Wptr,
        ):

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        Wptr2 = ce.Pointer()
        Wptr2.value = np.intp(Wptr)

        # => Workspace query <= #

        overlap_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_OVERLAPDERIVATIVECOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestOverlapDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Wptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestOverlapDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Wptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapDerivativeCompute failed')
        del overlap_compute_parameters

    @staticmethod
    def kinetic_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Gptr,
        Dptr,
        ):

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        # => Workspace query <= #

        kinetic_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_KINETICDERIVATIVECOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestKineticDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestKineticDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticDerivativeCompute failed')
        del kinetic_compute_parameters

    @staticmethod
    def potential_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        ncharge,
        xyz,
        q,
        Dptr,
        GptrBasis,
        GptrCharge,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        xyz2 = ce.Pointer()
        xyz2.value = np.intp(xyz)

        q2 = ce.Pointer()
        q2.value = np.intp(q)

        GptrBasis2 = ce.Pointer()
        GptrBasis2.value = np.intp(GptrBasis)

        GptrCharge2 = ce.Pointer()
        GptrCharge2.value = np.intp(GptrCharge)

        # => Workspace query <= #

        potential_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_POTENTIALDERIVATIVECOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPotentialDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            densityMatrix=Dptr2,
            outBasisGradient=GptrBasis2,
            outChargeGradient=GptrCharge2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPotentialDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            densityMatrix=Dptr2,
            outBasisGradient=GptrBasis2,
            outChargeGradient=GptrCharge2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialDerivativeCompute failed')
        del potential_compute_parameters


CuestOEIntCompute

#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_handle import CuestHandle
from .cuest_oe_int_plan import CuestOEIntPlan

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace
from .cuest_parameters import CuestParameters

import numpy as np

class CuestOEIntCompute(object):

    @staticmethod
    def overlap(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Sptr,
        ):

        Sptr2 = ce.Pointer()
        Sptr2.value = np.intp(Sptr)

        # => Workspace query <= #

        overlap_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_OVERLAPCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestOverlapComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outSMatrix=Sptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestOverlapCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            outSMatrix=Sptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapCompute failed')
        del overlap_compute_parameters

    @staticmethod
    def kinetic(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Tptr,
        ):

        Tptr2 = ce.Pointer()
        Tptr2.value = np.intp(Tptr)

        # => Workspace query <= #

        kinetic_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_KINETICCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestKineticComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outTMatrix=Tptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestKineticCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            outTMatrix=Tptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticCompute failed')
        del kinetic_compute_parameters

    @staticmethod
    def potential(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        ncharge,
        xyz,
        q,
        Vptr,
        ):

        Vptr2 = ce.Pointer()
        Vptr2.value = np.intp(Vptr)

        xyz2 = ce.Pointer()
        xyz2.value = np.intp(xyz)

        q2 = ce.Pointer()
        q2.value = np.intp(q)

        # => Workspace query <= #

        potential_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_POTENTIALCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPotentialComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            outVMatrix=Vptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPotentialCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            outVMatrix=Vptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialCompute failed')
        del potential_compute_parameters

    @staticmethod
    def overlap_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Gptr,
        Wptr,
        ):

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        Wptr2 = ce.Pointer()
        Wptr2.value = np.intp(Wptr)

        # => Workspace query <= #

        overlap_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_OVERLAPDERIVATIVECOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestOverlapDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Wptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestOverlapDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Wptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapDerivativeCompute failed')
        del overlap_compute_parameters

    @staticmethod
    def kinetic_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Gptr,
        Dptr,
        ):

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        # => Workspace query <= #

        kinetic_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_KINETICDERIVATIVECOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestKineticDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestKineticDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticDerivativeCompute failed')
        del kinetic_compute_parameters

    @staticmethod
    def potential_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        ncharge,
        xyz,
        q,
        Dptr,
        GptrBasis,
        GptrCharge,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        xyz2 = ce.Pointer()
        xyz2.value = np.intp(xyz)

        q2 = ce.Pointer()
        q2.value = np.intp(q)

        GptrBasis2 = ce.Pointer()
        GptrBasis2.value = np.intp(GptrBasis)

        GptrCharge2 = ce.Pointer()
        GptrCharge2.value = np.intp(GptrCharge)

        # => Workspace query <= #

        potential_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_POTENTIALDERIVATIVECOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPotentialDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            densityMatrix=Dptr2,
            outBasisGradient=GptrBasis2,
            outChargeGradient=GptrCharge2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPotentialDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            densityMatrix=Dptr2,
            outBasisGradient=GptrBasis2,
            outChargeGradient=GptrCharge2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialDerivativeCompute failed')
        del potential_compute_parameters


overlap

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_handle import CuestHandle
from .cuest_oe_int_plan import CuestOEIntPlan

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace
from .cuest_parameters import CuestParameters

import numpy as np

class CuestOEIntCompute(object):

    @staticmethod
    def overlap(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Sptr,
        ):

        Sptr2 = ce.Pointer()
        Sptr2.value = np.intp(Sptr)

        # => Workspace query <= #

        overlap_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_OVERLAPCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestOverlapComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outSMatrix=Sptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestOverlapCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            outSMatrix=Sptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapCompute failed')
        del overlap_compute_parameters

    @staticmethod
    def kinetic(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Tptr,
        ):

        Tptr2 = ce.Pointer()
        Tptr2.value = np.intp(Tptr)

        # => Workspace query <= #

        kinetic_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_KINETICCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestKineticComputeWorkspaceQuery(


kinetic

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestOverlapCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            outSMatrix=Sptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapCompute failed')
        del overlap_compute_parameters

    @staticmethod
    def kinetic(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Tptr,
        ):

        Tptr2 = ce.Pointer()
        Tptr2.value = np.intp(Tptr)

        # => Workspace query <= #

        kinetic_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_KINETICCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestKineticComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outTMatrix=Tptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestKineticCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            outTMatrix=Tptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticCompute failed')
        del kinetic_compute_parameters

    @staticmethod
    def potential(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        ncharge,
        xyz,
        q,
        Vptr,
        ):

        Vptr2 = ce.Pointer()
        Vptr2.value = np.intp(Vptr)

        xyz2 = ce.Pointer()
        xyz2.value = np.intp(xyz)

        q2 = ce.Pointer()


potential

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestKineticCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            outTMatrix=Tptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticCompute failed')
        del kinetic_compute_parameters

    @staticmethod
    def potential(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        ncharge,
        xyz,
        q,
        Vptr,
        ):

        Vptr2 = ce.Pointer()
        Vptr2.value = np.intp(Vptr)

        xyz2 = ce.Pointer()
        xyz2.value = np.intp(xyz)

        q2 = ce.Pointer()
        q2.value = np.intp(q)

        # => Workspace query <= #

        potential_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_POTENTIALCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPotentialComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            outVMatrix=Vptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPotentialCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            outVMatrix=Vptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialCompute failed')
        del potential_compute_parameters

    @staticmethod
    def overlap_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Gptr,
        Wptr,
        ):

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        Wptr2 = ce.Pointer()
        Wptr2.value = np.intp(Wptr)

        # => Workspace query <= #

        overlap_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_OVERLAPDERIVATIVECOMPUTE_PARAMETERS)


        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPotentialCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            outVMatrix=Vptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialCompute failed')
        del potential_compute_parameters

    @staticmethod
    def overlap_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Gptr,
        Wptr,
        ):

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        Wptr2 = ce.Pointer()
        Wptr2.value = np.intp(Wptr)

        # => Workspace query <= #

        overlap_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_OVERLAPDERIVATIVECOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestOverlapDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Wptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestOverlapDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Wptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapDerivativeCompute failed')
        del overlap_compute_parameters

    @staticmethod
    def kinetic_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Gptr,
        Dptr,
        ):

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        # => Workspace query <= #

        kinetic_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_KINETICDERIVATIVECOMPUTE_PARAMETERS)


        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestOverlapDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=overlap_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Wptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOverlapDerivativeCompute failed')
        del overlap_compute_parameters

    @staticmethod
    def kinetic_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        Gptr,
        Dptr,
        ):

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        # => Workspace query <= #

        kinetic_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_KINETICDERIVATIVECOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestKineticDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestKineticDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticDerivativeCompute failed')
        del kinetic_compute_parameters

    @staticmethod
    def potential_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        ncharge,
        xyz,
        q,
        Dptr,
        GptrBasis,
        GptrCharge,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        xyz2 = ce.Pointer()
        xyz2.value = np.intp(xyz)


        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestKineticDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=kinetic_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestKineticDerivativeCompute failed')
        del kinetic_compute_parameters

    @staticmethod
    def potential_gradient(
        *,
        handle : CuestHandle,
        oe_int_plan : CuestOEIntPlan,
        ncharge,
        xyz,
        q,
        Dptr,
        GptrBasis,
        GptrCharge,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        xyz2 = ce.Pointer()
        xyz2.value = np.intp(xyz)

        q2 = ce.Pointer()
        q2.value = np.intp(q)

        GptrBasis2 = ce.Pointer()
        GptrBasis2.value = np.intp(GptrBasis)

        GptrCharge2 = ce.Pointer()
        GptrCharge2.value = np.intp(GptrCharge)

        # => Workspace query <= #

        potential_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_POTENTIALDERIVATIVECOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPotentialDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            densityMatrix=Dptr2,
            outBasisGradient=GptrBasis2,
            outChargeGradient=GptrCharge2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialDerivativeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPotentialDerivativeCompute(
            handle=handle.handle,
            plan=oe_int_plan.oe_int_plan_handle,
            parameters=potential_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            numCharges=ncharge,
            xyz=xyz2,
            q=q2,
            densityMatrix=Dptr2,
            outBasisGradient=GptrBasis2,
            outChargeGradient=GptrCharge2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPotentialDerivativeCompute failed')
        del potential_compute_parameters


# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_handle import CuestHandle
from .cuest_pcm_int_plan import CuestPCMIntPlan

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace
from .cuest_parameters import CuestParameters
from .cuest_results import CuestResults

import numpy as np

class CuestPCMIntCompute(object):

    @staticmethod
    def compute_pcm_energy_and_potential(
        *,
        handle : CuestHandle,
        pcm_int_plan : CuestPCMIntPlan,
        Dptr,
        inQptr,
        outQptr,
        Vptr,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        inQptr2 = ce.Pointer()
        inQptr2.value = np.intp(inQptr)

        outQptr2 = ce.Pointer()
        outQptr2.value = np.intp(outQptr)

        Vptr2 = ce.Pointer()
        Vptr2.value = np.intp(Vptr)

        # => Workspace query <= #

        pcm_results_handle = CuestResults(resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS, results_handle=ce.cuestPCMResultsHandle())
        # pcm parameters
        pcm_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_PCMPOTENTIALCOMPUTE_PARAMETERS)

        convergence_threshold = ce.data_double(pcm_int_plan.convergence_tol)
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_PCMPOTENTIALCOMPUTE_PARAMETERS,
            parameters=pcm_compute_parameters.parameters,
            attribute=ce.CuestPCMPotentialComputeParametersAttributes.CUEST_PCMPOTENTIALCOMPUTE_PARAMETERS_CONVERGENCE_THRESHOLD,
            attributeValue=convergence_threshold,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed: %d' % status)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPCMPotentialComputeWorkspaceQuery(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMPotentialMatrix=Vptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMPotentialComputeWorkspaceQuery failed: %d' % status)

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPCMPotentialCompute(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMPotentialMatrix=Vptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMPotentialCompute failed: %d' % status)
        del pcm_compute_parameters

        # get results
        Epcm = ce.data_double()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_PCM_DIELECTRIC_ENERGY,
            attributeValue=Epcm,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        converged = ce.data_int32_t()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED,
            attributeValue=converged,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        residual = ce.data_double()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED_RESIDUAL,
            attributeValue=residual,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        del pcm_results_handle
        return Epcm.value, converged.value, residual.value

    @staticmethod
    def compute_pcm_gradient(
        *,
        handle : CuestHandle,
        pcm_int_plan : CuestPCMIntPlan,
        Dptr,
        inQptr,
        outQptr,
        Gptr,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        inQptr2 = ce.Pointer()
        inQptr2.value = np.intp(inQptr)

        outQptr2 = ce.Pointer()
        outQptr2.value = np.intp(outQptr)

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        pcm_results_handle = CuestResults(resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS, results_handle=ce.cuestPCMResultsHandle())
        # pcm parameters
        pcm_derivative_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_PCMDERIVATIVECOMPUTE_PARAMETERS)

        convergence_threshold = ce.data_double(pcm_int_plan.convergence_tol)
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_PCMDERIVATIVECOMPUTE_PARAMETERS,
            parameters=pcm_derivative_compute_parameters.parameters,
            attribute=ce.CuestPCMDerivativeComputeParametersAttributes.CUEST_PCMDERIVATIVECOMPUTE_PARAMETERS_CONVERGENCE_THRESHOLD,
            attributeValue=convergence_threshold,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed: %d' % status)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPCMDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_derivative_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMGradient=Gptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMDerivativeComputeWorkspaceQuery failed: %d' % status)

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPCMDerivativeCompute(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_derivative_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMGradient=Gptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMDerivativeCompute failed: %d' % status)
        del pcm_derivative_compute_parameters

        # get results
        converged = ce.data_int32_t()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED,
            attributeValue=converged,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        residual = ce.data_double()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED_RESIDUAL,
            attributeValue=residual,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        del pcm_results_handle
        return converged.value, residual.value


CuestPCMIntCompute

# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_handle import CuestHandle
from .cuest_pcm_int_plan import CuestPCMIntPlan

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace
from .cuest_parameters import CuestParameters
from .cuest_results import CuestResults

import numpy as np

class CuestPCMIntCompute(object):

    @staticmethod
    def compute_pcm_energy_and_potential(
        *,
        handle : CuestHandle,
        pcm_int_plan : CuestPCMIntPlan,
        Dptr,
        inQptr,
        outQptr,
        Vptr,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        inQptr2 = ce.Pointer()
        inQptr2.value = np.intp(inQptr)

        outQptr2 = ce.Pointer()
        outQptr2.value = np.intp(outQptr)

        Vptr2 = ce.Pointer()
        Vptr2.value = np.intp(Vptr)

        # => Workspace query <= #

        pcm_results_handle = CuestResults(resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS, results_handle=ce.cuestPCMResultsHandle())
        # pcm parameters
        pcm_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_PCMPOTENTIALCOMPUTE_PARAMETERS)

        convergence_threshold = ce.data_double(pcm_int_plan.convergence_tol)
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_PCMPOTENTIALCOMPUTE_PARAMETERS,
            parameters=pcm_compute_parameters.parameters,
            attribute=ce.CuestPCMPotentialComputeParametersAttributes.CUEST_PCMPOTENTIALCOMPUTE_PARAMETERS_CONVERGENCE_THRESHOLD,
            attributeValue=convergence_threshold,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed: %d' % status)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPCMPotentialComputeWorkspaceQuery(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMPotentialMatrix=Vptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMPotentialComputeWorkspaceQuery failed: %d' % status)

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPCMPotentialCompute(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMPotentialMatrix=Vptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMPotentialCompute failed: %d' % status)
        del pcm_compute_parameters

        # get results
        Epcm = ce.data_double()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_PCM_DIELECTRIC_ENERGY,
            attributeValue=Epcm,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        converged = ce.data_int32_t()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED,
            attributeValue=converged,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        residual = ce.data_double()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED_RESIDUAL,
            attributeValue=residual,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        del pcm_results_handle
        return Epcm.value, converged.value, residual.value

    @staticmethod
    def compute_pcm_gradient(
        *,
        handle : CuestHandle,
        pcm_int_plan : CuestPCMIntPlan,
        Dptr,
        inQptr,
        outQptr,
        Gptr,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        inQptr2 = ce.Pointer()
        inQptr2.value = np.intp(inQptr)

        outQptr2 = ce.Pointer()
        outQptr2.value = np.intp(outQptr)

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        pcm_results_handle = CuestResults(resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS, results_handle=ce.cuestPCMResultsHandle())
        # pcm parameters
        pcm_derivative_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_PCMDERIVATIVECOMPUTE_PARAMETERS)

        convergence_threshold = ce.data_double(pcm_int_plan.convergence_tol)
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_PCMDERIVATIVECOMPUTE_PARAMETERS,
            parameters=pcm_derivative_compute_parameters.parameters,
            attribute=ce.CuestPCMDerivativeComputeParametersAttributes.CUEST_PCMDERIVATIVECOMPUTE_PARAMETERS_CONVERGENCE_THRESHOLD,
            attributeValue=convergence_threshold,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed: %d' % status)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPCMDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_derivative_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMGradient=Gptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMDerivativeComputeWorkspaceQuery failed: %d' % status)

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPCMDerivativeCompute(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_derivative_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMGradient=Gptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMDerivativeCompute failed: %d' % status)
        del pcm_derivative_compute_parameters

        # get results
        converged = ce.data_int32_t()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED,
            attributeValue=converged,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        residual = ce.data_double()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED_RESIDUAL,
            attributeValue=residual,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        del pcm_results_handle
        return converged.value, residual.value


# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_handle import CuestHandle
from .cuest_pcm_int_plan import CuestPCMIntPlan

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace
from .cuest_parameters import CuestParameters
from .cuest_results import CuestResults

import numpy as np

class CuestPCMIntCompute(object):

    @staticmethod
    def compute_pcm_energy_and_potential(
        *,
        handle : CuestHandle,
        pcm_int_plan : CuestPCMIntPlan,
        Dptr,
        inQptr,
        outQptr,
        Vptr,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        inQptr2 = ce.Pointer()
        inQptr2.value = np.intp(inQptr)

        outQptr2 = ce.Pointer()
        outQptr2.value = np.intp(outQptr)

        Vptr2 = ce.Pointer()
        Vptr2.value = np.intp(Vptr)

        # => Workspace query <= #

        pcm_results_handle = CuestResults(resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS, results_handle=ce.cuestPCMResultsHandle())
        # pcm parameters
        pcm_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_PCMPOTENTIALCOMPUTE_PARAMETERS)

        convergence_threshold = ce.data_double(pcm_int_plan.convergence_tol)
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_PCMPOTENTIALCOMPUTE_PARAMETERS,
            parameters=pcm_compute_parameters.parameters,
            attribute=ce.CuestPCMPotentialComputeParametersAttributes.CUEST_PCMPOTENTIALCOMPUTE_PARAMETERS_CONVERGENCE_THRESHOLD,
            attributeValue=convergence_threshold,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed: %d' % status)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPCMPotentialComputeWorkspaceQuery(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMPotentialMatrix=Vptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMPotentialComputeWorkspaceQuery failed: %d' % status)

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPCMPotentialCompute(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMPotentialMatrix=Vptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMPotentialCompute failed: %d' % status)
        del pcm_compute_parameters

        # get results
        Epcm = ce.data_double()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_PCM_DIELECTRIC_ENERGY,
            attributeValue=Epcm,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        converged = ce.data_int32_t()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED,
            attributeValue=converged,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        residual = ce.data_double()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED_RESIDUAL,
            attributeValue=residual,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        del pcm_results_handle
        return Epcm.value, converged.value, residual.value

    @staticmethod
    def compute_pcm_gradient(
        *,
        handle : CuestHandle,
        pcm_int_plan : CuestPCMIntPlan,
        Dptr,
        inQptr,
        outQptr,
        Gptr,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        inQptr2 = ce.Pointer()
        inQptr2.value = np.intp(inQptr)

        outQptr2 = ce.Pointer()
        outQptr2.value = np.intp(outQptr)


            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED,
            attributeValue=converged,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        residual = ce.data_double()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED_RESIDUAL,
            attributeValue=residual,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        del pcm_results_handle
        return Epcm.value, converged.value, residual.value

    @staticmethod
    def compute_pcm_gradient(
        *,
        handle : CuestHandle,
        pcm_int_plan : CuestPCMIntPlan,
        Dptr,
        inQptr,
        outQptr,
        Gptr,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        inQptr2 = ce.Pointer()
        inQptr2.value = np.intp(inQptr)

        outQptr2 = ce.Pointer()
        outQptr2.value = np.intp(outQptr)

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        pcm_results_handle = CuestResults(resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS, results_handle=ce.cuestPCMResultsHandle())
        # pcm parameters
        pcm_derivative_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_PCMDERIVATIVECOMPUTE_PARAMETERS)

        convergence_threshold = ce.data_double(pcm_int_plan.convergence_tol)
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_PCMDERIVATIVECOMPUTE_PARAMETERS,
            parameters=pcm_derivative_compute_parameters.parameters,
            attribute=ce.CuestPCMDerivativeComputeParametersAttributes.CUEST_PCMDERIVATIVECOMPUTE_PARAMETERS_CONVERGENCE_THRESHOLD,
            attributeValue=convergence_threshold,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed: %d' % status)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestPCMDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_derivative_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMGradient=Gptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMDerivativeComputeWorkspaceQuery failed: %d' % status)

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestPCMDerivativeCompute(
            handle=handle.handle,
            plan=pcm_int_plan.pcm_int_plan_handle,
            parameters=pcm_derivative_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            inQ=inQptr2,
            outQ=outQptr2,
            outPCMResults=pcm_results_handle.results,
            outPCMGradient=Gptr2,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestPCMDerivativeCompute failed: %d' % status)
        del pcm_derivative_compute_parameters

        # get results
        converged = ce.data_int32_t()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED,
            attributeValue=converged,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        residual = ce.data_double()
        status = ce.cuestResultsQuery(
            resultsType=ce.CuestResultsType.CUEST_PCM_RESULTS,
            results=pcm_results_handle.results,
            attribute=ce.CuestPCMResultAttributes.CUEST_PCMRESULT_CONVERGED_RESIDUAL,
            attributeValue=residual,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsQuery failed: %d' % status)

        del pcm_results_handle
        return converged.value, residual.value