diff --git a/src/pygama/raw/buffer_processor/buffer_processor.py b/src/pygama/raw/buffer_processor/buffer_processor.py index c4968e681..335b32de4 100644 --- a/src/pygama/raw/buffer_processor/buffer_processor.py +++ b/src/pygama/raw/buffer_processor/buffer_processor.py @@ -9,7 +9,7 @@ import pygama.lgdo as lgdo from pygama.dsp.errors import ProcessingChainError from pygama.dsp.processing_chain import build_processing_chain as bpc -from pygama.lgdo import Array, ArrayOfEqualSizedArrays +from pygama.lgdo import Array, ArrayOfEqualSizedArrays, Table if TYPE_CHECKING: from pygama.raw.raw_buffer import RawBuffer @@ -17,10 +17,11 @@ log = logging.getLogger(__name__) -def buffer_processor(rb: RawBuffer) -> None: +def buffer_processor(rb: RawBuffer) -> Table: r""" Takes in a :class:`.RawBuffer`, performs any processes specified in the :class:`.RawBuffer`'s ``proc_spec`` - attribute. Currently implemented attributes: + attribute, and returns a :class:`pygama.lgdo.Table` with the processed buffer. This `tmp_table` shares columns with the :class:`.RawBuffer`'s lgdo, + so no data is copied. Currently implemented attributes: - "window" (list): [in_name, start_index, stop_index, out_name] Windows objects with a name specified by the first argument passed in the ``proc_spec``, the window start and stop indices are the next two @@ -42,7 +43,9 @@ def buffer_processor(rb: RawBuffer) -> None: Notes ----- - The original "waveforms" column in the table is deleted if requested! All updates to the rb.lgdo are done in place + The original "waveforms" column in the table is not written to file if request! All updates are done on the + `tmp_table`, which shares the fields with `rb.lgdo` and are done in place. The `tmp_table` is necessary so that + the `rb.lgdo` keeps arrays needed by the table in the buffer. An example ``proc_spec`` in an :mod:`pygama.raw.build_raw` ``out_spec`` is below .. code-block:: json @@ -89,37 +92,39 @@ def buffer_processor(rb: RawBuffer) -> None: """ # Check that there is a valid object to process + if isinstance(rb.lgdo, lgdo.Table) or isinstance(rb.lgdo, lgdo.Struct): + # Create the temporary table that will be written to file + rb_table_size = rb.lgdo.size + tmp_table = Table(size=rb_table_size) + tmp_table.join(other_table=rb.lgdo) + # This is needed if there is a "*" key expansion for decoders in build_raw - if isinstance(rb.lgdo, lgdo.Scalar): - log.info("Cannot process rb.lgdo of type Scalar") - return None + # In the worst case, just return an unprocessed rb.lgdo + else: + log.info(f"Cannot process buffer with an lgdo of type {type(rb.lgdo)}") + tmp_table = rb.lgdo + return tmp_table # Perform windowing, if requested if "window" in rb.proc_spec.keys(): - process_window(rb) + process_window(rb, tmp_table) # Read in and perform the DSP routine if "dsp_config" in rb.proc_spec.keys(): - process_dsp(rb) + process_dsp(rb, tmp_table) # Cast as requested dtype before writing to the table if "dtype_conv" in rb.proc_spec.keys(): - process_dtype_conv(rb) + process_dtype_conv(rb, tmp_table) # Drop any requested columns from the table if "drop" in rb.proc_spec.keys(): - for drop_keys in rb.proc_spec["drop"]: - try: - rb.lgdo.pop(drop_keys) - rb.lgdo.update_datatype() - except KeyError: - log.info(f"Cannot remove field {drop_keys} from rb.lgdo") - return None + process_drop(rb, tmp_table) - return None + return tmp_table -def process_window(rb: RawBuffer) -> None: +def process_window(rb: RawBuffer, tmp_table: Table) -> None: r""" Windows arrays of equal sized arrays according to specifications given in the rb.proc_spec "window" key. @@ -135,6 +140,8 @@ def process_window(rb: RawBuffer) -> None: ---------- rb A :class:`.RawBuffer` to be processed + tmp_table + A :class:`pygama.lgdo.Table` that shares columns with the `rb.lgdo` Notes ----- @@ -160,7 +167,7 @@ def process_window(rb: RawBuffer) -> None: ) # Window the waveform values - array_of_arrays = rb.lgdo[window_in_name].values + array_of_arrays = tmp_table[window_in_name].values windowed_array_of_arrays = window_array_of_arrays( array_of_arrays, window_start_idx, window_end_idx ) @@ -170,16 +177,16 @@ def process_window(rb: RawBuffer) -> None: t0=t0s, dt=rb.lgdo[window_in_name].dt, values=windowed_array_of_arrays ) - # add this wf_table to the original table - rb.lgdo.add_field(window_out_name, wf_table, use_obj_size=True) + # add this wf_table to the temporary table + tmp_table.add_field(window_out_name, wf_table, use_obj_size=True) # otherwise, it's (hopefully) just an array of equal sized arrays else: - array_of_arrays = rb.lgdo[window_in_name] + array_of_arrays = tmp_table[window_in_name] windowed_array_of_arrays = window_array_of_arrays( array_of_arrays, window_start_idx, window_end_idx ) - rb.lgdo.add_field( + tmp_table.add_field( window_out_name, windowed_array_of_arrays, use_obj_size=True ) @@ -187,13 +194,13 @@ def process_window(rb: RawBuffer) -> None: # otherwise, rb.lgdo is some other type and we only process it if the rb.out_name is the same as window_in_name elif rb.out_name == window_in_name: - array_of_arrays = rb.lgdo + array_of_arrays = tmp_table windowed_array_of_arrays = window_array_of_arrays( array_of_arrays, window_start_idx, window_end_idx ) rb.out_name = window_out_name - rb.lgdo = windowed_array_of_arrays + tmp_table = windowed_array_of_arrays return None @@ -233,11 +240,18 @@ def process_windowed_t0(t0s: Array, dts: Array, start_index: int) -> Array: return copy_t0s -def process_dsp(rb: RawBuffer) -> None: +def process_dsp(rb: RawBuffer, tmp_table: Table) -> None: r""" Run a provided DSP config from rb.proc_spec using build_processing_chain, and add specified outputs to the rb.lgdo. + Parameters + ---------- + rb + A :class:`.RawBuffer` that contains a `proc_spec` and an `lgdo` attribute + tmp_table + A :class:`pygama.lgdo.Table` that is temporarily created to be written to the raw file + Notes ----- rb.lgdo is assumed to be an lgdo.Table so that multiple DSP processor outputs can be written to it @@ -261,19 +275,15 @@ def process_dsp(rb: RawBuffer) -> None: # If the processor returns a waveform, create a new waveform table and add it to the original lgdo table for proc in dsp_out.keys(): # # Check what DSP routine the processors output is from, and manipulate accordingly - # for dsp_proc in dsp_dict["processors"].keys(): - # if proc in dsp_proc: - # # In the case of presumming, change the dts - # if dsp_dict["processors"][dsp_proc]["function"] == "presum": - # new_obj = process_presum(rb, dsp_out[proc], dsp_dict, proc) - rb.lgdo.add_field(proc, dsp_out[proc], use_obj_size=True) + tmp_table.add_field(proc, dsp_out[proc], use_obj_size=True) return None -def process_dtype_conv(rb: RawBuffer) -> None: +def process_dtype_conv(rb: RawBuffer, tmp_table: Table) -> None: """ - Change the types of fields in an rb.lgdo according to the values specified in the ``proc_spec``'s ``dtype_conv`` list + Change the types of fields in an rb.lgdo according to the values specified in the ``proc_spec``'s ``dtype_conv`` list. + It operates in place on `tmp_table`. Notes ----- @@ -283,7 +293,7 @@ def process_dtype_conv(rb: RawBuffer) -> None: for return_name in type_list.keys(): # Take care of nested tables with a for loop path = return_name.split("/") - return_value = rb.lgdo + return_value = tmp_table for key in path: try: return_value = return_value[key] @@ -299,3 +309,12 @@ def process_dtype_conv(rb: RawBuffer) -> None: raise TypeError(f"Cannot recast an object of type {type(return_value)}") return None + + +def process_drop(rb: RawBuffer, tmp_table: Table) -> None: + for drop_keys in rb.proc_spec["drop"]: + try: + tmp_table.remove_column(drop_keys, delete=False) + except KeyError: + log.info(f"Cannot remove field {drop_keys} from rb.lgdo") + return None diff --git a/src/pygama/raw/buffer_processor/lh5_buffer_processor.py b/src/pygama/raw/buffer_processor/lh5_buffer_processor.py index b18c766cb..70e2a4466 100644 --- a/src/pygama/raw/buffer_processor/lh5_buffer_processor.py +++ b/src/pygama/raw/buffer_processor/lh5_buffer_processor.py @@ -105,7 +105,7 @@ def lh5_buffer_processor( if isinstance(out_spec, dict): RawBufferLibrary(json_dict=out_spec) - # Write everything in the raw file to the new file, process appropriately + # Write everything in the raw file to the new file, check for proc_spec under either the group name, out_name, or the name for tb in lh5_tables: lgdo_obj, _ = raw_store.read_object(f"{tb}", lh5_file) @@ -131,9 +131,9 @@ def lh5_buffer_processor( out_name=out_name, proc_spec=out_spec[decoder_name][group_name]["proc_spec"], ) - buffer_processor(rb) + tmp_table = buffer_processor(rb) # Update the lgdo_obj to be written to the processed file - lgdo_obj = rb.lgdo + lgdo_obj = tmp_table else: pass @@ -147,9 +147,9 @@ def lh5_buffer_processor( out_name=out_name, proc_spec=out_spec[decoder_name][out_name]["proc_spec"], ) - buffer_processor(rb) + tmp_table = buffer_processor(rb) # Update the lgdo_obj to be written to the processed file - lgdo_obj = rb.lgdo + lgdo_obj = tmp_table else: pass @@ -183,9 +183,9 @@ def lh5_buffer_processor( list(out_spec[decoder_name].keys())[0] ]["proc_spec"], ) - buffer_processor(rb) + tmp_table = buffer_processor(rb) # Update the lgdo_obj to be written to the processed file - lgdo_obj = rb.lgdo + lgdo_obj = tmp_table else: pass else: diff --git a/src/pygama/raw/raw_buffer.py b/src/pygama/raw/raw_buffer.py index f31d2233e..3bb5ac0c3 100644 --- a/src/pygama/raw/raw_buffer.py +++ b/src/pygama/raw/raw_buffer.py @@ -452,12 +452,14 @@ def write_to_lh5_and_clear( # If a proc_spec if present for this RawBuffer, process that data and then write to the file! if rb.proc_spec is not None: # Perform the processing as requested in the `proc_spec` from `out_spec` in build_raw - buffer_processor(rb) + lgdo_to_write = buffer_processor(rb) + else: + lgdo_to_write = rb.lgdo # write if requested... if filename != "": lh5_store.write_object( - rb.lgdo, + lgdo_to_write, rb.out_name, filename, group=group, diff --git a/tests/raw/buffer_processor/test_buffer_processor.py b/tests/raw/buffer_processor/test_buffer_processor.py index 1cb6eaa0d..92a1ab530 100644 --- a/tests/raw/buffer_processor/test_buffer_processor.py +++ b/tests/raw/buffer_processor/test_buffer_processor.py @@ -575,7 +575,7 @@ def test_proc_geds_no_proc_spms(lgnd_test_data): } """ - # Do the data procming + # Do the data processing build_raw(in_stream=daq_file, out_spec=out_spec, overwrite=True) # Grab the proc_spec after keylist expansion from build_raw @@ -612,8 +612,8 @@ def test_proc_geds_no_proc_spms(lgnd_test_data): # Read in the presummed rate from the config file to modify the clock rate later group_name = raw_group.split("/raw")[0] pass_flag = False - # If the user passes procming on a group, then the presum_rate is just 1 and there is no windowing - # If a group_name is absent from the jsonfile, then that means no procming was performed + # If the user passes processing on a group, then the presum_rate is just 1 and there is no windowing + # If a group_name is absent from the jsonfile, then that means no processing was performed if group_name not in jsonfile.keys(): presum_rate = 1 window_start_index = 0 @@ -835,7 +835,7 @@ def test_buffer_processor_multiple_keys(lgnd_test_data): } } """ - # Do the data procming + # Do the data processing build_raw(in_stream=daq_file, out_spec=out_spec, overwrite=True) # Grab the proc_spec after keylist expansion from build_raw @@ -875,8 +875,8 @@ def test_buffer_processor_multiple_keys(lgnd_test_data): group_name = raw_group.split("/raw")[0] pass_flag = False - # If the user passes procming on a group, then the presum_rate is just 1 and there is no windowing - # If the group_name is absent from the jsonfile, then no procming was done + # If the user passes processing on a group, then the presum_rate is just 1 and there is no windowing + # If the group_name is absent from the jsonfile, then no processing was done if group_name not in jsonfile.keys(): presum_rate = 1 window_start_index = 0 @@ -1088,3 +1088,293 @@ def test_buffer_processor_all_pass(lgnd_test_data): proc_df = proc[obj].get_dataframe([str(sub_obj)]) assert raw_df.equals(proc_df) + + +# check that packet indexes match in verification test +def test_buffer_processor_drop_waveform_small_buffer(lgnd_test_data): + + # Set up I/O files, including config + daq_file = lgnd_test_data.get_path("orca/fc/L200-comm-20220519-phy-geds.orca") + processed_file = daq_file.replace( + "L200-comm-20220519-phy-geds.orca", + "L200-comm-20220519-phy-geds-key-test_proc.lh5", + ) + raw_file = daq_file.replace( + "L200-comm-20220519-phy-geds.orca", "L200-comm-20220519-phy-geds-key-test.lh5" + ) + + out_spec = { + "ORFlashCamADCWaveformDecoder": { + "ch{key}": { + "key_list": [0, 1], + "out_stream": processed_file + ":{name}", + "out_name": "raw", + "proc_spec": { + "window": ["waveform", 2000, -1000, "windowed_waveform"], + "dsp_config": { + "outputs": [ + "presum_rate", + "presummed_waveform", + "t_sat_lo", + "t_sat_hi", + ], + "processors": { + "presum_rate, presummed_waveform": { + "function": "presum", + "module": "pygama.dsp.processors", + "args": [ + "waveform", + 0, + "presum_rate", + "presummed_waveform(shape=len(waveform)/16, period=waveform.period*16, offset=waveform.offset)", + ], + "unit": "ADC", + }, + "t_sat_lo, t_sat_hi": { + "function": "saturation", + "module": "pygama.dsp.processors", + "args": ["waveform", 16, "t_sat_lo", "t_sat_hi"], + "unit": "ADC", + }, + }, + }, + "drop": ["waveform"], + "dtype_conv": { + "presummed_waveform/values": "uint32", + "t_sat_lo": "uint16", + "t_sat_hi": "uint16", + "presum_rate": "uint16", + }, + }, + }, + "chan{key}": { + "key_list": [3, 4], + "out_stream": processed_file + ":{name}", + "out_name": "raw", + }, + } + } + + copy_out_spec = { + "ORFlashCamADCWaveformDecoder": { + "ch{key}": { + "key_list": [0, 1], + "out_stream": raw_file + ":{name}", + "out_name": "raw", + }, + "chan{key}": { + "key_list": [3, 4], + "out_stream": raw_file + ":{name}", + "out_name": "raw", + }, + } + } + + raw_dsp_config = """ + { + "outputs": ["t_sat_lo", "t_sat_hi"], + "processors": { + "t_sat_lo, t_sat_hi": { + "function": "saturation", + "module": "pygama.dsp.processors", + "args": ["waveform", 16, "t_sat_lo", "t_sat_hi"], + "unit": "ADC" + } + } + } + """ + # Do the data processing + build_raw(in_stream=daq_file, out_spec=out_spec, overwrite=True, buffer_size=2) + + # Grab the proc_spec after keylist expansion from build_raw + proc_spec = {} + for key in out_spec["ORFlashCamADCWaveformDecoder"].keys(): + if "proc_spec" in out_spec["ORFlashCamADCWaveformDecoder"][key].keys(): + proc_spec[key] = out_spec["ORFlashCamADCWaveformDecoder"][key].pop( + "proc_spec" + ) + + # Build the unprocessed raw file for comparison + build_raw(in_stream=daq_file, out_spec=copy_out_spec, overwrite=True, buffer_size=2) + + lh5_tables = lgdo.ls(raw_file) + # check if group points to raw data; sometimes 'raw' is nested, e.g g024/raw + for i, tb in enumerate(lh5_tables): + if "raw" not in tb and lgdo.ls(raw_file, f"{tb}/raw"): + lh5_tables[i] = f"{tb}/raw" + elif not lgdo.ls(raw_file, tb): + del lh5_tables[i] + + jsonfile = proc_spec + + sto = lgdo.LH5Store() + + for raw_group in lh5_tables: + + # First, check the packet ids + raw_packet_ids, _ = sto.read_object(str(raw_group) + "/packet_id", raw_file) + processed_packet_ids, _ = sto.read_object( + str(raw_group) + "/packet_id", processed_file + ) + + assert np.array_equal(raw_packet_ids.nda, processed_packet_ids.nda) + + # Read in the presummed rate from the config file to modify the clock rate later + group_name = raw_group.split("/raw")[0] + + pass_flag = False + # If the user passes processing on a group, then the presum_rate is just 1 and there is no windowing + # If the group_name is absent from the jsonfile, then no processing was done + if group_name not in jsonfile.keys(): + presum_rate = 1 + window_start_index = 0 + window_end_index = 0 + pass_flag = True + else: + presum_rate_string = jsonfile[group_name]["dsp_config"]["processors"][ + "presum_rate, presummed_waveform" + ]["args"][3] + presum_rate_start_idx = presum_rate_string.find("/") + 1 + presum_rate_end_idx = presum_rate_string.find(",") + presum_rate = int( + presum_rate_string[presum_rate_start_idx:presum_rate_end_idx] + ) + + # This needs to be overwritten with the correct windowing values set in buffer_processor.py + window_start_index = int(jsonfile[group_name]["window"][1]) + window_end_index = int(jsonfile[group_name]["window"][2]) + + # Read in the waveforms + raw_packet_waveform_values = sto.read_object( + str(raw_group) + "/waveform/values", raw_file + ) + if pass_flag: + presummed_packet_waveform_values = sto.read_object( + str(raw_group) + "/waveform/values", processed_file + ) + windowed_packet_waveform_values = sto.read_object( + str(raw_group) + "/waveform/values", processed_file + ) + else: + presummed_packet_waveform_values = sto.read_object( + str(raw_group) + "/presummed_waveform/values", processed_file + ) + windowed_packet_waveform_values = sto.read_object( + str(raw_group) + "/windowed_waveform/values", processed_file + ) + + # Check that the lengths of the waveforms match what we expect + assert ( + len(raw_packet_waveform_values[0].nda[0]) + // len(presummed_packet_waveform_values[0].nda[0]) + == presum_rate + ) + assert len(raw_packet_waveform_values[0].nda[0]) == len( + windowed_packet_waveform_values[0].nda[0] + ) + np.abs(window_start_index) + np.abs(window_end_index) + assert isinstance(windowed_packet_waveform_values[0].nda[0][0], np.uint16) + + # Check that the waveforms match + # These are the channels that should be unprocessed + if group_name == "chan3" or group_name == "chan4": + raw_packet_waveform_values, _ = sto.read_object( + str(raw_group) + "/waveform/values", raw_file + ) + windowed_packet_waveform_values, _ = sto.read_object( + str(raw_group) + "/waveform/values", processed_file + ) + assert np.array_equal( + raw_packet_waveform_values.nda, windowed_packet_waveform_values.nda + ) + else: + raw_packet_waveform_values, _ = sto.read_object( + str(raw_group) + "/waveform/values", raw_file + ) + windowed_packet_waveform_values, _ = sto.read_object( + str(raw_group) + "/windowed_waveform/values", processed_file + ) + assert np.array_equal( + raw_packet_waveform_values.nda[:, window_start_index:window_end_index], + windowed_packet_waveform_values.nda, + ) + + # Check the t0 and dts are what we expect + raw_packet_waveform_t0s, _ = sto.read_object( + str(raw_group) + "/waveform/t0", raw_file + ) + raw_packet_waveform_dts, _ = sto.read_object( + str(raw_group) + "/waveform/dt", raw_file + ) + + if pass_flag: + windowed_packet_waveform_t0s, _ = sto.read_object( + str(raw_group) + "/waveform/t0", processed_file + ) + presummed_packet_waveform_t0s, _ = sto.read_object( + str(raw_group) + "/waveform/t0", processed_file + ) + else: + windowed_packet_waveform_t0s, _ = sto.read_object( + str(raw_group) + "/windowed_waveform/t0", processed_file + ) + presummed_packet_waveform_t0s, _ = sto.read_object( + str(raw_group) + "/presummed_waveform/t0", processed_file + ) + + # Check that the t0s match what we expect, with the correct units + assert ( + raw_packet_waveform_t0s.nda[0] + == windowed_packet_waveform_t0s.nda[0] + - raw_packet_waveform_dts.nda[0] * window_start_index + ) + assert ( + windowed_packet_waveform_t0s.attrs["units"] + == raw_packet_waveform_t0s.attrs["units"] + ) + assert raw_packet_waveform_t0s.nda[0] == presummed_packet_waveform_t0s.nda[0] + assert ( + presummed_packet_waveform_t0s.attrs["units"] + == raw_packet_waveform_t0s.attrs["units"] + ) + + if pass_flag: + + presummed_packet_waveform_dts, _ = sto.read_object( + str(raw_group) + "/waveform/dt", processed_file + ) + else: + + presummed_packet_waveform_dts, _ = sto.read_object( + str(raw_group) + "/presummed_waveform/dt", processed_file + ) + + # Check that the presum_rate is correctly identified + presum_rate_from_file, _ = sto.read_object( + str(raw_group) + "/presum_rate", processed_file + ) + assert presum_rate_from_file.nda[0] == presum_rate + # Check that the dts match what we expect, with the correct units + assert ( + raw_packet_waveform_dts.nda[0] + == presummed_packet_waveform_dts.nda[0] / presum_rate + ) + + # check that the t_lo_sat and t_sat_hi are correct + if not pass_flag: + wf_table, _ = sto.read_object(str(raw_group), raw_file) + pc, _, wf_out = bpc(wf_table, json.loads(raw_dsp_config)) + pc.execute() + raw_sat_lo = wf_out["t_sat_lo"] + raw_sat_hi = wf_out["t_sat_hi"] + + proc_sat_lo, _ = sto.read_object( + str(raw_group) + "/t_sat_lo", processed_file + ) + + proc_sat_hi, _ = sto.read_object( + str(raw_group) + "/t_sat_hi", processed_file + ) + + assert np.array_equal(raw_sat_lo.nda, proc_sat_lo.nda) + assert np.array_equal(raw_sat_hi.nda, proc_sat_hi.nda) + assert type(proc_sat_lo.nda[0]) == np.uint16 diff --git a/tests/raw/buffer_processor/test_lh5_buffer_processor.py b/tests/raw/buffer_processor/test_lh5_buffer_processor.py index cfffb8f3f..e8f3fa383 100644 --- a/tests/raw/buffer_processor/test_lh5_buffer_processor.py +++ b/tests/raw/buffer_processor/test_lh5_buffer_processor.py @@ -277,7 +277,7 @@ def test_lh5_buffer_processor_file_size_decrease(lgnd_test_data): sto.read_object(str(raw_group) + "/waveform/values", raw_file)[0].nda ) - # Make sure that we are actually procming the waveforms + # Make sure that we are actually processing the waveforms raw_packet_waveform_values = sto.read_object( str(raw_group) + "/waveform/values", raw_file ) @@ -625,8 +625,8 @@ def test_raw_geds_no_proc_spms(lgnd_test_data): # Read in the presummed rate from the config file to modify the clock rate later group_name = raw_group.split("/raw")[0] pass_flag = False - # If the user passes procming on a group, then the presum_rate is just 1 and there is no windowing - # If a group_name is absent from the jsonfile, then that means no procming was performed + # If the user passes processing on a group, then the presum_rate is just 1 and there is no windowing + # If a group_name is absent from the jsonfile, then that means no processing was performed if group_name not in jsonfile.keys(): presum_rate = 1 window_start_index = 0 @@ -844,7 +844,7 @@ def test_lh5_buffer_processor_multiple_keys(lgnd_test_data): # Build the raw file build_raw(in_stream=daq_file, out_spec=raw_out_spec, overwrite=True) - # Do the data procming on the raw file + # Do the data processing on the raw file lh5_buffer_processor( lh5_raw_file_in=raw_file, overwrite=True, out_spec=proc_out_spec ) @@ -883,8 +883,8 @@ def test_lh5_buffer_processor_multiple_keys(lgnd_test_data): group_name = raw_group.split("/raw")[0] pass_flag = False - # If the user passes procming on a group, then the presum_rate is just 1 and there is no windowing - # If the group_name is absent from the jsonfile, then no procming was done + # If the user passes processing on a group, then the presum_rate is just 1 and there is no windowing + # If the group_name is absent from the jsonfile, then no processing was done if group_name not in jsonfile.keys(): presum_rate = 1 window_start_index = 0