###################################################################################
# Copyright 2021 National Technology & Engineering Solutions of Sandia, #
# LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the #
# U.S. Government retains certain rights in this software. #
# If you want to use this code, please refer to the README.rst and LICENSE files. #
###################################################################################
import numpy as np
from PyNucleus_base.myTypes import INDEX, REAL
from PyNucleus_fem.functions import function, constant
from PyNucleus_fem.mesh import meshNd
from . twoPointFunctions import constantTwoPoint, inverseTwoPoint
from . interactionDomains import (interactionDomain,
fullSpace,
ball1_retriangulation,
ball2_retriangulation,
ballInf_retriangulation)
from . fractionalOrders import (fractionalOrderBase,
constFractionalOrder,
variableConstFractionalOrder,
singleVariableUnsymmetricFractionalOrder)
from . kernelNormalization import (constantFractionalLaplacianScaling,
constantFractionalLaplacianScalingDerivative,
variableFractionalLaplacianScaling,
constantIntegrableScaling,
variableIntegrableScaling,
)
from . kernelsCy import (Kernel,
FractionalKernel,
RangedFractionalKernel,
FRACTIONAL,
LOGINVERSEDISTANCE,
GREENS_2D,
GREENS_3D,
MONOMIAL,
getKernelEnum)
from . operatorInterpolation import admissibleSet
import warnings
def _getDim(dim):
if isinstance(dim, meshNd):
return dim.dim
elif isinstance(dim, (INDEX, int)):
return dim
else:
raise NotImplementedError('Dim: {}'.format(dim))
def _getKernelType(kernel):
if isinstance(kernel, str):
kType = getKernelEnum(kernel)
elif isinstance(kernel, int):
kType = kernel
else:
raise NotImplementedError('Kernel type: {}'.format(kernel))
return kType
def _getFractionalOrder(s):
if isinstance(s, fractionalOrderBase):
sFun = s
elif isinstance(s, admissibleSet):
sFun = s
elif isinstance(s, tuple) and len(s) == 2:
sFun = admissibleSet(s)
elif isinstance(s, (REAL, float)):
sFun = constFractionalOrder(s)
else:
raise NotImplementedError('Fractional order: {}'.format(s))
return sFun
def _getHorizon(horizon):
if isinstance(horizon, function):
horizonFun = horizon
elif isinstance(horizon, (REAL, float, int)):
horizonFun = constant(horizon)
elif horizon is None:
horizonFun = constant(np.inf)
else:
raise NotImplementedError('Horizon: {}'.format(horizon))
return horizonFun
def _getInteraction(interaction, horizon):
if isinstance(interaction, interactionDomain):
pass
elif isinstance(horizon, constant) and horizon.value == np.inf:
interaction = fullSpace()
elif interaction is None:
interaction = ball2_retriangulation(horizon)
elif isinstance(interaction, str):
if interaction == 'fullSpace':
interaction = fullSpace()
elif interaction == 'ball1':
interaction = ball1_retriangulation(horizon)
elif interaction == 'ball2':
interaction = ball2_retriangulation(horizon)
elif interaction == 'ballInf':
interaction = ballInf_retriangulation(horizon)
else:
raise NotImplementedError('Interaction: {}'.format(interaction))
else:
raise NotImplementedError('Interaction: {}'.format(interaction))
return interaction
[docs]
def getFractionalKernel(dim,
s,
horizon=None,
interaction=None,
scaling=None,
normalized=True,
piecewise=True,
phi=None,
boundary=False,
derivative=0,
tempered=0.,
max_horizon=np.nan,
manifold=False):
dim_ = _getDim(dim)
sFun = _getFractionalOrder(s)
horizonFun = _getHorizon(horizon)
interaction = _getInteraction(interaction, horizonFun)
if isinstance(sFun, admissibleSet):
kernel = RangedFractionalKernel(dim_, sFun, horizonFun, normalized=normalized, tempered=tempered)
else:
if scaling is None:
if isinstance(sFun, constFractionalOrder) and isinstance(horizonFun, constant):
if derivative == 0:
if normalized:
if not manifold:
scaling = constantFractionalLaplacianScaling(dim, sFun.value, horizonFun.value, tempered)
else:
scaling = constantFractionalLaplacianScalingManifold(dim-1, sFun.value, horizonFun.value, tempered)
else:
scaling = constantTwoPoint(0.5)
else:
if piecewise:
warnings.warn('Derivative kernels cannot be piecewise. Switching to piecewise == False.')
piecewise = False
scaling = constantFractionalLaplacianScalingDerivative(dim, sFun.value, horizonFun.value, normalized, boundary, derivative, tempered)
else:
symmetric = sFun.symmetric and isinstance(horizonFun, constant)
if piecewise and isinstance(sFun, singleVariableUnsymmetricFractionalOrder):
warnings.warn('Variable s kernels cannot be piecewise. Switching to piecewise == False.')
piecewise = False
scaling = variableFractionalLaplacianScaling(symmetric, normalized, boundary, derivative)
if boundary:
if isinstance(sFun, (constFractionalOrder,
variableConstFractionalOrder)):
fac = constantTwoPoint(1/sFun.value)
else:
fac = inverseTwoPoint(sFun)
if phi is not None:
phi = fac*phi
else:
phi = fac
kernel = FractionalKernel(dim_, sFun, horizonFun, interaction, scaling, phi, piecewise=piecewise, boundary=boundary,
derivative=derivative, tempered=tempered, max_horizon=max_horizon, manifold=manifold)
from . twoPointFunctions import parametrizedTwoPointFunction
if isinstance(kernel.scaling, parametrizedTwoPointFunction):
assert kernel.getParamPtrAddr() == kernel.scaling.getParamPtrAddr()
if isinstance(kernel.interaction, parametrizedTwoPointFunction):
assert kernel.getParamPtrAddr() == kernel.interaction.getParamPtrAddr()
return kernel
[docs]
def getIntegrableKernel(dim,
kernel,
horizon,
scaling=None,
interaction=None,
normalized=True,
piecewise=True,
phi=None,
boundary=False,
monomialPower=np.nan,
variance=1.,
exponentialRate=1.0,
a=1.,
max_horizon=np.nan):
dim_ = _getDim(dim)
kType = _getKernelType(kernel)
horizonFun = _getHorizon(horizon)
interaction = _getInteraction(interaction, horizonFun)
if scaling is None:
if normalized:
if isinstance(horizonFun, constant):
scaling = constantIntegrableScaling(kType, interaction, dim_, horizonFun.value, gaussian_variance=variance, exponentialRate=exponentialRate)
else:
scaling = variableIntegrableScaling(kType, interaction)
else:
scaling = constantTwoPoint(0.5)
if (not scaling.symmetric) or (phi is not None and not phi.symmetric):
piecewise = False
return Kernel(dim_, kType=kType, horizon=horizonFun, interaction=interaction, scaling=scaling, phi=phi, piecewise=piecewise,
boundary=boundary, monomialPower=monomialPower, max_horizon=max_horizon, variance=variance, exponentialRate=exponentialRate, a=a)
[docs]
def getKernel(dim,
s=None,
horizon=None,
scaling=None,
interaction=None,
normalized=True,
piecewise=True,
phi=None,
kernel=FRACTIONAL,
boundary=False,
max_horizon=np.nan,
variance=1.,
exponentialRate=1.0):
kType = _getKernelType(kernel)
if kType == FRACTIONAL:
return getFractionalKernel(dim, s, horizon, interaction, scaling, normalized, piecewise, phi, boundary, max_horizon=max_horizon)
else:
return getIntegrableKernel(dim,
kernel=kType,
horizon=horizon,
scaling=scaling,
interaction=interaction,
normalized=normalized,
piecewise=piecewise, phi=phi,
max_horizon=max_horizon,
variance=variance,
exponentialRate=exponentialRate)