def run_track(temp_dir,exp_full_name,out_conf_fil,date,rnx_rover): dowstring = ''.join([str(e) for e in conv.dt2gpstime(date)]) bigcomand = ' '.join(("track -f" , out_conf_fil , '-d' , conv.dt2doy(date) ,'-w', dowstring)) print('INFO : command launched :') print(bigcomand) # START OF PROCESSING os.chdir(temp_dir) subprocess.call([bigcomand], executable='/bin/bash', shell=True) outfiles = [] outfiles = outfiles + glob.glob(os.path.join(temp_dir,exp_full_name + '*sum*')) outfiles = outfiles + glob.glob(os.path.join(temp_dir,exp_full_name + '*pos*')) outfiles = outfiles + glob.glob(os.path.join(temp_dir,exp_full_name + '*cmd*')) Antobj_rov , Recobj_rov , Siteobj_rov , Locobj_rov = \ files_rw.read_rinex_2_dataobjts(rnx_rover) [shutil.copy(e,out_dir) for e in outfiles] [os.remove(e) for e in outfiles] print("TRACK RUN FINISHED") print('results available in ' , out_dir) return None
def compar_orbit(Data_inp_1, Data_inp_2, step_data=900, sats_used_list=['G'], name1='', name2='', use_name_1_2_for_table_name=False, RTNoutput=True, convert_ECEF_ECI=True, clean_null_values=True, conv_coef=10**3, return_satNull=False): """ Compares 2 GNSS orbits files (SP3), and gives a summary plot and a statistics table Parameters ---------- Data_inp_1 & Data_inp_2 : str or Pandas DataFrame contains the orbits or path (string) to the sp3 step_data : int per default data sampling sats_used_list : list of str used constellation or satellite : G E R C ... E01 , G02 ... Individuals satellites are prioritary on whole constellations e.g. ['G',"E04"] RTNoutput : bool select output, Radial Transverse Normal or XYZ convert_ECEF_ECI : bool convert sp3 ECEF => ECI, must be True in operational ! name1 & name2 : str (optionals) optional custom names for the 2 orbits use_name_1_2_for_table_name : bool False : use name 1 and 2 for table name, use datafile instead clean_null_values : bool or str if True or "all" remove sat position in all X,Y,Z values are null (0.000000) if "any", remove sat position if X or Y or Z is null if False, keep everything conv_coef : int conversion coefficient, km to m 10**3, km to mm 10**6 Returns ------- Diff_sat_all : Pandas DataFrame contains differences b/w Data_inp_1 & Data_inp_2 in Radial Transverse Normal OR XYZ frame Attributes of Diff_sat_all : Diff_sat_all.name : title of the table Note ---- clean_null_values if useful (and necessary) only if convert_ECEF_ECI = False if convert_ECEF_ECI = True, the cleaning will be done by a side effect trick : the convertion ECEF => ECI will generate NaN for a zero-valued position But, nevertheless, activating clean_null_values = True is better This Note is in fact usefull if you want to see bad positions on a plot => Then convert_ECEF_ECI = False and clean_null_values = False Source ------ "Coordinate Systems", ASEN 3200 1/24/06 George H. Born """ # selection of both used Constellations AND satellites const_used_list = [] sv_used_list = [] for sat in sats_used_list: if len(sat) == 1: const_used_list.append(sat) elif len(sat) == 3: sv_used_list.append(sat) if not sat[0] in const_used_list: const_used_list.append(sat[0]) # Read the files or DataFrames # metadata attributes are not copied # Thus, manual copy ... # (Dirty way, should be impoved without so many lines ...) if type(Data_inp_1) is str: D1orig = files_rw.read_sp3(Data_inp_1, epoch_as_pd_index=True) else: D1orig = Data_inp_1.copy(True) try: D1orig.name = Data_inp_1.name except: D1orig.name = "no_name" try: D1orig.path = Data_inp_1.path except: D1orig.path = "no_path" try: D1orig.filename = Data_inp_1.filename except: D1orig.filename = "no_filename" if type(Data_inp_2) is str: D2orig = files_rw.read_sp3(Data_inp_2, epoch_as_pd_index=True) else: D2orig = Data_inp_2.copy(True) try: D2orig.name = Data_inp_2.name except: D2orig.name = "no_name" try: D2orig.path = Data_inp_2.path except: D2orig.path = "no_path" try: D2orig.filename = Data_inp_2.filename except: D2orig.filename = "no_filename" #### NB : It has been decided with GM that the index of a SP3 dataframe #### will be integers, not epoch datetime anymore #### BUT here, for legacy reasons, the index has to be datetime if isinstance(D1orig.index[0], (int, np.integer)): D1orig.set_index("epoch", inplace=True) if isinstance(D2orig.index[0], (int, np.integer)): D2orig.set_index("epoch", inplace=True) Diff_sat_stk = [] # This block is for removing null values if clean_null_values: if clean_null_values == "all": all_or_any = np.all elif clean_null_values == "any": all_or_any = np.any else: all_or_any = np.all xyz_lst = ['x', 'y', 'z'] D1_null_bool = all_or_any(np.isclose(D1orig[xyz_lst], 0.), axis=1) D2_null_bool = all_or_any(np.isclose(D2orig[xyz_lst], 0.), axis=1) D1 = D1orig[np.logical_not(D1_null_bool)] D2 = D2orig[np.logical_not(D2_null_bool)] if np.any(D1_null_bool) or np.any(D2_null_bool): sat_nul = utils.join_improved( " ", *list(set(D1orig[D1_null_bool]["sat"]))) print("WARN : Null values contained in SP3 files : ") print( "f1:", np.sum(D1_null_bool), utils.join_improved(" ", *list(set(D1orig[D1_null_bool]["sat"])))) print( "f2:", np.sum(D2_null_bool), utils.join_improved(" ", *list(set(D2orig[D2_null_bool]["sat"])))) else: sat_nul = [] else: D1 = D1orig.copy() D2 = D2orig.copy() for constuse in const_used_list: D1const = D1[D1['const'] == constuse] D2const = D2[D2['const'] == constuse] # checking if the data correspond to the step bool_step1 = np.mod((D1const.index - np.min(D1.index)).seconds, step_data) == 0 bool_step2 = np.mod((D2const.index - np.min(D2.index)).seconds, step_data) == 0 D1window = D1const[bool_step1] D2window = D2const[bool_step2] # find common sats and common epochs sv_set = sorted( list(set(D1window['sv']).intersection(set(D2window['sv'])))) epoc_set = sorted( list(set(D1window.index).intersection(set(D2window.index)))) # if special selection of sats, then apply it # (it is late and this selection is incredibely complicated ...) if np.any([True if constuse in e else False for e in sv_used_list]): # first find the selected sats for the good constellation sv_used_select_list = [ int(e[1:]) for e in sv_used_list if constuse in e ] #and apply it sv_set = sorted( list(set(sv_set).intersection(set(sv_used_select_list)))) for svv in sv_set: # First research : find corresponding epoch for the SV # this one is sufficent if there is no gaps (e.g. with 0.00000) i.e. # same nb of obs in the 2 files # NB : .reindex() is smart, it fills the DataFrame # with NaN try: D1sv_orig = D1window[D1window['sv'] == svv].reindex(epoc_set) D2sv_orig = D2window[D2window['sv'] == svv].reindex(epoc_set) except Exception as exce: print("ERR : Unable to re-index with an unique epoch") print( " are you sure there is no multiple-defined epochs for the same sat ?" ) print( " it happens e.g. when multiple ACs are in the same DataFrame " ) print( "TIP : Filter the input Dataframe before calling this fct with" ) print(" DF = DF[DF['AC'] == 'gbm']") raise exce # Second research, it is a security in case of gap # This step is useless, because .reindex() will fill the DataFrame # with NaN if len(D1sv_orig) != len(D2sv_orig): print("INFO : different epochs nbr for SV", svv, len(D1sv_orig), len(D2sv_orig)) epoc_sv_set = sorted( list( set(D1sv_orig.index).intersection(set( D2sv_orig.index)))) D1sv = D1sv_orig.loc[epoc_sv_set] D2sv = D2sv_orig.loc[epoc_sv_set] else: D1sv = D1sv_orig D2sv = D2sv_orig P1 = D1sv[['x', 'y', 'z']] P2 = D2sv[['x', 'y', 'z']] # Start ECEF => ECI if convert_ECEF_ECI: # Backup because the columns xyz will be reaffected #D1sv_bkp = D1sv.copy() #D2sv_bkp = D2sv.copy() P1b = conv.ECEF2ECI( np.array(P1), conv.dt_gpstime2dt_utc(P1.index.to_pydatetime(), out_array=True)) P2b = conv.ECEF2ECI( np.array(P2), conv.dt_gpstime2dt_utc(P2.index.to_pydatetime(), out_array=True)) D1sv[['x', 'y', 'z']] = P1b D2sv[['x', 'y', 'z']] = P2b P1 = D1sv[['x', 'y', 'z']] P2 = D2sv[['x', 'y', 'z']] # End ECEF => ECI if not RTNoutput: # Compatible with the documentation + # empirically tested with OV software # it is P1 - P2 (and not P2 - P1) Delta_P = P1 - P2 Diff_sat = Delta_P.copy() Diff_sat.columns = ['dx', 'dy', 'dz'] else: rnorm = np.linalg.norm(P1, axis=1) Vx = utils.diff_pandas(D1sv, 'x') Vy = utils.diff_pandas(D1sv, 'y') Vz = utils.diff_pandas(D1sv, 'z') V = pd.concat((Vx, Vy, Vz), axis=1) V.columns = ['vx', 'vy', 'vz'] R = P1.divide(rnorm, axis=0) R.columns = ['xnorm', 'ynorm', 'znorm'] H = pd.DataFrame(np.cross(R, V), columns=['hx', 'hy', 'hz']) hnorm = np.linalg.norm(H, axis=1) C = H.divide(hnorm, axis=0) C.columns = ['hxnorm', 'hynorm', 'hznorm'] I = pd.DataFrame(np.cross(C, R), columns=['ix', 'iy', 'iz']) R_ar = np.array(R) I_ar = np.array(I) C_ar = np.array(C) #R_ar[1] Beta = np.stack((R_ar, I_ar, C_ar), axis=1) # Compatible with the documentation + # empirically tested with OV software # it is P1 - P2 (and not P2 - P1) Delta_P = P1 - P2 # Final determination Astk = [] for i in range(len(Delta_P)): A = np.dot(Beta[i, :, :], np.array(Delta_P)[i]) Astk.append(A) Diff_sat = pd.DataFrame(np.vstack(Astk), index=P1.index, columns=['dr', 'dt', 'dn']) Diff_sat = Diff_sat * conv_coef # metrer conversion Diff_sat['const'] = [constuse] * len(Diff_sat.index) Diff_sat['sv'] = [svv] * len(Diff_sat.index) Diff_sat['sat'] = [constuse + str(svv).zfill(2)] * len( Diff_sat.index) Diff_sat_stk.append(Diff_sat) Diff_sat_all = pd.concat(Diff_sat_stk) Date = Diff_sat.index[0] # Attribute definition if RTNoutput: Diff_sat_all.frame_type = 'RTN' # Pandas donesn't manage well iterable as attribute # So, it is separated Diff_sat_all.frame_col_name1 = 'dr' Diff_sat_all.frame_col_name2 = 'dt' Diff_sat_all.frame_col_name3 = 'dn' else: # Pandas donesn't manage well iterable as attribute # So, it is separated Diff_sat_all.frame_col_name1 = 'dx' Diff_sat_all.frame_col_name2 = 'dy' Diff_sat_all.frame_col_name3 = 'dz' if convert_ECEF_ECI: Diff_sat_all.frame_type = 'ECI' else: Diff_sat_all.frame_type = 'ECEF' # Name definitions if name1: Diff_sat_all.name1 = name1 else: Diff_sat_all.name1 = D1orig.name if name2: Diff_sat_all.name2 = name2 else: Diff_sat_all.name2 = D2orig.name Diff_sat_all.filename1 = D1orig.filename Diff_sat_all.filename2 = D2orig.filename Diff_sat_all.path1 = D1orig.path Diff_sat_all.path2 = D2orig.path Diff_sat_all.name = ' '.join( ('Orbits comparison (' + Diff_sat_all.frame_type + ') b/w', Diff_sat_all.name1, '(ref.) and', Diff_sat_all.name2, ',', Date.strftime("%Y-%m-%d"), ', doy', str(conv.dt2doy(Date)))) if return_satNull: return Diff_sat_all, sat_nul else: return Diff_sat_all
def track_runner(rnx_rover,rnx_base,working_dir,experience_prefix, XYZbase = [], XYZrover = [] , outtype = 'XYZ',mode = 'short', interval=None,antmodfile = "~/gg/tables/antmod.dat", calc_center='igs' , forced_sp3_path = '', const="G",silent=False,rinex_full_path=False, run_on_gfz_cluster=False,forced_iono_path=''): # paths & files working_dir = utils.create_dir(working_dir) temp_dir = utils.create_dir(os.path.join(working_dir,'TEMP')) out_dir = utils.create_dir(os.path.join(working_dir,'OUTPUT')) if operational.check_if_compressed_rinex(rnx_rover): rnx_rover = operational.crz2rnx(rnx_rover,temp_dir) else: shutil.copy(rnx_rover,temp_dir) if operational.check_if_compressed_rinex(rnx_base): rnx_base = operational.crz2rnx(rnx_base,temp_dir) else: shutil.copy(rnx_base,temp_dir) # RINEX START & END rov_srt, rov_end , rov_itv = operational.rinex_start_end(rnx_rover,1) bas_srt, bas_end , bas_itv = operational.rinex_start_end(rnx_base,1) # RINEX NAMES rov_name = os.path.basename(rnx_rover)[0:4] bas_name = os.path.basename(rnx_base)[0:4] rov_name_uper = rov_name.upper() bas_name_uper = bas_name.upper() srt_str = rov_srt.strftime("%Y_%j") exp_full_name = '_'.join((experience_prefix,rov_name,bas_name,srt_str)) out_conf_fil = os.path.join(out_dir,exp_full_name + '.cmd') out_result_fil = os.path.join(out_dir,exp_full_name + '.out' ) print(out_conf_fil) confobj = open(out_conf_fil,'w+') # Obs Files confobj.write(' obs_file' + '\n') ### just the basename, the caracter nb is limited (20210415) if not rinex_full_path: confobj.write(' '.join((' ',bas_name_uper,os.path.basename(rnx_base) ,'F'))+ '\n') confobj.write(' '.join((' ',rov_name_uper,os.path.basename(rnx_rover),'K'))+ '\n') else: confobj.write(' '.join((' ',bas_name_uper,rnx_base ,'F'))+ '\n') confobj.write(' '.join((' ',rov_name_uper,rnx_rover,'K'))+ '\n') confobj.write('\n') date = conv.rinexname2dt(os.path.basename(rnx_rover)) # Nav File if forced_sp3_path == '': strt_rnd = dt.datetime(*bas_srt.timetuple()[:3]) end_rnd = dt.datetime(*bas_end.timetuple()[:3]) orblis = operational.multi_downloader_orbs_clks( temp_dir , strt_rnd , end_rnd , archtype='/', calc_center = calc_center) #sp3Z = orblis[0] sp3 = [utils.uncompress(sp3Z) for sp3Z in orblis] sp3 = [e if ".sp3" in e[-5:] else e + ".sp3" for e in sp3] else: if utils.is_iterable(forced_sp3_path): sp3 = forced_sp3_path else: sp3 = [forced_sp3_path] for sp3_mono in sp3: confobj.write(' '.join((' ','nav_file',sp3_mono ,' sp3'))+ '\n') confobj.write('\n') # Iono file if forced_iono_path != '': confobj.write(' ionex_file ' + forced_iono_path + '\n' ) # Mode confobj.write(' mode ' + mode + '\n') confobj.write('\n') # Output confobj.write(' pos_root ' + exp_full_name +'.pos' + '\n' ) confobj.write(' res_root ' + exp_full_name +'.res' + '\n' ) confobj.write(' sum_file ' + exp_full_name +'.sum' + '\n' ) confobj.write('\n') # Outtype confobj.write(' out_type ' + outtype + '\n') confobj.write('\n') # Interval if not interval: confobj.write(' interval ' + str(rov_itv) + '\n') else: confobj.write(' interval ' + str(interval) + '\n') confobj.write('\n') # Coords bool_site_pos = False if XYZbase != []: if not bool_site_pos: confobj.write(' site_pos \n') bool_site_pos = True XYZbase = [str(e) for e in XYZbase] confobj.write(' '.join([' ', bas_name_uper] + XYZbase + ['\n'])) if XYZrover != []: if not bool_site_pos: confobj.write(' site_pos \n') bool_site_pos = True XYZrover = [str(e) for e in XYZrover] confobj.write(' '.join([' ', rov_name_uper] + XYZrover + ['\n'])) if bool_site_pos: confobj.write('\n') # Offsets confobj.write(' ante_off \n') Antobj_rov , Recobj_rov , Siteobj_rov , Locobj_rov = \ files_rw.read_rinex_2_dataobjts(rnx_rover) confobj.write(' '.join([' ', rov_name_uper , str(Antobj_rov.North_Ecc) , str(Antobj_rov.East_Ecc) , str(Antobj_rov.Up_Ecc) , Antobj_rov.Antenna_Type , '\n'])) Antobj_bas , Recobj_bas , Siteobj_bas , Locobj_bas = \ files_rw.read_rinex_2_dataobjts(rnx_base) confobj.write(' '.join([' ', bas_name_uper , str(Antobj_bas.North_Ecc) , str(Antobj_bas.East_Ecc) , str(Antobj_bas.Up_Ecc) , Antobj_bas.Antenna_Type , '\n'])) confobj.write('\n') # Site_stats confobj.write(' site_stats \n') confobj.write(' ' + bas_name_uper + " 0.1 0.1 0.1 0 0 0" + '\n') confobj.write(' ' + rov_name_uper + " 20 20 20 0.5 0.5 0.5" + '\n') confobj.write('\n') # constellqtions confobj.write(" TR_GNSS " + const + '\n') # Misc #confobj.write(" USE_GPTGMF" + '\n') confobj.write(" ATM_MODELC GMF 0.5" + '\n') confobj.write(" ANTMOD_FILE " + antmodfile + '\n') confobj.write(" DCB_FILE " + "~/gg/incremental_updates/tables/dcb.dat.gnss" + '\n') confobj.write(" atm_stats" + '\n') confobj.write(' all 0.1 0.00030.00023' + '\n') confobj.close() #END OF FILE WRITING dowstring = ''.join([str(e) for e in conv.dt2gpstime(date)]) bigcomand = ' '.join(("track -f" , out_conf_fil , '-d' , conv.dt2doy(date) ,'-w', dowstring)) if run_on_gfz_cluster: bigcomand = "cjob -c '" + bigcomand + "'" executable="/bin/csh" else: executable="/bin/bash" print('INFO : command launched :') print(bigcomand) # START OF PROCESSING if not silent: os.chdir(temp_dir) try: subprocess.call([bigcomand], executable=executable, shell=True,timeout=60*20) except subprocess.TimeoutExpired: print("WARN: command timeout expired, skip") pass outfiles = [] outfiles = outfiles + glob.glob(os.path.join(temp_dir,exp_full_name + '*sum*')) outfiles = outfiles + glob.glob(os.path.join(temp_dir,exp_full_name + '*pos*')) outfiles = outfiles + glob.glob(os.path.join(temp_dir,exp_full_name + '*cmd*')) Antobj_rov , Recobj_rov , Siteobj_rov , Locobj_rov = \ files_rw.read_rinex_2_dataobjts(rnx_rover) [shutil.copy(e,out_dir) for e in outfiles] [os.remove(e) for e in outfiles] print("TRACK RUN FINISHED") print('results available in ' , out_dir) else: print("Silent mode ON: nothing is launched") return bigcomand
def gpt3(dtin, lat, lon, h_ell, C, it=0): """ This subroutine determines pressure, temperature, temperature lapse rate, mean temperature of the water vapor, water vapour pressure, hydrostatic and wet mapping function coefficients ah and aw, water vapour decrease factor, geoid undulation and empirical tropospheric gradients for specific sites near the earth's surface. It is based on a 5 x 5 degree external grid file ('gpt3_5.grd') with mean values as well as sine and cosine amplitudes for the annual and semiannual variation of the coefficients. Parameters: ---------- dtin : datatime in Python datetime object lat: ellipsoidal latitude in radians [-pi/2:+pi/2] lon: longitude in radians [-pi:pi] or [0:2pi] h_ell: ellipsoidal height in m it: case 1 no time variation but static quantities, case 0 with time variation (annual and semiannual terms) Returns: ---------- p: pressure in hPa T: temperature in degrees Celsius dT: temperature lapse rate in degrees per km Tm: mean temperature weighted with the water vapor in degrees Kelvin e: water vapour pressure in hPa ah: hydrostatic mapping function coefficient at zero height (VMF3) aw: wet mapping function coefficient (VMF3) la: water vapour decrease factor undu: geoid undulation in m Gn_h: hydrostatic north gradient in m Ge_h: hydrostatic east gradient in m Gn_w: wet north gradient in m Ge_w: wet east gradient in m Notes ---------- Modified for Python by Chaiyaporn Kitpracha Source ---------- (c) Department of Geodesy and Geoinformation, Vienna University of Technology, 2017 The copyright in this document is vested in the Department of Geodesy and Geoinformation (GEO), Vienna University of Technology, Austria. This document may only be reproduced in whole or in part, or stored in a retrieval system, or transmitted in any form, or by any means electronic, mechanical, photocopying or otherwise, either with the prior permission of GEO or in accordance with the terms of ESTEC Contract No. 4000107329/12/NL/LvH. D. Landskron, J. Böhm (2018), VMF3/GPT3: Refined Discrete and Empirical Troposphere Mapping Functions, J Geod (2018) 92: 349., doi: 10.1007/s00190-017-1066-2. Download at: https://link.springer.com/content/pdf/10.1007%2Fs00190-017-1066-2.pdf """ lat = np.array(lat) lon = np.array(lon) h_ell = np.array(h_ell) # Extract data from grid p_grid = C[:, 2:7] # pressure in Pascal T_grid = C[:, 7:12] # temperature in Kelvin Q_grid = C[:, 12:17] / 1000 # specific humidity in kg/kg dT_grid = C[:, 17:22] / 1000 # temperature lapse rate in Kelvin/m u_grid = C[:, 22] # geoid undulation in m Hs_grid = C[:, 23] # orthometric grid height in m ah_grid = C[:, 24: 29] / 1000 # hydrostatic mapping function coefficient, dimensionless aw_grid = C[:, 29: 34] / 1000 # wet mapping function coefficient, dimensionless la_grid = C[:, 34:39] # water vapor decrease factor, dimensionless Tm_grid = C[:, 39:44] # mean temperature in Kelvin Gn_h_grid = C[:, 44:49] / 100000 # hydrostatic north gradient in m Ge_h_grid = C[:, 49:54] / 100000 # hydrostatic east gradient in m Gn_w_grid = C[:, 54:59] / 100000 # wet north gradient in m Ge_w_grid = C[:, 59:64] / 100000 # wet east gradient in m # Convert from datetime to doy doy = float(conv.dt2doy(dtin)) + conv.dt2fracday(dtin) # determine the GPT3 coefficients # mean gravity in m/s**2 gm = 9.80665 # molar mass of dry air in kg/mol dMtr = 28.965e-3 # universal gas constant in J/K/mol Rg = 8.3143 # factors for amplitudes if it == 1: # then constant parameters cosfy = 0 coshy = 0 sinfy = 0 sinhy = 0 else: cosfy = np.cos(doy / 365.25 * 2 * np.pi) # coefficient for A1 coshy = np.cos(doy / 365.25 * 4 * np.pi) # coefficient for B1 sinfy = np.sin(doy / 365.25 * 2 * np.pi) # coefficient for A2 sinhy = np.sin(doy / 365.25 * 4 * np.pi) # coefficient for B2 nstat = lat.size # initialization p = np.zeros([nstat, 1]) T = np.zeros([nstat, 1]) dT = np.zeros([nstat, 1]) Tm = np.zeros([nstat, 1]) e = np.zeros([nstat, 1]) ah = np.zeros([nstat, 1]) aw = np.zeros([nstat, 1]) la = np.zeros([nstat, 1]) undu = np.zeros([nstat, 1]) Gn_h = np.zeros([nstat, 1]) Ge_h = np.zeros([nstat, 1]) Gn_w = np.zeros([nstat, 1]) Ge_w = np.zeros([nstat, 1]) if lon < 0: plon = (lon + 2 * np.pi) * 180 / np.pi else: plon = lon * 180 / np.pi ppod = (-lat + np.pi / 2) * 180 / np.pi ipod = np.floor(ppod + 1) ilon = np.floor(plon + 1) # changed for the 1 degree grid diffpod = (ppod - (ipod - 0.5)) difflon = (plon - (ilon - 0.5)) if ipod == 181: ipod = 180 if ilon == 361: ilon = 1 if ilon == 0: ilon = 360 indx = np.zeros(4) indx[0] = (ipod - 1) * 360 + ilon # near the poles: nearest neighbour interpolation, otherwise: bilinear # with the 1 degree grid the limits are lower and upper bilinear = 0 if ppod > 0.5 and ppod < 179.5: bilinear = 1 if bilinear == 0: ix = int(indx[0]) - 1 # transforming ellipsoidal height to orthometric height undu = u_grid[ix] hgt = h_ell - undu # pressure, temperature at the height of the grid T0 = T_grid[ix, 0] + T_grid[ix, 1] * cosfy + T_grid[ ix, 2] * sinfy + T_grid[ix, 3] * coshy + T_grid[ix, 4] * sinhy p0 = p_grid[ix, 0] + p_grid[ix, 1] * cosfy + p_grid[ ix, 2] * sinfy + p_grid[ix, 3] * coshy + p_grid[ix, 4] * sinhy # specific humidity Q = Q_grid[ix, 0] + Q_grid[ix, 1] * cosfy + Q_grid[ ix, 2] * sinfy + Q_grid[ix, 3] * coshy + Q_grid[ix, 4] * sinhy # lapse rate of the temperature dT = dT_grid[ix, 0] + dT_grid[ix, 1] * cosfy + dT_grid[ ix, 2] * sinfy + dT_grid[ix, 3] * coshy + dT_grid[ix, 4] * sinhy # station height - grid height redh = hgt - Hs_grid[ix] # temperature at station height in Celsius T = T0 + dT * redh - 273.15 # temperature lapse rate in degrees / km dT = dT * 1000 # virtual temperature in Kelvin Tv = T0 * [1 + 0.6077 * Q] c = gm * dMtr / [Rg * Tv] # pressure in hPa p = [p0 * np.exp[-c * redh]] / 100 # hydrostatic and wet coefficients ah and aw ah = ah_grid[ix, 0] + ah_grid[ix, 2] * cosfy + ah_grid[ ix, 3] * sinfy + ah_grid[ix, 4] * coshy + ah_grid[ix, 5] * sinhy aw = aw_grid[ix, 0] + aw_grid[ix, 2] * cosfy + aw_grid[ ix, 3] * sinfy + aw_grid[ix, 4] * coshy + aw_grid[ix, 5] * sinhy # water vapour decrease factor la la = la_grid[ix,0] + \ la_grid[ix,1]*cosfy + la_grid[ix,2]*sinfy + \ la_grid[ix,3]*coshy + la_grid[ix,4]*sinhy # mean temperature Tm Tm = Tm_grid[ix,0] + \ Tm_grid[ix,1]*cosfy + Tm_grid[ix,2]*sinfy + \ Tm_grid[ix,3]*coshy + Tm_grid[ix,4]*sinhy # north and east gradients [total, hydrostatic and wet] Gn_h = Gn_h_grid[ix, 0] + Gn_h_grid[ix, 1] * cosfy + Gn_h_grid[ ix, 2] * sinfy + Gn_h_grid[ix, 3] * coshy + Gn_h_grid[ix, 4] * sinhy Ge_h = Ge_h_grid[ix, 0] + Ge_h_grid[ix, 1] * cosfy + Ge_h_grid[ ix, 2] * sinfy + Ge_h_grid[ix, 3] * coshy + Ge_h_grid[ix, 4] * sinhy Gn_w = Gn_w_grid[ix, 0] + Gn_w_grid[ix, 1] * cosfy + Gn_w_grid[ ix, 2] * sinfy + Gn_w_grid[ix, 3] * coshy + Gn_w_grid[ix, 4] * sinhy Ge_w = Ge_w_grid[ix, 0] + Ge_w_grid[ix, 1] * cosfy + Ge_w_grid[ ix, 2] * sinfy + Ge_w_grid[ix, 3] * coshy + Ge_w_grid[ix, 4] * sinhy # water vapor pressure in hPa e0 = Q * p0 / [0.622 + 0.378 * Q] / 100 # on the grid e = e0 * (100 * p / p0)**( la + 1) # on the station height - (14] Askne and Nordius, 1987 else: ipod1 = ipod + 1 * np.sign(diffpod) ilon1 = ilon + 1 * np.sign(difflon) # changed for the 1 degree grid if ilon1 == 361: ilon1 = 1 if ilon1 == 0: ilon1 = 360 # get the number of the line # changed for the 1 degree grid indx[1] = (ipod1 - 1) * 360 + ilon # along same longitude indx[2] = (ipod - 1) * 360 + ilon1 # along same polar distance indx[3] = (ipod1 - 1) * 360 + ilon1 # diagonal indx = indx.astype(int) indx = indx - 1 # transforming ellipsoidal height to orthometric height: Hortho = -N + Hell undul = u_grid[indx] hgt = h_ell - undul # pressure, temperature at the height of the grid T0 = T_grid[indx, 0] + T_grid[indx, 1] * cosfy + T_grid[ indx, 2] * sinfy + T_grid[indx, 3] * coshy + T_grid[indx, 4] * sinhy p0 = p_grid[indx, 0] + p_grid[indx, 1] * cosfy + p_grid[ indx, 2] * sinfy + p_grid[indx, 3] * coshy + p_grid[indx, 4] * sinhy # humidity Ql = Q_grid[indx, 0] + Q_grid[indx, 1] * cosfy + Q_grid[ indx, 2] * sinfy + Q_grid[indx, 3] * coshy + Q_grid[indx, 4] * sinhy # reduction = stationheight - gridheight Hs1 = Hs_grid[indx] redh = hgt - Hs1 # lapse rate of the temperature in degree / m dTl = dT_grid[indx, 0] + dT_grid[indx, 1] * cosfy + dT_grid[ indx, 2] * sinfy + dT_grid[indx, 3] * coshy + dT_grid[indx, 4] * sinhy # temperature reduction to station height Tl = T0 + dTl * redh - 273.15 # virtual temperature Tv = T0 * (1 + 0.6077 * Ql) c = gm * dMtr / (Rg * Tv) # pressure in hPa pl = (p0 * np.exp(-c * redh)) / 100 # hydrostatic and wet coefficients ah and aw ahl = ah_grid[indx, 0] + ah_grid[indx, 1] * cosfy + ah_grid[ indx, 2] * sinfy + ah_grid[indx, 3] * coshy + ah_grid[indx, 4] * sinhy awl = aw_grid[indx, 0] + aw_grid[indx, 1] * cosfy + aw_grid[ indx, 2] * sinfy + aw_grid[indx, 3] * coshy + aw_grid[indx, 4] * sinhy # water vapour decrease factor la lal = la_grid[indx, 0] + la_grid[indx, 1] * cosfy + la_grid[ indx, 2] * sinfy + la_grid[indx, 3] * coshy + la_grid[indx, 4] * sinhy # mean temperature of the water vapor Tm Tml = Tm_grid[indx, 0] + Tm_grid[indx, 1] * cosfy + Tm_grid[ indx, 2] * sinfy + Tm_grid[indx, 3] * coshy + Tm_grid[indx, 4] * sinhy # north and east gradients [total, hydrostatic and wet] Gn_hl = Gn_h_grid[indx, 0] + Gn_h_grid[indx, 1] * cosfy + Gn_h_grid[ indx, 2] * sinfy + Gn_h_grid[indx, 3] * coshy + Gn_h_grid[ indx, 4] * sinhy Ge_hl = Ge_h_grid[indx, 0] + Ge_h_grid[indx, 1] * cosfy + Ge_h_grid[ indx, 2] * sinfy + Ge_h_grid[indx, 3] * coshy + Ge_h_grid[ indx, 4] * sinhy Gn_wl = Gn_w_grid[indx, 0] + Gn_w_grid[indx, 1] * cosfy + Gn_w_grid[ indx, 2] * sinfy + Gn_w_grid[indx, 3] * coshy + Gn_w_grid[ indx, 4] * sinhy Ge_wl = Ge_w_grid[indx, 0] + Ge_w_grid[indx, 1] * cosfy + Ge_w_grid[ indx, 2] * sinfy + Ge_w_grid[indx, 3] * coshy + Ge_w_grid[ indx, 4] * sinhy # water vapor pressure in hPa e0 = Ql * p0 / (0.622 + 0.378 * Ql) / 100 # on the grid el = e0 * (100 * pl / p0)**( lal + 1) # on the station height - [14] Askne and Nordius, 1987 dnpod1 = abs(diffpod) # distance nearer point dnpod2 = 1 - dnpod1 # distance to distant point dnlon1 = abs(difflon) dnlon2 = 1 - dnlon1 # pressure R1 = dnpod2 * pl[0] + dnpod1 * pl[1] R2 = dnpod2 * pl[2] + dnpod1 * pl[3] p = dnlon2 * R1 + dnlon1 * R2 # temperature R1 = dnpod2 * Tl[0] + dnpod1 * Tl[1] R2 = dnpod2 * Tl[2] + dnpod1 * Tl[3] T = dnlon2 * R1 + dnlon1 * R2 # temperature in degree per km R1 = dnpod2 * dTl[0] + dnpod1 * dTl[1] R2 = dnpod2 * dTl[2] + dnpod1 * dTl[3] dT = (dnlon2 * R1 + dnlon1 * R2) * 1000 # water vapor pressure in hPa R1 = dnpod2 * el[0] + dnpod1 * el[1] R2 = dnpod2 * el[2] + dnpod1 * el[3] e = dnlon2 * R1 + dnlon1 * R2 # ah and aw R1 = dnpod2 * ahl[0] + dnpod1 * ahl[1] R2 = dnpod2 * ahl[2] + dnpod1 * ahl[3] ah = dnlon2 * R1 + dnlon1 * R2 R1 = dnpod2 * awl[0] + dnpod1 * awl[1] R2 = dnpod2 * awl[2] + dnpod1 * awl[3] aw = dnlon2 * R1 + dnlon1 * R2 # undulation R1 = dnpod2 * undul[0] + dnpod1 * undul[1] R2 = dnpod2 * undul[2] + dnpod1 * undul[3] undu = dnlon2 * R1 + dnlon1 * R2 # water vapor decrease factor la R1 = dnpod2 * lal[0] + dnpod1 * lal[1] R2 = dnpod2 * lal[2] + dnpod1 * lal[3] la = dnlon2 * R1 + dnlon1 * R2 # gradients R1 = dnpod2 * Gn_hl[0] + dnpod1 * Gn_hl[1] R2 = dnpod2 * Gn_hl[2] + dnpod1 * Gn_hl[3] Gn_h = (dnlon2 * R1 + dnlon1 * R2) R1 = dnpod2 * Ge_hl[0] + dnpod1 * Ge_hl[1] R2 = dnpod2 * Ge_hl[2] + dnpod1 * Ge_hl[3] Ge_h = (dnlon2 * R1 + dnlon1 * R2) R1 = dnpod2 * Gn_wl[0] + dnpod1 * Gn_wl[1] R2 = dnpod2 * Gn_wl[2] + dnpod1 * Gn_wl[3] Gn_w = (dnlon2 * R1 + dnlon1 * R2) R1 = dnpod2 * Ge_wl[0] + dnpod1 * Ge_wl[1] R2 = dnpod2 * Ge_wl[2] + dnpod1 * Ge_wl[3] Ge_w = (dnlon2 * R1 + dnlon1 * R2) # mean temperature of the water vapor Tm R1 = dnpod2 * Tml[0] + dnpod1 * Tml[1] R2 = dnpod2 * Tml[2] + dnpod1 * Tml[3] Tm = dnlon2 * R1 + dnlon1 * R2 soln = [np.round(p,3),np.round(T,3),np.round(dT,3),np.round(Tm,3),np.round(e,3), \ np.round(ah,3),np.round(aw,3),np.round(la,3),np.round(undu,3),np.round(Gn_h,3),np.round(Ge_h,3), \ np.round(Gn_w,3),np.round(Ge_w,3)] return soln