Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repeated call of sTriangulation freezes #85

Open
kitchenknif opened this issue Sep 28, 2020 · 9 comments
Open

Repeated call of sTriangulation freezes #85

kitchenknif opened this issue Sep 28, 2020 · 9 comments

Comments

@kitchenknif
Copy link

kitchenknif commented Sep 28, 2020

Running this code seems to randomly hang after ~3000 iterations, and I have been unable to deduce why.
Using quadrature points from here.

import time
import numpy as np
import stripy

def get_lebedev_quadrature(order=29):
    phi, theta, weights = [], [], []
    with open("lebedev_{:03d}.txt".format(order), "r") as f:
        lines = f.readlines()
        for line in lines:
            ph, th, w = line.split()
            phi.append(float(ph) * np.pi / 180 + np.pi)
            theta.append(float(th) * np.pi / 180)
            weights.append(float(w))

    return np.asarray(phi), np.asarray(theta), np.asarray(weights)

if __name__ == "__main__":
    phi, theta, weights = get_lebedev_quadrature(29)
    for i in range(10000):
        a = time.time()
        tri = stripy.sTriangulation(lons=phi - np.pi, lats=-theta + np.pi / 2, permute=True)
        b = time.time() - a
        print(i, b)

lebedev_029.txt

@lmoresi
Copy link
Member

lmoresi commented Sep 28, 2020 via email

@kitchenknif
Copy link
Author

kitchenknif commented Sep 28, 2020

I've been trying to forcibly run garbage collection at the beginning / end of the loop, but that doesn't seem to have any effect.

Explicitly deleting the triangulation after use seems to postpone the hang by a few thousand iterations, but it still ends up hanging.

@lmoresi
Copy link
Member

lmoresi commented Sep 28, 2020 via email

@kitchenknif
Copy link
Author

Yeah, that's another Issue that I have,
and it is weird that it only occurs sometimes, considering that the input points are exactly the same during each call to build the triangulation.

@lmoresi
Copy link
Member

lmoresi commented Sep 28, 2020 via email

@brmather
Copy link
Member

The "TRMESH - Fatal error!" message is printed at the fortran level if a permutation fails to produce non-collinear points in the first 3 entries of the lon / lat arrays, but stripy simply reshuffles them again before handing it back. In the past I have written initial checks for collinear points prior to constructing the mesh, but they occasionally terminated at the fortran TRMESH routine. It may just be floating point precision causing that particular issue.

I was able to reproduce the bug for a single case. Download this permutation.txt file and execute the following code:

lons, lats, p, ip = np.loadtxt("permutation.txt", unpack=True)
p  = p.astype(np.int)
ip = ip.astype(np.int)

lons0 = lons[p]
lats0 = lats[p]

tri = stripy.sTriangulation(lons0, lats0, permute=False)

🕥

@lmoresi - I'm not sure what is wrong with this permutation for it to hang. The first 3 points are not collinear and they seem adequately spaced apart...

def is_left(x1,y1,z1, x2,y2,z2, x0,y0,z0):
    left = x0 * ( y1 * z2 - y2 * z1 ) \
         - y0 * ( x1 * z2 - x2 * z1 ) \
         + z0 * ( x1 * y2 - x2 * y1 ) >= 0.0
    return left

def is_collinear(lons, lats):
    from stripy.spherical import lonlat2xyz
    x, y, z = lonlat2xyz(lons[:3], lats[:3])
    
    if not is_left(x[0],y[0],z[0], x[1],y[1],z[1], x[2],y[2],z[2]):
        collinear = False
    elif not is_left(x[1],y[1],z[1], x[0],y[0],z[0], x[2],y[2],z[2]):
        collinear = False
    else:
        collinear = True
        
    cartesian_coords = np.c_[x,y,z]
    
    A = np.linalg.norm(cartesian_coords[1] - cartesian_coords[0])
    B = np.linalg.norm(cartesian_coords[2] - cartesian_coords[0])
    C = np.linalg.norm(cartesian_coords[2] - cartesian_coords[1])
    
    s = 0.5*(A+B+C)
    area = np.sqrt(s*(s-A)*(s-B)*(s-C))
    
    det = np.linalg.det(cartesian_coords.T)
    if np.isclose(det, 0.0):
        collinear = True

    print(area)

    return collinear

is_collinear(lons, lats)
> 0.10537979877033213
> False

@lmoresi
Copy link
Member

lmoresi commented Sep 29, 2020 via email

@brmather
Copy link
Member

brmather commented Oct 1, 2020

@kitchenknif for now you can fix your code by manually permuting the first 3 points in your list. Adding this line:

phi[1], phi[4] = phi[4], phi[1]
theta[1], theta[4] = theta[4], theta[1]

and setting permute=False was enough to get your loop working.

We will keep troubleshooting to determine the root cause of the problem.

@kitchenknif
Copy link
Author

My current solution looks like this, manually permuting the points if something goes wrong.

    theta = np.roll(theta, 10)
    phi = np.roll(phi, 10)
    weights = np.roll(weights, 10)

    tri = None
    while tri is None:
        try:
            tri = stripy.sTriangulation(lons=phi - np.pi, lats=-theta + np.pi / 2, permute=False)
        except ValueError as e:
            print(e)
            phi = np.roll(phi, 1)
            theta = np.roll(theta, 1)
            weights = np.roll(weights, 1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants