Пример #1
0
    def __calcFromReference(self, planet, r, pclat=90.0, delta_lng=0.0):
        if isinstance(self.referenceGeoid, bool):
            print('Calculating reference geoid at P_ref={}'.format(planet.config.p_ref))
            self.referenceRadius = planet.config.Req
            self.__calcGeoid(planet, planet.config.Req, 90, 0.0)
            self.referenceGeoid = np.array(self.referenceGeoid)
        rlat = np.interp(pclat, self.referenceGeoid[:, 0], self.referenceGeoid[:, 1]) * (r / self.referenceRadius)
        gamma = np.interp(pclat, self.referenceGeoid[:, 0], self.referenceGeoid[:, 2])

        lat = u.d2r(pclat)
        lng = u.d2r(delta_lng)
        norm = np.array([0.0, math.sin(lat + gamma), math.cos(lat + gamma)])
        norm = rotY(lng, norm)
        tang = np.array([0.0, math.cos(lat + gamma), -math.sin(lat + gamma)])
        tang = rotY(lng, tang)
        r_vec = np.array([0.0, rlat * math.sin(lat), rlat * math.cos(lat)])
        r_vec = rotY(lng, r_vec)
        self.gamma = gamma
        self.pclat = lat
        self.pglat = lat + gamma
        self.delta_lng = lng
        self.r = r_vec
        self.rmag = np.linalg.norm(r_vec)
        self.n = norm
        self.t = tang
        self.g = [0.0, 0.0]
        self.gmag = 0.0

        if self.saveShape:  # This is here to fake saveShape to act like __calcGeoid
            plot_latstep = 0.1  # can't be as small as gravcalc since too many recursions
            self.saveShape.append(list(self.r))
            pclat -= plot_latstep
            if pclat > 0.0:
                self.__calcFromReference(planet, r, pclat, delta_lng)
        return self.rmag
Пример #2
0
    def __calcGeoid(self, planet, r, pclat, delta_lng):
        """Starts at equatorial radius and moves north or south to compute geoid at pclat"""
        self.calcCounter += 1
        print('Geoid calc counter: ', self.calcCounter)

        if pclat == 0.0:
            nsp = 1.0
        else:
            nsp = np.sign(pclat)
        latstep = nsp * self.gravcalc_latstep
        pclatSteps = np.arange(0.0, pclat + latstep, latstep)

        if self.gtype == 'reference' and type(self.referenceGeoid) == bool:
            self.referenceGeoid = []

        GM = np.interp(r, planet.layerProperty[planet.config.LP['R']],
                       planet.layerProperty[planet.config.LP['GM']])
        for latv in pclatSteps:
            radlatv = u.d2r(latv)
            vw = np.interp(latv, planet.config.vwlat,
                           planet.config.vwdat) / 1000.0
            self.omega = planet.config.omega_m + vw / (r * np.cos(radlatv))
            self.__gravity__(latv, delta_lng, r, GM, self.omega,
                             planet.config.Jn, planet.config.RJ)
            dlat = u.d2r(latstep)
            dr_vec = r * dlat * self.t
            r_vec = self.r + dr_vec
            r = np.linalg.norm(r_vec)
            if self.gtype == 'reference':
                self.referenceGeoid.append([latv, r, self.gamma])
            if self.saveShape:
                self.saveShape.append(list(self.r))
        del pclatSteps
        return self.rmag
Пример #3
0
    def __calcGeoid(self, planet, r, pclat, delta_lng):
        """Starts at equatorial radius and moves north or south to compute geoid at pclat"""
        self.calcCounter += 1
        print('Geoid calc counter: ', self.calcCounter)

        if pclat == 0.0:
            nsp = 1.0
        else:
            nsp = np.sign(pclat)
        latstep = nsp * self.gravcalc_latstep
        pclatSteps = np.arange(0.0, pclat + latstep, latstep)

        if self.gtype == 'reference' and type(self.referenceGeoid) == bool:
            self.referenceGeoid = []

        GM = np.interp(r, planet.layerProperty[planet.config.LP['R']], planet.layerProperty[planet.config.LP['GM']])
        for latv in pclatSteps:
            radlatv = u.d2r(latv)
            vw = np.interp(latv, planet.config.vwlat, planet.config.vwdat) / 1000.0
            self.omega = planet.config.omega_m + vw / (r * np.cos(radlatv))
            self.__gravity__(latv, delta_lng, r, GM, self.omega, planet.config.Jn, planet.config.RJ)
            dlat = u.d2r(latstep)
            dr_vec = r * dlat * self.t
            r_vec = self.r + dr_vec
            r = np.linalg.norm(r_vec)
            if self.gtype == 'reference':
                self.referenceGeoid.append([latv, r, self.gamma])
            if self.saveShape:
                self.saveShape.append(list(self.r))
        del pclatSteps
        return self.rmag
