def _find_test_times( base_dir, test_date ): """ Locates start and end times of tests in a larger dataframe containing all tube data Parameters ---------- base_dir : str Base data directory, (e.g. `/d/Data/Raw/`) test_date : str ISO 8601 formatted date of test data Returns ------- pd.DataFrame Dataframe containing start and end times of each test """ # end times # The tube will only automatically go `Closed -> Vent` at the end of # a completed test cycle loc_state = os.path.join(base_dir, test_date, "tube state.tdms") df_state = TdmsFile(loc_state).as_dataframe() df_state.columns = ["time", "state", "mode"] df_test_times = pd.DataFrame(columns=["shot", "start", "end"]) df_test_times["end"] = df_state[ (df_state["state"].shift(1) == "Tube Closed") & (df_state["state"] == "Tube Vent") & (df_state["mode"] == "auto") ]["time"] df_test_times.reset_index(drop=True, inplace=True) df_test_times["shot"] = df_test_times.index.values # start times # A test will be considered to have started at the last automatic mix # section purge preceding its end time. for i, time in enumerate(df_test_times["end"].values): df_test_times.at[i, "start"] = df_state[ (df_state["time"].values < time) & (df_state["state"] == "Mix Section Purge") & (df_state["mode"] == "auto") ].iloc[-1].time df_test_times["start"] = pd.to_datetime(df_test_times["start"]) return df_test_times
event_times = [] for time in events_df['Time']: timestamp = time.split('-')[-1] hh,mm,ss = timestamp.split(':') timestamp = 3600*int(hh)+60*int(mm)+int(ss)-int(ignition) event_times.append(timestamp) events_df['Time Elapsed']=event_times print(events_df) events_df = events_df.set_index('Event') for event in events_df: event.split('-') events_dict[test] = events_df # exit() #Read data dataframe data_df.columns = [column[13:-1] for column in data_df.columns.values] #Make a list of elapsed time elapsed_time = [] for t in data_df['Time']: timestamp = t.split(' ')[-1] hh,mm,ss = timestamp.split(':') timestamp = 3600*int(hh)+60*int(mm)+int(ss)-int(ignition) elapsed_time.append(timestamp) #Set index as elapsed time data_df['Elapsed Time'] = elapsed_time data_df = data_df.set_index('Elapsed Time')
event_times = [] for time in events_df['Time']: timestamp = time.split('-')[-1] hh, mm, ss = timestamp.split(':') timestamp = 3600 * int(hh) + 60 * int(mm) + int(ss) - int(ignition) event_times.append(timestamp) events_df['Time Elapsed'] = event_times print(events_df) events_df = events_df.set_index('Event') for event in events_df: event.split('-') events_dict[test] = events_df # exit() #Read data dataframe data_df.columns = [column[13:-1] for column in data_df.columns.values] #Make a list of elapsed time elapsed_time = [] for t in data_df['Time']: timestamp = t.split(' ')[-1] hh, mm, ss = timestamp.split(':') timestamp = 3600 * int(hh) + 60 * int(mm) + int(ss) - int(ignition) elapsed_time.append(timestamp) #Set index as elapsed time data_df['Elapsed Time'] = elapsed_time data_df = data_df.set_index('Elapsed Time') #Divide data datafrane into pre_exp_data = data_df.loc[:-1, :]
def __call__( cls, base_dir, test_date, sample_time=pd.Timedelta(seconds=70), mech="gri30.cti", diode_spacing=1.0668, multiprocess=False ): """ Process data from a day of testing using the newer directory structure Parameters ---------- base_dir : str Base data directory, (e.g. `/d/Data/Raw/`) test_date : str ISO 8601 formatted date of test data sample_time : None or pd.Timedelta Length of hold period at the end of a fill state. If None is passed, value will be read from nominal test conditions. mech : str Mechanism for cantera calculations diode_spacing : float Diode spacing, in meters multiprocess : bool Set true to parallelize data analysis Returns ------- Tuple[pd.DataFrame, Dict] Tuple containing a dataframe of test results and a dictionary of background subtracted schlieren images """ dir_data = os.path.join(base_dir, test_date) df_tests = cls._find_test_times(base_dir, test_date) n_found_tests = len(df_tests) n_shot_dirs = len([d for d in os.listdir(dir_data) if "Shot" in d]) if n_found_tests == 0: raise ValueError("No tests detected in sensor log.tdms") elif n_found_tests != n_shot_dirs: raise ValueError("Number of tests does not match number of shots") df_nominal = cls._load_nominal_conditions(dir_data) df_sensor = TdmsFile(os.path.join( dir_data, "sensor log.tdms" )).as_dataframe() df_pressure = cls._extract_sensor_data(df_sensor, "pressure") df_temperature = cls._extract_sensor_data(df_sensor, "temperature") del df_sensor df_schlieren = pd.DataFrame(columns=["shot", "schlieren"]) df_schlieren["schlieren"] = _collect_schlieren_dirs( base_dir, test_date ) df_schlieren["shot"] = df_schlieren["schlieren"] df_schlieren["shot"] = [ int(os.path.split(d)[1].lower().replace("shot", "").strip()) for d in df_schlieren["schlieren"] if "failed" not in d ] df_tests = df_tests.merge(df_schlieren, on="shot", how="left") df_diode_locs = pd.DataFrame(columns=["shot", "diodes"]) df_diode_locs["diodes"] = find_diode_data(dir_data) df_diode_locs["shot"] = [ int( os.path.split( os.path.dirname(d))[1].lower().replace( "shot", "" ).strip() ) for d in df_diode_locs["diodes"] ] df_tests = df_tests.merge(df_diode_locs, on="shot", how="left") df_state = TdmsFile(os.path.join( base_dir, test_date, "tube state.tdms" )).as_dataframe() df_state.columns = ["time", "state", "mode"] images = dict() if multiprocess: pool = mp.Pool() results = pool.starmap( cls._process_single_test, [[ idx, df_nominal, df_pressure, df_temperature, df_state, sample_time, test_time_row, mech, diode_spacing ] for idx, test_time_row in df_tests.iterrows()] ) for idx, row_results in results: if row_results["schlieren"] is not None: images.update(row_results["schlieren"]) df_tests.at[idx, "t_0"] = row_results["t_0"] df_tests.at[idx, "u_t_0"] = row_results["u_t_0"] df_tests.at[idx, "p_0_nom"] = row_results["p_0_nom"] df_tests.at[idx, "p_0"] = row_results["p_0"] df_tests.at[idx, "u_p_0"] = row_results["u_p_0"] df_tests.at[idx, "phi_nom"] = row_results["phi_nom"] df_tests.at[idx, "phi"] = row_results["phi"] df_tests.at[idx, "u_phi"] = row_results["u_phi"] df_tests.at[idx, "fuel"] = row_results["fuel"] df_tests.at[idx, "p_fuel"] = row_results["p_fuel"] df_tests.at[idx, "u_p_fuel"] = row_results["u_p_fuel"] df_tests.at[idx, "oxidizer"] = row_results["oxidizer"] df_tests.at[idx, "p_oxidizer"] = row_results["p_oxidizer"] df_tests.at[idx, "u_p_oxidizer"] = row_results["u_p_oxidizer"] df_tests.at[idx, "diluent"] = row_results["diluent"] df_tests.at[idx, "p_diluent"] = row_results["p_diluent"] df_tests.at[idx, "u_p_diluent"] = row_results["u_p_diluent"] df_tests.at[idx, "dil_mf_nom"] = row_results["dil_mf_nom"] df_tests.at[idx, "dil_mf"] = row_results["dil_mf"] df_tests.at[idx, "u_dil_mf"] = row_results["u_dil_mf"] df_tests.at[idx, "wave_speed"] = row_results["wave_speed"] df_tests.at[idx, "u_wave_speed"] = row_results["u_wave_speed"] df_tests.at[idx, "cutoff_fuel"] = row_results["cutoff_fuel"] df_tests.at[idx, "cutoff_vacuum"] = row_results["cutoff_vacuum"] df_tests.at[idx, "cutoff_diluent"] = \ row_results["cutoff_diluent"] df_tests.at[idx, "cutoff_oxidizer"] = \ row_results["cutoff_oxidizer"] df_tests.at[idx, "u_cutoff_fuel"] = \ row_results["u_cutoff_fuel"] df_tests.at[idx, "u_cutoff_vacuum"] = \ row_results["u_cutoff_vacuum"] df_tests.at[idx, "u_cutoff_diluent"] = \ row_results["u_cutoff_diluent"] df_tests.at[idx, "u_cutoff_oxidizer"] = \ row_results["u_cutoff_oxidizer"] else: for idx, test_time_row in df_tests.iterrows(): # noinspection PyTypeChecker _, row_results = cls._process_single_test( idx, df_nominal, df_pressure, df_temperature, df_state, sample_time, test_time_row, mech, diode_spacing ) # output results if row_results["schlieren"] is not None: images.update(row_results["schlieren"]) df_tests.at[idx, "t_0"] = row_results["t_0"] df_tests.at[idx, "u_t_0"] = row_results["u_t_0"] df_tests.at[idx, "p_0_nom"] = row_results["p_0_nom"] df_tests.at[idx, "p_0"] = row_results["p_0"] df_tests.at[idx, "u_p_0"] = row_results["u_p_0"] df_tests.at[idx, "phi_nom"] = row_results["phi_nom"] df_tests.at[idx, "phi"] = row_results["phi"] df_tests.at[idx, "u_phi"] = row_results["u_phi"] df_tests.at[idx, "fuel"] = row_results["fuel"] df_tests.at[idx, "p_fuel"] = row_results["p_fuel"] df_tests.at[idx, "u_p_fuel"] = row_results["u_p_fuel"] df_tests.at[idx, "oxidizer"] = row_results["oxidizer"] df_tests.at[idx, "p_oxidizer"] = row_results["p_oxidizer"] df_tests.at[idx, "u_p_oxidizer"] = row_results["u_p_oxidizer"] df_tests.at[idx, "diluent"] = row_results["diluent"] df_tests.at[idx, "p_diluent"] = row_results["p_diluent"] df_tests.at[idx, "u_p_diluent"] = row_results["u_p_diluent"] df_tests.at[idx, "dil_mf_nom"] = row_results["dil_mf_nom"] df_tests.at[idx, "dil_mf"] = row_results["dil_mf"] df_tests.at[idx, "u_dil_mf"] = row_results["u_dil_mf"] df_tests.at[idx, "wave_speed"] = row_results["wave_speed"] df_tests.at[idx, "u_wave_speed"] = row_results["u_wave_speed"] df_tests.at[idx, "cutoff_fuel"] = row_results["cutoff_fuel"] df_tests.at[idx, "cutoff_vacuum"] = row_results["cutoff_vacuum"] df_tests.at[idx, "cutoff_diluent"] = \ row_results["cutoff_diluent"] df_tests.at[idx, "cutoff_oxidizer"] = \ row_results["cutoff_oxidizer"] df_tests.at[idx, "u_cutoff_fuel"] = \ row_results["u_cutoff_fuel"] df_tests.at[idx, "u_cutoff_vacuum"] = \ row_results["u_cutoff_vacuum"] df_tests.at[idx, "u_cutoff_diluent"] = \ row_results["u_cutoff_diluent"] df_tests.at[idx, "u_cutoff_oxidizer"] = \ row_results["u_cutoff_oxidizer"] df_tests["date"] = test_date # keep diluent dtype consistent as object. Using notna because pd.where # works backwards compared with np.where and also my brain. df_tests["diluent"].where( df_tests["diluent"].notna(), "None", inplace=True ) return df_tests, images