3 from collections.abc 
import Iterable
 
    4 from copy 
import deepcopy
 
    8 from scipy.spatial 
import cKDTree
 
   12   def __init__(self, XIn, YIn, ZIn, nInterpPoints = 5,
 
   13                weightMethod = 'barycentricScalar',
 
   14                distanceMethod = 'cartesian',
 
   15                calculateDiagnostics = False):
 
   16     assert len(XIn) == len(YIn), 
'InterpolateCartesian: input coordinates must be identical size' 
   17     assert len(XIn) == len(ZIn), 
'InterpolateCartesian: input coordinates must be identical size' 
   34       'barycentricScalar': {
 
   45         'distanceMethod': 
'cartesian',
 
   48     assert weightMethod 
in list(weightMethods.keys()), \
 
   49       'InterpolateCartesian: '+weightMethod+
' is not one of the available weightMethods' 
   51     self.
weightMethodweightMethod = weightMethods[weightMethod][
'method']
 
   53     self.
minInterpPointsminInterpPoints = weightMethods[weightMethod][
'minInterpPoints']
 
   56       'InterpolateCartesian: '+weightMethod+
' weightMethod requires nInterpPoints > '+str(self.
minInterpPointsminInterpPoints)
 
   63       'distanceMethod', distanceMethod)
 
   67     self.
nInnIn = len(XIn)
 
   72     XYZ = np.empty((self.
nInnIn, 3))
 
   73     for ii 
in np.arange(0, self.
nInnIn):
 
   74       XYZ[ii,:] = np.asarray([self.
XInXIn[ii], self.
YInYIn[ii], self.
ZInZIn[ii]])
 
   75     self.
ScaleScale = np.mean(np.sqrt(np.square(XYZ).sum(axis=1)))
 
   77     self.
TreeInTreeIn = cKDTree(list(zip(XIn, YIn, ZIn)))
 
   86     self.nnInterpDistances, self.
nnInterpIndsnnInterpInds = \
 
   88         list(zip(XOut, YOut, ZOut)),
 
   95         'InterpolateCartesian: '+distanceMethod+
' is not one of the available distanceMethods' 
  107     if isinstance(Inds1, Iterable) 
and isinstance(Inds2, Iterable):
 
  108       assert len(Inds1) == len(Inds2), 
'Inds1 must be same size as Inds2' 
  110     X1 = self.
XInXIn[Inds1]
 
  111     Y1 = self.
YInYIn[Inds1]
 
  112     Z1 = self.
ZInZIn[Inds1]
 
  114     X2 = self.
XInXIn[Inds2]
 
  115     Y2 = self.
YInYIn[Inds2]
 
  116     Z2 = self.
ZInZIn[Inds2]
 
  121               updateNeighbors = False):
 
  123       assert len(XOut) == len(YOut), 
'InterpolateCartesian::initWeights: output coordinates must be identical size' 
  124       assert len(XOut) == len(ZOut), 
'InterpolateCartesian::initWeights: output coordinates must be identical size' 
  125       if len(self.
nnInterpIndsnnInterpInds) != len(XOut) 
or updateNeighbors:
 
  131     for kk, nnDistances 
in enumerate(self.nnInterpDistances):
 
  132       if nnDistances.min() < self.
epseps:
 
  138     nnInterpWeightSums = np.sum(self.
nnInterpWeightsnnInterpWeights, axis=1)
 
  146     masks = np.logical_not(np.identity(self.
nInterpPointsnInterpPoints))
 
  147     for kk, (nnInds, nnDistances) 
in enumerate(
 
  148       list(zip(self.
nnInterpIndsnnInterpInds, self.nnInterpDistances))):
 
  149       if nnDistances.min()*self.
ScaleScale < self.
epseps:
 
  153         for jj, (nnInd, nnDistance, mask) 
in enumerate(
 
  154           list(zip(nnInds, nnDistances, masks))):
 
  156           wprod = np.prod(otherDistances)
 
  157           bw[jj] = 1.0 / np.prod(otherDistances)
 
  160         for jj, (nnInd, nnDistance) 
