def remove_seasonals_by_notch(Data): # Using Sang-Ho's notch filter script to remove power at frequencies corresponding to 1 year and 6 months. # We are also removing a linear trend in this step. Data = gps_ts_functions.remove_nans(Data); # Parameters # % x 1-D signal array # % fs sampling frequency, Hz # % fn notch frequency, Hz # % Bn notch bandwidth, Hz dt_interval = 1.0; # one day fs = 1 / dt_interval; fn1 = 1.0 / 365.24; # fn = notch frequency, annual Bn1 = 0.1 * fn1; fn2 = 2.0 / 365.24; # fn = notch frequency, semiannual Bn2 = 0.1 * fn2; # a choice: 10% seems to work well. decyear = gps_ts_functions.get_float_times(Data.dtarray); dE_detrended = np.zeros(np.shape(Data.dE)); dN_detrended = np.zeros(np.shape(Data.dN)); dU_detrended = np.zeros(np.shape(Data.dU)); dE_trended = np.zeros(np.shape(Data.dE)); dN_trended = np.zeros(np.shape(Data.dN)); dU_trended = np.zeros(np.shape(Data.dU)); # East x = Data.dE; dE_filt = notch_filter.notchfilt(x, fs, fn1, Bn1, filtfiltopt=True); dE_filt = notch_filter.notchfilt(dE_filt, fs, fn2, Bn2, filtfiltopt=True); east_coef = np.polyfit(decyear, dE_filt, 1)[0]; for i in range(len(dE_filt)): dE_detrended[i] = dE_filt[i] - east_coef * decyear[i] - (dE_filt[0] - east_coef * decyear[0]); dE_trended[i] = dE_filt[i]; # North x = Data.dN; dN_filt = notch_filter.notchfilt(x, fs, fn1, Bn1, filtfiltopt=True); dN_filt = notch_filter.notchfilt(dN_filt, fs, fn2, Bn2, filtfiltopt=True); north_coef = np.polyfit(decyear, dN_filt, 1)[0]; for i in range(len(dN_filt)): dN_detrended[i] = dN_filt[i] - north_coef * decyear[i] - (dN_filt[0] - north_coef * decyear[0]); dN_trended[i] = dN_filt[i]; # Up x = Data.dU; dU_filt = notch_filter.notchfilt(x, fs, fn1, Bn1, filtfiltopt=True); dU_filt = notch_filter.notchfilt(dU_filt, fs, fn2, Bn2, filtfiltopt=True); vert_coef = np.polyfit(decyear, dU_filt, 1)[0]; for i in range(len(dU_filt)): dU_detrended[i] = dU_filt[i] - vert_coef * decyear[i] - (dU_filt[0] - vert_coef * decyear[0]); dU_trended[i] = dU_filt[i]; detrended = gps_io_functions.Timeseries(name=Data.name, coords=Data.coords, dtarray=Data.dtarray, dN=dN_detrended, dE=dE_detrended, dU=dU_detrended, Sn=Data.Sn, Se=Data.Se, Su=Data.Su, EQtimes=Data.EQtimes); trended = gps_io_functions.Timeseries(name=Data.name, coords=Data.coords, dtarray=Data.dtarray, dN=dN_trended, dE=dE_trended, dU=dU_trended, Sn=Data.Sn, Se=Data.Se, Su=Data.Su, EQtimes=Data.EQtimes); return detrended, trended;
def remove_seasonals_by_GRACE(Data, grace_dir): # Here we use pre-computed GRACE load model time series to correct the GPS time series. # We recognize that the horizontals will be bad, and that the resolution of GRACE is coarse. # For these reasons, this is not an important part of the analysis. # Read and interpolate GRACE loading model # Subtract the GRACE model # Remove a trend from the GPS data # Return the object. filename = grace_dir + "scaled_" + Data.name + "_PREM_model_ts.txt"; if not os.path.isfile(filename): print("Error! GRACE not found for %s" % Data.name); print("Returning placeholder object."); wimpyObj = get_wimpy_object(Data) return wimpyObj, wimpyObj; # If the station has been pre-computed with GRACE: Data = gps_ts_functions.remove_nans(Data); [grace_model] = gps_io_functions.read_grace(filename); my_paired_ts = grace_ts_functions.pair_GPSGRACE(Data, grace_model); decyear = gps_ts_functions.get_float_times(my_paired_ts.dtarray); # Subtract the GRACE object dE_filt, dN_filt, dU_filt = [], [], []; for i in range(len(my_paired_ts.dtarray)): dE_filt.append(my_paired_ts.east[i] - my_paired_ts.u[i]); dN_filt.append(my_paired_ts.north[i] - my_paired_ts.v[i]); dU_filt.append(my_paired_ts.vert[i] - my_paired_ts.w[i]); # A Simple detrending dE_detrended = np.zeros(np.shape(decyear)); dN_detrended = np.zeros(np.shape(decyear)); dU_detrended = np.zeros(np.shape(decyear)); east_coef = np.polyfit(decyear, dE_filt, 1)[0]; for i in range(len(dE_filt)): dE_detrended[i] = dE_filt[i] - east_coef * decyear[i] - (dE_filt[0] - east_coef * decyear[0]); north_coef = np.polyfit(decyear, dN_filt, 1)[0]; for i in range(len(dN_filt)): dN_detrended[i] = (dN_filt[i] - north_coef * decyear[i]) - (dN_filt[0] - north_coef * decyear[0]); vert_coef = np.polyfit(decyear, dU_filt, 1)[0]; for i in range(len(dU_filt)): dU_detrended[i] = (dU_filt[i] - vert_coef * decyear[i]) - (dU_filt[0] - vert_coef * decyear[0]); detrended = gps_io_functions.Timeseries(name=Data.name, coords=Data.coords, dtarray=my_paired_ts.dtarray, dN=dN_detrended, dE=dE_detrended, dU=dU_detrended, Sn=my_paired_ts.N_err, Se=my_paired_ts.E_err, Su=my_paired_ts.V_err, EQtimes=Data.EQtimes); trended = gps_io_functions.Timeseries(name=Data.name, coords=Data.coords, dtarray=my_paired_ts.dtarray, dN=dN_filt, dE=dE_filt, dU=dU_filt, Sn=my_paired_ts.N_err, Se=my_paired_ts.E_err, Su=my_paired_ts.V_err, EQtimes=Data.EQtimes); return detrended, trended; # 0 = successful completion
def remove_seasonals_by_german_load(Data, lsdm_dir): station = Data.name; files = glob.glob(lsdm_dir + station + '*.txt'); if not files: # found an empty array print("Error! LSDM file not found for %s" % Data.name); print("Returning placeholder object."); wimpyObj = get_wimpy_object(Data); return wimpyObj, wimpyObj; else: filename = files[0]; # Read the hydro model and pair it to the GPS [hydro_data] = gps_io_functions.read_lsdm_file(filename); # Clean up and pair data Data = gps_ts_functions.remove_nans(Data); hydro_data = gps_ts_functions.remove_nans(hydro_data); # this may or may not be necessary. [gps_data, hydro_data] = gps_ts_functions.pair_gps_model(Data, hydro_data); # matched in terms of dtarray. # Subtract the model from the data. dE_filt, dN_filt, dU_filt = [], [], []; for i in range(len(gps_data.dtarray)): dE_filt.append(gps_data.dE[i] - hydro_data.dE[i]); dN_filt.append(gps_data.dN[i] - hydro_data.dN[i]); dU_filt.append(gps_data.dU[i] - hydro_data.dU[i]); # A Simple detrending decyear = gps_ts_functions.get_float_times(gps_data.dtarray); dE_detrended = np.zeros(np.shape(decyear)); dN_detrended = np.zeros(np.shape(decyear)); dU_detrended = np.zeros(np.shape(decyear)); east_coef = np.polyfit(decyear, dE_filt, 1)[0]; for i in range(len(dE_filt)): dE_detrended[i] = dE_filt[i] - east_coef * decyear[i] - (dE_filt[0] - east_coef * decyear[0]); north_coef = np.polyfit(decyear, dN_filt, 1)[0]; for i in range(len(dN_filt)): dN_detrended[i] = (dN_filt[i] - north_coef * decyear[i]) - (dN_filt[0] - north_coef * decyear[0]); vert_coef = np.polyfit(decyear, dU_filt, 1)[0]; for i in range(len(dU_filt)): dU_detrended[i] = (dU_filt[i] - vert_coef * decyear[i]) - (dU_filt[0] - vert_coef * decyear[0]); detrended = gps_io_functions.Timeseries(name=gps_data.name, coords=gps_data.coords, dtarray=gps_data.dtarray, dE=dE_detrended, dN=dN_detrended, dU=dU_detrended, Se=gps_data.Se, Sn=gps_data.Sn, Su=gps_data.Su, EQtimes=gps_data.EQtimes); trended = gps_io_functions.Timeseries(name=gps_data.name, coords=gps_data.coords, dtarray=gps_data.dtarray, dE=dE_filt, dN=dN_filt, dU=dU_filt, Se=gps_data.Se, Sn=gps_data.Sn, Su=gps_data.Su, EQtimes=gps_data.EQtimes); return detrended, trended;
def remove_offsets(Data0, offsets_obj): # the actual subtraction of offsets. if not offsets_obj: return Data0; if len(offsets_obj.e_offsets) == 0: return Data0; newdtarray = []; newdN, newdE, newdU = [], [], []; # Removing offsets for i in range(len(Data0.dtarray)): # For each day... tempE = Data0.dE[i]; tempN = Data0.dN[i]; tempU = Data0.dU[i]; for j in range(len(offsets_obj.evdts)): # print("removing %f mm from east at %s" % (offsets_obj.e_offsets[j], offsets_obj.evdts[j])); if Data0.dtarray[i] == offsets_obj.evdts[j]: # removing the date of the offset directly (can be messed up) tempE = np.nan; tempN = np.nan; tempU = np.nan; if Data0.dtarray[i] > offsets_obj.evdts[j]: tempE = tempE - offsets_obj.e_offsets[j]; tempN = tempN - offsets_obj.n_offsets[j]; tempU = tempU - offsets_obj.u_offsets[j]; newdtarray.append(Data0.dtarray[i]); newdE.append(tempE); newdN.append(tempN); newdU.append(tempU); newData = gps_io_functions.Timeseries(name=Data0.name, coords=Data0.coords, dtarray=newdtarray, dN=newdN, dE=newdE, dU=newdU, Sn=Data0.Sn, Se=Data0.Se, Su=Data0.Su, EQtimes=Data0.EQtimes); return newData;
def read_loading_ts(infile): [dtstrings, u, v, w] = np.loadtxt(infile, usecols=(0, 4, 5, 6), unpack=True, dtype={ 'names': ('d', 'u', 'v', 'w'), 'formats': ('U10', np.float, np.float, np.float)}); dtarray = [dt.datetime.strptime(x, "%Y-%m-%d") for x in dtstrings]; S = np.zeros(np.shape(u)); loading_defo = gps_io_functions.Timeseries(name='', coords=[], dtarray=dtarray, dE=u, dN=v, dU=w, Sn=S, Se=S, Su=S, EQtimes=[]); return loading_defo;
def remove_by_model(Data0, data_config_file): # Right now configured for the Hines data. starttime1 = dt.datetime.strptime("20100403", "%Y%m%d"); endtime1 = dt.datetime.strptime("20100405", "%Y%m%d"); starttime2 = dt.datetime.strptime("20200328", "%Y%m%d"); endtime2 = dt.datetime.strptime("20200330", "%Y%m%d"); # Input Hines data. model_data = get_station_hines(Data0.name, data_config_file); if not model_data: # if None return Data0; if len(Data0.dtarray) == 0: # if empty return Data0; if model_data.dtarray[-1] < Data0.dtarray[-1]: print("\nWARNING! Trying to use a short postseismic model to fix a long GNSS time series."); print("PROBLEMS MAY OCCUR- tread carefully!!\n\n"); # These will be the same size. Data0, model = gps_ts_functions.pair_gps_model_keeping_gps(Data0, model_data); # pair_gps_model_keeping_gps leaves data outside of the model timespan # Data0, model = gps_ts_functions.pair_gps_model(Data0, model_data); # removes data outside of the model timespan. # Subtract the model from the data. dtarray, dE_gps, dN_gps, dU_gps = [], [], [], []; Se_gps, Sn_gps, Su_gps = [], [], []; for i in range(len(Data0.dtarray)): dtarray.append(Data0.dtarray[i]); dE_gps.append(Data0.dE[i] - model.dE[i]); dN_gps.append(Data0.dN[i] - model.dN[i]); dU_gps.append(Data0.dU[i] - model.dU[i]); Se_gps.append(Data0.Se[i]); Sn_gps.append(Data0.Sn[i]); Su_gps.append(Data0.Su[i]); # In this method, we correct for offsets at the beginning and end of the modeled time series. interval1 = [starttime1, endtime1]; east_offset1 = offsets.fit_single_offset(dtarray, dE_gps, interval1, 20); north_offset1 = offsets.fit_single_offset(dtarray, dN_gps, interval1, 20); vert_offset1 = offsets.fit_single_offset(dtarray, dU_gps, interval1, 20); interval2 = [starttime2, endtime2]; east_offset2 = offsets.fit_single_offset(dtarray, dE_gps, interval2, 20); north_offset2 = offsets.fit_single_offset(dtarray, dN_gps, interval2, 20); vert_offset2 = offsets.fit_single_offset(dtarray, dU_gps, interval2, 20); offsets_obj = offsets.Offsets(e_offsets=[east_offset1, east_offset2], n_offsets=[north_offset1, north_offset2], u_offsets=[vert_offset1, vert_offset2], evdts=[starttime1, starttime2]); corrected_data = gps_io_functions.Timeseries(name=Data0.name, coords=Data0.coords, dtarray=dtarray, dE=dE_gps, dN=dN_gps, dU=dU_gps, Se=Se_gps, Sn=Sn_gps, Su=Su_gps, EQtimes=Data0.EQtimes); corrected_data = offsets.remove_offsets(corrected_data, offsets_obj); return corrected_data;
def remove_seasonals_by_lakes(Data, lakes_dir, lake_name): station = Data.name; files = glob.glob(lakes_dir + station + "_" + lake_name + "*.txt"); if not files: # found an empty array print("Error! Lake %s file not found for %s" % (lake_name, Data.name)); print("Returning placeholder object."); wimpyObj = get_wimpy_object(Data); return wimpyObj, wimpyObj; else: filename = files[0]; print("Reading loading TS from %s " % filename); loading_ts = read_loading_ts(filename); [GPS_paired, loading_paired] = gps_ts_functions.pair_gps_model(Data, loading_ts); dE = [GPS_paired.dE[i] - loading_paired.dE[i] for i in range(len(GPS_paired.dE))]; dN = [GPS_paired.dN[i] - loading_paired.dN[i] for i in range(len(GPS_paired.dN))]; dU = [GPS_paired.dU[i] - loading_paired.dU[i] for i in range(len(GPS_paired.dU))]; decyear = gps_ts_functions.get_float_times(GPS_paired.dtarray); dE_detrended = np.zeros(np.shape(dE)); dN_detrended = np.zeros(np.shape(dN)); dU_detrended = np.zeros(np.shape(dU)); east_coef = np.polyfit(decyear, dE, 1)[0]; for i in range(len(dE)): dE_detrended[i] = dE[i] - east_coef * decyear[i] - (dE[0] - east_coef * decyear[0]); north_coef = np.polyfit(decyear, dN, 1)[0]; for i in range(len(dN)): dN_detrended[i] = (dN[i] - north_coef * decyear[i]) - (dN[0] - north_coef * decyear[0]); vert_coef = np.polyfit(decyear, dU, 1)[0]; for i in range(len(dU)): dU_detrended[i] = (dU[i] - vert_coef * decyear[i]) - (dU[0] - vert_coef * decyear[0]); corrected_object = gps_io_functions.Timeseries(name=Data.name, coords=Data.coords, dtarray=GPS_paired.dtarray, dE=dE_detrended, dN=dN_detrended, dU=dU_detrended, Se=GPS_paired.Se, Sn=GPS_paired.Sn, Su=GPS_paired.Su, EQtimes=Data.EQtimes); trended = gps_io_functions.Timeseries(name=Data.name, coords=Data.coords, dtarray=GPS_paired.dtarray, dE=dE, dN=dN, dU=dU, Se=GPS_paired.Se, Sn=GPS_paired.Sn, Su=GPS_paired.Su, EQtimes=Data.EQtimes); return corrected_object, trended;
def input_data(st_name, datasource, refframe, data_config_file): [myData, offset_obj, eq_obj] = gps_input_pipeline.get_station_data(st_name, datasource, data_config_file, refframe) # First, we embed the data with the eq object (always useful) myData = gps_io_functions.Timeseries(name=myData.name, coords=myData.coords, dtarray=myData.dtarray, dN=myData.dN, dE=myData.dE, dU=myData.dU, Sn=myData.Sn, Se=myData.Se, Su=myData.Su, EQtimes=eq_obj.evdts) return [myData, offset_obj, eq_obj]
def get_wimpy_object(Data): placeholder = np.full_like(Data.dtarray, np.nan, dtype=np.double) wimpyObj = gps_io_functions.Timeseries(name=Data.name, coords=Data.coords, dtarray=Data.dtarray, dN=placeholder, dE=placeholder, dU=placeholder, Sn=Data.Sn, Se=Data.Se, Su=Data.Su, EQtimes=Data.EQtimes); return wimpyObj;
def remove_seasonals_by_hydro(Data, hydro_dir, scaling=False): station = Data.name; files = glob.glob(hydro_dir + station.lower() + '*.hyd'); if not files: # found an empty array print("Error! Hydro file not found for %s" % Data.name); print("Returning placeholder object."); wimpyObj = get_wimpy_object(Data); return wimpyObj, wimpyObj; else: filename = files[0]; # Read the hydro model and pair it to the GPS [hydro_data] = gps_io_functions.read_pbo_hydro_file(filename); # Clean up and pair data Data = gps_ts_functions.remove_nans(Data); # hydro_data=gps_ts_functions.remove_nans(hydro_data); # this may or may not be necessary. [gps_data, hydro_data] = gps_ts_functions.pair_gps_model(Data, hydro_data); # matched in terms of dtarray. if scaling is True: [_, _, vert_gps] = gps_ts_functions.get_linear_annual_semiannual(gps_data); [_, _, vert_hydro] = gps_ts_functions.get_linear_annual_semiannual(hydro_data); gps_amp = np.sqrt(vert_gps[1] * vert_gps[1] + vert_gps[2] * vert_gps[2]); hydro_amp = np.sqrt(vert_hydro[1] * vert_hydro[1] + vert_hydro[2] * vert_hydro[2]); if hydro_amp == 0.0: print("ERROR! NLDAS amplitude is exactly 0!! You should probably fix this. "); wimpyObj = get_wimpy_object(Data); print("Returning placeholder object."); return wimpyObj, wimpyObj; scale_factor = gps_amp / hydro_amp; # print("GPS Amplitude is %.2f mm" % gps_amp); # print("NLDAS Amplitude is %.2f mm" % hydro_amp); print("NLDAS scaling factor is %.2f" % scale_factor); else: scale_factor = 1; # Subtract the model from the data. dE_filt, dN_filt, dU_filt = [], [], []; for i in range(len(gps_data.dtarray)): dE_filt.append(gps_data.dE[i] - scale_factor * hydro_data.dE[i]); dN_filt.append(gps_data.dN[i] - scale_factor * hydro_data.dN[i]); dU_filt.append(gps_data.dU[i] - scale_factor * hydro_data.dU[i]); # A Simple detrending decyear = gps_ts_functions.get_float_times(gps_data.dtarray); dE_detrended = np.zeros(np.shape(decyear)); dN_detrended = np.zeros(np.shape(decyear)); dU_detrended = np.zeros(np.shape(decyear)); east_coef = np.polyfit(decyear, dE_filt, 1)[0]; for i in range(len(dE_filt)): dE_detrended[i] = dE_filt[i] - east_coef * decyear[i] - (dE_filt[0] - east_coef * decyear[0]); north_coef = np.polyfit(decyear, dN_filt, 1)[0]; for i in range(len(dN_filt)): dN_detrended[i] = (dN_filt[i] - north_coef * decyear[i]) - (dN_filt[0] - north_coef * decyear[0]); vert_coef = np.polyfit(decyear, dU_filt, 1)[0]; for i in range(len(dU_filt)): dU_detrended[i] = (dU_filt[i] - vert_coef * decyear[i]) - (dU_filt[0] - vert_coef * decyear[0]); corrected_object = gps_io_functions.Timeseries(name=gps_data.name, coords=gps_data.coords, dtarray=gps_data.dtarray, dE=dE_detrended, dN=dN_detrended, dU=dU_detrended, Se=gps_data.Se, Sn=gps_data.Sn, Su=gps_data.Su, EQtimes=gps_data.EQtimes); trended = gps_io_functions.Timeseries(name=gps_data.name, coords=gps_data.coords, dtarray=gps_data.dtarray, dE=dE_filt, dN=dN_filt, dU=dU_filt, Se=gps_data.Se, Sn=gps_data.Sn, Su=gps_data.Su, EQtimes=gps_data.EQtimes); return corrected_object, trended;
def remove_seasonals_by_STL(Data, STL_dir): # Has an issue: Not sure if it returns trended data. # Right now only returns detrended data. filename = STL_dir + Data.name + "_STL_30.txt"; if os.path.isfile(filename): # If a precomputed file exists... [dtstrings, dE, dN, dU, Se, Sn, Su] = np.loadtxt(filename, unpack=True, usecols=(0, 1, 2, 3, 4, 5, 6), dtype={'names': ('dt', 'dE', 'dN', 'dU', 'Se', 'Sn', 'Su'), 'formats': ('U8', np.float, np.float, np.float, np.float, np.float, np.float)}); final_dtarray = [dt.datetime.strptime(x, "%Y%m%d") for x in dtstrings]; Data = gps_io_functions.Timeseries(name=Data.name, coords=Data.coords, dtarray=final_dtarray, dN=dN, dE=dE, dU=dU, Sn=Sn, Se=Se, Su=Su, EQtimes=Data.EQtimes); else: # ELSE: WE NEED TO RECOMPUTE print("Warning! STL not found for %s" % Data.name); print("We did not find a pre-computed array, so we are re-computing STL. "); # Preprocess data: remove nans, fill in gaps. Data = gps_ts_functions.remove_nans(Data); [_, dE, Se] = preprocess_stl(Data.dtarray, Data.dE, Data.Se); [_, dN, Sn] = preprocess_stl(Data.dtarray, Data.dN, Data.Sn); [new_dtarray, dU, Su] = preprocess_stl(Data.dtarray, Data.dU, Data.Su); # Write E, N, U ofile = open('raw_ts_data.txt', 'w'); for i in range(len(dE)): mystring = dt.datetime.strftime(new_dtarray[i], "%Y%m%d"); ofile.write('%s %f %f %f\n' % (mystring, dE[i], dN[i], dU[i])); ofile.close(); # Call driver in matlab (read, STL, write) subprocess.call(['matlab', '-nodisplay', '-nosplash', '-r', 'stl_driver'], shell=False); # Read / Detrended data [dE, dN, dU] = np.loadtxt('filtered_ts_data.txt', unpack=True, usecols=(1, 2, 3)); # East, North, Up Detrending decyear = gps_ts_functions.get_float_times(new_dtarray); dE_detrended = np.zeros(np.shape(dE)); dN_detrended = np.zeros(np.shape(dN)); dU_detrended = np.zeros(np.shape(dU)); east_coef = np.polyfit(decyear, dE, 1)[0]; for i in range(len(dE)): dE_detrended[i] = dE[i] - east_coef * decyear[i] - (dE[0] - east_coef * decyear[0]); north_coef = np.polyfit(decyear, dN, 1)[0]; for i in range(len(dN)): dN_detrended[i] = (dN[i] - north_coef * decyear[i]) - (dN[0] - north_coef * decyear[0]); vert_coef = np.polyfit(decyear, dU, 1)[0]; for i in range(len(dU)): dU_detrended[i] = (dU[i] - vert_coef * decyear[i]) - (dU[0] - vert_coef * decyear[0]); # Put the gaps back in: final_dtarray, final_dE, final_dN, final_dU = [], [], [], []; final_Se, final_Sn, final_Su = [], [], []; for i in range(len(new_dtarray)): if new_dtarray[i] in Data.dtarray: final_dtarray.append(new_dtarray[i]); final_dE.append(dE_detrended[i]); final_dN.append(dN_detrended[i]); final_dU.append(dU_detrended[i]); final_Se.append(Se[i]); final_Sn.append(Sn[i]); final_Su.append(Su[i]); final_dE = np.array(final_dE); final_dN = np.array(final_dN); final_dU = np.array(final_dU); final_Se = np.array(final_Se); final_Sn = np.array(final_Sn); final_Su = np.array(final_Su); # Return data Data = gps_io_functions.Timeseries(name=Data.name, coords=Data.coords, dtarray=final_dtarray, dN=final_dN, dE=final_dE, dU=final_dU, Sn=final_Sn, Se=final_Se, Su=final_Su, EQtimes=Data.EQtimes); # Write the file so that we don't recompute it next time. output_stl(Data, STL_dir); return Data, Data;