Package gov.fnal.eag.healpix

Source Code of gov.fnal.eag.healpix.PixTools

/*
* Created on Mar 10, 2005
*
*/
package gov.fnal.eag.healpix;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Vector;
import java.lang.Number;

import javax.vecmath.Vector3d;

/**
*
*  contains methods translated from HEALPix Fortran90
*  with increased map resolution in comparison to original Fortran code.
*
* @author N Kuropatkin
*/
public class PixTools {

  private static double twothird = 2. / 3.;

  private static double PI = Math.PI;

  private static double TWOPI = 2. * PI;

  private static double FOURPI = 4. * PI;

  private static double HALFPI = PI / 2.0;

    private static int ns_max = 1048576; // 2^20

    private static int xmax = 16384;

    private static int pixmax = 131072;

    private static int xmid = 4096;
   
  private static long[] x2pix = new long[xmax+1];

  private static long[] y2pix = new long[xmax+1];

  private static long[] pix2x = new long[pixmax+1];

  private static long[] pix2y = new long[pixmax+1];

  private Vector3d pixVect = new Vector3d(0., 0., 0.);

  private double[][] pixVertex = new double[3][4];

  private BitManipulation bm = new BitManipulation();

  /**
   * defauld constructor
   *
   * 
   */
  public PixTools() {
    for (int i = 0; i <= xmax; i++) {
      x2pix[i] = 0;
      y2pix[i] = 0;
    }
    for (int i = 0; i <= pixmax; i++) {
      pix2x[i] = 0;
      pix2y[i] = 0;
    }
  }

  /**
   * finds pixels having a colatitude (measured from North pole) : theta1 <
   * colatitude < theta2 with o <= theta1 < theta2 <= Pi if theta2 < theta1
   * then pixels with 0 <= colatitude < theta2 or theta1 < colatitude < Pi are
   * returned
   *
   * @param nside
   *            long the map resolution parameter
   * @param theta1
   *            lower edge of the colatitude
   * @param theta2
   *            upper adge of the colatitude
   * @param nest
   *            long if = 1 result is in NESTED scheme
   * @return  ArrayList of  pixel numbers (long)
   * @throws IllegalArgumentException
   */
  public ArrayList query_strip(long nside, double theta1, double theta2,
      long nest) throws Exception {
    ArrayList res = new ArrayList();
    ArrayList listir = new ArrayList();
    long npix, nstrip;
    long iz, ip,  irmin, irmax;
        int is;
    double phi0, dphi;
    double[] colrange = new double[4];
    boolean nest_flag = false;
    String SID = " QUERY_STRIP";
    /* ---------------------------------------- */
    npix = Nside2Npix(nside);
    if (nest == 1)
      nest_flag = true;
    if (npix < 0) {
      throw new IllegalArgumentException(SID + " Nside should be power of 2");
    }
    if ((theta1 < 0.0 || theta1 > PI) || (theta2 < 0.0 || theta2 > PI)) {
      throw new IllegalArgumentException(SID + " Illegal value of theta1, theta2");
    }
    if (theta1 <= theta2) {
      nstrip = 1;
      colrange[0] = theta1;
      colrange[1] = theta2;
    } else {
      nstrip = 2;
      colrange[0] = 0.0;
      colrange[1] = theta2;
      colrange[2] = theta1;
      colrange[3] = PI;
    }
    /* loops on strips */
    for (is = 0; is < nstrip; is++) {
      irmin = RingNum(nside, Math.cos(colrange[2 * is]));
      irmax = RingNum(nside, Math.cos(colrange[2 * is + 1]));
      /* loop on ring number */
      for (iz = irmin; iz <= irmax; iz++) {
        phi0 = 0.;
        dphi = PI;
        listir = InRing(nside, iz, phi0, dphi, nest_flag);
        res.addAll(listir);
      }
    }
    return res;
  }

  /**
   * finds pixels that lie within a CONVEX polygon defined by its vertex on
   * sphere
   *
   * @param nside
   *            the map resolution
   * @param vlist
   *            ArrayList of vectors defining the polygin vertices
   * @param nest
   *            if set to 1 use NESTED scheme
   * @param inclusive
   *            if set 1 returns all pixels crossed by polygon boundaries
   * @return  ArrayList of pixels
   *
   * algorithm: the polygon is divided into triangles vertex 0 belongs to all
   * triangles
   * @throws IllegalArgumentException
   */
  public ArrayList query_polygon(long nside, ArrayList vlist, long nest,
      long inclusive) throws Exception {
    ArrayList res = new ArrayList();
    int nv = vlist.size();
    Vector3d vp0, vp1, vp2;
    Vector3d vo;
    ArrayList vvlist = new ArrayList();
    double surface, fsky, hand;
    double[] ss = new double[nv];
    int n_in_trg, ilist, ntl;
        long npix;
    int ix = 0;
   
    int n_remain, np, nm, nlow;
    String SID = "QUERY_POLYGON";

    //    System.out.println("Start polygon");
    for (int k = 0; k < nv; k++)
      ss[k] = 0.;
    /* -------------------------------------- */
    n_remain = nv;
    if (n_remain < 3) {
      throw new IllegalArgumentException(SID + " Number of vertices should be >= 3");
    }
    /*---------------------------------------------------------------- */
    /* Check that the poligon is convex or has only one concave vertex */
    /*---------------------------------------------------------------- */
    int i0 = 0;
    int i2 = 0;
    if (n_remain > 3) { // a triangle is always convex
      for (int i1 = 1; i1 <= n_remain - 1; i1++) { // in [0,n_remain-1]
        i0 = (int) bm.MODULO(i1 - 1, n_remain);
        i2 = (int) bm.MODULO(i1 + 1, n_remain);
        vp0 = (Vector3d) vlist.get(i0); // select vertices by 3
                        // neighbour
        vp1 = (Vector3d) vlist.get(i1);
        vp2 = (Vector3d) vlist.get(i2);
        // computes handedness (v0 x v2) . v1 for each vertex v1
        vo = new Vector3d(crossProduct(vp0, vp2));
        hand = dotProduct(vo, vp1);
        if (hand >= 0.) {
          ss[i1] = 1.0;
        } else {
          ss[i1] = -1.0;
        }

      }
      np = 0; // number of vert. with positive handedness
      for (int i = 0; i < nv; i++) {
        if (ss[i] > 0.)
          np++;
      }
      nm = n_remain - np;

      nlow = Math.min(np, nm);

      if (nlow != 0) {
        if (nlow == 1) { // only one concave vertex
          if (np == 1) { // ix index of the vertex in the list
            for (int k = 0; k < nv - 1; k++) {
              if (Math.abs(ss[k] - 1.0) <= 1.e-12) {
                ix = k;
                break;
              }
            }
          } else {
            for (int k = 0; k < nv - 1; k++) {
              if (Math.abs(ss[k] + 1.0) <= 1.e-12) {
                ix = k;
                break;
              }
            }
          }

          // rotate pixel list to put that vertex in #0
          int n_rot = vlist.size() - ix;
          int ilast = vlist.size() - 1;
          for (int k = 0; k < n_rot; k++) {
            Vector3d temp = new Vector3d((Vector3d) vlist
                .get(ilast));
            vlist.remove(ilast);
            vlist.add(0, (Object) temp);
          }
        }
        if (nlow > 1) { // more than 1concave vertex
          System.out
              .println(" The polygon has more than one concave vertex");
          System.out.println(" The result is unpredictable");
        }
      }
    }
    /* fill the poligon, one triangle at a time */
    npix = (long) Nside2Npix(nside);
    while (n_remain >= 3) {
      vp0 = (Vector3d) vlist.get(0);
      vp1 = (Vector3d) vlist.get(n_remain - 2);
      vp2 = (Vector3d) vlist.get(n_remain - 1);

      /* find pixels within the triangle */
      ArrayList templist = new ArrayList();
      templist = query_triangle(nside, vp0, vp1, vp2, nest, inclusive);

      vvlist.addAll(templist);
      n_remain--;
    }
    /* make final pixel list */
    npix = vvlist.size();
    long[] pixels = new long[(int)npix];
    for (int i = 0; i < npix; i++) {
      pixels[i] = ((Long) vvlist.get(i)).longValue();
    }
    Arrays.sort(pixels);
    int k = 0;
    res.add(k, new Long(pixels[0]));
    for (int i = 1; i < pixels.length; i++) {
      if (pixels[i] > pixels[i - 1]) {
        k++;
        res.add(k, new Long(pixels[i]));
      }
    }

    return res;
  }

  /**
   * generates a list of pixels that lie inside a triangle defined by
   * the three vertex vectors
   *
   * @param nside
   *            long map resolution parameter
   * @param v1
   *            Vector3d defines one vertex of the triangle
   * @param v2
   *            Vector3d anothe vertex
   * @param v3
   *            Vector3d yet another one
   * @param nest
   *            long 0 (default) RING numbering scheme, if set to 1 the NESTED
   *            scheme will be used.
   * @param inclusive
   *            long 0 (default) only pixels whose centers are inside the
   *            triangle will be listed, if set to 1 all pixels overlaping the
   *            triangle will be listed
   * @return ArrayList with pixel numbers
   * @throws healpixException if the triangle is degenerated
   * @throws IllegalArgumentException
   */
  public ArrayList query_triangle(long nside, Vector3d v1, Vector3d v2,
      Vector3d v3, long nest, long inclusive) throws Exception {
    ArrayList res;
    res = new ArrayList();
    ArrayList listir;
    long npix, ilist, iz, irmin, irmax, n12, n123a, n123b, ndom = 0;
    boolean test1, test2, test3;
    boolean test1a, test1b, test2a, test2b, test3a, test3b;
    double dth1, dth2, determ, sdet;
    double zmax, zmin, z1max, z1min, z2max, z2min, z3max, z3min;
    double z, zz, tgth, st, offset, sin_off;
    double phi_pos, phi_neg;
    Vector3d[] vv = new Vector3d[3];
    Vector3d[] vo = new Vector3d[3];
    double[] sprod = new double[3];
    double[] sto = new double[3];
    double[] phi0i = new double[3];
    double[] tgthi = new double[3];
    double[] dc = new double[3];
    double[][] dom = new double[3][2];
    double[] dom12 = new double[4];
    double[] dom123a = new double[4];
    double[] dom123b = new double[4];
    double[] alldom = new double[6];
    double a_i, b_i, phi0, dphiring;
    long idom, nir, ip, status;
    boolean do_inclusive = false;
    boolean do_nest = false;
    String SID = "QUERY_TRIANGLE";
    long nsidesq = nside * nside;
    /*                                       */

    //    System.out.println("in query_triangle");
    npix = Nside2Npix(nside);
    if (npix < 0) {
      throw new IllegalArgumentException(SID + " Nside should be power of 2 >0 and < "+ns_max);
    }
    if (inclusive == 1)
      do_inclusive = true;
    if (nest == 1)
      do_nest = true;
    vv[0] = new Vector3d(v1);
    vv[0].normalize();
    vv[1] = new Vector3d(v2);
    vv[1].normalize();
    vv[2] = new Vector3d(v3);
    vv[2].normalize();

    /*                                  */
    dth1 = 1.0 / (3.0 * nsidesq);
    dth2 = 2.0 / (3.0 * nside);
    /*
     * determ = (v1 X v2) . v3 determines the left ( <0) or right (>0)
     * handedness of the triangle
     */
    Vector3d vt = new Vector3d(0., 0., 0.);
    vt = crossProduct(vv[0], vv[1]);
    determ = dotProduct(vt, vv[2]);

    if (Math.abs(determ) < 1.0e-20) {
      throw new HealpixException(
          SID
              + ": the triangle is degenerated - query cannot be performed");
    }
    if (determ >= 0.) { // The sign of determ
      sdet = 1.0;
    } else {
      sdet = -1.0;
    }

    sprod[0] = dotProduct(vv[1], vv[2]);
    sprod[1] = dotProduct(vv[2], vv[0]);
    sprod[2] = dotProduct(vv[0], vv[1]);
    /* vector ortogonal to the great circle containing the vertex doublet */

    vo[0] = crossProduct(vv[1], vv[2]);
    vo[1] = crossProduct(vv[2], vv[0]);
    vo[2] = crossProduct(vv[0], vv[1]);
    vo[0].normalize();
    vo[1].normalize();
    vo[2].normalize();

    /* test prsence of poles in the triangle */
    zmax = -1.0;
    zmin = 1.0;
    test1 = (vo[0].z * sdet >= 0.0); // north pole in hemisphere defined by
    // 2-3
    test2 = (vo[1].z * sdet >= 0.0); // north pole in the hemisphere defined
    // by 1-2
    test3 = (vo[2].z * sdet >= 0.0); // north pole in hemisphere defined by
    // 1-3
    if (test1 && test2 && test3)
      zmax = 1.0; // north pole in the triangle
    if ((!test1) && (!test2) && (!test3))
      zmin = -1.0; // south pole in the triangle
    /* look for northenest and southernest points in the triangle */
    test1a = ((vv[2].z - sprod[0] * vv[1].z) >= 0.0); // segment 2-3
    test1b = ((vv[1].z - sprod[0] * vv[2].z) >= 0.0);
    test2a = ((vv[2].z - sprod[1] * vv[0].z) >= 0.0); // segment 1-3
    test2b = ((vv[0].z - sprod[1] * vv[2].z) >= 0.0);
    test3a = ((vv[1].z - sprod[2] * vv[0].z) >= 0.0); // segment 1-2
    test3b = ((vv[0].z - sprod[2] * vv[1].z) >= 0.0);

    /* sin of theta for orthogonal vector */
    for (int i = 0; i < 3; i++) {
      sto[i] = Math.sqrt((1.0 - vo[i].z) * (1.0 + vo[i].z));
    }
    /*
     * for each segment ( side of the triangle ) the extrema are either -
     * -the 2 vertices - one of the vertices and a point within the segment
     */
    // segment 2-3
    z1max = vv[1].z;
    z1min = vv[2].z;
    //    if (test1a == test1b) {
    //      zz = sto[0];
    //      if (vv[1].z + vv[2].z >= 0.0) {
    //        z1max = zz;
    //      } else {
    //        z1min = -zz;
    //      }
    //    }
    // segment 1-3
    z2max = vv[2].z;
    z2min = vv[0].z;
    //    if (test2a == test2b) {
    //      zz = sto[1];
    //      if (vv[0].z + vv[2].z >= 0.0) {
    //        z2max = zz;
    //      } else {
    //        z2min = -zz;
    //      }
    //    }
    // segment 1-2
    z3max = vv[0].z;
    z3min = vv[1].z;
    //    if (test3a == test3b) {
    //      zz = sto[2];
    //      if (vv[0].z + vv[1].z >= 0.0) {
    //        z3max = zz;
    //      } else {
    //        z3min = -zz;
    //      }
    //    }

    zmax = Math.max(Math.max(z1max, z2max), Math.max(z3max, zmax));
    zmin = Math.min(Math.min(z1min, z2min), Math.min(z3min, zmin));
    /*
     * if we are inclusive, move upper point up, and lower point down, by a
     * half pixel size
     */
    offset = 0.0;
    sin_off = 0.0;
    if (do_inclusive) {
      offset = PI / (4.0 * nside); // half pixel size
      sin_off = Math.sin(offset);
      zmax = Math.min(1.0, Math.cos(Math.acos(zmax) - offset));
      zmin = Math.max(-1.0, Math.cos(Math.acos(zmin) + offset));
    }

    irmin = RingNum(nside, zmax);
    irmax = RingNum(nside, zmin);

    //    System.out.println("irmin = " + irmin + " irmax =" + irmax);

    /* loop on the rings */
    for (int i = 0; i < 3; i++) {
      tgthi[i] = -1.0e30 * vo[i].z;
      phi0i[i] = 0.0;
    }
    for (int j = 0; j < 3; j++) {
      if (sto[j] > 1.0e-10) {
        tgthi[j] = -vo[j].z / sto[j]; // - cotan(theta_orth)

        phi0i[j] = Math.atan2(vo[j].y, vo[j].x); // Should make it 0-2pi
                             // ?
        /* Bring the phi0i to the [0,2pi] domain if need */

        if (phi0i[j] < 0.) {
          phi0i[j] = bm.MODULO(
              (Math.atan2(vo[j].y, vo[j].x) + TWOPI), TWOPI); //  [0-2pi]
        }

      }
    }
    /*
     * the triangle boundaries are geodesics: intersection of the sphere
     * with plans going through (0,0,0) if we are inclusive, the boundaries
     * are the intersection of the sphere with plains pushed outward by
     * sin(offset)
     */
    double temp = 0.;
    boolean found = false;
    for (iz = irmin; iz <= irmax; iz++) {
      found = false;
      if (iz <= nside - 1) { // North polar cap
        z = 1.0 - iz * iz * dth1;
      } else if (iz <= 3 * nside) { // tropical band + equator
        z = (2.0 * nside - iz) * dth2;
      } else {
        z = -1.0 + (4.0 * nside - iz) * (4.0 * nside - iz) * dth1;
      }

      /* computes the 3 intervals described by the 3 great circles */
      st = Math.sqrt((1.0 - z) * (1.0 + z));
      tgth = z / st; // cotan(theta_ring)
      for (int j = 0; j < 3; j++) {
        dc[j] = tgthi[j] * tgth - sdet * sin_off
            / ((sto[j] + 1.0e-30) * st);

      }
      for (int k = 0; k < 3; k++) {
        if (dc[k] * sdet <= -1.0) { // the whole iso-latitude ring is on
          // right side of the great circle
          dom[k][0] = 0.0;
          dom[k][1] = TWOPI;
        } else if (dc[k] * sdet >= 1.0) { // all on the wrong side
          dom[k][0] = -1.000001 * (k + 1);
          dom[k][1] = -1.0 * (k + 1);
        } else { // some is good some is bad
          phi_neg = phi0i[k] - (Math.acos(dc[k]) * sdet);
          phi_pos = phi0i[k] + (Math.acos(dc[k]) * sdet);
          //         
          if (phi_pos < 0.)
            phi_pos += TWOPI;
          if (phi_neg < 0.)
            phi_neg += TWOPI;

          //

          dom[k][0] = bm.MODULO(phi_neg, TWOPI);
          dom[k][1] = bm.MODULO(phi_pos, TWOPI);

        }
        //

      }
      /* identify the intersections (0,1,2 or 3) of the 3 intervals */

      dom12 = intrs_intrv(dom[0], dom[1]);
      n12 = dom12.length / 2;
      if (n12 != 0) {
        if (n12 == 1) {
          dom123a = intrs_intrv(dom[2], dom12);
          n123a = dom123a.length / 2;

          if (n123a == 0)
            found = true;
          if (!found) {
            for (int l = 0; l < dom123a.length; l++) {
              alldom[l] = dom123a[l];
            }

            ndom = n123a; // 1 or 2
          }
        }
        if (!found) {
          if (n12 == 2) {
            double[] tmp = { dom12[0], dom12[1] };
            dom123a = intrs_intrv(dom[2], tmp);
            double[] tmp1 = { dom12[2], dom12[3] };
            dom123b = intrs_intrv(dom[2], tmp1);
            n123a = dom123a.length / 2;
            n123b = dom123b.length / 2;
            ndom = n123a + n123b; // 0, 1, 2 or 3

            if (ndom == 0)
              found = true;
            if (!found) {
              if (n123a != 0) {
                for (int l = 0; l < 2 * n123a; l++) {
                  alldom[l] = dom123a[l];
                }
              }
              if (n123b != 0) {
                for (int l = 0; l < 2 * n123b; l++) {
                  alldom[(int) (l + 2 * n123a)] = dom123b[l];
                }
              }
              if (ndom > 3) {
                throw new HealpixException(SID
                    + ": too many intervals found");
              }
            }
          }
        }
        if (!found) {
          for (idom = 0; idom < ndom; idom++) {
            a_i = alldom[(int) (2 * idom)];
            b_i = alldom[(int) (2 * idom + 1)];
            phi0 = (a_i + b_i) / 2.0;
            dphiring = Math.abs(b_i - a_i) / 2.0;

            if (dphiring < 0.0) {
              phi0 += PI;
              dphiring += PI;
            }

            /* finds pixels in the triangle on that ring */
            listir = InRing(nside, iz, phi0, dphiring, do_nest);
            res.addAll(listir);

          }
        }
      }

    }
    return res;
  }

