All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ucar.nc2.dataset.conv.Cosmic1Convention Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2018 John Caron and University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */


package ucar.nc2.dataset.conv;

import ucar.ma2.*;

import ucar.nc2.Attribute;
import ucar.nc2.Dimension;

import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.CDM;
import ucar.nc2.constants._Coordinate;
import ucar.nc2.dataset.*;
import ucar.nc2.util.CancelTask;

import java.io.IOException;


/**
 * Cosmic data - version 1.
 * Add time coordinate from global atts start_time, stop_time, assuming its linear along the vertical dimension.
 *
 * @author caron
 * @since Jul 29, 2009
 */
public class Cosmic1Convention extends CoordSysBuilder {

  /**
   * @param ncfile the NetcdfFile to test
   * @return true if we think this is a Zebra file.
   */
  public static boolean isMine(NetcdfFile ncfile) {

    //   :start_time = 9.17028312E8; // double
    // :stop_time = 9.170284104681826E8; // double

    if ((null == ncfile.findDimension("MSL_alt"))
            && (null == ncfile.findDimension("time"))) {
      return false;
    }
    // if (null == ncfile.findGlobalAttribute( "start_time")) return false;
    // if (null == ncfile.findGlobalAttribute( "stop_time")) return false;

    String center = ncfile.findAttValueIgnoreCase(null, "center", null);
    return (center != null) && center.equals("UCAR/CDAAC");
  }

  /**
   * _more_
   */
  public Cosmic1Convention() {
    this.conventionName = "Cosmic1";
  }