Пример #4
0
    def __calcEllipse(self, planet, r, pclat, delta_lng):
        a = r
        if self.gtype == 'ellipse':
            b = (planet.config.Rpol / planet.config.Req) * r
        else:
            b = r
        lat = u.d2r(pclat)
        lng = u.d2r(delta_lng)
        if lat == 0.0:
            nsl = 1.0
            lat = 1.0E-6
        else:
            nsl = np.sign(lat)

        norm = np.array([0.0, a * math.sin(lat), b * math.cos(lat)])
        norm = norm / np.linalg.norm(norm)
        norm = rotY(lng, norm)
        tang = np.array([0.0, -b * math.cos(lat), a * math.sin(lat)])
        tang = tang / np.linalg.norm(tang)
        tang = rotY(lng, tang)
        r_vec = np.array([0.0, b * math.sin(lat), a * math.cos(lat)])
        r_vec = rotY(lng, r_vec)
        self.rmag = np.linalg.norm(r_vec)
        GM = np.interp(r, planet.layerProperty[planet.config.LP['R']],
                       planet.layerProperty[planet.config.LP['GM']])
        self.g_static = GM / self.rmag**2
        try:
            self.gamma = nsl * math.acos(
                np.dot(r_vec, norm) / self.rmag
            )  # don't need to worry about direction here, since norm etc defined
        except ValueError:
            arg = np.dot(r_vec, norm) / self.rmag
            print('gamma warning (%s):  [{:.2f},{:.2f},{:.2f},{:.2f}]'.format(
                self.gtype, arg, a, b, pclat),
                  end='')
            print('...but proceeding anyway by setting gamma=0.0')
            self.gamma = 0.0
        self.pclat = lat
        self.pglat = lat + self.gamma
        self.delta_lng = lng
        self.r = r_vec
        self.n = norm
        self.t = tang
        self.g = [self.g_static, self.g_static]
        self.gmag = self.g_static

        if self.saveShape:  # This is here to fake saveShape to act like __calcGeoid
            plot_latstep = 0.1  # can't be as small as gravcalc since too many recursions
            self.saveShape.append(list(self.r))
            pclat -= plot_latstep
            if pclat > 0.0:
                self.__calcEllipse(planet, r, pclat, delta_lng)

        return self.rmag
Пример #5
0
    def __calcEllipse(self, planet, r, pclat, delta_lng):
        a = r
        if self.gtype == 'ellipse':
            b = (planet.config.Rpol / planet.config.Req) * r
        else:
            b = r
        lat = u.d2r(pclat)
        lng = u.d2r(delta_lng)
        if lat == 0.0:
            nsl = 1.0
            lat = 1.0E-6
        else:
            nsl = np.sign(lat)

        norm = np.array([0.0, a * math.sin(lat), b * math.cos(lat)])
        norm = norm / np.linalg.norm(norm)
        norm = rotY(lng, norm)
        tang = np.array([0.0, -b * math.cos(lat), a * math.sin(lat)])
        tang = tang / np.linalg.norm(tang)
        tang = rotY(lng, tang)
        r_vec = np.array([0.0, b * math.sin(lat), a * math.cos(lat)])
        r_vec = rotY(lng, r_vec)
        self.rmag = np.linalg.norm(r_vec)
        GM = np.interp(r, planet.layerProperty[planet.config.LP['R']], planet.layerProperty[planet.config.LP['GM']])
        self.g_static = GM / self.rmag**2
        try:
            self.gamma = nsl * math.acos(np.dot(r_vec, norm) / self.rmag)  # don't need to worry about direction here, since norm etc defined
        except ValueError:
            arg = np.dot(r_vec, norm) / self.rmag
            print('gamma warning (%s):  [{:.2f},{:.2f},{:.2f},{:.2f}]'.format(self.gtype, arg, a, b, pclat), end='')
            print('...but proceeding anyway by setting gamma=0.0')
            self.gamma = 0.0
        self.pclat = lat
        self.pglat = lat + self.gamma
        self.delta_lng = lng
        self.r = r_vec
        self.n = norm
        self.t = tang
        self.g = [self.g_static, self.g_static]
        self.gmag = self.g_static

        if self.saveShape:  # This is here to fake saveShape to act like __calcGeoid
            plot_latstep = 0.1  # can't be as small as gravcalc since too many recursions
            self.saveShape.append(list(self.r))
            pclat -= plot_latstep
            if pclat > 0.0:
                self.__calcEllipse(planet, r, pclat, delta_lng)

        return self.rmag