in enumerate(
 
  161           list(zip(nnInds, nnDistances))):
 
  162           bsw += bw[jj] / nnDistance
 
  170     masks = np.logical_not(np.identity(self.
nInterpPointsnInterpPoints))
 
  171     for kk, (nnInds, nnDistances) 
in enumerate(
 
  172       list(zip(self.
nnInterpIndsnnInterpInds, self.nnInterpDistances))):
 
  173       if nnDistances.min()*self.
ScaleScale < self.
epseps:
 
  177         for jj, (nnInd, nnDistance, mask) 
in enumerate(
 
  178           list(zip(nnInds, nnDistances, masks))):
 
  180           unstWeights[jj] = 1.0 / np.prod(otherDistances) / nnDistance
 
  181         self.
nnInterpWeightsnnInterpWeights[kk,:] = unstWeights / unstWeights.sum()
 
  186     allOutInds = np.arange(0, self.
nOutnOut)
 
  189     OnNode = self.nnInterpDistances.min(axis=1)*self.
ScaleScale < self.
epseps
 
  190     OnNodeInds = allOutInds[OnNode]
 
  191     minInds = np.argmin(self.nnInterpDistances[OnNodeInds,:], axis=1)
 
  192     for (kk, minInd) 
in list(zip(OnNodeInds, minInds)):
 
  193       unstWeights[kk, minInd] = 1.0
 
  196     OffNodeInds = allOutInds[np.logical_not(OnNode)]
 
  197     otherNodesMasks = np.logical_not(np.identity(self.
nInterpPointsnInterpPoints))
 
  198     otherNodesMaskInds = []
 
  200     for otherNodesMask 
in otherNodesMasks:
 
  201       otherNodesMaskInds.append(allNodesInds[otherNodesMask])
 
  203     unstWeights[OffNodeInds, :] = 1.0 / self.nnInterpDistances[OffNodeInds,:]
 
  205     for jj, otherNodesInds 
in enumerate(otherNodesMaskInds):
 
  206       for otherNodeInd 
in otherNodesInds:
 
  209           self.
nnInterpIndsnnInterpInds[OffNodeInds, otherNodeInd]
 
  211         unstWeights[OffNodeInds, jj] /= otherDistances
 
  213     unstWeightsSum = unstWeights[OffNodeInds].sum(axis=1)
 
  214     for node 
in np.arange(0, unstWeights.shape[1]):
 
  215       unstWeights[OffNodeInds,node] /= unstWeightsSum
 
  224     subsetIndsPermutations = []
 
  225     for inds 
in itertools.combinations(
 
  227       subsetIndsPermutations.append(list(inds))
 
  228     subsetIndsPermutations = np.asarray(subsetIndsPermutations)
 
  233     for kk, (nnInds, nnDistances) 
in enumerate(
 
  234       list(zip(self.
nnInterpIndsnnInterpInds, self.nnInterpDistances))):
 
  239         for orderedSubsetInds 
in subsetIndsPermutations:
 
  244           subsetInds = np.roll(orderedSubsetInds, 1)
 
  247           nnSubsetInds = nnInds[subsetInds]
 
  270           x3 = (-d1**2 + d2**2 + d3**2) / (2 * d3)
 
  271           radicand = d1**2 - (d3 - x3)**2
 
  275           if (radicand/(d1**2)) < np.square(minAspectRatio):
 
  277           y3 = np.sqrt(radicand)
 
  280           denom = (y2-y3)*(x1-x3) + (x3-x2)*(y1-y3)
 
  281           if np.abs(denom) == 0.0: 
continue 
  283           l1, l2, l3 = nnDistances[subsetInds]
 
  285           x = (-l2**2 + l1**2 + d3**2) / (2 * d3)
 
  286           radicand = l2**2 - (d3 - x)**2
 
  287           if (radicand/(l2**2)) < self.
epseps:
 
  291             y = np.sqrt(radicand)
 
  293           baryWeights[subsetInds[0]] = ((y2-y3)*(x-x3) + (x3-x2)*(y-y3)) / denom
 
  294           baryWeights[subsetInds[1]] = ((y3-y1)*(x-x3) + (x1-x3)*(y-y3)) / denom
 
  295           baryWeights[subsetInds[2]] = 1. - baryWeights[subsetInds[0]] \
 
  296                                           - baryWeights[subsetInds[1]]
 
  299           minBaryCheck = baryWeights.min() >= 0.0
 
  300           maxBaryCheck = baryWeights.max() <= 1.0 
and baryWeights.max() > 0.0
 
  301           if minBaryCheck 
and maxBaryCheck: 
break 
  303         assert minBaryCheck 
and maxBaryCheck, \
 
  305   baryWeights checks not satisfied; try increasing nInterpPoints 
  306   baryWeights = '''+str(baryWeights)+
''' 
  307   nnInterpDistances = '''+str(nnDistances)+
''' 
  308   nnInds = '''+str(nnInds)+
''' 
  309   denom = '''+str(denom)+
''' 
  322   d1^2 = '''+str(d1**2)+
''' 
  323   (d3-x3)^2 = '''+str((d3 - x3)**2)+
''' 
  324   l2^2 = '''+str(l2**2)+
''' 
  325   (d3-x)^2 = '''+str((d3 - x)**2)+
''' 
  328   LatIn = '''+str(self.LatIn[nnInds]*180.0/np.pi)+
''' 
  329   LonIn = '''+str(self.LonIn[nnInds]*180.0/np.pi)+
''' 
  330   LatIn = '''+str(self.LatIn[nnSubsetInds]*180.0/np.pi)+
''' 
  331   LonIn = '''+str(self.LonIn[nnSubsetInds]*180.0/np.pi)+
''' 
  337     minAspectRatio = 0.01
 
  344     minBaryCheck = np.full(self.
nOutnOut, 
False)
 
  345     maxBaryCheck = np.full(self.
nOutnOut, 
False)
 
  346     allOutInds = np.arange(0, self.
nOutnOut)
 
  360     for ii, indsSet 
in enumerate(itertools.combinations(
 
  363       orderedSubsetInds = np.array(list(indsSet))
 
  368       subsetInds = np.roll(orderedSubsetInds, 1)
 
  370       KeepSearching = np.logical_or(
 
  371         np.logical_not(minBaryCheck),
 
  372         np.logical_not(maxBaryCheck)
 
  374       KeepSearchingInds = allOutInds[KeepSearching]
 
  375       nTargets = len(KeepSearchingInds)
 
  376       if nTargets == 0: 
break 
  381       nnSubsetInds = self.
nnInterpIndsnnInterpInds[KeepSearchingInds,:]
 
  382       nnSubsetInds = nnSubsetInds[:,subsetInds]
 
  384       baryWeights[KeepSearchingInds,:] = 0.0
 
  405       x1, y1 = np.zeros(nTargets), np.zeros(nTargets)
 
  406       x2, y2 = d3, np.zeros(nTargets)
 
  407       x3 = (-d1**2 + d2**2 + d3**2) / (2 * d3)
 
  408       radicand = d1**2 - (d3 - x3)**2
 
  413       AspectCheck = (radicand/(d3**2)) >= np.square(minAspectRatio)
 
  414       y3 = np.zeros(nTargets)
 
  415       y3[AspectCheck] = np.sqrt(radicand[AspectCheck])
 
  418       denom = (y2-y3)*(x1-x3) + (x3-x2)*(y1-y3)
 
  419       DeterminantCheck = np.abs(denom) > 0.0
 
  422       KeepGoing = np.logical_and(AspectCheck, DeterminantCheck)
 
  423       if KeepGoing.sum() == 0: 
continue 
  426       x1, y1 = x1[KeepGoing], y1[KeepGoing]
 
  427       x2, y2 = x2[KeepGoing], y2[KeepGoing]
 
  428       x3, y3 = x3[KeepGoing], y3[KeepGoing]
 
  429       denom = denom[KeepGoing]
 
  430       KeepSearchingInds = KeepSearchingInds[KeepGoing]
 
  431       nTargets = len(KeepSearchingInds)
 
  434         self.
triangleAreatriangleArea[KeepSearchingInds] = 0.5 * d3 * y3
 
  435         self.
aspectRatioaspectRatio[KeepSearchingInds] = y3 / d3
 
  437       l1 = self.nnInterpDistances[KeepSearchingInds,subsetInds[0]]
 
  438       l2 = self.nnInterpDistances[KeepSearchingInds,subsetInds[1]]
 
  440       x = (-l2**2 + l1**2 + d3**2) / (2 * d3)
 
  441       radicand = l2**2 - (d3 - x)**2
 
  445       ValidY = (radicand >= 0.0)
 
  446       if ValidY.sum() == 0: 
continue 
  448       y = np.zeros(nTargets)
 
  449       y[ValidY] = np.sqrt(radicand[ValidY])
 
  451       w1 = ((y2-y3)*(x-x3) + (x3-x2)*(y-y3)) / denom
 
  452       w2 = ((y3-y1)*(x-x3) + (x1-x3)*(y-y3)) / denom
 
  455       KeepSearchingInds = KeepSearchingInds[ValidY]
 
  458         self.
determinantdeterminant[KeepSearchingInds] = denom[ValidY]
 
  459         self.
ycoordycoord[KeepSearchingInds] = y[ValidY]
 
  461       baryWeights[KeepSearchingInds,subsetInds[0]] = w1
 
  462       baryWeights[KeepSearchingInds,subsetInds[1]] = w2
 
  463       baryWeights[KeepSearchingInds,subsetInds[2]] = 1. - (w1 + w2)
 
  467       for kk 
in KeepSearchingInds:
 
  468         minBaryCheck[kk] = baryWeights[kk,:].min() >= 0.0
 
  469         maxBaryCheck[kk] = baryWeights[kk,:].max() <= 1.0 
and baryWeights[kk,:].max() > 0.0
 
  471     allChecks = np.logical_and(minBaryCheck, maxBaryCheck)
 
  473     assert np.all(allChecks), \
 
  475   baryWeights checks not satisfied for '''+str(self.
nOutnOut - allChecks.sum())+
' of '+str(self.
nOutnOut)+
''' target locations 
  476   --> try increasing nInterpPoints 
  482     minAspectRatio = 0.01
 
  489     minBaryCheck = np.full(self.
nOutnOut, 
False)
 
  490     maxBaryCheck = np.full(self.
nOutnOut, 
False)
 
  491     allOutInds = np.arange(0, self.
nOutnOut)
 
  505     for ii, indsSet 
in enumerate(itertools.combinations(
 
  508       orderedSubsetInds = np.array(list(indsSet))
 
  512       subsetInds = orderedSubsetInds
 
  514       KeepSearching = np.logical_or(
 
  515         np.logical_not(minBaryCheck),
 
  516         np.logical_not(maxBaryCheck)
 
  518       KeepSearchingInds = allOutInds[KeepSearching]
 
  519       nTargets = len(KeepSearchingInds)
 
  520       if nTargets == 0: 
break 
  523       print(nTargets, subsetInds)
 
  525       nnSubsetInds = self.
nnInterpIndsnnInterpInds[KeepSearchingInds,:]
 
  526       nnSubsetInds = nnSubsetInds[:,subsetInds]
 
  528       baryWeights[KeepSearchingInds,:] = 0.0
 
  549       x1, y1 = np.zeros(nTargets), np.zeros(nTargets)
 
  550       x2, y2 = d3, np.zeros(nTargets)
 
  551       x3 = (-d1**2 + d2**2 + d3**2) / (2 * d3)
 
  552       radicand = d1**2 - (d3 - x3)**2
 
  557       AspectCheck = (radicand/(d3**2)) >= np.square(minAspectRatio)
 
  558       y3 = np.zeros(nTargets)
 
  559       y3[AspectCheck] = np.sqrt(radicand[AspectCheck])
 
  562       denom = (y2-y3)*(x1-x3) + (x3-x2)*(y1-y3)
 
  563       DeterminantCheck = np.abs(denom) > 0.0
 
  566       KeepGoing = np.logical_and(AspectCheck, DeterminantCheck)
 
  567       if KeepGoing.sum() == 0: 
continue 
  570       x1, y1 = x1[KeepGoing], y1[KeepGoing]
 
  571       x2, y2 = x2[KeepGoing], y2[KeepGoing]
 
  572       x3, y3 = x3[KeepGoing], y3[KeepGoing]
 
  573       denom = denom[KeepGoing]
 
  574       KeepSearchingInds = KeepSearchingInds[KeepGoing]
 
  575       nnSubsetInds = nnSubsetInds[KeepGoing,:]
 
  577       nTargets = len(KeepSearchingInds)
 
  580         self.
triangleAreatriangleArea[KeepSearchingInds] = 0.5 * d3 * y3
 
  581         self.
aspectRatioaspectRatio[KeepSearchingInds] = y3 / d3
 
  586       XTarget = self.
XOutXOut[KeepSearchingInds]
 
  587       YTarget = self.
YOutYOut[KeepSearchingInds]
 
  588       ZTarget = self.
ZOutZOut[KeepSearchingInds]
 
  590       X1 = self.
XInXIn[nnSubsetInds[:,0]]
 
  591       Y1 = self.
YInYIn[nnSubsetInds[:,0]]
 
  592       Z1 = self.
ZInZIn[nnSubsetInds[:,0]]
 
  594       X2 = self.
XInXIn[nnSubsetInds[:,1]]
 
  595       Y2 = self.
YInYIn[nnSubsetInds[:,1]]
 
  596       Z2 = self.
ZInZIn[nnSubsetInds[:,1]]
 
  598       X3 = self.
XInXIn[nnSubsetInds[:,2]]
 
  599       Y3 = self.
YInYIn[nnSubsetInds[:,2]]
 
  600       Z3 = self.
ZInZIn[nnSubsetInds[:,2]]
 
  613       Nx, Ny, Nz = np.cross(
 
  614         np.array([D3x, D3y, D3z]),
 
  615         np.array([D2x, D2y, D2z]),
 
  631       c = np.abs(np.array([L1x*Nx, L1y*Ny, L1z*Nz]).sum(axis=0))
 
  636       XTarget_ = XTarget - c * Nx
 
  637       YTarget_ = YTarget - c * Ny
 
  638       ZTarget_ = ZTarget - c * Nz
 
  650       x = (-l2**2 + l1**2 + d3**2) / (2 * d3)
 
  651       radicand = l2**2 - (d3 - x)**2
 
  655       ValidY = (radicand >= 0.0)
 
  656       if ValidY.sum() == 0: 
continue 
  658       y = np.zeros(nTargets)
 
  659       y[ValidY] = np.sqrt(radicand[ValidY])
 
  661       w1 = ((y2-y3)*(x-x3) + (x3-x2)*(y-y3)) / denom
 
  662       w2 = ((y3-y1)*(x-x3) + (x1-x3)*(y-y3)) / denom
 
  665       KeepSearchingInds = KeepSearchingInds[ValidY]
 
  668         self.
determinantdeterminant[KeepSearchingInds] = denom[ValidY]
 
  669         self.
ycoordycoord[KeepSearchingInds] = y[ValidY]
 
  671       baryWeights[KeepSearchingInds,subsetInds[0]] = w1
 
  672       baryWeights[KeepSearchingInds,subsetInds[1]] = w2
 
  673       baryWeights[KeepSearchingInds,subsetInds[2]] = 1. - (w1 + w2)
 
  677       for kk 
in KeepSearchingInds:
 
  678         minBaryCheck[kk] = baryWeights[kk,:].min() >= 0.0
 
  679         maxBaryCheck[kk] = baryWeights[kk,:].max() <= 1.0 
and baryWeights[kk,:].max() > 0.0
 
  681     allChecks = np.logical_and(minBaryCheck, maxBaryCheck)
 
  683     assert np.all(allChecks), \
 
  685   baryWeights checks not satisfied for '''+str(self.
nOutnOut - allChecks.sum())+
' of '+str(self.
nOutnOut)+
''' target locations 
  686   --> try increasing nInterpPoints 
  691     assert isinstance(fIn, Iterable) 
and \
 
  692            fIn.shape == self.
XInXIn.shape, 
'InterpolateCartesian::apply: fIn must have same shape as original XIn' 
  698     elif isinstance(OutInds, Iterable):
 
  712   def __init__(self, LonIn, LatIn, nInterpPoints = 5,
 
  713                weightMethod = 'unstinterp',
 
  714                distanceMethod = 'greatcircle',
 
  716                calculateDiagnostics = False):
 
  721     super().
__init__(XIn, YIn, ZIn, nInterpPoints,
 
  724       calculateDiagnostics,
 
  736       for kk, (nnInds, lon, lat) 
in enumerate(
 
  737         list(zip(self.
nnInterpIndsnnInterpInds, LonOut, LatOut))):
 
  740           self.
LonInLonIn[nnInds], self.
LatInLatIn[nnInds],
 
  744     if len(self.
nnInterpIndsnnInterpInds) != len(LatOut) 
or updateNeighbors:
 
  750       self.
LonInLonIn[Inds1], self.
LatInLatIn[Inds1],
 
  751       self.
LonInLonIn[Inds2], self.
LatInLatIn[Inds2],
 
  757     calculates cartesion coordinates from longitude and latitude 
  758     of a point on a sphere with radius R 
  760     lon and lat are in radians 
  762     x =  R * np.cos(lat) * np.cos(lon)
 
  763     y = R * np.cos(lat) * np.sin(lon)
 
  768   return np.sqrt((X2 - X1)**2 + (Y2 - Y1)**2 + (Z2 - Z1)**2)
 
  778     if isinstance(lat1, Iterable):
 
  779       assert isinstance(lon1, Iterable), 
'lon1 must be same type as lat1' 
  780       assert len(lon1) == len(lat1), 
'lon1 must be same size as lat1' 
  781     if isinstance(lat2, Iterable):
 
  782       assert isinstance(lon2, Iterable), 
'lon2 must be same type as lat2' 
  783       assert len(lon2) == len(lat2), 
'lon2 must be same size as lat2' 
  784     if isinstance(lat1, Iterable) 
and isinstance(lat2, Iterable):
 
  785       assert len(lat1) == len(lat2), 
'lat1 must be same size as lat2' 
  787     dtheta = np.subtract(lat2, lat1)
 
  788     dphi   = np.subtract(lon2, lon1)
 
  790     a = np.add(np.square(np.sin(np.divide(dtheta, 2.))),
 
  791                np.multiply(np.multiply(np.cos(lat1), np.cos(lat2)),
 
  792                            np.square(np.sin(np.divide(dphi, 2.)))
 
  796     return np.multiply(2.*R, np.arctan2(np.sqrt(a), np.sqrt(1. - a)))
 
def apply(self, fIn, OutInds=None)
 
def unstinterpBarycentScalarWeights(self)
 
def cartesianInDistances(self, Inds1, Inds2)
 
def unstinterpBarycentWeights(self)
 
def __init__(self, XIn, YIn, ZIn, nInterpPoints=5, weightMethod='barycentricScalar', distanceMethod='cartesian', calculateDiagnostics=False)
 
def barycentricWeights(self)
 
def applyAtIndex(self, fIn, OutInd)
 
def InDistances(self, Inds1, Inds2)
 
def unstinterpBarycentCleanupWeights(self)
 
def initNeighbors(self, XOut, YOut, ZOut)
 
def initWeights(self, XOut=None, YOut=None, ZOut=None, updateNeighbors=False)
 
distanceMethodInitialized
 
def barycentricScalarWeights(self)
 
def inverseDistanceWeights(self)
 
def projectedBarycentricWeights(self)
 
def __init__(self, LonIn, LatIn, nInterpPoints=5, weightMethod='unstinterp', distanceMethod='greatcircle', Radius=1., calculateDiagnostics=False)
 
def initNeighbors(self, LonOut, LatOut)
 
def greatcircleInDistances(self, Inds1, Inds2)
 
def initWeights(self, LonOut, LatOut, updateNeighbors=False)
 
def CartesianDistance(X1, X2, Y1, Y2, Z1, Z2)
 
def HaversineDistance(lon1, lat1, lon2, lat2, R=1.)
 
def LonLat2Cartesian(lon, lat, R=1.)