  /**
   * _more_
   *
   * @param ds         _more_
   * @param cancelTask _more_
   * @throws IOException _more_
   */
  public void augmentDataset(NetcdfDataset ds,
                             CancelTask cancelTask) throws IOException {

    Attribute leoAtt = ds.findGlobalAttribute("leoId");

    if (leoAtt == null) {
      if (ds.findVariable("time") == null) {
        // create a time variable - assume its linear along the vertical dimension
        double start = ds.readAttributeDouble(null, "start_time",
                Double.NaN);
        double stop = ds.readAttributeDouble(null, "stop_time",
                Double.NaN);

        if (Double.isNaN(start) && Double.isNaN(stop)) {
          double top = ds.readAttributeDouble(null, "toptime",
                  Double.NaN);
          double bot = ds.readAttributeDouble(null, "bottime",
                  Double.NaN);

          this.conventionName = "Cosmic2";
          if (top > bot) {
            stop = top;
            start = bot;
          } else {
            stop = bot;
            start = top;
          }

        }

        Dimension dim = ds.findDimension("MSL_alt");
        Variable dimV = ds.findVariable("MSL_alt");
        Array dimU = dimV.read();
        int inscr = (dimU.getFloat(1) - dimU.getFloat(0)) > 0
                ? 1
                : 0;
        int n = dim.getLength();
        double incr = (stop - start) / n;

        String timeUnits = "seconds since 1980-01-06 00:00:00";
        Variable timeVar = new VariableDS(ds, null, null, "time",
                DataType.DOUBLE, dim.getShortName(),
                timeUnits, null);
        ds.addVariable(null, timeVar);
        timeVar.addAttribute(new Attribute(CDM.UNITS, timeUnits));
        timeVar.addAttribute(new Attribute(_Coordinate.AxisType,
                AxisType.Time.toString()));
        int dir = ds.readAttributeInteger(null, "irs", 1);
        ArrayDouble.D1 data =
                (ArrayDouble.D1) Array.factory(DataType.DOUBLE,
                        new int[]{n});
        if (inscr == 0) {
          if (dir == 1) {
            for (int i = 0; i < n; i++) {
              data.set(i, start + i * incr);
            }
          } else {
            for (int i = 0; i < n; i++) {
              data.set(i, stop - i * incr);
            }
          }
        } else {
          for (int i = 0; i < n; i++) {
            data.set(i, stop - i * incr);
          }
        }
        timeVar.setCachedData(data, false);
      }

      Variable v = ds.findVariable("Lat");
      if (v == null) {
        v = ds.findVariable("GEO_lat");
      }
      v.addAttribute(new Attribute(_Coordinate.AxisType,
              AxisType.Lat.toString()));
      Variable v1 = ds.findVariable("Lon");
      if (v1 == null) {
        v1 = ds.findVariable("GEO_lon");
      }
      v1.addAttribute(new Attribute(_Coordinate.AxisType,
              AxisType.Lon.toString()));
    } else {
      Dimension dim = ds.findDimension("time");
      int n = dim.getLength();
      Variable latVar = new VariableDS(ds, null, null, "Lat",
              DataType.FLOAT, dim.getShortName(),
              "degree", null);
      latVar.addAttribute(new Attribute(_Coordinate.AxisType,
              AxisType.Lat.toString()));
      ds.addVariable(null, latVar);
      Variable lonVar = new VariableDS(ds, null, null, "Lon",
              DataType.FLOAT, dim.getShortName(),
              "degree", null);
      lonVar.addAttribute(new Attribute(_Coordinate.AxisType,
              AxisType.Lon.toString()));
      ds.addVariable(null, lonVar);
      Variable altVar = new VariableDS(ds, null, null, "MSL_alt",
              DataType.FLOAT, dim.getShortName(),
              "meter", null);
      altVar.addAttribute(new Attribute(_Coordinate.AxisType,
              AxisType.Height.toString()));
      ds.addVariable(null, altVar);

      // cal data array
      ArrayFloat.D1 latData =
              (ArrayFloat.D1) Array.factory(DataType.FLOAT,
                      new int[]{n});
      ArrayFloat.D1 lonData =
              (ArrayFloat.D1) Array.factory(DataType.FLOAT,
                      new int[]{n});
      ArrayFloat.D1 altData =
              (ArrayFloat.D1) Array.factory(DataType.FLOAT,
                      new int[]{n});
      ArrayDouble.D1 timeData =
              (ArrayDouble.D1) Array.factory(DataType.DOUBLE,
                      new int[]{n});
      this.conventionName = "Cosmic3";

      int iyr = ds.readAttributeInteger(null, "year", 2009);
      int mon = ds.readAttributeInteger(null, "month", 0);
      int iday = ds.readAttributeInteger(null, "day", 0);
      int ihr = ds.readAttributeInteger(null, "hour", 0);
      int min = ds.readAttributeInteger(null, "minute", 0);
      int sec = ds.readAttributeInteger(null, "second", 0);

      double start = ds.readAttributeDouble(null, "startTime",
              Double.NaN);
      double stop = ds.readAttributeDouble(null, "stopTime",
              Double.NaN);
      double incr = (stop - start) / n;
      int t = 0;
      // double julian = juday(mon, iday, iyr);
      // cal the dtheta based pm attributes
      double dtheta = gast(iyr, mon, iday, ihr, min, sec, t);

      Variable tVar = ds.findVariable("time");
      String timeUnits = "seconds since 1980-01-06 00:00:00";  //dtime.getUnit().toString();
      tVar.removeAttributeIgnoreCase(CDM.VALID_RANGE);
      tVar.removeAttributeIgnoreCase(CDM.UNITS);
      tVar.addAttribute(new Attribute(CDM.UNITS, timeUnits));
      tVar.addAttribute(new Attribute(_Coordinate.AxisType,
              AxisType.Time.toString()));

      Variable v = ds.findVariable("xLeo");
      Array xLeo = v.read();
      v = ds.findVariable("yLeo");
      Array yLeo = v.read();
      v = ds.findVariable("zLeo");
      Array zLeo = v.read();
      double a = 6378.1370;
      double b = 6356.7523142;
      IndexIterator iiter0 = xLeo.getIndexIterator();
      IndexIterator iiter1 = yLeo.getIndexIterator();
      IndexIterator iiter2 = zLeo.getIndexIterator();
      int i = 0;

      while (iiter0.hasNext()) {

        double[] v_inertial = new double[3];
        v_inertial[0] = iiter0.getDoubleNext();  //.getDouble(i); //.nextDouble();
        v_inertial[1] = iiter1.getDoubleNext();  //.getDouble(i); //.nextDouble();
        v_inertial[2] = iiter2.getDoubleNext();  //.getDouble(i); //.nextDouble();
        double[] uvz = new double[3];
        uvz[0] = 0.0;
        uvz[1] = 0.0;
        uvz[2] = 1.0;
        // v_ecef should be in the (approximate) ECEF frame

        // double[] v_ecf = execute(v_inertial, julian);
        double[] v_ecf = spin(v_inertial, uvz, -1 * dtheta);

        // cal lat/lon here
        // double [] llh = ECFtoLLA(v_ecf[0]*1000, v_ecf[1]*1000, v_ecf[2]*1000, a,  b);
        double[] llh = xyzell(a, b, v_ecf);
        latData.set(i, (float) llh[0]);
        lonData.set(i, (float) llh[1]);
        altData.set(i, (float) llh[2]);
        timeData.set(i, start + i * incr);
        i++;
      }

      latVar.setCachedData(latData, false);
      lonVar.setCachedData(lonData, false);
      altVar.setCachedData(altData, false);
      tVar.setCachedData(timeData, false);
    }
    ds.finish();

  }