Пример #6
0
 def __gravity__(self, pclat, delta_lng, r, GM, omega, Jn, RJ):
     self.g_static = GM / r**2
     lat = u.d2r(pclat)
     lng = u.d2r(delta_lng)
     if lat == 0.0:
         nsl = 1.0
     else:
         nsl = np.sign(lat)
     dphi = nsl * 0.00001
     Sr = 0.0
     Sp = 0.0
     sp = np.sin(lat)
     sp1 = np.sin(lat + dphi)
     sp0 = np.sin(lat - dphi)
     for i in range(len(Jn)):
         # g(r)
         Sr += (i + 1.0) * Jn[i] * pow(RJ / r, i) * scisp.legendre(i)(sp)
         # g(phi)
         dP = (scisp.legendre(i)(sp1) - scisp.legendre(i)(sp)) / dphi
         dP += (scisp.legendre(i)(sp) - scisp.legendre(i)(sp0)) / dphi
         dP *= 0.5
         Sp += Jn[i] * pow(RJ / r, i) * dP
     # g(r)
     gr = self.g_static * (1.0 - Sr) - (2.0 / 3.0) * (omega**2.0) * r * (
         1.0 - scisp.legendre(2)(sp))
     # g(phi)
     dP = (3.0 * sp * np.sqrt(1.0 - sp**2))
     gp = (1.0 / 3.0) * (omega**2.0) * r * dP + self.g_static * Sp
     gt = math.sqrt(gr**2 + gp**2)
     # geoid
     gamma = math.atan2(gp, gr)
     norm = np.array([0.0, math.sin(lat + gamma), math.cos(lat + gamma)])
     norm = rotY(lng, norm)
     tang = np.array([0.0, math.cos(lat + gamma), -math.sin(lat + gamma)])
     tang = rotY(lng, tang)
     r_vec = np.array([0.0, r * math.sin(lat), r * math.cos(lat)])
     r_vec = rotY(lng, r_vec)
     self.gamma = gamma
     self.pclat = lat
     self.pglat = lat + gamma
     self.delta_lng = lng
     self.r = r_vec
     self.rmag = np.linalg.norm(r_vec)
     self.n = norm
     self.t = tang
     self.g = [gr, gp]
     self.gmag = gt
Пример #7
0
 def __gravity__(self, pclat, delta_lng, r, GM, omega, Jn, RJ):
     self.g_static = GM / r**2
     lat = u.d2r(pclat)
     lng = u.d2r(delta_lng)
     if lat == 0.0:
         nsl = 1.0
     else:
         nsl = np.sign(lat)
     dphi = nsl * 0.00001
     Sr = 0.0
     Sp = 0.0
     sp = np.sin(lat)
     sp1 = np.sin(lat + dphi)
     sp0 = np.sin(lat - dphi)
     for i in range(len(Jn)):
         # g(r)
         Sr += (i + 1.0) * Jn[i] * pow(RJ / r, i) * scisp.legendre(i)(sp)
         # g(phi)
         dP = (scisp.legendre(i)(sp1) - scisp.legendre(i)(sp)) / dphi
         dP += (scisp.legendre(i)(sp) - scisp.legendre(i)(sp0)) / dphi
         dP *= 0.5
         Sp += Jn[i] * pow(RJ / r, i) * dP
     # g(r)
     gr = self.g_static * (1.0 - Sr) - (2.0 / 3.0) * (omega**2.0) * r * (1.0 - scisp.legendre(2)(sp))
     # g(phi)
     dP = (3.0 * sp * np.sqrt(1.0 - sp**2))
     gp = (1.0 / 3.0) * (omega**2.0) * r * dP + self.g_static * Sp
     gt = math.sqrt(gr**2 + gp**2)
     # geoid
     gamma = math.atan2(gp, gr)
     norm = np.array([0.0, math.sin(lat + gamma), math.cos(lat + gamma)])
     norm = rotY(lng, norm)
     tang = np.array([0.0, math.cos(lat + gamma), -math.sin(lat + gamma)])
     tang = rotY(lng, tang)
     r_vec = np.array([0.0, r * math.sin(lat), r * math.cos(lat)])
     r_vec = rotY(lng, r_vec)
     self.gamma = gamma
     self.pclat = lat
     self.pglat = lat + gamma
     self.delta_lng = lng
     self.r = r_vec
     self.rmag = np.linalg.norm(r_vec)
     self.n = norm
     self.t = tang
     self.g = [gr, gp]
     self.gmag = gt
Пример #8
0
    def __calcFromReference(self, planet, r, pclat=90.0, delta_lng=0.0):
        if type(self.referenceGeoid) == bool:
            print('Calculating reference geoid at P_ref={}'.format(
                planet.config.p_ref))
            self.referenceRadius = planet.config.Req
            self.__calcGeoid(planet, planet.config.Req, 90, 0.0)
            self.referenceGeoid = np.array(self.referenceGeoid)
        rlat = np.interp(pclat, self.referenceGeoid[:, 0],
                         self.referenceGeoid[:,
                                             1]) * (r / self.referenceRadius)
        gamma = np.interp(pclat, self.referenceGeoid[:, 0],
                          self.referenceGeoid[:, 2])

        lat = u.d2r(pclat)
        lng = u.d2r(delta_lng)
        norm = np.array([0.0, math.sin(lat + gamma), math.cos(lat + gamma)])
        norm = rotY(lng, norm)
        tang = np.array([0.0, math.cos(lat + gamma), -math.sin(lat + gamma)])
        tang = rotY(lng, tang)
        r_vec = np.array([0.0, rlat * math.sin(lat), rlat * math.cos(lat)])
        r_vec = rotY(lng, r_vec)
        self.gamma = gamma
        self.pclat = lat
        self.pglat = lat + gamma
        self.delta_lng = lng
        self.r = r_vec
        self.rmag = np.linalg.norm(r_vec)
        self.n = norm
        self.t = tang
        self.g = [0.0, 0.0]
        self.gmag = 0.0

        if self.saveShape:  # This is here to fake saveShape to act like __calcGeoid
            plot_latstep = 0.1  # can't be as small as gravcalc since too many recursions
            self.saveShape.append(list(self.r))
            pclat -= plot_latstep
            if pclat > 0.0:
                self.__calcFromReference(planet, r, pclat, delta_lng)
        return self.rmag