  /**
   * computes the intersection di of 2 intervals d1 (= [a1,b1])
   * and d2 (= [a2,b2]) on the periodic domain (=[A,B] where A and B
   * arbitrary) ni is the resulting number of intervals (0,1, or 2) if a1 <b1
   * then d1 = {x |a1 <= x <= b1} if a1>b1 then d1 = {x | a1 <=x <= B U A <=x
   * <=b1}
   *
   * @param d1 double[] first interval
   * @param d2 double[] second interval
   * @return double[] one or two intervals intersections
   */
  public double[] intrs_intrv(double[] d1, double[] d2) {
    double[] res;
    double epsilon = 1.0e-10;
    double temp = 0.;
    int ni;
    double[] dk;
    double[] di = { 0. };
    int ik = 0;
    boolean tr12, tr21, tr34, tr43, tr13, tr31, tr24, tr42, tr14, tr32;
    /*                                             */

    tr12 = (d1[0] < d1[1] + epsilon);
    tr21 = !tr12; // d1[0] >= d1[1]
    tr34 = (d2[0] < d2[1] + epsilon);
    tr43 = !tr34; // d2[0]>d2[1]
    tr13 = (d1[0] < d2[0] + epsilon); //  d2[0] can be in interval
    tr31 = !tr13; // d1[0] in longerval
    tr24 = (d1[1] < d2[1] + epsilon); // d1[1] upper limit
    tr42 = !tr24; // d2[1] upper limit
    tr14 = (d1[0] < d2[1] + epsilon); // d1[0] in interval
    tr32 = (d2[0] < d1[1] + epsilon); // d2[0] in interval

    ik = 0;
    dk = new double[] { -1.0e9, -1.0e9, -1.0e9, -1.0e9 };
    /* d1[0] lower limit case 1 */
    if ((tr34 && tr31 && tr14) || (tr43 && (tr31 || tr14))) {
      ik++; // ik = 1;
      dk[ik - 1] = d1[0]; // a1

    }
    /* d2[0] lower limit case 1 */
    if ((tr12 && tr13 && tr32) || (tr21 && (tr13 || tr32))) {
      ik++; // ik = 1
      dk[ik - 1] = d2[0]; // a2

    }
    /* d1[1] upper limit case 2 */
    if ((tr34 && tr32 && tr24) || (tr43 && (tr32 || tr24))) {
      ik++; // ik = 2
      dk[ik - 1] = d1[1]; // b1

    }
    /* d2[1] upper limit case 2 */
    if ((tr12 && tr14 && tr42) || (tr21 && (tr14 || tr42))) {
      ik++; // ik = 2
      dk[ik - 1] = d2[1]; // b2

    }
    di = new double[1];
    di[0] = 0.;
    switch (ik) {

    case 2:
      di = new double[2];

      di[0] = dk[0] - epsilon;
      di[1] = dk[1] + epsilon;
      break;
    case 4:

      di = new double[4];
      di[0] = dk[0] - epsilon;
      di[1] = dk[3] + epsilon;
      di[2] = dk[1] - epsilon;
      di[3] = dk[2] + epsilon;
      break;
    }
    res = di;

    return res;
  }

  /**
   * an obsolete method. Use query_disc instead.
   *
   * @param nside
   * @param vector0
   * @param radius
   * @return - ArrayList of long
   */
  public ArrayList getDisc_ring(long nside, Vector3d vector0, double radius) {
    ArrayList res;
    int nest = 0;
    int inclusive = 0;
    res = query_disc(nside, vector0, radius, nest, inclusive);
    return res;
  }

  /**
   * generates in the RING or NESTED scheme all pixels that lies within an
   * angular distance Radius of the center.
   *
   * @param nside
   *            long map resolution
   * @param vector
   *            Vector3d pointing to the disc center
   * @param radius
   *            double angular radius of the disk (in RADIAN )
   * @param nest
   *            int 0 (default) if output is in RING scheme, if set to 1
   *            output is in NESTED
   * @param inclusive
   *            int 0 (default) only pixsels whose center lie in the triangle
   *            are listed, if set to 1, all pixels overlapping the triangle
   *            are listed
   * @return  ArrayList of pixel numbers
   *
   * calls: RingNum(nside, ir) InRing(nside, iz, phi0, dphi,nest)
   */
  public ArrayList query_disc(long nside, Vector3d vector, double radius,
      int nest, int inclusive)  {
    ArrayList res = new ArrayList();
    long irmin, irmax, iz, ip, nir, npix, ilist;
    double norm_vect0, x0, y0, z0, radius_eff;
    double a, b, c, cosang;
    double dth1, dth2;
    double phi0, cosphi0, cosdphi, dphi;
    double rlat0, rlat1, rlat2, zmin, zmax, z;
    long status, list_size, nlost;
    boolean do_inclusive = false;
    boolean do_nest = false;
    String SID = "QUERY_DISC";
    /*                             */
    long nsidesq = nside * nside;
    npix = 12 * nsidesq;

    if (radius < 0.0 || radius > PI) {
      throw new IllegalArgumentException(SID
          + ": angular radius is in RADIAN and should be in [0,pi]");
    }
    if (inclusive == 1)
      do_inclusive = true;
    if (nest == 1)
      do_nest = true;

    dth1 = 1.0 / (3.0 * nside * nside);
    dth2 = 2.0 / (3.0 * nside);

    radius_eff = radius;
    if (do_inclusive)
      radius_eff += PI / (4.0 * nside); // increas radius by half pixel
    cosang = Math.cos(radius_eff);
    /* disc center */
    vector.normalize();
    x0 = vector.x; // norm_vect0;
    y0 = vector.y; // norm_vect0;
    z0 = vector.z; // norm_vect0;

    phi0 = 0.0;
    dphi = 0.0;
    if (x0 != 0. || y0 != 0.)
      phi0 = bm.MODULO(Math.atan2(y0, x0) + TWOPI, TWOPI)// in [0, 2pi]
      cosphi0 = Math.cos(phi0);
    a = x0 * x0 + y0 * y0;
    /* coordinate z of highest and lowest points in the disc */
    rlat0 = Math.asin(z0); // latitude in RAD of the center
    rlat1 = rlat0 + radius_eff;
    rlat2 = rlat0 - radius_eff;
    //
    if (rlat1 >= HALFPI) {
      zmax = 1.0;
    } else {
      zmax = Math.sin(rlat1);
    }
    irmin = RingNum(nside, zmax);
    irmin = Math.max(1, irmin - 1); // start from a higher point to be safe
    if (rlat2 <= -HALFPI) {
      zmin = -1.0;
    } else {
      zmin = Math.sin(rlat2);
    }
    irmax = RingNum(nside, zmin);
    irmax = Math.min(4 * nside - 1, irmax + 1); // go down to a lower point

    ilist = -1;
    /* loop on ring number */
    for (iz = irmin; iz <= irmax; iz++) {
      if (iz <= nside - 1) { // north polar cap
        z = 1.0 - iz * iz * dth1;
      } else if (iz <= 3 * nside) { // tropical band + equator
        z = (2.0 * nside - iz) * dth2;
      } else {
        z = -1.0 + (4.0 * nside - iz) * (4.0 * nside - iz) * dth1;
      }
      /* find phi range in the disc for each z */
      b = cosang - z * z0;
      c = 1.0 - z * z;
      cosdphi = b / Math.sqrt(a * c);
      long done = 0;

      if (Math.abs(x0) <= 1.0e-12 && Math.abs(y0) <= 1.0e-12) {
        cosdphi = -1.0;
        dphi = PI;
        done = 1;
      }
      if (done == 0) {
        if (Math.abs(cosdphi) <= 1.0) {
          dphi = Math.acos(cosdphi); // in [0,pi]
        } else {
          if (cosphi0 >= cosdphi) {
            dphi = PI; // all the pixels at this elevation are in
            // the disc
          } else {
            done = 2; // out of the disc
          }
        }

      }
      if (done < 2) { // pixels in disc
        /* find pixels in the disc */

        ArrayList listir = InRing(nside, iz, phi0, dphi, do_nest);
        res.addAll(listir);
      }
    }
    return res;
  }

  /**
   * renders theta and phi coordinates of the nominal pixel center for the
   * pixel number ipix (RING scheme) given the map resolution parameter nside
   *
   * @param nside
   *            long map resolution
   * @param ipix
   *            long pixel number
   * @return double[] theta,phi
   */
  public double[] pix2ang_ring(long nside, long ipix)  {
    double[] res = { 0., 0. };
    long nl2, nl4, npix, ncap, iring, iphi, ip, ipix1;
    double fodd, hip, fihip, theta, phi;
    String SID = "pix2ang_ring:";
    /*                            */
    if (nside < 1 || nside > ns_max) {
      throw new IllegalArgumentException(SID + " Nside should be power of 2 >0 and < "+ns_max);
    }
    long nsidesq = nside * nside;
    npix = 12 * nsidesq; // total number of pixels
    if (ipix < 0 || ipix > npix - 1) {
      throw new IllegalArgumentException(SID + " ipix out of range calculated from nside");
    }
    ipix1 = ipix + 1; //  in [1, npix]
    nl2 = 2 * nside;
    ncap = 2 * nside * (nside - 1); // points in each polar cap, =0 for
    // nside =1

    if (ipix1 <= ncap) { // North polar cap
      hip = ipix1 / 2.0;
      fihip = (long) hip; // get integer part of hip
      iring = (long) (Math.sqrt(hip - Math.sqrt(fihip))) + 1; // counted from north
                                                             // pole
      iphi = ipix1 - 2 * iring * (iring - 1);
      theta = Math.acos(1.0 - iring * iring / (3.0 * nsidesq));
      phi = (iphi - 0.5) * PI / (2.0 * iring);

    } else if (ipix1 <= nl2 * (5 * nside + 1)) { // equatorial region
      ip = ipix1 - ncap - 1;
      nl4 = 4 * nside;
      iring = (long) (ip / nl4) + nside; // counted from North pole
      iphi = (long) bm.MODULO(ip, nl4) + 1;
      fodd = 0.5 * (1. + bm.MODULO(iring + nside, 2)); // 1 if iring+nside
                                                       // is odd, 1/2 otherwise
      theta = Math.acos((nl2 - iring) / (1.5 * nside));
      phi = (iphi - fodd) * PI / (2.0 * nside);
    } else { // South pole cap
      ip = npix - ipix1 + 1;
      hip = ip / 2.0;
      fihip = (long) hip;
      iring = (long) (Math.sqrt(hip - Math.sqrt(fihip))) + 1; // counted from South
                                                             // pole
      iphi = 4 * iring + 1 - (ip - 2 * iring * (iring - 1));
      theta = Math.acos(-1.0 + iring * iring / (3.0 * nsidesq));
      phi = (iphi - 0.5) * PI / (2.0 * iring);
    }
    res[0] = theta;
    res[1] = phi;
    return res;
  }

  /**
   * returns the vector pointing in the center of the pixel ipix. The vector
   * is calculated by makePix2Vect_ring method
   *
   * @param nside map resolution
   * @param ipix pixel number
   * @return Vector3d
   */
  public Vector3d pix2vect_ring(long nside, long ipix)  {

    makePix2Vect_ring(nside, ipix);
    Vector3d res = new Vector3d(pixVect);
    return res;
  }