  /* private DateTime getDateTime(int year, int month, int day, int hour,
                               int min, int sec) throws Exception {
    GregorianCalendar convertCal =
            new GregorianCalendar(DateUtil.TIMEZONE_GMT);
    convertCal.clear();
    convertCal.set(Calendar.YEAR, year);
    //The MONTH is 0 based. The incoming month is 1 based
    convertCal.set(Calendar.MONTH, month - 1);
    convertCal.set(Calendar.DAY_OF_MONTH, day);
    convertCal.set(Calendar.HOUR_OF_DAY, hour);
    convertCal.set(Calendar.MINUTE, min);
    convertCal.set(Calendar.SECOND, sec);
    return new DateTime(convertCal.getTime());
  }  */

  /**
   * _more_
   *
   * @param ncDataset _more_
   * @param v         _more_
   * @return _more_
   */
  protected AxisType getAxisType(NetcdfDataset ncDataset,
                                 VariableEnhanced v) {
    String name = v.getShortName();
    if (name.equals("time")) {
      return AxisType.Time;
    }
    if (name.equals("Lat") || name.equals("GEO_lat")) {
      return AxisType.Lat;
    }
    if (name.equals("Lon") || name.equals("GEO_lon")) {
      return AxisType.Lon;
    }
    // if (name.equals("xLeo") ) return AxisType.GeoX;
    // if (name.equals("yLeo") ) return AxisType.GeoY;
    if (name.equals("MSL_alt")) {
      return AxisType.Height;
    }
    return null;
  }