Пример #9
0
def compute_ds(atm, b, orientation=None, gtype=None, verbose=False, plot=True):
    """Computes the path length through the atmosphere given:
            b = impact parameter (fractional distance to outer edge at that latitude in observer's coordinates)
            orientation = position angle of the planet [0]='tip', [1]='subearth latitude' """
    if gtype is None:
        gtype = atm.config.gtype
    if orientation is None:
        orientation = atm.config.orientation
    path = Ray()
    req = atm.layerProperty[atm.config.LP['R']]   # radius of layers along equator
    rNorm = req[0]
    nr = atm.layerProperty[atm.config.LP['N']]    # refractive index of layers
    P = atm.gas[atm.config.C['P']]
    if (b[0]**2 + b[1]**2) > 1.0:
        return path

    mu = math.sqrt(1.0 - b[0]**2 - b[1]**2)

    f = 1.0 - atm.config.Rpol / atm.config.Req
    tip, rotate = computeAspect(orientation, f)
    if verbose:
        print('intersection:  ({:.3f}, {:.3f})    '.format(b[0], b[1]), end='')
        print('aspect:  ({:%.4f},  {:.4f})'.format(tip * 180.0 / np.pi, rotate * 180.0 / np.pi))
        print('Finding atmospheric edge', end='')
    edge, b = findEdge(atm, b, rNorm, tip, rotate, gtype)
    if edge is None:
        return path
    r1 = np.linalg.norm(edge)

    # get planetocentric latitude/longitude
    pclat = utils.r2d(math.asin(np.dot(edge, yHat) / np.linalg.norm(edge)))
    delta_lng = utils.r2d(math.atan2(np.dot(edge, xHat), np.dot(edge, zHat)))
    geoid = shape.Shape(gtype)
    r2 = geoid.calcShape(atm, rNorm, pclat, delta_lng)
    if verbose:
        print(' within {:.2f} m'.format(abs(r1 - r2) * 100.0))
        geoid.printShort()
    if plot:
        plotStuff(atm=atm, r=rNorm, b=b, gtype=gtype, delta_lng=delta_lng, geoid=geoid, tip=tip, rotate=rotate)

    # initialize - everything below is in planetocentric coordinates, so need to rotate s-vector
    start = np.array([0.0, 0.0, -1.0])
    start = rotate2planet(rotate, tip, start)
    s = [start]
    n = [geoid.n]
    r = [geoid.r]
    t_inc = [math.acos(-np.dot(s[-1], n[-1]))]            # incident angle_0
    nratio = nr[0] / nr[1]                                # refractive index ratio_0
    t_tran = [math.asin(nratio * math.sin(t_inc[-1]))]    # transmitted angle_0

    # return array initialization, use a value to keep indexing numbering for loop
    ds = [0.0]
    layer4ds = [0.0]
    r4ds = [0.0]  # not needed, but for information
    P4ds = [0.0]  # not needed, but for information
    doppler = []

    # loop while in atmosphere
    i = 0                      # loops over the path
    layer = 0                  # keeps track which physical layer you are in
    inAtmosphere = True
    direction = 'ingress'
    while inAtmosphere:
        if verbose:
            print('------------------')
            print('\tstep {d}:  layer {d} {s} '.format(i, layer, direction))
            print('\ts = [{:.4f}, {:.4f}, {:.4f}],  ds = {:.4f}'.format(s[-1][_X], s[-1][_Y], s[-1][_Z], ds[-1]))
            geoid.print_a_step()
            print('\tt_inc, tran:  {:.8f} -> {:.8f}'.format(utils.r2d(t_inc[-1]), utils.r2d(t_tran[-1])))
        # update s-vector
        s.append(nratio * s[i] + raypathdir[direction] * (nratio * math.cos(t_inc[i]) * n[i] - math.cos(t_tran[i]) * n[i]))
        rNowMag = geoid.rmag
        rNextMag = geoid.calcShape(atm, req[layer + raypathdir[direction]], pclat, delta_lng)
        rdots = np.dot(r[i], s[i + 1])

        vw = np.interp(pclat, atm.config.vwlat, atm.config.vwdat) / 1000.0
        dopp = 1.0 - (atm.config.omega_m * rNowMag * math.cos(utils.d2r(pclat)) + vw) * math.sin(utils.d2r(delta_lng)) / 3.0E5

        # get ds, checking for exit, errors and warnings...
        try:
            dsp = -rdots + math.sqrt(rdots**2.0 + rNextMag**2.0 - rNowMag**2.0)
            dsm = -rdots - math.sqrt(rdots**2.0 + rNextMag**2.0 - rNowMag**2.0)
            if direction == 'ingress':
                ds_step = dsm
            elif direction == 'egress':
                ds_step = dsp
        except ValueError:  # tangent layer (probably)
            if direction == 'ingress':
                print('In tangent layer  ', end='')
                direction = 'tangent'
                ds_step = -2.0 * rdots
                if ds_step > rNorm:
                    inAtmosphere = False
                    print('Error:  tangent ds too large')
                    break
                rNextMag = rNowMag
            else:
                inAtmosphere = False
                break
        if ds_step < 0.0:   # What is correct here?  Is this true for egress, or only in error?  8/1/14 I commented out if statement,
                            # but only print statement was indented
            print('Error:  ds < 0  ({}:  r.s={}, ds={}, [{},{}])'.format(direction, rdots, ds_step, dsp, dsm))
            inAtmosphere = False
            break

        if atm.config.limb == 'sec':  # overwrite ds_step with secant version
            ds_step = abs(rNextMag - rNowMag) / mu

        # append to return arrays
        ds.append(ds_step)
        layer4ds.append(layer)
        r4ds.append(rNowMag)
        P4ds.append(atm.gas[atm.config.C['P']][layer])
        doppler.append(dopp)

        # get next step, double-check r value (and compute n, etc)
        rnext = r[i] + ds[i + 1] * s[i + 1]
        pclat = utils.r2d(math.asin(np.dot(rnext, yHat) / np.linalg.norm(rnext)))
        delta_lng = utils.r2d(math.atan2(np.dot(rnext, xHat), np.dot(rnext, zHat)))
        r2 = geoid.calcShape(atm, req[layer + raypathdir[direction]], pclat, delta_lng)
        if abs(r2 - rNextMag) > 2.0 and layer != 0:
            print('Warning:  {} != {} ({} km) at layer {}'.format(r2, rNextMag, r2 - rNextMag, layer))
        r.append(rnext)  # which is also geoid.r, or should be
        n.append(geoid.n)

        # get new incident angle
        layer += raypathdir[direction]
        if direction == 'tangent':
            direction = 'egress'
            t_inc.append(np.pi / 2.0)
        else:
            try:
                t_inc.append(math.acos(-raypathdir[direction] * np.dot(s[i + 1], n[i + 1])))
            except ValueError:
                print('t_inc ValueError |s_(i+1)| = {}, |n_(i+1)| = {} - set to previous'.format(np.linalg.norm(s[i + 1]), np.linalg.norm(n[i + 1])))
                t_inc.append(t_inc[i])
                inAtmosphere = False
                break
        i += 1

        # get refractive index ratio and check for exit
        try:
            nratio = nr[layer] / nr[layer + raypathdir[direction]]
            nratio = 1.0
            try:
                t_tmp = math.asin(nratio * math.sin(t_inc[-1]))
            except ValueError:
                t_tmp = nratio * np.pi / 2.0
            t_tran.append(t_tmp)
        except IndexError:
            inAtmosphere = False
        # ## end loop ###

    # Get rid of the first entry, which was just used to make indexing in loop consistent
    del ds[0], layer4ds[0], r4ds[0], P4ds[0]
    dsmu = []
    for i in range(min(len(ds), len(r4ds)) - 1):
        if abs(r4ds[i] - r4ds[i + 1]) < 1E-6:
            dsmuappend = 0.001
        else:
            dsmuappend = ds[i] / (r4ds[i] - r4ds[i + 1])
        dsmu.append(dsmuappend)
    path.update(ds=ds, layer4ds=layer4ds, r4ds=r4ds, P4ds=P4ds, doppler=doppler, tip=tip, rotate=rotate, rNorm=rNorm)
    if plot:
        plt.figure('test_ds')
        plt.plot(dsmu)
        plt.plot([0, 1499], [1.0 / mu, 1.0 / mu])
        plotStuff(r=np.array(r), ray=path)
    del s, r, n, ds, layer4ds, r4ds, P4ds, geoid, req, nr
    return path