  /**
   * returns double [][] with coordinates of the pixel corners. The array is
   * calculated by makePix2Vect_ring method
   *
   * @param nside map resolution
   * @param ipix pixel number
   * @return  double[][] list of vertex coordinates
   */
  public double[][] pix2vertex_ring(long nside, long ipix)  {
    double[][] res;
    makePix2Vect_ring(nside, ipix);
    res = pixVertex;
    return res;
  }

  /**
   * renders vector (x,y,z) coordinates of the nominal pixel center for pixel
   * ipix (RING scheme) given the map resolution parameter nside. It also
   * calculates (x,y,z) positions of the four vertices in order N,W,S,E. These
   * results are stored in pixVect and pixVertex structures. Those can be
   * obtained using pix2Vect_ring and pix2vert_ring methods
   *
   * @param nside
   *            long map resolution
   * @param ipix
   *            pixel number
   */
  private void makePix2Vect_ring(long nside, long ipix)  {
    long nl2;
        long nl4;
        long iring, iphi, ip, ipix1;
        long npix,ncap;
    double phi_nv, phi_wv, phi_sv, phi_ev;
    double z_nv, z_sv, sth_nv, sth_sv, hdelta_phi;
    double fact1, fact2, fodd, hip, fihip, z, sth, phi;
    long iphi_mod;
        long iphi_rat;
    boolean do_vertex = true;
    long nsidesq = nside * nside;
    String SID = " Pix2Vect_ring:";
    /*                                 */
    if (nside < 1 || nside > ns_max) {
      throw new IllegalArgumentException(SID + " Nside should be power of 2 >0 and < "+ns_max);
    }

    npix = 12 * nsidesq;
    if (ipix < 0 || ipix > npix - 1) {
      throw new IllegalArgumentException(SID + " ipix out of range calculated from nside");
    }

    ipix1 = ipix + 1; //  in [1, npix]
    nl2 = 2 * nside;
    nl4 = 4 * nside;
    ncap = 2 * nside * (nside - 1); // points in each polar cap
    fact1 = 1.5 * nside;
    fact2 = 3.0 * nsidesq;
    phi_nv = 0.0;
    phi_sv = 0.0;
    if (ipix1 <= ncap) { // north polar cap
      hip = ipix1 / 2.0;
      fihip = (long) hip;
      iring = (long) (Math.sqrt(hip - Math.sqrt(fihip))) + 1; // counted from north
                                                             // pole
      iphi = ipix1 - 2 * iring * (iring - 1);
      z = 1.0 - iring * iring / fact2;
      phi = (iphi - 0.5) * PI / (2.0 * iring);

      hdelta_phi = PI / (4.0 * iring); // half pixel width
      z_nv = 1.0 - (iring - 1) * (iring - 1) / fact2;
      z_sv = 1.0 - (iring + 1) * (iring + 1) / fact2;
      iphi_mod = (long) bm.MODULO(iphi - 1, iring); // in [0,1,...,iring-1]
      iphi_rat = (iphi - 1) / iring; // in [0,1,2,3]
      if (iring > 1)
        phi_nv = HALFPI * (iphi_rat + iphi_mod / (iring - 1.0));
      phi_sv = HALFPI * (iphi_rat + (iphi_mod + 1.0) / (iring + 1.0));
    } else if (ipix1 <= nl2 * (5 * nside + 1)) { // equatorial region
      ip =  (ipix1 - ncap - 1);
      iring = (long) (ip / nl4) + nside; // counted from North pole
      iphi = (long) bm.MODULO(ip, nl4) + 1;
      fodd = 0.5 * (1. + bm.MODULO(iring + nside, 2)); // 1 if iring+nside
                                                       // is odd or 1/2
      z = (nl2 - iring) / fact1;
      phi = (iphi - fodd) * PI / (2.0 * nside);
      hdelta_phi = PI / (4.0 * nside); // half pixel width
      phi_nv = phi;
      phi_sv = phi;
      z_nv = (nl2 - iring + 1) / fact1;
      z_sv = (nl2 - iring - 1) / fact1;
      if (iring == nside) { // nothern transition
        z_nv = 1.0 - (nside - 1) * (nside - 1) / fact2;
        iphi_mod = (long) bm.MODULO(iphi - 1, nside); // in [0,1,...,nside-1]
        iphi_rat = (iphi - 1) / nside; // in [0,1,2,3]
        if (nside > 1)
          phi_nv = HALFPI * (iphi_rat + iphi_mod / (nside - 1.));
      } else if (iring == 3 * nside) { // southern transition
        z_sv = -1.0 + (nside - 1) * (nside - 1) / fact2;
        iphi_mod = (long) bm.MODULO(iphi - 1, nside); // in [0,1,... iring-1]
        iphi_rat = (iphi - 1) / nside; // in [0,1,2,3]
        if (nside > 1)
          phi_sv = HALFPI * (iphi_rat + iphi_mod / (nside - 1.0));
      }

    } else { // South polar cap
      ip = npix - ipix1 + 1;
      hip = ip / 2.0;
      fihip = (long) hip;
      iring = (long) (Math.sqrt(hip - Math.sqrt(fihip))) + 1; // counted from South
                                                             // pole
      iphi = 4 * iring + 1 - (ip - 2 * iring * (iring - 1));
      z = -1.0 + iring * iring / fact2;
      phi = (iphi - 0.5) * PI / (2.0 * iring);
      hdelta_phi = PI / (4.0 * iring); // half pixel width
      z_nv = -1.0 + (iring + 1) * (iring + 1) / fact2;
      z_sv = -1.0 + (iring - 1) * (iring - 1) / fact2;
      iphi_mod = (long) bm.MODULO(iphi - 1, iring); // in [0,1,...,iring-1]
      iphi_rat = (iphi - 1) / iring; // in [0,1,2,3]
      phi_nv = HALFPI * (iphi_rat + (iphi_mod + 1) / (iring + 1.0));
      if (iring > 1)
        phi_sv = HALFPI * (iphi_rat + iphi_mod / (iring - 1.0));

    }
    /* pixel center */
    sth = Math.sqrt((1.0 - z) * (1.0 + z));
    pixVect.x = sth * Math.cos(phi);
    pixVect.y = sth * Math.sin(phi);
    pixVect.z = z;
    pixVect = new Vector3d(sth * Math.cos(phi), sth * Math.sin(phi), z);
    /* west vertex */
    phi_wv = phi - hdelta_phi;
    pixVertex[0][1] = sth * Math.cos(phi_wv);
    pixVertex[1][1] = sth * Math.sin(phi_wv);
    pixVertex[2][1] = z;
    /* east vertex */
    phi_ev = phi + hdelta_phi;
    pixVertex[0][3] = sth * Math.cos(phi_ev);
    pixVertex[1][3] = sth * Math.sin(phi_ev);
    pixVertex[2][3] = z;
    /* north vertex */
    sth_nv = Math.sqrt((1.0 - z_nv) * (1.0 + z_nv));
    pixVertex[0][0] = sth_nv * Math.cos(phi_nv);
    pixVertex[1][0] = sth_nv * Math.sin(phi_nv);
    pixVertex[2][0] = z_nv;
    /* south vertex */
    sth_sv = Math.sqrt((1.0 - z_sv) * (1.0 + z_sv));
    pixVertex[0][2] = sth_sv * Math.cos(phi_sv);
    pixVertex[1][2] = sth_sv * Math.sin(phi_sv);
    pixVertex[2][2] = z_sv;
  }

  /**
   * renders the pixel number ipix (RING scheme) for a pixel which contains a
   * point with coordinates theta and phi, given the map resolution parameter
   * nside.
   *
   * @param nside
   *            long map resolution parameter
   * @param theta
   *            double theta
   * @param phi -
   *            double phi
   * @return  long ipix
   */
  public long ang2pix_ring(long nside, double theta, double phi) {
    long nl4;
        long jp, jm, kshift;
        long ip;
        long ir;
    double z, za, tt, tp, tmp;
    long pix = 0;
    long ipix1;
    long nl2,  ncap, npix;
    String SID = "ang2pix_ring:";
    /*                                       */
    if (nside < 1 || nside > ns_max) {
      throw new IllegalArgumentException(SID + " Nside should be power of 2 >0 and < "+ns_max);
    }
    if (theta < 0.0 || theta > PI) {
      throw new IllegalArgumentException(SID + " Theta out of range [0,pi]");
    }
   
    z = Math.cos(theta);
    za = Math.abs(z);




    if (phi < 0.)
      phi += TWOPI; //  phi in [0, 2pi]
//    tt = phi / HALFPI; // in [0,4]
    tt = bm.MODULO(phi, TWOPI) / HALFPI; // in [0,4]
    nl2 = 2 * nside;
    nl4 = 4 * nside;
    ncap = nl2 * (nside - 1); // number of pixels in the north polar cap
    npix = 12 * nside * nside;
    if (za < twothird) { // equatorial region
      jp = (long) (nside * (0.5 + tt - 0.75 * z)); // index of ascending
      // edge line
      jm = (long) (nside * (0.5 + tt + 0.75 * z)); // index of descending
      // edge line

      ir = nside + 1 + jp - jm; // in [1,2n+1]
      kshift = 0;
      if ((long) bm.MODULO(ir, 2) == 0)
        kshift = 1; // 1 if ir even, 0 otherwise
      ip = (long) ((jp + jm - nside + kshift + 1) / 2) + 1; // in [1,4n]
      ipix1 = ncap + nl4 * (ir - 1) + ip;
    } else { // North and South polar caps
      tp = tt - (long) tt;
      tmp = Math.sqrt(3.0 * (1.0 - za));
      jp = (long) (nside * tp * tmp); // increasing edge line index
      jm = (long) (nside * (1.0 - tp) * tmp); // decreasing edge index

      ir = jp + jm + 1; // ring number counted from closest pole
      ip = (long) (tt * ir) + 1; // in [1,4*ir]
      if (ip > 4 * ir)
        ip = ip - 4 * ir;

      ipix1 = 2 * ir * (ir - 1) + ip;
      if (z <= 0.0)
        ipix1 = npix - 2 * ir * (ir + 1) + ip;
    }
    pix = ipix1 - 1; // in [0, npix-1]
   

    return pix;
  }

  /**
   * renders the pixel number ipix (RING scheme) for a pixel which contains a
   * point on a sphere at coordinate vector (x,y,z), given the map resolution
   * parameter nside
   *
   * @param nside
   *            long map resolution
   * @param vector
   *            Vector3d of the point coordinates
   * @return  long pixel number
   * @throws IllegalArgumentException
   */
  public long vect2pix_ring(long nside, Vector3d vector)  {
    long res = 0;
    long nl2, nl4, ncap, npix, jp, jm, ipix1;
    double z, za, tt, tp, tmp, dnorm, phi;
    long ir, ip, kshift;
    String SID = " vect2pix_ring:";
    /*                                      */
    if (nside < 1 || nside > ns_max) {
      throw new IllegalArgumentException(SID + " Nside should be power of 2 >0 and < "+ns_max);
    }
    dnorm = vector.length();
    z = vector.z / dnorm;
    phi = 0.;
    if (vector.x != 0. || vector.y != 0.)
      phi = Math.atan2(vector.y, vector.x); // phi in [-pi,pi]
    za = Math.abs(z);
    if (phi < 0.)
      phi += TWOPI; //  phi in [0, 2pi]
    tt = phi / HALFPI; // in [0,4]

    nl2 = 2 * nside;
    nl4 = 4 * nside;
    ncap = nl2 * (nside - 1); // number of pixels in the north polar cap
    npix = 12 * nside * nside;
    if (za < twothird) { // equatorial region
      jp = (long) (nside * (0.5 + tt - 0.75 * z)); // index of ascending
      // edge line
      jm = (long) (nside * (0.5 + tt + 0.75 * z)); // index of descending
      // edge line

      ir = nside + 1 + jp - jm; // in [1,2n+1]
      kshift = 0;
      if ((long) bm.MODULO(ir, 2) == 0)
        kshift = 1; // 1 if ir even, 0 otherwise
      ip = (long) ((jp + jm - nside + kshift + 1) / 2) + 1; // in [1,4n]
      ipix1 = ncap + nl4 * (ir - 1) + ip;
    } else { // North and South polar caps
      tp = tt - (long) tt;
      tmp = Math.sqrt(3.0 * (1.0 - za));
      jp = (long) (nside * tp * tmp); // increasing edge line index
      jm = (long) (nside * (1.0 - tp) * tmp); // decreasing edge index

      ir = jp + jm + 1; // ring number counted from closest pole
      ip = (long) (tt * ir) + 1; // in [1,4*ir]
      if (ip > 4 * ir)
        ip = ip - 4 * ir;

      ipix1 = 2 * ir * (ir - 1) + ip;
      if (z <= 0.0)
        ipix1 = npix - 2 * ir * (ir + 1) + ip;
    }
    res = ipix1 - 1; // in [0, npix-1]
    return res;
  }

  /**
   *
   * Renders theta and phi coordinates of the normal pixel center for the
   * pixel number ipix (NESTED scheme) given the map resolution parameter
   * nside.
   *
   * @param nside
   *            map resolution parameter - long
   * @param ipix
   *            long pixel number
   * @return double[] (theta, phi)
   * @throws IllegalArgumentException
   */
  public double[] pix2ang_nest(long nside, long ipix)  {
    double[] res = new double[2];
    double theta = 0.;
    double phi = 0.;
    long npix, npface, ipf, ip_low, ip_trunc, ip_med, ip_hi;
    long jrt, jr, nr, jpt, jp, kshift, nl4, ix, iy, face_num;
    double z, fn, fact1, fact2;
    String SID = "pix2ang_nest:";
    long[] jrll = { 0, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 }; // in units of
    // nside
    long[] jpll = { 0, 1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7 }; // in units of
    // nside/2
    /*                                                              */
    if (nside < 1 || nside > ns_max) {
      throw new IllegalArgumentException(SID + " Nside should be power of 2 >0 and < "+ns_max);
    }
    long nsidesq = nside * nside;
    npix = 12 * nsidesq;
    if (ipix < 0 || ipix > npix - 1) {
      throw new IllegalArgumentException(SID + " ipix out of range calculated from nside");
    }
    if (pix2x[1023] <= 0)
      mk_pix2xy();
    fn = nside;
    fact1 = 1.0 / (3.0 * fn * fn);
    fact2 = 2.0 / (3.0 * fn);
    nl4 = 4 * nside;
    /* findes the face, and the number in the face */
    npface = nside * nside;
    face_num = ipix / npface; // face number [0,11]
    ipf = (long) bm.MODULO(ipix, npface); // pixel in the face [0, npface-1]
    /*
     * findes x,y on the face (starting from the lowest corner) from pixel
     * number
     */
    ip_low = (long) bm.MODULO(ipf, pixmax);
    ip_trunc = ipf / pixmax;
    ip_med = (long) bm.MODULO(ip_trunc, pixmax);
    ip_hi = ip_trunc / pixmax;

    ix = pixmax * pix2x[(int)ip_hi] + xmid * pix2x[(int)ip_med] + pix2x[(int) ip_low];
    iy = pixmax * pix2y[(int)ip_hi] + xmid * pix2y[(int)ip_med] + pix2y[(int)ip_low];
    /* transform these in (horizontal, vertical) coordinates */
    jrt = ix + iy; // [0,2*(nside-1)]
    jpt = ix - iy; // [ -nside+1, nside -1]
    /* computes the z coordinate on the sphere */
    jr = jrll[(int) (face_num + 1)] * nside - jrt - 1; // ring number in [1,
    // 4*nside-1]

    nr = nside; // equatorial region (the most frequent )
    z = (2 * nside - jr) * fact2;
    kshift = (long) bm.MODULO(jr - nside, 2);
    if (jr < nside) { // north pole region
      nr = jr;
      z = 1.0 - nr * nr * fact1;
      kshift = 0;
    } else if (jr > 3 * nside) { // south pole region
      nr = nl4 - jr;
      z = -1.0 + nr * nr * fact1;
      kshift = 0;
    }
    theta = Math.acos(z);
    /* computes phi coordinate on the sphere, in [0,2pi] */
    jp = (jpll[(int) (face_num + 1)] * nr + jpt + 1 + kshift) / 2;
    if (jp > nl4)
      jp = jp - nl4;
    if (jp < 1)
      jp = jp + nl4;

    phi = (jp - (kshift + 1) / 2.0) * (HALFPI / nr);
    res[0] = theta;
    res[1] = phi;
    return res;
  }

  /**
   * renders vector (x,y,z) coordinates of the nominal pixel center for the
   * pixel ipix (NESTED scheme ) given the map resolution parameter nside.
   * Also calculates the (x,y,z) positions of 4 pixel vertices (corners) in
   * the order N,W,S,E. These can be get using method pix2vertex_nest.
   *
   * @param nside the map resolution
   * @param ipix long pixel number
   * @return Vector3d
   * @throws IllegalArgumentException
   */
  public Vector3d pix2vect_nest(long nside, long ipix)  {

    makePix2Vect_Nest(nside, ipix);
    Vector3d res = new Vector3d(pixVect);
    return res;
  }

  /**
   * renders vector (x,y,z) coordinates of the nominal pixel center for the
   * pixel ipix (NESTED scheme ) given the map resolution parameter nside.
   * Also calculates the (x,y,z) positions of 4 pixel vertices (corners) in
   * the order N,W,S,E.
   *
   * @param nside the map resolution
   * @param ipix long pixel number
   * @return Vector3d
   * @throws IllegalArgumentException
   */
  public double[][] pix2vertex_nest(long nside, long ipix) {
    double[][] res = new double[3][4];
    makePix2Vect_Nest(nside, ipix);
    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 4; j++) {
        res[i][j] = pixVertex[i][j];
      }
    }
    return res;
  }

  /**
   * renders vector (x,y,z) coordinates of the nominal pixel center for the
   * pixel ipix (NESTED scheme ) given the map resolution parameter nside. Tis
   * can be get using method pix2vect_nest Also calculates the (x,y,z)
   * positions of 4 pixel vertices (corners) in the order N,W,S,E. This can be
   * get using method pix2vertex_nest.
   * @param nside long the map resolution
   * @param ipix long pixel number
   */
  private void makePix2Vect_Nest(long nside, long ipix)  {
    long npix, npface, ipf, ip_low, ip_trunc, ip_med, ip_hi;
    long jrt, jr, nr, jpt, jp, kshift, nl4;
    double z, fn, fact1, fact2, sth, phi;
    long ix, iy, face_num;
    int[] jrll = { 0, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 };
    int[] jpll = { 0, 1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7 };
    double phi_nv, phi_wv, phi_sv, phi_ev, phi_up, phi_dn;
    double z_nv, z_sv, sth_nv, sth_sv;
    double hdelta_phi;
    long iphi_mod, iphi_rat;
    boolean do_vertex = true;
    String SID = "Pix2Vect_Nest:";
    z_nv = 0.;
    z_sv = 0.;
    /*                                 */
    if (nside < 1 || nside > ns_max) {
      throw new IllegalArgumentException(SID + " Nside should be power of 2 >0 and < "+ns_max);
    }
    long nsidesq = nside * nside;
    npix = 12 * nsidesq;
    if (ipix < 0 || ipix > npix - 1) {
      throw new IllegalArgumentException(SID + " ipix out of range calculated from nside");
    }
    /* initiates the array for the pixel number -> (x,y) mapping */
    if (pix2x[pixmax] <= 0)
      mk_pix2xy();
    fn = nside;
    fact1 = 1.0 / (3.0 * fn * fn);
    fact2 = 2.0 / (3.0 * fn);
    nl4 = 4 * nside;

    /* finds the face and the number in the face */
    npface = nsidesq;
    //    System.out.println("ipix="+ipix+" npface="+npface);
    face_num = ipix / npface; // face number in [0, 11]
    ipf = (long) bm.MODULO(ipix, npface); // pixel number in the face [0,npface-1]
    /*
     * finds the x,y on the face (starting from the lowest corner) from the
     * pixel number
     */
    ip_low = (long) bm.MODULO(ipf, pixmax); // last 15 bits
    ip_trunc = ipf / pixmax; // trancateion of the last 15 bits
    ip_med = (long) bm.MODULO(ip_trunc, pixmax); // next 15 bits
    ip_hi = ip_trunc / pixmax; // high 10 bits

    ix = pixmax * pix2x[(int)ip_hi] + xmid * pix2x[(int)ip_med] + pix2x[(int)ip_low];
    iy = pixmax * pix2y[(int)ip_hi] + xmid * pix2y[(int)ip_med] + pix2y[(int)ip_low];

    /* transform this in (vertical, horizontal) coordinates */
    jrt = ix + iy; //  vertical in [0,2*(nside-1)]
    jpt = ix - iy; //  horizontal in [ -nside+1, nside-1]
    /* computes the z coordinate on the sphere */
    jr = jrll[(int) (face_num + 1)] * nside - jrt - 1; // ring number in
    // [1,4*nside-1]

    nr = nside; // equatorial region (the most frequent )
    z = (2.0 * nside - jr) * fact2;

    kshift = (long) bm.MODULO(jr - nside, 2);
    z_nv = (2.0 * nside - jr + 1.0) * fact2;
    z_sv = (2.0 * nside - jr - 1.0) * fact2;
    if (jr == nside) { // northen transition
      z_nv = 1.0 - (nside - 1.0) * (nside - 1.0) * fact1;
    } else if (jr == 3 * nside) { // southern transition
      z_sv = -1.0 + (nside - 1.0) * (nside - 1.0) * fact1;
    }

    if (jr < nside) { // north pole region
      nr = jr;
      z = 1.0 - nr * nr * fact1;
      kshift = 0;

      z_nv = 1.0 - (nr - 1) * (nr - 1) * fact1;
      z_sv = 1.0 - (nr + 1) * (nr + 1) * fact1;

    } else if (jr > 3 * nside) { // south pole region
      nr = nl4 - jr;
      z = -1.0 + nr * nr * fact1;
      kshift = 0;

      z_nv = -1.0 + (nr + 1) * (nr + 1) * fact1;
      z_sv = -1.0 + (nr - 1) * (nr - 1) * fact1;

    }
    /* computes the phi coordinate on the sphere, in [0,2pi] */
    jp = (jpll[(int) (face_num + 1)] * nr + jpt + 1 + kshift) / 2; // phi in the ring in
                                                           // [1,4*nr]
    if (jp > nl4)
      jp = jp - nl4;
    if (jp < 1)
      jp = jp + nl4;

    phi = (jp - (kshift + 1) / 2.) * (HALFPI / nr);

    sth = Math.sqrt((1.0 - z) * (1.0 + z));
    pixVect.x = sth * Math.cos(phi);
    pixVect.y = sth * Math.sin(phi);
    pixVect.z = z;

    phi_nv = phi;
    phi_sv = phi;

    phi_up = 0.0;
    iphi_mod = (long) bm.MODULO(jp - 1, nr); // in [0,1,...,nr-1]
    iphi_rat = (jp - 1) / nr; // in [0,1,2,3]
    if (nr > 1)
      phi_up = HALFPI * (iphi_rat + iphi_mod / (nr - 1.));
    phi_dn = HALFPI * (iphi_rat + (iphi_mod + 1) / (nr + 1.));

    if (jr < nside) { // north polar cap
      phi_nv = phi_up;
      phi_sv = phi_dn;
    } else if (jr > 3 * nside) { // south polar cap
      phi_nv = phi_dn;
      phi_sv = phi_up;
    } else if (jr == nside) { // north transition
      phi_nv = phi_up;
    } else if (jr == 3 * nside) { // south transition
      phi_sv = phi_up;
    }
    hdelta_phi = PI / (4.0 * nr);
    /* west vertex */
    phi_wv = phi = hdelta_phi;
    pixVertex[0][1] = sth * Math.cos(phi_wv);
    pixVertex[1][1] = sth * Math.sin(phi_wv);
    pixVertex[2][1] = z;
    /* east vertex */
    phi_ev = phi + hdelta_phi;
    pixVertex[0][3] = sth * Math.cos(phi_ev);
    pixVertex[1][3] = sth * Math.sin(phi_ev);
    pixVertex[2][3] = z;
    /* north vertex */
    sth_nv = Math.sqrt((1.0 - z_nv) * (1.0 + z_nv));
    pixVertex[0][0] = sth_nv * Math.cos(phi_nv);
    pixVertex[1][0] = sth_nv * Math.sin(phi_nv);
    pixVertex[2][0] = z_nv;
    /* south vertex */
    sth_sv = Math.sqrt((1.0 - z_sv) * (1.0 + z_sv));
    pixVertex[0][2] = sth_sv * Math.cos(phi_sv);
    pixVertex[1][2] = sth_sv * Math.sin(phi_sv);
    pixVertex[2][2] = z_sv;

  }

  /**
   * renders the pixel number pix (NESTED scheme) for a pixel which contains a
   * point on a sphere at coordinates theta and phi, given map resolution
   * parameter nside.
   *
   * The computation is made to the highest resolution available and then
   * degraded to requared resolution by integer division. It makes sure that
   * the treatment of roun-off will be consistent for every resolution.
   *
   * @param nside the map resolution parameter
   * @param theta double theta coordinate
   * @param phi double phi coordinate
   * @return pixel number long
   * @throws IllegalArgumentException
   */
  public long ang2pix_nest(long nside, double theta, double phi) {
    long pix = 0;
    long ipix1;
    double z, za, tt, tp, tmp;
    long jp, jm, ifp, ifm, face_num, ix, iy, ix_low, ix_hi;
    long iy_low, iy_hi, ipf, ntt;
    long nl2, nl4, ncap, npix, kshift, ir, ip;
    String SID = "ang2pix_nest:";
    /*                              */
    if (nside < 1 || nside > ns_max) {
      throw new IllegalArgumentException(SID + " Nside should be power of 2 >0 and < "+ns_max);
    }
    if (theta < 0.0 || theta > PI) {
      throw new IllegalArgumentException(SID + " theta is out of range [0.,PI]");
    }
    if (x2pix[xmax-1] <= 0)
      mk_xy2pix();
    z = Math.cos(theta);
    za = Math.abs(z);


    if (phi < 0.)
      phi += TWOPI; // phi in [0,2pi]
    tt = bm.MODULO(phi, TWOPI) / HALFPI; // in [0,4]
//    tt = 2. * phi / PI; // in [0,4]
    if (za <= twothird) { // Equatorial region
      /*
       * the index of edge lines increases when the longitude = phi goes
       * up
       */
      jp = (long) (ns_max * (0.5 + tt - z * 0.75)); // ascending edge line
      // index
      jm = (long) (ns_max * (0.5 + tt + z * 0.75)); // descending edge line
      // index
      /* find the face */
      ifp = jp / ns_max; // in [0,4]
      ifm = jm / ns_max;
      if (ifp == ifm) { // faces 4 to 7
        face_num = (long) bm.MODULO(ifp, 4) + 4;
      } else if (ifp < ifm) { // (half-) faces 0 to 3
        face_num = (long) bm.MODULO(ifp, 4);
      } else { // (half-) faces 8 to 11
        face_num = (long) bm.MODULO(ifm, 4) + 8;
      }

      ix = (long) bm.MODULO(jm, ns_max);
      iy = ns_max - (long) bm.MODULO(jp, ns_max) - 1;
    } else { // polar region, za > 2/3
      ntt = (long) tt;
      if (ntt >= 4)
        ntt = 3;
      tp = tt - ntt;
      tmp = Math.sqrt(3.0 * (1.0 - za)); // in [0,1]
      /*
       * the index of edge lines increases when distance from the closest
       * pole goes up
       */
      jp = (long) (ns_max * tp * tmp); // line going toward the pole has
      // phi increases
      jm = (long) (ns_max * (1.0 - tp) * tmp); // that one goes away of the
      // closest pole
      jp = (long) Math.min(ns_max - 1, jp); // for pointss too close to the
      // boundary
      jm = (long) Math.min(ns_max - 1, jm);
      /* finds the face and pixel's (x,y) */
      if (z >= 0) {
        face_num = ntt; // in [0,3]
        ix = ns_max - jm - 1;
        iy = ns_max - jp - 1;
      } else {
        face_num = ntt + 8; // in [8,11]
        ix = jp;
        iy = jm;
      }
    }
    ix_low = (long) bm.MODULO(ix, xmax);
    ix_hi = ix / xmax;
    iy_low = (long) bm.MODULO(iy, xmax);
    iy_hi = iy / xmax;

    ipf = (x2pix[(int) (ix_hi + 1)] + y2pix[(int) (iy_hi + 1)]) * (xmax * xmax)
        + (x2pix[(int) (ix_low + 1)] + y2pix[(int) (iy_low + 1)]);
    ipf = ipf / ((ns_max / nside) * (ns_max / nside)); // in [0, nside**2
    // -1]
    pix = ipf + face_num * nside * nside; // in [0, 12*nside**2 -1]
    return pix;
  }

  /**
   * make the conversion NEST to RING
   *
   * @param nside the map resolution parameter
   * @param map Object[] the map in NESTED scheme
   * @return - Object[] a map in RING scheme
   * @throws IllegalArgumentException
   */
  public Object[] nest2ring(long nside, Object[] map)  {
    Object[] res;
    long npix, ipn;
        int ipr;
    npix = 12 * nside * nside;
    res = new Object[(int) npix];
    for (ipn = 0; ipn < npix; ipn++) {
      ipr = (int) nest2ring(nside, ipn);
      res[ipr] = map[(int) ipn];
    }
    return res;
  }

  /**
   * makes the conversion RING to NEST
   *
   * @param nside
   *            long resolution
   * @param map
   *            map in RING
   * @return  map in NEST
   * @throws IllegalArgumentException
   */
  public Object[] convert_ring2nest(long nside, Object[] map)  {
    Object[] res;
    long npix, ipn, ipr;
    npix = 12 * nside * nside;
    res = new Object[(int) npix];
    for (ipr = 0; ipr < npix; ipr++) {
      ipn = ring2nest(nside, ipr);
      res[(int) ipn] = map[(int)ipr];
    }
    return res;
  }

  /**
   * converts a 8 byte Object map from RING to NESTED and vice versa in place,
   * ie without allocation a temporary map (Has no reason for Java). This
   * method is more general but slower than convert_nest2ring.
   *
   * This method is a wrapper for functions ring2nest and nest2ring. Their
   * names are supplied in the subcall argument.
   *
   * @param subcall
   *            String name of the method to use.
   * @param map
   *            Object[] map
   * @return  resulting Object[] map.
   * @throws IllegalArgumentException
   */
  public Object[] convert_inplace_long(String subcall, Object[] map) {
    Object[] res;
    long npix, nside;
    boolean[] check;
    long ilast, i1, i2;
    String SID = "convert_in_place:";
    Object pixbuf1, pixbuf2;
    npix = map.length;
    nside = (long) Math.sqrt(npix / 12.);
    if (nside > ns_max) {
      throw new IllegalArgumentException(SID + " Map is too big");
    }
    check = new boolean[(int) npix];
    for (int i = 0; i < npix; i++)
      check[i] = false;
    ilast = 0; // start from first pixel
    for (int i = 0; i < npix; i++) {
      pixbuf2 = map[(int) ilast];
      i1 = ilast;
      if (subcall.equalsIgnoreCase("ring2nest")) {
        i2 = ring2nest(nside, i1);
      } else {
        i2 = nest2ring(nside, i1);
      }
      while (!check[(int) i2]) {
        pixbuf1 = map[(int) i2];
        map[(int) i2] = pixbuf2;
        pixbuf2 = pixbuf1;
        i1 = i2;
        if (subcall.equalsIgnoreCase("ring2nest")) {
          i2 = ring2nest(nside, i1);
        } else {
          i2 = nest2ring(nside, i1);
        }
      }
      while (!(check[(int) ilast] && (ilast < npix - 1))) {
        ilast++;
      }
    }
    res = map;
    return res;
  }

  /**
   * returns 7 or 8 neighbours of any pixel in the nested scheme The neighbours
   * are ordered in the following way: First pixel is the one to the south (
   * the one west of the south direction is taken for pixels that don't have a
   * southern neighbour). From then on the neighbors are ordered in the
   * clockwise direction.
   *
   * @param nside the map resolution
   * @param ipix long pixel number
   * @return ArrayList
   * @throws IllegalArgumentException
   */
  public ArrayList neighbours_nest(long nside, long ipix)  {
    ArrayList res = new ArrayList();
    long npix, ipf, ipo, ix, ixm, ixp, iy, iym, iyp, ixo, iyo;
    long face_num, other_face;
    long ia, ib, ibp, ibm, ib2,  nsidesq;
        int icase;
    long local_magic1, local_magic2;
    long arb_const = 0;
    long[] ixiy = new long[2];
    long[] ixoiyo = new long[2];
    String SID = "neighbours_nest:";
    /* fill the pixel list with 0 */
    res.add(0, new Long(0));
    res.add(1, new Long(0));
    res.add(2, new Long(0));
    res.add(3, new Long(0));
    res.add(4, new Long(0));
    res.add(5, new Long(0));
    res.add(6, new Long(0));
    res.add(7, new Long(0));
    icase = 0;
    /*                                 */
    if ((nside < 1) || (nside > ns_max)) {
      throw new IllegalArgumentException(SID + " Nside should be power of 2 >0 and < "+ns_max);
    }
    nsidesq = nside * nside;
    npix = 12 * nsidesq; // total number of pixels
    if ((ipix < 0) || (ipix > npix - 1)) {
      throw new IllegalArgumentException(SID + " ipix out of range ");
    }
    if (x2pix[xmax-1] <= 0)
      mk_xy2pix();
    local_magic1 = (nsidesq - 1) / 3;
    local_magic2 = 2 * local_magic1;
    face_num = ipix / nsidesq;
    ipf = (long) bm.MODULO(ipix, nsidesq); // Pixel number in face
    ixiy = pix2xy_nest(nside, ipf);
    ix = ixiy[0];
    iy = ixiy[1];
    //
    ixm = ixiy[0] - 1;
    ixp = ixiy[0] + 1;
    iym = ixiy[1] - 1;
    iyp = ixiy[1] + 1;

    icase = 0; // inside the face

    /* exclude corners */
    if (ipf == local_magic2 && icase == 0)
      icase = 5; // West corner
    if (ipf == (nsidesq - 1) && icase == 0)
      icase = 6; // North corner
    if (ipf == 0 && icase == 0)
      icase = 7; // South corner
    if (ipf == local_magic1 && icase == 0)
      icase = 8; // East corner

    /* detect edges */
    if ((ipf & local_magic1) == local_magic1 && icase == 0)
      icase = 1; // NorthEast
    if ((ipf & local_magic1) == 0 && icase == 0)
      icase = 2; // SouthWest
    if ((ipf & local_magic2) == local_magic2 && icase == 0)
      icase = 3; // NorthWest
    if ((ipf & local_magic2) == 0 && icase == 0)
      icase = 4; // SouthEast

    /* iside a face */
    if (icase == 0) {
      res.add(0, new Long( xy2pix_nest(nside, ixm, iym, face_num)));
      res.add(1, new Long( xy2pix_nest(nside, ixm, iy, face_num)));
      res.add(2, new Long( xy2pix_nest(nside, ixm, iyp, face_num)));
      res.add(3, new Long( xy2pix_nest(nside, ix, iyp, face_num)));
      res.add(4, new Long( xy2pix_nest(nside, ixp, iyp, face_num)));
      res.add(5, new Long( xy2pix_nest(nside, ixp, iy, face_num)));
      res.add(6, new Long( xy2pix_nest(nside, ixp, iym, face_num)));
      res.add(7, new Long( xy2pix_nest(nside, ix, iym, face_num)));
    }
    /*                 */
    ia = face_num / 4; // in [0,2]
    ib = (long) bm.MODULO(face_num, 4); // in [0,3]
    ibp = (long) bm.MODULO(ib + 1, 4);
    ibm = (long) bm.MODULO(ib + 4 - 1, 4);
    ib2 = (long) bm.MODULO(ib + 2, 4);

    if (ia == 0) { // North pole region
      switch (icase) {
      case 1: // north-east edge
        other_face = 0 + ibp;
        res.set(0, new Long( xy2pix_nest(nside, ixm, iym, face_num)));
        res.set(1, new Long( xy2pix_nest(nside, ixm, iy, face_num)));
        res.set(2, new Long( xy2pix_nest(nside, ixm, iyp, face_num)));
        res.set(3, new Long( xy2pix_nest(nside, ix, iyp, face_num)));
        res.set(7, new Long( xy2pix_nest(nside, ix, iym, face_num)));
        ipo = (long) bm.MODULO(bm.swapLSBMSB( ipf), nsidesq);
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(4, new Long( xy2pix_nest(nside, ixo + 1, iyo,
            other_face)));
        res.set(5, new Long( (other_face * nsidesq + ipo)));
        res.set(6, new Long( xy2pix_nest(nside, ixo - 1, iyo,
            other_face)));
        break;
      case 2: // SouthWest edge
        other_face = 4 + ib;
        ipo = (long) bm.MODULO(bm.invLSB( ipf), nsidesq); // SW-NE flip
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(0, new Long( xy2pix_nest(nside, ixo, iyo - 1,
            other_face)));
        res.set(1, new Long( (other_face * nsidesq + ipo)));
        res.set(2, new Long( xy2pix_nest(nside, ixo, iyo + 1,
            other_face)));
        res.set(3, new Long( xy2pix_nest(nside, ix, iyp, face_num)));
        res.set(4, new Long( xy2pix_nest(nside, ixp, iyp, face_num)));
        res.set(5, new Long( xy2pix_nest(nside, ixp, iy, face_num)));
        res.set(6, new Long( xy2pix_nest(nside, ixp, iym, face_num)));
        res.set(7, new Long( xy2pix_nest(nside, ix, iym, face_num)));
        break;
      case 3: // NorthWest edge
        other_face = 0 + ibm;
        ipo = (long) bm.MODULO(bm.swapLSBMSB( ipf), nsidesq); // E-W flip
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(0, new Long( xy2pix_nest(nside, ixm, iym, face_num)));
        res.set(1, new Long( xy2pix_nest(nside, ixm, iy, face_num)));
        res.set(2, new Long( xy2pix_nest(nside, ixo, iyo - 1,
            other_face)));
        res.set(3, new Long( (other_face * nsidesq + ipo)));
        res.set(4, new Long( xy2pix_nest(nside, ixo, iyo + 1,
            other_face)));
        res.set(5, new Long( xy2pix_nest(nside, ixp, iy, face_num)));
        res.set(6, new Long( xy2pix_nest(nside, ixp, iym, face_num)));
        res.set(7, new Long( xy2pix_nest(nside, ix, iym, face_num)));
        break;
      case 4: // SouthEast edge
        other_face = 4 + ibp;
        ipo = (long) bm.MODULO(bm.invMSB( ipf), nsidesq); // SE-NW flip
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(0, new Long( xy2pix_nest(nside, ixo - 1, iyo,
            other_face)));
        res.set(1, new Long( xy2pix_nest(nside, ixm, iy, face_num)));
        res.set(2, new Long( xy2pix_nest(nside, ixm, iyp, face_num)));
        res.set(3, new Long( xy2pix_nest(nside, ix, iyp, face_num)));
        res.set(4, new Long( xy2pix_nest(nside, ixp, iyp, face_num)));
        res.set(5, new Long( xy2pix_nest(nside, ixp, iy, face_num)));
        res.set(6, new Long( xy2pix_nest(nside, ixo + 1, iyo,
            other_face)));
        res.set(7, new Long( (other_face * nsidesq + ipo)));
        break;
      case 5: // West corner
        other_face = 4 + ib;
        arb_const = other_face * nsidesq + nsidesq - 1;
        res.set(0, new Long( (arb_const - 2)));
        res.set(1, new Long( arb_const));
        other_face = 0 + ibm;
        arb_const = other_face * nsidesq + local_magic1;
        res.set(2, new Long( arb_const));
        res.set(3, new Long( (arb_const + 2)));
        res.set(4, new Long( (ipix + 1)));
        res.set(5, new Long( (ipix - 1)));
        res.set(6, new Long( (ipix - 2)));
        res.remove(7);
        break;
      case 6: //  North corner
        other_face = 0 + ibm;
        res.set(0, new Long( (ipix - 3)));
        res.set(1, new Long( (ipix - 1)));
        arb_const = other_face * nsidesq + nsidesq - 1;
        res.set(2, new Long( (arb_const - 2)));
        res.set(3, new Long( arb_const));
        other_face = 0 + ib2;
        res.set(4, new Long( (other_face * nsidesq + nsidesq - 1)));
        other_face = 0 + ibp;
        arb_const = other_face * nsidesq + nsidesq - 1;
        res.set(5, new Long( arb_const));
        res.set(6, new Long( (arb_const - 1)));
        res.set(7, new Long( (ipix - 2)));
        break;
      case 7: // South corner
        other_face = 8 + ib;
        res.set(0, new Long( (other_face * nsidesq + nsidesq - 1)));
        other_face = 4 + ib;
        arb_const = other_face * nsidesq + local_magic1;
        res.set(1, new Long( arb_const));
        res.set(2, new Long( (arb_const + 2)));
        res.set(3, new Long( (ipix + 2)));
        res.set(4, new Long( (ipix + 3)));
        res.set(5, new Long( (ipix + 1)));
        other_face = 4 + ibp;
        arb_const = other_face * nsidesq + local_magic2;
        res.set(6, new Long( (arb_const + 1)));
        res.set(7, new Long( arb_const));
        break;
      case 8: // East corner
        other_face = 0 + ibp;
        res.set(1, new Long( (ipix - 1)));
        res.set(2, new Long( (ipix + 1)));
        res.set(3, new Long( (ipix + 2)));
        arb_const = other_face * nsidesq + local_magic2;
        res.set(4, new Long( (arb_const + 1)));
        res.set(5, new Long(( arb_const)));
        other_face = 4 + ibp;
        arb_const = other_face * nsidesq + nsidesq - 1;
        res.set(0, new Long( (arb_const - 1)));
        res.set(6, new Long( arb_const));
        res.remove(7);
        break;
      }
    } else if (ia == 1) { // Equatorial region
      switch (icase) {
      case 1: // north-east edge
        other_face = 0 + ibp;
        res.set(0, new Long( xy2pix_nest(nside, ixm, iym, face_num)));
        res.set(1, new Long( xy2pix_nest(nside, ixm, iy, face_num)));
        res.set(2, new Long( xy2pix_nest(nside, ixm, iyp, face_num)));
        res.set(3, new Long( xy2pix_nest(nside, ix, iyp, face_num)));
        res.set(7, new Long( xy2pix_nest(nside, ix, iym, face_num)));
        ipo = (long) bm.MODULO(bm.invLSB( ipf), nsidesq); // NE-SW flip
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(4, new Long( xy2pix_nest(nside, ixo, iyo + 1,
            other_face)));
        res.set(5, new Long( (other_face * nsidesq + ipo)));
        res.set(6, new Long( xy2pix_nest(nside, ixo, iyo - 1,
            other_face)));
        break;
      case 2: // SouthWest edge
        other_face = 8 + ibm;
        ipo = (long) bm.MODULO(bm.invLSB( ipf), nsidesq); // SW-NE flip
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(0, new Long( xy2pix_nest(nside, ixo, iyo - 1,
            other_face)));
        res.set(1, new Long((other_face * nsidesq + ipo)));
        res.set(2, new Long( xy2pix_nest(nside, ixo, iyo + 1,
            other_face)));
        res.set(3, new Long( xy2pix_nest(nside, ix, iyp, face_num)));
        res.set(4, new Long( xy2pix_nest(nside, ixp, iyp, face_num)));
        res.set(5, new Long( xy2pix_nest(nside, ixp, iy, face_num)));
        res.set(6, new Long( xy2pix_nest(nside, ixp, iym, face_num)));
        res.set(7, new Long( xy2pix_nest(nside, ix, iym, face_num)));
        break;
      case 3: // NortWest edge
        other_face = 0 + ibm;
        ipo = (long) bm.MODULO(bm.invMSB( ipf), nsidesq); // NW-SE flip
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(2, new Long( xy2pix_nest(nside, ixo - 1, iyo,
            other_face)));
        res.set(3, new Long( (other_face * nsidesq + ipo)));
        res.set(4, new Long( xy2pix_nest(nside, ixo + 1, iyo,
            other_face)));
        res.set(0, new Long( xy2pix_nest(nside, ixm, iym, face_num)));
        res.set(1, new Long( xy2pix_nest(nside, ixm, iy, face_num)));
        res.set(5, new Long( xy2pix_nest(nside, ixp, iy, face_num)));
        res.set(6, new Long( xy2pix_nest(nside, ixp, iym, face_num)));
        res.set(7, new Long(xy2pix_nest(nside, ix, iym, face_num)));
        break;
      case 4: // SouthEast edge
        other_face = 8 + ib;
        ipo = (long) bm.MODULO(bm.invMSB( ipf), nsidesq); // SE-NW flip
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(0, new Long( xy2pix_nest(nside, ixo - 1, iyo,
            other_face)));
        res.set(1, new Long( xy2pix_nest(nside, ixm, iy, face_num)));
        res.set(2, new Long( xy2pix_nest(nside, ixm, iyp, face_num)));
        res.set(3, new Long( xy2pix_nest(nside, ix, iyp, face_num)));
        res.set(4, new Long( xy2pix_nest(nside, ixp, iyp, face_num)));
        res.set(5, new Long( xy2pix_nest(nside, ixp, iy, face_num)));
        res.set(6, new Long( xy2pix_nest(nside, ixo + 1, iyo,
            other_face)));
        res.set(7, new Long( (other_face * nsidesq + ipo)));
        break;
      case 5: // West corner
        other_face = 8 + ibm;
        arb_const = other_face * nsidesq + nsidesq - 1;
        res.set(0, new Long( (arb_const - 2)));
        res.set(1, new Long( arb_const));
        other_face = 4 + ibm;
        res.set(2, new Long( (other_face * nsidesq + local_magic1)));
        other_face = 0 + ibm;
        arb_const = other_face * nsidesq;
        res.set(3, new Long( arb_const));
        res.set(4, new Long( (arb_const + 1)));
        res.set(5, new Long( (ipix + 1)));
        res.set(6, new Long( (ipix - 1)));
        res.set(7, new Long( (ipix - 2)));
        break;
      case 6: //  North corner
        other_face = 0 + ibm;
        res.set(0, new Long( (ipix - 3)));
        res.set(1, new Long( (ipix - 1)));
        arb_const = other_face * nsidesq + local_magic1;
        res.set(2, new Long( (arb_const - 1)));
        res.set(3, new Long( arb_const));
        other_face = 0 + ib;
        arb_const = other_face * nsidesq + local_magic2;
        res.set(4, new Long( arb_const));
        res.set(5, new Long( (arb_const - 2)));
        res.set(6, new Long( (ipix - 2)));
        res.remove(7);
        break;
      case 7: // South corner
        other_face = 8 + ibm;
        arb_const = other_face * nsidesq + local_magic1;
        res.set(0, new Long( arb_const));
        res.set(1, new Long( (arb_const + 2)));
        res.set(2, new Long( (ipix + 2)));
        res.set(3, new Long( (ipix + 3)));
        res.set(4, new Long( (ipix + 1)));
        other_face = 8 + ib;
        arb_const = other_face * nsidesq + local_magic2;
        res.set(5, new Long( (arb_const + 1)));
        res.set(6, new Long( arb_const));
        res.remove(7);
        break;
      case 8: // East corner
        other_face = 8 + ib;
        arb_const = other_face * nsidesq + nsidesq - 1;
        res.set(0, new Long( (arb_const - 1)));
        res.set(1, new Long( (ipix - 1)));
        res.set(2, new Long( (ipix + 1)));
        res.set(3, new Long( (ipix + 2)));
        res.set(7, new Long( arb_const));
        other_face = 0 + ib;
        arb_const = other_face * nsidesq;
        res.set(4, new Long( (arb_const + 2)));
        res.set(5, new Long( arb_const));
        other_face = 4 + ibp;
        res.set(6, new Long( (other_face * nsidesq + local_magic2)));
        break;
      }
    } else { // South pole region
      switch (icase) {
      case 1: // North-East edge
        other_face = 4 + ibp;
        res.set(0, new Long( xy2pix_nest(nside, ixm, iym, face_num)));
        res.set(1, new Long( xy2pix_nest(nside, ixm, iy, face_num)));
        res.set(2, new Long( xy2pix_nest(nside, ixm, iyp, face_num)));
        res.set(3, new Long( xy2pix_nest(nside, ix, iyp, face_num)));
        res.set(7, new Long( xy2pix_nest(nside, ix, iym, face_num)));
        ipo = (long) bm.MODULO(bm.invLSB( ipf), nsidesq); // NE-SW flip
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(4, new Long( xy2pix_nest(nside, ixo, iyo + 1,
            other_face)));
        res.set(5, new Long( (other_face * nsidesq + ipo)));
        res.set(6, new Long( xy2pix_nest(nside, ixo, iyo - 1,
            other_face)));
        break;
      case 2: // SouthWest edge
        other_face = 8 + ibm;
        ipo = (long) bm.MODULO(bm.swapLSBMSB( ipf), nsidesq); // W-E flip
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(0, new Long( xy2pix_nest(nside, ixo - 1, iyo,
            other_face)));
        res.set(1, new Long( (other_face * nsidesq + ipo)));
        res.set(2, new Long( xy2pix_nest(nside, ixo + 1, iyo,
            other_face)));
        res.set(3, new Long( xy2pix_nest(nside, ix, iyp, face_num)));
        res.set(4, new Long( xy2pix_nest(nside, ixp, iyp, face_num)));
        res.set(5, new Long( xy2pix_nest(nside, ixp, iy, face_num)));
        res.set(6, new Long(xy2pix_nest(nside, ixp, iym, face_num)));
        res.set(7, new Long( xy2pix_nest(nside, ix, iym, face_num)));
        break;
      case 3: // NorthWest edge
        other_face = 4 + ib;
        ipo = (long) bm.MODULO(bm.invMSB( ipf), nsidesq);
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(0, new Long( xy2pix_nest(nside, ixm, iym, face_num)));
        res.set(1, new Long( xy2pix_nest(nside, ixm, iy, face_num)));
        res.set(2, new Long( xy2pix_nest(nside, ixo - 1, iyo,
            other_face)));
        res.set(3, new Long( (other_face * nsidesq + ipo)));
        res.set(4, new Long( xy2pix_nest(nside, ixo + 1, iyo,
            other_face)));
        res.set(5, new Long( xy2pix_nest(nside, ixp, iy, face_num)));
        res.set(6, new Long( xy2pix_nest(nside, ixp, iym, face_num)));
        res.set(7, new Long( xy2pix_nest(nside, ix, iym, face_num)));
        break;
      case 4: // SouthEast edge
        other_face = 8 + ibp;
        ipo = (long) bm.MODULO(bm.swapLSBMSB( ipf), nsidesq); // SE-NW
        // flip
        ixoiyo = pix2xy_nest(nside, ipo);
        ixo = ixoiyo[0];
        iyo = ixoiyo[1];
        res.set(0, new Long( xy2pix_nest(nside, ixo, iyo - 1,
            other_face)));
        res.set(1, new Long( xy2pix_nest(nside, ixm, iy, face_num)));
        res.set(2, new Long( xy2pix_nest(nside, ixm, iyp, face_num)));
        res.set(3, new Long( xy2pix_nest(nside, ix, iyp, face_num)));
        res.set(4, new Long( xy2pix_nest(nside, ixp, iyp, face_num)));
        res.set(5, new Long( xy2pix_nest(nside, ixp, iy, face_num)));
        res.set(6, new Long( xy2pix_nest(nside, ixo, iyo + 1,
            other_face)));
        res.set(7, new Long( (other_face * nsidesq + ipo)));
        break;
      case 5: // West corner
        other_face = 8 + ibm;
        arb_const = other_face * nsidesq + local_magic1;
        res.set(0, new Long( (arb_const - 2)));
        res.set(1, new Long( arb_const));
        other_face = 4 + ib;
        res.set(2, new Long( (other_face * nsidesq)));
        res.set(3, new Long( (other_face * nsidesq + 1)));
        res.set(4, new Long( (ipix + 1)));
        res.set(5, new Long( (ipix - 1)));
        res.set(6, new Long( (ipix - 2)));
        res.remove(7);
        break;
      case 6: //  North corner
        other_face = 4 + ib;
        res.set(0, new Long( (ipix - 3)));
        res.set(1, new Long((ipix - 1)));
        arb_const = other_face * nsidesq + local_magic1;
        res.set(2, new Long( (arb_const - 1)));
        res.set(3, new Long( arb_const));
        other_face = 0 + ib;
        res.set(4, new Long( (other_face * nsidesq)));
        other_face = 4 + ibp;
        arb_const = other_face * nsidesq + local_magic2;
        res.set(5, new Long( arb_const));
        res.set(6, new Long( (arb_const - 2)));
        res.set(7, new Long( (ipix - 2)));
        break;
      case 7: // South corner
        other_face = 8 + ib2;
        res.set(0, new Long( (other_face * nsidesq)));
        other_face = 8 + ibm;
        arb_const = other_face * nsidesq;
        res.set(1, new Long( arb_const));
        res.set(2, new Long( (arb_const + 1)));
        res.set(3, new Long( (ipix + 2)));
        res.set(4, new Long( (ipix + 3)));
        res.set(5, new Long( (ipix + 1)));
        other_face = 8 + ibp;
        arb_const = other_face * nsidesq;
        res.set(6, new Long( (arb_const + 2)));
        res.set(7, new Long( arb_const));
        break;
      case 8: // East corner
        other_face = 8 + ibp;
        res.set(1, new Long( (ipix - 1)));
        res.set(2, new Long( (ipix + 1)));
        res.set(3, new Long( (ipix + 2)));
        arb_const = other_face * nsidesq + local_magic2;
        res.set(6, new Long( arb_const));
        res.set(0, new Long( (arb_const - 2)));
        other_face = 4 + ibp;
        arb_const = other_face * nsidesq;
        res.set(4, new Long( (arb_const + 2)));
        res.set(5, new Long( arb_const));
        res.remove(7);
        break;
      }
    }
    return res;
  }

  /**
   * returns the list of pixels in RING or NEST scheme with latitude in [phi0 -
   * dpi, phi0 + dphi] on the ring iz in [1, 4*nside -1 ] The pixel id numbers
   * are in [0, 12*nside^2 - 1] the indexing is in RING, unless nest is set to
   * 1
   *
   * @param nside
   *            long the map resolution
   * @param iz
   *           long ring number
   * @param phi0
   *            double
   * @param dphi
   *            double
   * @param nest
   *            boolean format flag
   * @return ArrayList of pixels
   * @throws IllegalArgumentException
   */
  public ArrayList InRing(long nside, long iz, double phi0, double dphi,
      boolean nest)  {
    boolean take_all = false;
    boolean to_top = false;
    boolean do_ring = true;
    boolean conservative = false;
    String SID = "InRing:";
    double epsilon = 1.0e-13; // the constant to eliminate
    // java calculation jitter
    if (nest)
      do_ring = false;
    double shift = 0.;
    long ir = 0;
    long kshift, nr, ipix1, ipix2, nir1, nir2, ncap, npix;
    long ip_low = 0, ip_hi = 0, in, inext, nir;
    ArrayList res = new ArrayList();
    npix = 12 * nside * nside; // total number of pixels
    ncap = 2 * nside * (nside - 1); // number of pixels in the north polar
    // cap
    double phi_low = bm.MODULO(phi0 - dphi, TWOPI) - epsilon; // phi min,
                                  // excluding
    // 2pi period
    double phi_hi = bm.MODULO(phi0 + dphi, TWOPI) + epsilon;

    if (Math.abs(dphi - PI) < 1.0e-6)
      take_all = true;
    /* identifies ring number */
    if ((iz >= nside) && (iz <= 3 * nside)) { // equatorial region
      ir = iz - nside + 1; // in [1, 2*nside + 1]
      ipix1 = ncap + 4 * nside * (ir - 1); // lowest pixel number in the
      // ring
      ipix2 = ipix1 + 4 * nside - 1; // highest pixel number in the ring
      kshift = (long) bm.MODULO(ir, 2.);

      nr = nside * 4;
    } else {
      if (iz < nside) { // north pole
        ir = iz;
        ipix1 = 2 * ir * (ir - 1); // lowest pixel number
        ipix2 = ipix1 + 4 * ir - 1; // highest pixel number
      } else { // south pole
        ir = 4 * nside - iz;

        ipix1 = npix - 2 * ir * (ir + 1); // lowest pixel number
        ipix2 = ipix1 + 4 * ir - 1; // highest pixel number
      }
      nr = ir * 4;
      kshift = 1;
    }
    // Construct the pixel list
    if (take_all) {
      nir = ipix2 - ipix1 + 1;
      if (do_ring) {
        long ind = 0;
        for (long i =  ipix1; i <= ipix2; i++) {
          res.add((int) ind, new Long(i));
          ind++;
        }
      } else {
        in = ring2nest(nside, ipix1);
        res.add(0, new Long( in));
        for (int i = 1; i < nir; i++) {
          inext = next_in_line_nest(nside, in);
          in = inext;
          res.add( i, new Long(in));
        }
      }
      return res;
    }
    shift = kshift / 2.0;

    // conservative : include every intersected pixel, even if the
    // pixel center is out of the [phi_low, phi_hi] region
    if (conservative) {
      ip_low = (long) Math.round((nr * phi_low) / TWOPI - shift);
      ip_hi = (long) Math.round((nr * phi_hi) / TWOPI - shift);
      ip_low = (long) bm.MODULO(ip_low, nr); // in [0, nr - 1]
      ip_hi = (long) bm.MODULO(ip_hi, nr); // in [0, nr - 1]
    } else { // strict: includes only pixels whose center is in
      //                                                    [phi_low,phi_hi]

      ip_low = (long) Math.round((nr * phi_low) / TWOPI - shift);
      ip_hi = (long) Math.round((nr * phi_hi) / TWOPI - shift);
      if (ip_low == ip_hi + 1)
        ip_low = ip_hi;

      if ((ip_low - ip_hi == 1) && (dphi * nr < PI)) {
        // the interval is too small ( and away from pixel center)
        // so no pixels is included in the list
        System.out
            .println("the longerval is too small and avay from center");
        return res; // return empty list
      }
      ip_low = Math.min(ip_low, nr - 1);
      ip_hi = Math.max(ip_hi, 0);
    }
    //
    if (ip_low > ip_hi)
      to_top = true;
    ip_low += ipix1;
    ip_hi += ipix1;
    if (to_top) {
      nir1 = ipix2 - ip_low + 1;
      nir2 = ip_hi - ipix1 + 1;
      nir = nir1 + nir2;
      if (do_ring) {
        int ind = 0;
        for (long i =  ip_low; i <= ipix2; i++) {
          res.add(ind, new Long(i));
          ind++;
        }
        //        ind = nir1;
        for (long i =  ipix1; i <= ip_hi; i++) {
          res.add(ind, new Long(i));
          ind++;
        }
      } else {
        in = ring2nest(nside, ip_low);
        res.add(0, new Long(in));
        for (long i = 1; i <= nir - 1; i++) {
          inext = next_in_line_nest(nside, in);
          in = inext;
          res.add((int) i, new Long(in));
        }
      }
    } else {
      nir = ip_hi - ip_low + 1;
      if (do_ring) {
        int ind = 0;
        for (long i =  ip_low; i <= ip_hi; i++) {
          res.add(ind, new Long(i));
          ind++;
        }
      } else {
        in = ring2nest(nside, ip_low);
        res.add(0, new Long(in));
        for (int i = 1; i <= nir - 1; i++) {
          inext = next_in_line_nest(nside, in);
          in = inext;
          res.add(i, new Long(in));
        }
      }
    }
    return res;
  }

  /**
   * calculates the pixel that lies on the East side (and the same
   * latitude) as the given NESTED pixel number - ipix
   *
   * @param nside
   *            long resolution
   * @param ipix
   *            long pixel number
   * @return  long next pixel in line
   * @throws IllegalArgumentException
   */
  public long next_in_line_nest(long nside, long ipix)  {
    long npix, ipf, ipo, ix, ixp, iy, iym, ixo, iyo, face_num, other_face;
    long ia, ib, ibp, ibm, ib2, nsidesq;
        int icase;
    long local_magic1, local_magic2;
    long[] ixiy = new long[2];
    long inext = 0; // next in line pixel in Nest scheme
    String SID = "next_in_line:";
    if ((nside < 1) || (nside > ns_max)) {
      throw new IllegalArgumentException(SID + " nside should be power of 2 >0 and < "+ns_max);
    }
    nsidesq = nside * nside;
    npix = 12 * nsidesq; // total number of pixels
    if ((ipix < 0) || (ipix > npix - 1)) {
      throw new IllegalArgumentException(SID + " ipix out of range defined by nside");
    }
    // initiates array for (x,y) -> pixel number -> (x,y) mapping
    if (x2pix[xmax-1] <= 0)
      mk_xy2pix();
    local_magic1 = (nsidesq - 1) / 3;
    local_magic2 = 2 * local_magic1;
    face_num = ipix / nsidesq;
    ipf = (long) bm.MODULO(ipix, nsidesq); // Pixel number in face
    ixiy = pix2xy_nest(nside, ipf);
    ix = ixiy[0];
    iy = ixiy[1];
    ixp = ix + 1;
    iym = iy - 1;
    boolean sel = false;
    icase = -1; // iside the nest flag
    // Exclude corners
    if (ipf == local_magic2) { // west coirner
      inext = ipix - 1;
      return inext;
    }
    if ((ipf == nsidesq - 1) && !sel) { // North corner
      icase = 6;
      sel = true;
    }
    if ((ipf == 0) && !sel) { // Siuth corner
      icase = 7;
      sel = true;
    }
    if ((ipf == local_magic1) && !sel) { // East corner
      icase = 8;
      sel = true;
    }
    // Detect edges
    if (((ipf & local_magic1) == local_magic1) && !sel) { // North-East
      icase = 1;
      sel = true;
    }
    if (((ipf & local_magic2) == 0) && !sel) { // South-East
      icase = 4;
      sel = true;
    }
    if (!sel) { // iside a face
      inext = xy2pix_nest(nside, ixp, iym, face_num);
      return inext;
    }
    //
    ia = face_num / 4; // in [0,2]
    ib = (long) bm.MODULO(face_num, 4); // in [0,3]
    ibp = (long) bm.MODULO(ib + 1, 4);
    ibm = (long) bm.MODULO(ib + 4 - 1, 4);
    ib2 = (long) bm.MODULO(ib + 2, 4);

    if (ia == 0) { // North pole region
      switch (icase) {
      case 1:
        other_face = 0 + ibp;
        ipo = (long) bm.MODULO(bm.swapLSBMSB( ipf), nsidesq);
        inext = other_face * nsidesq + ipo;
        break;
      case 4:
        other_face = 4 + ibp;
        ipo = (long) bm.MODULO(bm.invMSB( ipf), nsidesq); // SE-NW flip

        ixiy = pix2xy_nest(nside, ipo);
        ixo = ixiy[0];
        iyo = ixiy[1];

        inext = xy2pix_nest(nside, ixo + 1, iyo, other_face);

        break;
      case 6: // North corner
        other_face = 0 + ibp;
        inext = other_face * nsidesq + nsidesq - 1;
        break;
      case 7:
        other_face = 4 + ibp;
        inext = other_face * nsidesq + local_magic2 + 1;
        break;
      case 8:
        other_face = 0 + ibp;
        inext = other_face * nsidesq + local_magic2;
        break;
      }

    } else if (ia == 1) { // Equatorial region
      switch (icase) {
      case 1: // NorthEast edge
        other_face = 0 + ib;
//                System.out.println("ipf="+ipf+" nsidesq="+nsidesq+" invLSB="+bm.invLSB(ipf));
        ipo = (long) bm.MODULO((double)bm.invLSB( ipf), (double)nsidesq); // NE-SW flip
//                System.out.println(" ipo="+ipo);
               
        ixiy = pix2xy_nest(nside, ipo);
        ixo = ixiy[0];
        iyo = ixiy[1];
        inext = xy2pix_nest(nside, ixo, iyo - 1, other_face);
        break;
      case 4: // SouthEast edge
        other_face = 8 + ib;
        ipo = (long) bm.MODULO(bm.invMSB( ipf), nsidesq);
        ixiy = pix2xy_nest(nside, ipo);
        inext = xy2pix_nest(nside, ixiy[0] + 1, ixiy[1], other_face);
        break;
      case 6: // Northy corner
        other_face = 0 + ib;
        inext = other_face * nsidesq + local_magic2 - 2;
        break;
      case 7: // South corner
        other_face = 8 + ib;
        inext = other_face * nsidesq + local_magic2 + 1;
        break;
      case 8: // East corner
        other_face = 4 + ibp;
        inext = other_face * nsidesq + local_magic2;
        break;

      }
    } else { // South pole region
      switch (icase) {
      case 1: // NorthEast edge
        other_face = 4 + ibp;
        ipo = (long) bm.MODULO(bm.invLSB( ipf), nsidesq); // NE-SW flip
        ixiy = pix2xy_nest(nside, ipo);
        inext = xy2pix_nest(nside, ixiy[0], ixiy[1] - 1, other_face);
        break;
      case 4: // SouthEast edge
        other_face = 8 + ibp;
        ipo = (long) bm.MODULO(bm.swapLSBMSB( ipf), nsidesq); // E-W flip
        inext = other_face * nsidesq + ipo; // (8)
        break;
      case 6: // North corner
        other_face = 4 + ibp;
        inext = other_face * nsidesq + local_magic2 - 2;
        break;
      case 7: // South corner
        other_face = 8 + ibp;
        inext = other_face * nsidesq;
        break;
      case 8: // East corner
        other_face = 8 + ibp;
        inext = other_face * nsidesq + local_magic2;
        break;
      }
    }
    return inext;
  }

  /**
   * renders the pixel number pix (NESTED scheme) for a pixel which contains a
   * point on a sphere at coordinate vector (x,y,z), given the map resolution
   * parameter nside.
   *
   * The computation is made to the highest resolution available (nside=ns_max)
   * and then degraded to that requared (by Integer division) this doesn't
   * cost much, and it makes sure that the treatment of round-off will be
   * consistent for every resolution
   *
   * @param nside
   *            long the map resolution
   * @param vector
   *            Vewctor3d the input vector
   * @return pixel long
   * @throws IllegalArgumentException
   */
  public long vect2pix_nest(long nside, Vector3d vector)  {
    long pix = 0;
    double z, za, tt, tp, tmp, dnorm, phi;
    long jp, jm, ifp, ifm, face_num, ix, iy, ix_low, ix_hi;
    long iy_low, iy_hi, ipf, ntt;
    String SID = " vect2pix_nest:";
    /*                      */
    if (nside < 1 || nside > ns_max) {
      throw new IllegalArgumentException(SID + " nside should be power of 2 >0 and < ns_max");
    }
    if (x2pix[xmax-1] <= 0)
      mk_xy2pix();
    dnorm = vector.length();
    z = vector.z / dnorm;
    phi = 0.; // phi in [-pi,pi]
    if (vector.x != 0. || vector.y != 0.)
      phi = Math.atan2(vector.y, vector.x);
    za = Math.abs(z);
    if (phi < 0.)
      phi += TWOPI; // phi in [0,2pi]
    tt = 2. * phi / PI; // in [0,4]
    if (za <= twothird) { // Equatorial region
      /*
       * the index of edge lines increases when the longitude = phi goes
       * up
       */
      jp = (long) (ns_max * (0.5 + tt - z * 0.75)); // ascending edge line
      // index
      jm = (long) (ns_max * (0.5 + tt + z * 0.75)); // descending edge line
      // index
      /* find the face */
      ifp = jp / ns_max; // in [0,4]
      ifm = jm / ns_max;
      if (ifp == ifm) { // faces 4 to 7
        face_num = (long) bm.MODULO(ifp, 4) + 4;
      } else if (ifp < ifm) { // (half-) faces 0 to 3
        face_num = (long) bm.MODULO(ifp, 4);
      } else { // (half-) faces 8 to 11
        face_num = (long) bm.MODULO(ifm, 4) + 8;
      }

      ix = (long) bm.MODULO(jm, ns_max);
      iy = ns_max - (long) bm.MODULO(jp, ns_max) - 1;
    } else { // polar region, za > 2/3
      ntt = (long) tt;
      if (ntt >= 4)
        ntt = 3;
      tp = tt - ntt;
      tmp = Math.sqrt(3.0 * (1.0 - za)); // in [0,1]
      /*
       * the index of edge lines increases when distance from the closest
       * pole goes up
       */
      jp = (long) (ns_max * tp * tmp); // line going toward the pole has
      // phi increases
      jm = (long) (ns_max * (1.0 - tp) * tmp); // that one goes away of the
      // closest pole
      jp = Math.min(ns_max - 1, jp); // for points too close to the
      // boundary
      jm = Math.min(ns_max - 1, jm);
      /* finds the face and pixel's (x,y) */
      if (z >= 0) {
        face_num = ntt; // in [0,3]
        ix = ns_max - jm - 1;
        iy = ns_max - jp - 1;
      } else {
        face_num = ntt + 8; // in [8,11]
        ix = jp;
        iy = jm;
      }
    }
    ix_low = (long) bm.MODULO(ix, xmax);
    ix_hi = ix / xmax;
    iy_low = (long) bm.MODULO(iy, xmax);
    iy_hi = iy / xmax;

    ipf = (x2pix[(int) (ix_hi + 1)] + y2pix[(int) (iy_hi + 1)]) * (xmax * xmax)
        + (x2pix[(int) (ix_low + 1)] + y2pix[(int) (iy_low + 1)]);
    ipf = ipf / ((ns_max / nside) * (ns_max / nside)); // in [0, nside**2
    // -1]
    pix = ipf + face_num * nside * nside; // in [0, 12*nside**2 -1]
    return pix;
  }

  /**
   * gives the pixel number ipix (NESTED) corresponding to ix, iy and face_num
   *
   * @param nside
   *            the map resolution parameter
   * @param ix
   *            Integer x coordinate
   * @param iy
   *            Integer y coordinate
   * @param face_num
   *            long face number
   * @return  long pixel number ipix
   * @throws IllegalArgumentException
   */
  private long xy2pix_nest(long nside, long ix, long iy, long face_num){
    long res = 0;
    long ix_low, ix_hi, iy_low, iy_hi, ipf;
    String SID = "xy2pix_nest:";
    //
    if ((nside < 1) || (nside > ns_max)) {
      throw new IllegalArgumentException(SID + " nside should be power of 2 >0 and < "+ns_max);
    }
    if ((ix < 0) || (ix > nside - 1)) {
      throw new IllegalArgumentException(SID + " ix out of range [0, nside-1]");
    }
    if ((iy < 0) || (iy > nside - 1)) {
      throw new IllegalArgumentException(SID + " iy out of range [0, nside-1]");
    }
    if (x2pix[xmax-1] <= 0)
      mk_xy2pix();
    ix_low = (long) bm.MODULO(ix, xmax);
    ix_hi = ix / xmax;
    iy_low = (long) bm.MODULO(iy, xmax);
    iy_hi = iy / xmax;

    ipf = (x2pix[(int) (ix_hi + 1)] + y2pix[(int) (iy_hi + 1)]) * xmax * xmax
        + (x2pix[(int) (ix_low + 1)] + y2pix[(int) (iy_low + 1)]);
    res = ipf + face_num * nside * nside; // in [0, 12*nside^2 - 1]

    return res;
  }

  /**
   * gives the x,y coordinates in a face from pixel number within the face
   * (NESTED) scheme.
   *
   * @param nside
   *            long resolution parameter
   * @param ipf
   *            long pixel number
   * @return ixiy  long[] contains x and y coordinates
   * @throws IllegalArgumentException
   */
  private long[] pix2xy_nest(long nside, long ipf)  {
    long[] ixiy = { 0, 0 };
    long ip_low, ip_trunc, ip_med, ip_hi;
    String SID = "pix2xy_nest:";
//        System.out.println(" ipf="+ipf+" nside="+nside);
    if ((nside < 1) || (nside > ns_max)) {
      throw new IllegalArgumentException(SID + " nside should be power of 2 >0 and < "+ns_max);
    }
    if ((ipf < 0) || (ipf > nside * nside - 1)) {
      throw new IllegalArgumentException(SID + " ipix out of range defined by nside");
    }
    if (pix2x[pixmax] <= 0)
      mk_pix2xy();
    ip_low = (long) bm.MODULO(ipf, pixmax); // contents of last 15 bits
    ip_trunc = ipf / pixmax; // truncation of the last 15 bits
    ip_med = (long) bm.MODULO(ip_trunc, pixmax); // next 15 bits
    ip_hi = ip_trunc / pixmax; // select high 15 bits

    long ix = pixmax * pix2x[(int) ip_hi] + xmid * pix2x[(int) ip_med] + pix2x[(int) ip_low];
    long iy = pixmax * pix2y[(int) ip_hi] + xmid * pix2y[(int) ip_med] + pix2y[(int) ip_low];
    ixiy[0] = ix;
    ixiy[1] = iy;
    return ixiy;
  }

  /**
   * creates an array of pixel numbers pix2x from x and y coordinates in the
   * face. Suppose NESTED scheme of pixel ordering Bits corresponding to x and
   * y are interleaved in the pixel number in even and odd bits.
   */
  private void mk_pix2xy() {
    long kpix, jpix, ix, iy, ip, id;
    boolean flag = true;
    for (kpix = 0; kpix <= pixmax; kpix++) { // loop on pixel numbers
      jpix = kpix;
      ix = 0;
      iy = 0;
      ip = 1; // bit position in x and y
      flag = true;
      while (flag) { // go through all the bits
        if (jpix == 0) {
          flag = false;
          break;
        }
        id = (long) bm.MODULO(jpix, 2); // bit value (in kpix), goes in x
        jpix /= 2;
        ix += id * ip;

        id = (long) bm.MODULO(jpix, 2); // bit value, goes in iy
        jpix /= 2;
        iy += id * ip;

        ip *= 2; // next bit (in x and y )
      }
//           System.out.println("ix="+ix+" iy="+iy);
      pix2x[(int) kpix] = ix; // in [0,128]
      pix2y[(int) kpix] = iy; // in [0,128]

    }
  }

  /**
   * converts pixel number from ring numbering scheme to the nested one
   *
   * @param nside
   *            long resolution
   * @param ipring-
   *            long pixel number in ring scheme
   * @return long pixel number in nest scheme
   * @throws IllegalArgumentException
   */
  public long ring2nest(long nside, long ipring)  {
    long ipnest = 0;
    double fihip;
    double hip;
    long npix, nl2, nl4, ncap, ip, iphi, ipt, ipring1, kshift, face_num;
    long nr, irn, ire, irm, irs, irt, ifm, ifp, ix, iy, ix_low, ix_hi, iy_low;
    long iy_hi, ipf;
    int[] jrll = { 0, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 }; // in units of
    // nside
    int[] jpll = { 0, 1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7 }; // in units of
    // nside/2
    String SID = "ring2nest:";
    //
    face_num = 0;
    if ((nside < 1) || (nside > ns_max)) {
      throw new IllegalArgumentException(SID + " nside should be power of 2 >0 and < "+ns_max);
    }
    npix = 12 * nside * nside; // total number of points
    if ((ipring < 0) || (ipring > npix - 1)) {
      throw new IllegalArgumentException(SID + " ipring out of range [0,npix-1]");
    }
    if (x2pix[xmax-1] <= 0)
      mk_xy2pix();

    nl2 = 2 * nside;
    nl4 = 4 * nside;
    ncap = nl2 * (nside - 1); // points in each polar cap, =0 for nside = 1
    ipring1 = ipring + 1;
    // finds the ring number, the position of the ring and the face number
    if (ipring1 <= ncap) { // north polar cap
      hip = ipring1 / 2.0;
      fihip = Math.round(hip);
      irn = (long) Math.sqrt(hip - Math.sqrt(fihip)) + 1; // counted from
      // north pole
      iphi = ipring1 - 2 * irn * (irn - 1);

      kshift = 0;
      nr = irn; // 1/4 of the number of points on the current ring
      face_num = (iphi - 1) / irn; // in [0,3 ]
    } else if (ipring1 <= nl2 * (5 * nside + 1)) { // equatorial region
      ip = ipring1 - ncap - 1;
      irn = (ip / nl4) + nside; // counted from north pole
      iphi = (long) bm.MODULO(ip, nl4) + 1;

      kshift = (long) bm.MODULO(irn + nside, 2); // 1 if odd 0
      // otherwise
      nr = nside;
      ire = irn - nside + 1; // in [1, 2*nside+1]
      irm = nl2 + 2 - ire;
      ifm = (iphi - ire / 2 + nside - 1) / nside; // face boundary
      ifp = (iphi - irm / 2 + nside - 1) / nside;
      if (ifp == ifm) {
        face_num = (long) bm.MODULO(ifp, 4.) + 4;
      } else if (ifp + 1 == ifm) { // (half-) faces 0 to 3
        face_num = ifp;
      } else if (ifp - 1 == ifm) { // (half-) faces 8 to 11
        face_num = ifp + 7;
      }
    } else { // south polar cap
      ip = npix - ipring1 + 1;
      hip = ip / 2.0;
      fihip = Math.rint(hip);
      irs = (long) Math.sqrt(hip - Math.sqrt(fihip)) + 1;
      iphi = 4 * irs + 1 - (ip - 2 * irs * (irs - 1));
      kshift = 0;
      nr = irs;
      irn = nl4 - irs;
      face_num = (iphi - 1) / irs + 8; // in [8,11]
    }
    // finds the (x,y) on the face
    irt = irn - jrll[(int) (face_num + 1)] * nside + 1; // in [-nside+1,0]
    ipt = 2 * iphi - jpll[(int) (face_num + 1)] * nr - kshift - 1; // in [-nside+1,
    // nside-1]
    if (ipt >= nl2)
      ipt -= 8 * nside; // for the face #4

    ix = (ipt - irt) / 2;
    iy = -(ipt + irt) / 2;

    ix_low = (long) bm.MODULO(ix, xmax);
    ix_hi = ix / xmax;
    iy_low = (long) bm.MODULO(iy, xmax);
    iy_hi = iy / xmax;
    ipf = (x2pix[(int) (ix_hi + 1)] + y2pix[(int) (iy_hi + 1)]) * xmax * xmax
        + (x2pix[(int) (ix_low + 1)] + y2pix[(int) (iy_low + 1)]); // in [0, nside**2 -1]
    ipnest = ipf + face_num * nside * nside; // in [0, 12*nside**2 -1]
    return ipnest;

  }

  /**
   * converts from NESTED to RING pixel numbering
   *
   * @param nside
   *            long resolution
   * @param ipnest-
   *            long NEST pixel number
   * @return ipring  long RING pixel number
   * @throws IllegalArgumentException
   */
  public long nest2ring(long nside, long ipnest)  {
    long res = 0;
    long npix, npface, face_num, ncap, n_before, ipf, ip_low, ip_trunc;
    long ip_med, ip_hi, ix, iy, jrt, jr, nr, jpt, jp, kshift, nl4;
    long[] ixiy = { 0, 0 };
    // coordinates of lowest corner of each face
    long[] jrll = { 0, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 }; // in units of
    // nside
    long[] jpll = { 0, 1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7 }; // in units of
    // nside/2
    String SID = "nest2ring:";
    //
    if ((nside < 1) || (nside > ns_max)) {
      throw new IllegalArgumentException(SID + " nside should be power of 2 >0 and < ns_max");
    }
    npix = 12 * nside * nside;
    if ((ipnest < 0) || (ipnest > npix - 1)) {
      throw new IllegalArgumentException(SID + " ipnest out of range [0,npix-1]");
    }
    if (pix2x[pixmax-1] <= 0)
      mk_pix2xy();
    ncap = 2 * nside * (nside - 1); // number of points in the North polar
    // cap
    nl4 = 4 * nside;
    // finds the face and the number in the face
    npface = nside * nside;

    face_num = ipnest / npface; // face number in [0,11]
    if (ipnest >= npface) {
      ipf = (long) bm.MODULO(ipnest, npface); // pixel number in the face
    } else {
      ipf = ipnest;
    }

    // finds the x,y on the face
    //  from the pixel number
    ip_low = (long) bm.MODULO(ipf, pixmax); // last 15 bits
    if (ip_low < 0)
      ip_low = -ip_low;

    ip_trunc = ipf / pixmax; // truncate last 15 bits
    ip_med = (long) bm.MODULO(ip_trunc, pixmax); // next 15 bits
    if (ip_med < 0)
      ip_med = -ip_med;
    ip_hi = ip_trunc / pixmax; // high 15 bits

    ix = pixmax * pix2x[(int) ip_hi] + xmid * pix2x[(int) ip_med] + pix2x[(int) ip_low];
    iy = pixmax * pix2y[(int) ip_hi] + xmid * pix2y[(int) ip_med] + pix2y[(int) ip_low];

    // transform this in (horizontal, vertical) coordinates
    jrt = ix + iy; // vertical in [0,2*(nside -1)]
    jpt = ix - iy; // horizontal in [-nside+1, nside - 1]
    // calculate the z coordinate on the sphere
    jr = jrll[(int) (face_num + 1)] * nside - jrt - 1; // ring number in [1,4*nside
    // -1]
    nr = nside; // equatorial region (the most frequent)
    n_before = ncap + nl4 * (jr - nside);
    kshift = (long) bm.MODULO(jr - nside, 2);
    if (jr < nside) { // north pole region
      nr = jr;
      n_before = 2 * nr * (nr - 1);
      kshift = 0;
    } else if (jr > 3 * nside) { // south pole region
      nr = nl4 - jr;
      n_before = npix - 2 * (nr + 1) * nr;
      kshift = 0;
    }
    // computes the phi coordinate on the sphere in [0,2pi]
    jp = (jpll[(int) (face_num + 1)] * nr + jpt + 1 + kshift) / 2; // 'phi' number
    // in ring
    // [1,4*nr]
    if (jp > nl4)
      jp -= nl4;
    if (jp < 1)
      jp += nl4;
    res = n_before + jp - 1; // in [0, npix-1]
    return res;
  }

  /**
   * fills arrays x2pix and y2pix giving the number of the pixel lying in
   * (x,y). x and y are in [1,512] the pixel number is in [0, 512**2 -1]
   *
   * if i-1 = sum_p=0 b_p*2^p then ix = sum+p=0 b_p*4^p iy = 2*ix ix + iy in
   * [0,512**2 -1]
   */
  private void mk_xy2pix() {
    long k, ip, id;
    for (int i = 1; i <= xmax; i++) {
      long j = i - 1;
      k = 0;
      ip = 1;
      while (j != 0) {
        id = (long) bm.MODULO(j, 2);
        j /= 2;
        k += ip * id;
        ip *= 4;
      }
      x2pix[i] = k;
      y2pix[i] = 2 * k;
  //          System.out.println("y2pix="+2*k);
    }

  }

  /**
   * returns the ring number in {1, 4*nside - 1} calculated from z coordinate
   *
   * @param nside
   *            long resolution
   * @param z
   *            double z coordinate
   * @return long ring number
   */
  public long RingNum(long nside, double z) {
    long iring = 0;
    /* equatorial region */

    iring = (long) Math.round(nside * (2.0 - 1.5 * z));
    /* north cap */
    if (z > twothird) {
      iring = (long) Math.round(nside * Math.sqrt(3.0 * (1.0 - z)));
      if (iring == 0)
        iring = 1;
    }
    /* south cap */
    if (z < -twothird) {
      iring = (long) Math.round(nside * Math.sqrt(3.0 * (1.0 + z)));
      if (iring == 0)
        iring = 1;
      iring = 4 * nside - iring;
    }
    return iring;
  }

  /**
   * calculates vector corresponding to angles theta (co-latitude
   * measured from North pole, in [0,pi] radians) phi (longitude measured
   * eastward in [0,2pi] radians) North pole is (x,y,z) = (0, 0, 1)
   *
   * @param theta double
   * @param phi double
   * @return Vector3d
   * @throws IllegalArgumentException
   */
  public Vector3d Ang2Vec(double theta, double phi)  {
    double PI = Math.PI;
    String SID = "Ang2Vec:";
    Vector3d v;
    if ((theta < 0.0) || (theta > PI)) {
      throw new IllegalArgumentException(SID + " theta out of range [0.,PI]");
    }
    double stheta = Math.sin(theta);
    double x = stheta * Math.cos(phi);
    double y = stheta * Math.sin(phi);
    double z = Math.cos(theta);
    v = new Vector3d(x, y, z);
    return v;
  }

  /**
   * converts a Vector3d in a tuple of angles tup[0] = theta
   * co-latitude measured from North pole, in [0,PI] radians, tup[1] = phi
   * longitude measured eastward, in [0,2PI] radians
   *
   * @param v
   *            Vector3d
   * @return double[] out_tup out_tup[0] = theta out_tup[1] = phi
   */
  public double[] Vect2Ang(Vector3d v) {
    double[] out_tup = new double[2];
    double norm = v.length();
    double z = v.z / norm;
    double theta = Math.acos(z);
    double phi = 0.;
    if ((v.x != 0.) || (v.y != 0)) {
      phi = Math.atan2(v.y, v.x); // phi in [-pi,pi]
    }
    if (phi < 0)
      phi += 2.0 * Math.PI; // phi in [0, 2pi]
    out_tup[0] = theta;
    out_tup[1] = phi;
    return out_tup;
  }

  /**
   * returns nside such that npix = 12*nside^2 nside should by
   * power of 2 and smaller than ns_max if not return -1
   *
   * @param npix
   *            long the number of pixels in the map
   * @return nside long the map resolution parameter
   */
  public long Npix2Nside(long npix) {
    long nside = 0;
    long npixmax = 12 *(long) ns_max *(long) ns_max;
        System.out.println("ns_max="+ns_max+"  npixmax="+npixmax);
    String SID = "Npix2Nside:";
    nside = (long) Math.rint(Math.sqrt(npix / 12));
    if (npix < 12) {
      throw new IllegalArgumentException(SID + " npix is too small should be > 12");
    }
    if (npix > npixmax) {
      throw new IllegalArgumentException(SID + " npix is too large > 12 * ns_max^2");
    }
    double fnpix = 12.0 * nside * nside;
    if (Math.abs(fnpix - npix) > 1.0e-2) {
      throw new IllegalArgumentException(SID + "  npix is not 12*nside*nside");
    }
    double flog = Math.log((double) nside) / Math.log(2.0);
    double ilog = Math.rint(flog);
    if (Math.abs(flog - ilog) > 1.0e-6) {
      throw new IllegalArgumentException(SID + "  nside is not power of 2");
    }
    return nside;
  }

  /**
   * calculates npix such that npix = 12*nside^2 nside should be
   * a power of 2, and smaller than ns_max otherwise return -1
   *
   * @param nside
   *            long the map resolution
   * @return npix long the number of pixels in the map
   */
  public long Nside2Npix(long nside) {

    long[] nsidelist = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
        4096, 8192, 16384, 32768, 65563, 131072, 262144, 524288, 1048576,
                2097152, 4194304};

    long res = 0;
    long nside_max = ns_max;
    String SID = "Nside2Npix:";
    if (Arrays.binarySearch(nsidelist, nside) < 0) {
      throw new IllegalArgumentException(SID + " nside should be >0, power of 2, <"+ns_max);
    }
    res = 12 * nside * nside;
    return res;
  }

  /**
   * calculates the surface of spherical triangle defined by
   * vertices v1,v2,v3 Algorithm: finds triangle sides and uses l'Huilier
   * formula to compute "spherical excess" = surface area of triangle on a
   * sphere of radius one see, eg Bronshtein, Semendyayev Eq 2.86 half
   * perimeter hp = 0.5*(side1+side2+side3) l'Huilier formula x0 = tan( hp/2.)
   * x1 = tan((hp - side1)/2.) x2 = tan((hp - side2)/2.) x3 = tan((hp -
   * side3)/2.)
   *
   * @param v1 Vector3d
   * @param v2 Vector3d
   * @param v3 Vector3d vertices of the triangle
   * @return  double the triangle surface
   * @throws Exception
   * 
   */
  public double SurfaceTriangle(Vector3d v1, Vector3d v2, Vector3d v3)
      throws Exception {
    double res = 0.;
    double side1 = AngDist(v2, v3) / 4.0;
    double side2 = AngDist(v3, v1) / 4.0;
    double side3 = AngDist(v1, v2) / 4.0;
    double x0 = Math.tan(side1 + side2 + side3);
    double x1 = Math.tan(side2 + side3 - side1);
    double x2 = Math.tan(side1 + side3 - side2);
    double x3 = Math.tan(side1 + side2 - side3);
    res = 4.0 * Math.atan(Math.sqrt(x0 * x1 * x2 * x3));

    return res;
  }

  /**
   * calculates angular distance (in radians) between 2 Vectors
   * v1 and v2 In general dist = acos(v1.v2) axcept if the vectors are almost
   * aligned
   *
   * @param v1 Vector3d
   * @param v2 Vector3d
   * @return double dist
   * @throws Exception
   */
  public double AngDist(Vector3d v1, Vector3d v2) throws Exception {
    double dist = 0.;
    double aligned = 0.999;
    /* Normalize both vectors */
    Vector3d r1 = v1;
    Vector3d r2 = v2;
    r1.normalize();
    r2.normalize();
    double sprod = r1.dot(r2);
    /* This takes care about the bug in vecmath method from java3d project */
    if (sprod > aligned) { // almost aligned
      r1.sub(r2);
      double diff = r1.length();
      dist = 2.0 * Math.asin(diff / 2.0);

    } else if (sprod < -aligned) {
      r1.add(r2);
      double diff = r1.length();
      dist = Math.PI - 2.0 * Math.asin(diff / 2.0);
    } else {
      dist = r1.angle(r2);
    }
    return dist;
  }

  /**
   * calculates a vector production of two vectors.
   *
   * @param v1
   *            Vectror containing 3 elements of Number type
   * @param v2
   *            Vector containing 3 elements of Number type
   * @return Vector of 3 Objects of Double type
   * @throws Exception
   */
  public Vector VectProd(Vector v1, Vector v2) throws Exception {
    Vector res = new Vector();
    double[] val = new double[3];
    double[] v1_element = new double[3];
    double[] v2_element = new double[3];
    for (int i = 0; i < 3; i++) {
      if (v1.get(i).getClass().isInstance(Number.class)) {
        v1_element[i] = ((Number) v1.get(i)).doubleValue();
      } else {
        throw new Exception();
      }
      if (v2.get(i).getClass().isInstance(Number.class)) {
        v2_element[i] = ((Number) v2.get(i)).doubleValue();
      } else {
        throw new Exception();
      }

    }

    Double value = new Double(v1_element[1] * v2_element[2] - v1_element[2]
        * v2_element[1]);
    res.add((Object) value);
    value = new Double(v1_element[1] * v2_element[2] - v1_element[2]
        * v2_element[1]);
    res.add((Object) value);
    value = new Double(v1_element[1] * v2_element[2] - v1_element[2]
        * v2_element[1]);
    res.add((Object) value);
    return res;
  }

  /**
   * calculates a dot product (inner product) of two 3D vectors
   *  the result is double
   *
   * @param v1
   *            3d Vector of Number Objects (Double, long .. )
   * @param v2
   *            3d Vector
   * @return  double
   * @throws Exception
   */
  public double dotProduct(Vector3d v1, Vector3d v2) throws Exception {
    double product = 0.;
    double v1_component = 0.;
    double v2_component = 0.;
    double prod = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;

    return prod;
  }

  /**
   * calculate cross product of two vectors
   *
   * @param v1
   *            Vector3d
   * @param v2
   *            Vector3d
   * @return  Vector3d result of the product
   */
  public Vector3d crossProduct(Vector3d v1, Vector3d v2) {
    Vector3d res = new Vector3d(0., 0., 0.);
    double x = v1.y * v2.z - v1.z * v2.y;
    double y = v1.z * v2.x - v1.x * v2.z;
    double z = v1.x * v2.y - v1.y * v2.x;
    res.x = x;
    res.y = y;
    res.z = z;
    return res;
  }
    /**
     * calculates angular resolution of the pixel map
     * in arc seconds.
     * @param nside
     * @return double resolution in arcsec
     */
    public double PixRes(long nside) {
        double res = 0.;
        double degrad = Math.toDegrees(1.0);
        double skyArea = 4.*PI*degrad*degrad; // 4PI steredian in deg^2
        double arcSecArea = skyArea*3600.*3600.// 4PI steredian in (arcSec^2)
        long npixels = 12*nside*nside;
        res = arcSecArea/npixels;       // area per pixel
        res = Math.sqrt(res);           // angular size of the pixel arcsec
        return res;
    }
    /**
     * calculate requared nside given pixel size in arcsec
     * @param pixsize in arcsec
     * @return long nside parameter
     */
    public long GetNSide(double pixsize) {
      long[] nsidelist = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
        4096, 8192, 16384, 32768, 65563, 131072, 262144, 524288, 1048576 };
      long res = 0;
      double pixelArea = pixsize*pixsize;
      double degrad = Math.toDegrees(1.);
      double skyArea = 4.*PI*degrad*degrad*3600.*3600.;
      long npixels = (long) (skyArea/pixelArea);
      long nsidesq = npixels/12;
      long nside_req = (long) Math.sqrt(nsidesq);
      long mindiff = ns_max;
      int indmin = 0;
      for (int i=0; i<nsidelist.length; i++) {
        if (Math.abs(nside_req - nsidelist[i]) <= mindiff) {
          mindiff = Math.abs(nside_req - nsidelist[i]);
          res = nsidelist[i];
          indmin = i;
        }
        if ((nside_req > res) && (nside_req < ns_max)) res = nsidelist[indmin+1];
           if (nside_req > ns_max ) {
            System.out.println("nside cannot be bigger than "+ns_max);
            return ns_max;
          }
       
      }
      return res;
    }
}
TOP

Related Classes of gov.fnal.eag.healpix.PixTools

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.