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
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
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
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
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
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
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
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
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
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
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