Пример #10
0
def compute_ds(atm, b, orientation=None, gtype=None, verbose=False, plot=True):
    """Computes the path length through the atmosphere given:
            b = impact parameter (fractional distance to outer edge at that latitude in observer's coordinates)
            orientation = position angle of the planet [0]='tip', [1]='subearth latitude' """
    if gtype is None:
        gtype = atm.config.gtype
    if orientation is None:
        orientation = atm.config.orientation
    path = Ray()
    req = atm.layerProperty[
        atm.config.LP['R']]  # radius of layers along equator
    rNorm = req[0]
    nr = atm.layerProperty[atm.config.LP['N']]  # refractive index of layers
    P = atm.gas[atm.config.C['P']]
    if (b[0]**2 + b[1]**2) > 1.0:
        return path

    mu = math.sqrt(1.0 - b[0]**2 - b[1]**2)

    f = 1.0 - atm.config.Rpol / atm.config.Req
    tip, rotate = computeAspect(orientation, f)
    if verbose:
        print('intersection:  ({:.3f}, {:.3f})    '.format(b[0], b[1]), end='')
        print('aspect:  ({:%.4f},  {:.4f})'.format(tip * 180.0 / np.pi,
                                                   rotate * 180.0 / np.pi))
        print('Finding atmospheric edge', end='')
    edge, b = findEdge(atm, b, rNorm, tip, rotate, gtype)
    if edge is None:
        return path
    r1 = np.linalg.norm(edge)

    # get planetocentric latitude/longitude
    pclat = utils.r2d(math.asin(np.dot(edge, yHat) / np.linalg.norm(edge)))
    delta_lng = utils.r2d(math.atan2(np.dot(edge, xHat), np.dot(edge, zHat)))
    geoid = shape.Shape(gtype)
    r2 = geoid.calcShape(atm, rNorm, pclat, delta_lng)
    if verbose:
        print(' within {:.2f} m'.format(abs(r1 - r2) * 100.0))
        geoid.printShort()
    if plot:
        plotStuff(atm=atm,
                  r=rNorm,
                  b=b,
                  gtype=gtype,
                  delta_lng=delta_lng,
                  geoid=geoid,
                  tip=tip,
                  rotate=rotate)

    # initialize - everything below is in planetocentric coordinates, so need to rotate s-vector
    start = np.array([0.0, 0.0, -1.0])
    start = rotate2planet(rotate, tip, start)
    s = [start]
    n = [geoid.n]
    r = [geoid.r]
    t_inc = [math.acos(-np.dot(s[-1], n[-1]))]  # incident angle_0
    nratio = nr[0] / nr[1]  # refractive index ratio_0
    t_tran = [math.asin(nratio * math.sin(t_inc[-1]))]  # transmitted angle_0

    # return array initialization, use a value to keep indexing numbering for loop
    ds = [0.0]
    layer4ds = [0.0]
    r4ds = [0.0]  # not needed, but for information
    P4ds = [0.0]  # not needed, but for information
    doppler = []

    # loop while in atmosphere
    i = 0  # loops over the path
    layer = 0  # keeps track which physical layer you are in
    inAtmosphere = True
    direction = 'ingress'
    while inAtmosphere:
        if verbose:
            print('------------------')
            print('\tstep {d}:  layer {d} {s} '.format(i, layer, direction))
            print('\ts = [{:.4f}, {:.4f}, {:.4f}],  ds = {:.4f}'.format(
                s[-1][_X], s[-1][_Y], s[-1][_Z], ds[-1]))
            geoid.print_a_step()
            print('\tt_inc, tran:  {:.8f} -> {:.8f}'.format(
                utils.r2d(t_inc[-1]), utils.r2d(t_tran[-1])))
        # update s-vector
        s.append(
            nratio * s[i] + raypathdir[direction] *
            (nratio * math.cos(t_inc[i]) * n[i] - math.cos(t_tran[i]) * n[i]))
        rNowMag = geoid.rmag
        rNextMag = geoid.calcShape(atm, req[layer + raypathdir[direction]],
                                   pclat, delta_lng)
        rdots = np.dot(r[i], s[i + 1])

        vw = np.interp(pclat, atm.config.vwlat, atm.config.vwdat) / 1000.0
        dopp = 1.0 - (atm.config.omega_m * rNowMag * math.cos(utils.d2r(pclat))
                      + vw) * math.sin(utils.d2r(delta_lng)) / 3.0E5

        # get ds, checking for exit, errors and warnings...
        try:
            dsp = -rdots + math.sqrt(rdots**2.0 + rNextMag**2.0 - rNowMag**2.0)
            dsm = -rdots - math.sqrt(rdots**2.0 + rNextMag**2.0 - rNowMag**2.0)
            if direction == 'ingress':
                ds_step = dsm
            elif direction == 'egress':
                ds_step = dsp
        except ValueError:  # tangent layer (probably)
            if direction == 'ingress':
                print('In tangent layer  ', end='')
                direction = 'tangent'
                ds_step = -2.0 * rdots
                if ds_step > rNorm:
                    inAtmosphere = False
                    print('Error:  tangent ds too large')
                    break
                rNextMag = rNowMag
            else:
                inAtmosphere = False
                break
        if ds_step < 0.0:  # What is correct here?  Is this true for egress, or only in error?  8/1/14 I commented out if statement,
            # but only print statement was indented
            print('Error:  ds < 0  ({}:  r.s={}, ds={}, [{},{}])'.format(
                direction, rdots, ds_step, dsp, dsm))
            inAtmosphere = False
            break

        if atm.config.limb == 'sec':  # overwrite ds_step with secant version
            ds_step = abs(rNextMag - rNowMag) / mu

        # append to return arrays
        ds.append(ds_step)
        layer4ds.append(layer)
        r4ds.append(rNowMag)
        P4ds.append(atm.gas[atm.config.C['P']][layer])
        doppler.append(dopp)

        # get next step, double-check r value (and compute n, etc)
        rnext = r[i] + ds[i + 1] * s[i + 1]
        pclat = utils.r2d(
            math.asin(np.dot(rnext, yHat) / np.linalg.norm(rnext)))
        delta_lng = utils.r2d(
            math.atan2(np.dot(rnext, xHat), np.dot(rnext, zHat)))
        r2 = geoid.calcShape(atm, req[layer + raypathdir[direction]], pclat,
                             delta_lng)
        if abs(r2 - rNextMag) > 2.0 and layer != 0:
            print('Warning:  {} != {} ({} km) at layer {}'.format(
                r2, rNextMag, r2 - rNextMag, layer))
        r.append(rnext)  # which is also geoid.r, or should be
        n.append(geoid.n)

        # get new incident angle
        layer += raypathdir[direction]
        if direction == 'tangent':
            direction = 'egress'
            t_inc.append(np.pi / 2.0)
        else:
            try:
                t_inc.append(
                    math.acos(-raypathdir[direction] *
                              np.dot(s[i + 1], n[i + 1])))
            except ValueError:
                print(
                    't_inc ValueError |s_(i+1)| = {}, |n_(i+1)| = {} - set to previous'
                    .format(np.linalg.norm(s[i + 1]),
                            np.linalg.norm(n[i + 1])))
                t_inc.append(t_inc[i])
                inAtmosphere = False
                break
        i += 1

        # get refractive index ratio and check for exit
        try:
            nratio = nr[layer] / nr[layer + raypathdir[direction]]
            nratio = 1.0
            try:
                t_tmp = math.asin(nratio * math.sin(t_inc[-1]))
            except ValueError:
                t_tmp = nratio * np.pi / 2.0
            t_tran.append(t_tmp)
        except IndexError:
            inAtmosphere = False
        # ## end loop ###

    # Get rid of the first entry, which was just used to make indexing in loop consistent
    del ds[0], layer4ds[0], r4ds[0], P4ds[0]
    dsmu = []
    for i in range(min(len(ds), len(r4ds)) - 1):
        if abs(r4ds[i] - r4ds[i + 1]) < 1E-6:
            dsmuappend = 0.001
        else:
            dsmuappend = ds[i] / (r4ds[i] - r4ds[i + 1])
        dsmu.append(dsmuappend)
    path.update(ds=ds,
                layer4ds=layer4ds,
                r4ds=r4ds,
                P4ds=P4ds,
                doppler=doppler,
                tip=tip,
                rotate=rotate,
                rNorm=rNorm)
    if plot:
        plt.figure('test_ds')
        plt.plot(dsmu)
        plt.plot([0, 1499], [1.0 / mu, 1.0 / mu])
        plotStuff(r=np.array(r), ray=path)
    del s, r, n, ds, layer4ds, r4ds, P4ds, geoid, req, nr
    return path
Пример #11
0
    def set_b(self, b, block):
        """Process b request.
           bType (see below), outType ('image', 'spectrum', 'profile'), and imSize get set as attributes
           b is list of ordered pairs on return

           Parameters:
           ------------
           b:   list of ordered pairs -> returns that list (bType='points')
                float -> returns a full grid (bType='image')
                'disc' (or 'disk') -> returns [[0.0, 0.0]] (bType='disc')
                'stamp' -> returns grid of postage stamp (bType='stamp')
                string defining line: csv list of values or range as <start>:<stop>:<step>
                                      optional ',angle=DEG' [defaults to 0.0]
                                      (bType='line')
           block:  image block as pair, e.g. [4, 10] is "block 4 of 10"
                   if not image, can define block='profile' (default is 'spectrum')
           """
        self.header['b'] = '# b request:  {}  {}\n'.format(str(b), str(block))
        self.imSize = None
        self.outType = 'spectrum'
        if isinstance(block, str) and block[0].lower() == 'p':
            self.outType = 'profile'
        # Do some pre-processing to handle line vs single point and ndarrays
        if len(np.shape(b)) == 1 and len(b) > 2:
            b = ','.join([str(x) for x in b])
        if isinstance(b, str) and len(b.split(',')) == 2:
            b = b.split(',')

        # Handle lists/arrays
        if len(np.shape(b)) > 0:
            if len(np.shape(b)) == 1 and len(b) == 2:
                b = [b]
            if len(np.shape(
                    b)) == 2:  # This is just a list of b pairs, so return.
                self.bType = 'points'
                return b
            else:
                raise ValueError("Invalid b request.")

        if isinstance(
                b,
                float):  # this generates a grid at that spacing and blocking
            self.bType = 'image'
            self.outType = 'image'
            grid = -1.0 * np.flipud(np.arange(b, 1.5 + b, b))
            grid = np.concatenate((grid, np.arange(0.0, 1.5 + b, b)))
            # get blocks
            bsplit = len(grid) / abs(block[1])
            lastRow = block[0] / abs(block[1])
            if abs(block[1]) == 1:
                lastRow = 0
            b = []
            for i in range(int(bsplit + lastRow)):
                ii = i + int((block[0] - 1) * bsplit)
                vrow = grid[ii]
                for vcol in grid:
                    b.append([vcol, vrow])
            self.imSize = [len(grid), len(b) / len(grid)]
            return b

        if not isinstance(b, str):
            raise ValueError("Invalid b request.")
        self.bType = b.lower()

        if self.bType == 'disc' or self.bType == 'disk':
            self.bType = 'disc'
            return [[0.0, 0.0]]

        if self.bType == 'stamp':
            self.outType = 'image'
            print('Setting to postage stamp.  Need more information')
            bres = float(
                raw_input('...Input postage stamp resolution in b-units:  '))
            bx = [
                float(x)
                for x in raw_input('...Input bx_min, bx_max:  ').split(',')
            ]
            by = [
                float(x)
                for x in raw_input('...Input by_min, by_max:  ').split(',')
            ]
            b = []
            for x in np.arange(bx[0], bx[1] + bres / 2.0, bres):
                for y in np.arange(by[0], by[1] + bres / 2.0, bres):
                    b.append([y, x])
            xbr = len(np.arange(by[0], by[1] + bres / 2.0, bres))
            self.imSize = [xbr, len(b) / xbr]
            return b

        # It is a line request
        line = {'mag_b': [], 'angle_b': 0.0, 'range': ':' in self.bType}
        cmd = self.bType.split(',')
        self.bType = 'line'
        for v in cmd:
            if '<' in v:
                line['angle_b'] = utils.d2r(float(v.split('<')[1]))
                v = v.split('<')[0]
            if ':' in v:
                start, stop, step = [float(x) for x in v.split(':')]
                line['mag_b'] = np.arange(start, stop + step / 2.0, step)
            if not line['range'] and len(v):
                line['mag_b'].append(float(v))
        b = []
        for v in line['mag_b']:
            b.append(
                [v * math.cos(line['angle_b']), v * math.sin(line['angle_b'])])
        return b
Пример #12
0
    def set_b(self, b, block):
        """Process b request.
           bType (see below), outType ('image', 'spectrum', 'profile'), and imSize get set as attributes
           b is list of ordered pairs on return

           Parameters:
           ------------
           b:   list of ordered pairs -> returns that list (bType='points')
                float -> returns a full grid (bType='image')
                'disc' (or 'disk') -> returns [[0.0, 0.0]] (bType='disc')
                'stamp' -> returns grid of postage stamp (bType='stamp')
                string defining line: csv list of values or range as <start>:<stop>:<step>
                                      optional ',angle=DEG' [defaults to 0.0]
                                      (bType='line')
           block:  image block as pair, e.g. [4, 10] is "block 4 of 10"
                   if not image, can define block='profile' (default is 'spectrum')
           """
        self.header['b'] = '# b request:  {}  {}\n'.format(str(b), str(block))
        self.imSize = None
        self.outType = 'spectrum'
        if isinstance(block, six.string_types) and block[0].lower() == 'p':
            self.outType = 'profile'
        # Do some pre-processing to handle line vs single point and ndarrays
        if len(np.shape(b)) == 1 and len(b) > 2:
            b = ','.join([str(x) for x in b])
        if isinstance(b, six.string_types) and len(b.split(',')) == 2:
            b = b.split(',')

        # Handle lists/arrays
        if len(np.shape(b)) > 0:
            if len(np.shape(b)) == 1 and len(b) == 2:
                b = [b]
            if len(np.shape(b)) == 2:  # This is just a list of b pairs, so return.
                self.bType = 'points'
                return b
            else:
                raise ValueError("Invalid b request.")

        if isinstance(b, float):  # this generates a grid at that spacing and blocking
            self.bType = 'image'
            self.outType = 'image'
            grid = -1.0 * np.flipud(np.arange(b, 1.5 + b, b))
            grid = np.concatenate((grid, np.arange(0.0, 1.5 + b, b)))
            # get blocks
            bsplit = len(grid) / abs(block[1])
            lastRow = block[0] / abs(block[1])
            if abs(block[1]) == 1:
                lastRow = 0
            b = []
            for i in range(int(bsplit + lastRow)):
                ii = i + int((block[0] - 1) * bsplit)
                vrow = grid[ii]
                for vcol in grid:
                    b.append([vcol, vrow])
            self.imSize = [len(grid), len(b) / len(grid)]
            return b

        if not isinstance(b, six.string_types):
            raise ValueError("Invalid b request.")
        self.bType = b.lower()

        if self.bType == 'disc' or self.bType == 'disk':
            self.bType = 'disc'
            return [[0.0, 0.0]]

        if self.bType == 'stamp':
            self.outType = 'image'
            print('Setting to postage stamp.  Need more information')
            bres = float(raw_input('...Input postage stamp resolution in b-units:  '))
            bx = [float(x) for x in raw_input('...Input bx_min, bx_max:  ').split(',')]
            by = [float(x) for x in raw_input('...Input by_min, by_max:  ').split(',')]
            b = []
            for x in np.arange(bx[0], bx[1] + bres / 2.0, bres):
                for y in np.arange(by[0], by[1] + bres / 2.0, bres):
                    b.append([y, x])
            xbr = len(np.arange(by[0], by[1] + bres / 2.0, bres))
            self.imSize = [xbr, len(b) / xbr]
            return b

        # It is a line request
        line = {'mag_b': [], 'angle_b': 0.0, 'range': ':' in self.bType}
        cmd = self.bType.split(',')
        self.bType = 'line'
        for v in cmd:
            if '<' in v:
                line['angle_b'] = utils.d2r(float(v.split('<')[1]))
                v = v.split('<')[0]
            if ':' in v:
                start, stop, step = [float(x) for x in v.split(':')]
                line['mag_b'] = np.arange(start, stop + step / 2.0, step)
            if not line['range'] and len(v):
                line['mag_b'].append(float(v))
        b = []
        for v in line['mag_b']:
            b.append([v * math.cos(line['angle_b']), v * math.sin(line['angle_b'])])
        return b