  /**
   * NAME       :  XYZELL
   * 

* CALL XYZELL(A,B,XSTAT,XSTELL) *

* PURPOSE : COMPUTATION OF ELLIPSOIDAL COORDINATES "XSTELL" * GIVEN THE CARTESIAN COORDINATES "XSTAT" *

* PARAMETERS : * IN : A : SEMI-MAJOR AXIS OF THE REFERENCE R*8 * ELLIPSOID IN METERS * B : SEMI-MINOR AXIS OF THE REFERENCE R*8 * ELLIPSOID IN METERS * DXELL(3): TRANSLATION COMPONENTS FROM THE R*8 * ORIGIN OF THE CART. COORD. SYSTEM * (X,Y,Z) TO THE CENTER OF THE REF. * ELLIPSOID (IN METRES) * SCELL : SCALE FACTOR BETWEEN REF. ELLIPSOID R*8 * AND WGS-84 * XSTAT(3): CARTESIAN COORDINATES (M) R*8 * OUT : XSTELL(3): ELLIPSOIDAL COORDINATES R*8 * XSTELL(1): ELL. LATITUDE (RADIAN) * XSTELL(2): ELL. LONGITUDE (RADIAN) * XSTELL(3): ELL. HEIGHT (M) *

* SR CALLED : DMLMTV *

* REMARKS : --- *

* AUTHOR : M. ROTHACHER *

* VERSION : 3.4 (JAN 93) *

* CREATED : 87/11/03 12:32 LAST MODIFIED : 88/11/21 17:36 *

* COPYRIGHT : ASTRONOMICAL INSTITUTE * 1987 UNIVERSITY OF BERNE * SWITZERLAND * * @param a _more_ * @param b _more_ * @param xstat _more_ * @return _more_ */ public double[] xyzell(double a, double b, double[] xstat) { double[] xstell = new double[3]; double e2, s, rlam, zps, h, phi, n, hp, phip; int i, niter; e2 = (a * a - b * b) / (a * a); s = Math.sqrt(xstat[0] * xstat[0] + xstat[1] * xstat[1]); rlam = Math.atan2(xstat[1], xstat[0]); zps = xstat[2] / s; h = Math.sqrt(xstat[0] * xstat[0] + xstat[1] * xstat[1] + xstat[2] * xstat[2]) - a; phi = Math.atan(zps / (1.0 - e2 * a / (a + h))); niter = 0; for (i = 1; i <= 10000000; i++) { n = a / Math.sqrt(1.0 - e2 * Math.sin(phi) * Math.sin(phi)); hp = h; phip = phi; h = s / Math.cos(phi) - n; phi = Math.atan(zps / (1.0 - e2 * n / (n + h))); niter = niter + 1; if ((Math.abs(phip - phi) <= 1.e-11) && (Math.abs(hp - h) <= 1.e-5)) { break; } if (niter >= 10) { phi = -999.0; rlam = -999.0; h = -999.0; break; } } xstell[0] = phi * 180 / 3.1415926; xstell[1] = rlam * 180 / 3.1415926; xstell[2] = h; return xstell; } /** * gast.f * Compute hour angle dtheta * * ! iyr, mon, iday, ihr, min and sec form a base (epoch) time, * ! t is an offset from the base time in seconds * ! dtheta is the output hour angle in radians * * Calculation of local time * * ! glon -- East longitude in degrees, -180 to 180 * * * call vprod.f spin.f rnorm.f * Calculation of the unit vector normal to the occultation plane * (clockwise rotated from GPS to LEO) * * @param iyr _more_ * @param imon _more_ * @param iday _more_ * @param ihr _more_ * @param imin _more_ * @param sec _more_ * @param dsec _more_ * * @return _more_ */ /* double dtheta = gast(iyr,mon,iday,ihr,min,sec,t) utc=ihr*1.d0+min/60.d0 timloc=utc+24.d0*glon/360.d0 if (timloc.gt.24.d0) timloc=timloc-24.d0 if (timloc.lt.0.d0) timloc=timloc+24.d0 */ // In the inertial reference frame /* v_inertial(1)= ! Inertial GPS position vectors, XYZ v_inertial(2)= v_inertial(3)= */ // In the Earth-fixed reference frame // Z axis to rotate around (unit vector Z) /* uvz(1)=0.0; uvz(2)=0.0; uvz(3)=1.0; double [] v_ecf = spin(v_inertial,uvz,-180.d0*dtheta/pi) */ // after this call, v_ecef should be in the (approximate) ECEF frame /** * ---------------------------------------------------------------------- * gast.f *

* This subroutine computes the Greenwich Apparent Siderial * Time angle given a UTC date and time. *

* parameter Input parameters: * Inputs: * * @param iyr integer year 1995 * @param imon integer month 5 * @param iday integer day 5 * @param ihr integer hour 5 * @param imin integer minute 5 * @param sec double second 31.0 * @param dsec double second 0.0 * Outputs: * @return theta GAST angle in radians *

* author Bill Schreiner * @since May 1995 * version $URL: svn://ursa.cosmic.ucar.edu/trunk/src/roam/gast.f $ $Id: gast.f 10129 2008-07-30 17:10:52Z dhunt $ * ----------------------------------------------------------------------- */ public double gast(int iyr, int imon, int iday, int ihr, int imin, double sec, double dsec) { // // implicit double precision (a-h,o-z) // character(len=*), parameter :: header = '$URL: svn://ursa.cosmic.ucar.edu/trunk/src/roam/gast.f $ $Id: gast.f 10129 2008-07-30 17:10:52Z dhunt $' // // Coordinate transform from the celestial inertial reference frame to the geo- // centered Greenwich reference frame. // Call a subroutine to calculate the Julian day "djd": double djd = juday(imon, iday, iyr); //djd=julean day. double tu = (djd - 2451545.0) / 36525.0; double gmst = 24110.548410 + 8640184.8128660 * tu + 0.093104 * tu * tu - 6.2E-6 * Math.pow(tu, 3); // !gmst=Greenwich mean... double utco = (ihr * 3600) + (imin * 60) + sec; return togreenw(dsec, utco, gmst); } /** * JDAY calculates the Julian Day number (JD) from the Gregorian month * ,day, and year (M,D,Y). (NOT VALID BEFORE 10/15/1582) * * @param M _more_ * @param D _more_ * @param Y _more_ * @return _more_ */ public double juday(int M, int D, int Y) { double JD; double IY = Y - (12 - M) / 10; double IM = M + 1 + 12 * ((12 - M) / 10); double I = IY / 100; double J = 2 - I + I / 4 + Math.round(365.25 * IY) + Math.round(30.6001 * IM); JD = (J + D + 1720994.50); return JD; } /** * This subroutine is to transform the locations and velocities of the GPS and * LEO satellites from the celestial inertial reference frame to the Earth * centered Greenwich reference frame. * The dummy arguments iyear, month and iday are the calender year, month and * day of the occultation event. The dummy arguments ihour, minute and sec * are the UTC time. * Reference: Astronomical Alamanus, 1993 *

* Modified subroutine from Dasheng's code. * * @param rectt _more_ * @param utco _more_ * @param gmst _more_ * @return _more_ */ public double togreenw(double rectt, double utco, double gmst) { double pi = Math.acos(-1.00); // // For each occultation ID, its TU and GMST are the same. However, every // occultation event takes place at gmst+uts, uts is progressively increasing // with every occultation event. double utc = (utco + rectt) * 1.0027379093; gmst = gmst + utc; //in seconds, without eoe correction. // gmst may be a positive number or may be a negative number. while (gmst < 0.0) { gmst = gmst + 86400.00; } while (gmst > 86400.00) { gmst = gmst - 86400.00; } // gmst = the Greenwich mean sidereal time. // This gmst is without the corrections from the equation of equinoxes. For // GPS/MET applications, the corrections from equation of equinoxes is not // necessary because of the accurary needed. return gmst * 2.0 * pi / 86400.0; //!*** This is the THETA in radian. } /** * ---------------------------------------------------------------------- * file spin.f *

* This subroutine rotates vector V1 around vector VS * at angle A. V2 is the vector after the rotation. *

*

* parameter Input parameters: * v1 - Vector to be rotated * vs - Vector around which to rotate v1 * a - angle of rotation * Output parameters: * v2 - output vector *

* S.V.Sokolovskiy * URL: svn://ursa.cosmic.ucar.edu/trunk/src/roam/spin.f $ $Id: spin.f 10129 2008-07-30 17:10:52Z dhunt $ * ----------------------------------------------------------------------- * * @param v1 - Vector to be rotated * @param vs - Vector around which to rotate v1 * @param a - angle of rotation * @return _more_ */ public double[] spin(double[] v1, double[] vs, double a) { // implicit real*8(a-h,o-z) // dimension v1(3),vs(3),vsn(3),v2(3),v3(3),s(3,3) // Calculation of the unit vector around which // the rotation should be done. double[] v2 = new double[3]; double[] vsn = new double[3]; double[] v3 = new double[3]; double vsabs = Math.sqrt(vs[0] * vs[0] + vs[1] * vs[1] + vs[2] * vs[2]); for (int i = 0; i < 3; i++) { vsn[i] = vs[i] / vsabs; } // Calculation of the rotation matrix. double a1 = Math.cos(a); double a2 = 1.0 - a1; double a3 = Math.sin(a); double[][] s = new double[3][3]; s[0][0] = a2 * vsn[0] * vsn[0] + a1; s[0][1] = a2 * vsn[0] * vsn[1] - a3 * vsn[2]; s[0][2] = a2 * vsn[0] * vsn[2] + a3 * vsn[1]; s[1][0] = a2 * vsn[1] * vsn[0] + a3 * vsn[2]; s[1][1] = a2 * vsn[1] * vsn[1] + a1; s[1][2] = a2 * vsn[1] * vsn[2] - a3 * vsn[0]; s[2][0] = a2 * vsn[2] * vsn[0] - a3 * vsn[1]; s[2][1] = a2 * vsn[2] * vsn[1] + a3 * vsn[0]; s[2][2] = a2 * vsn[2] * vsn[2] + a1; // Calculation of the rotated vector. for (int i = 0; i < 3; i++) { v3[i] = s[i][0] * v1[0] + s[i][1] * v1[1] + s[i][2] * v1[2]; } System.arraycopy(v3, 0, v2, 0, 3); return v2; } /** * _more_ */ protected final static double RTD = 180. / Math.PI; /** * _more_ */ protected final static double DTR = Math.PI / 180.; /** * _more_ * * @param eci _more_ * @param julian _more_ * @return _more_ */ public double[] execute(double[] eci, double julian) { double Xi = eci[0]; double Yi = eci[1]; double Zi = eci[2]; double c, s; double GHA; double[] ecef = new double[3]; //Compute GHAD /* System generated locals */ double d__1, d__2, d__3; /* Local variables */ double tsec, tday, gmst, t, omega, tfrac, tu, dat; /* INPUT IS TIME "secondsSince1970" IN SECONDS AND "TDAY" */ /* WHICH IS WHOLE DAYS FROM 1970 JAN 1 0H */ /* THE OUTPUT IS GREENWICH HOUR ANGLE IN DEGREES */ /* XOMEGA IS ROTATION RATE IN DEGREES/SEC */ /* FOR COMPATABILITY */ tday = (double) ((int) (julian / 86400.)); tsec = julian - tday * 86400; /* THE NUMBER OF DAYS FROM THE J2000 EPOCH */ /* TO 1970 JAN 1 0H UT1 IS -10957.5 */ t = tday - (float) 10957.5; tfrac = tsec / 86400.; dat = t; tu = dat / 36525.; /* Computing 2nd power */ d__1 = tu; /* Computing 3rd power */ d__2 = tu; d__3 = d__2; gmst = tu * 8640184.812866 + 24110.54841 + d__1 * d__1 * .093104 - d__3 * (d__2 * d__2) * 6.2e-6; /* COMPUTE THE EARTH'S ROTATION RATE */ /* Computing 2nd power */ d__1 = tu; omega = tu * 5.098097e-6 + 86636.55536790872 - d__1 * d__1 * 5.09e-10; /* COMPUTE THE GMST AND GHA */ // da is earth nutation - currently unused double da = 0.0; gmst = gmst + omega * tfrac + da * RTD * 86400. / 360.; gmst = gmst % 86400; if (gmst < 0.) { gmst += 86400.; } gmst = gmst / 86400. * 360.; //ghan = gmst; // returns gha in radians gmst = gmst * DTR; GHA = gmst; //RotateZ c = Math.cos(GHA); s = Math.sin(GHA); double X = c * Xi + s * Yi; double Y = -s * Xi + c * Yi; //Set outputs ecef[0] = X; ecef[1] = Y; ecef[2] = Zi; return ecef; } /** * comparing api to others * * @param x _more_ * @param y _more_ * @param z _more_ * @param a _more_ * @param b _more_ * @return _more_ */ public static double[] ECFtoLLA(double x, double y, double z, double a, double b) { double longitude = Math.atan2(y, x); double ePrimeSquared = (a * a - b * b) / (b * b); double p = Math.sqrt(x * x + y * y); double theta = Math.atan((z * a) / (p * b)); double sineTheta = Math.sin(theta); double cosTheta = Math.cos(theta); double f = 1 / 298.257223563; double e2 = 2 * f - f * f; double top = z + ePrimeSquared * b * sineTheta * sineTheta * sineTheta; double bottom = p - e2 * a * cosTheta * cosTheta * cosTheta; double geodeticLat = Math.atan(top / bottom); double sineLat = Math.sin(geodeticLat); double N = a / Math.sqrt(1 - e2 * sineLat * sineLat); double altitude = (p / Math.cos(geodeticLat)) - N; // maintain longitude btw -PI and PI if (longitude > Math.PI) { longitude -= 2 * Math.PI; } else if (longitude < -Math.PI) { longitude += 2 * Math.PI; } return new double[]{geodeticLat, longitude, altitude}; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy