From f63c1d230a8e2cee75ff2f8bfbacb3e1d59c4ca5 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Fri, 3 May 2024 00:33:15 -0400 Subject: [PATCH] add ble_sensed_summary to confirmed trips Since sections now have a `ble_sensed_mode` property in addition to `sensed_mode`, we can use the `ble_sensed_mode` as the basis for a new kind of section summary. To enable this, the `get_section_summary` function was refactored to accept an additional argument, which can be either `sensed_mode` or `ble_sensed_mode`. If it's `ble_sensed_mode`, the summary values will be summed and grouped by the `baseMode` of the vehicle that was sensed by BLE. If the additional argument is not given, it just defaults to `sensed_mode` (same behavior as before) Testing done: -using a dump of dfc-fermata from 24 april loaded into my local database -reset and re-ran the pipeline for a user -inspected the `ble_sensed_summary`s of the resulting confirmed trips: ``` ts = esta.TimeSeries.get_time_series(user_id) entries = ts.find_entries(["analysis/confirmed_trip"]) for e in entries: print(e['data']['ble_sensed_summary']) ``` Output: ``` {'distance': {'UNKNOWN': 4294.125850161847}, 'duration': {'UNKNOWN': 10379.947390556335}, 'count': {'UNKNOWN': 2}} {'distance': {'UNKNOWN': 1511402.9404509964}, 'duration': {'UNKNOWN': 131559.69582343102}, 'count': {'UNKNOWN': 4}} {'distance': {'UNKNOWN': 34462.99760301494}, 'duration': {'UNKNOWN': 977.1180453300476}, 'count': {'UNKNOWN': 3}} {'distance': {'UNKNOWN': 19485.795458445176}, 'duration': {'UNKNOWN': 3718.8894975185394}, 'count': {'UNKNOWN': 2}} {'distance': {'UNKNOWN': 850.4852679201318}, 'duration': {'UNKNOWN': 15861.93504524231}, 'count': {'UNKNOWN': 1}} {'distance': {'UNKNOWN': 47455.78820030493}, 'duration': {'UNKNOWN': 7241.158731937408}, 'count': {'UNKNOWN': 3}} {'distance': {'UNKNOWN': 1551245.9810044689}, 'duration': {'UNKNOWN': 13537.040816783905}, 'count': {'UNKNOWN': 5}} {'distance': {'UNKNOWN': 713.4707286619786}, 'duration': {'UNKNOWN': 1448.6543893814087}, 'count': {'UNKNOWN': 1}} {'distance': {'UNKNOWN': 3981236.406827432}, 'duration': {'UNKNOWN': 26685.684997320175}, 'count': {'UNKNOWN': 2}} {'distance': {'UNKNOWN': 333.2678850005484}, 'duration': {'UNKNOWN': 21.80204725265503}, 'count': {'UNKNOWN': 1}} {'distance': {'UNKNOWN': 2866.186136018516}, 'duration': {'UNKNOWN': 3249.8193860054016}, 'count': {'UNKNOWN': 1}} {'distance': {'UNKNOWN': 2645.5964919933926}, 'duration': {'UNKNOWN': 750.7993273735046}, 'count': {'UNKNOWN': 1}} {'distance': {'UNKNOWN': 2442.091053542208}, 'duration': {'UNKNOWN': 489.8975965976715}, 'count': {'UNKNOWN': 1}} {'distance': {'UNKNOWN': 4449.832978365483}, 'duration': {'UNKNOWN': 2710.8742623329163}, 'count': {'UNKNOWN': 1}} {'distance': {'UNKNOWN': 6409.15214382765}, 'duration': {'UNKNOWN': 745.2548396587372}, 'count': {'UNKNOWN': 1}} {'distance': {'UNKNOWN': 163.76752941202727}, 'duration': {'UNKNOWN': 12.731597900390625}, 'count': {'UNKNOWN': 1}} {'distance': {'UNKNOWN': 4440.681532305813}, 'duration': {'UNKNOWN': 93.64632654190063}, 'count': {'UNKNOWN': 3}} {'distance': {'UNKNOWN': 366.71884583356365}, 'duration': {'UNKNOWN': 1299.6981484889984}, 'count': {'UNKNOWN': 1}} {'distance': {'UNKNOWN': 2078.9642225193907}, 'duration': {'UNKNOWN': 11704.498789787292}, 'count': {'UNKNOWN': 1}} {'distance': {'E_CAR': 2328.846316296626, 'UNKNOWN': 6971.404103278014}, 'duration': {'E_CAR': 3389.3658237457275, 'UNKNOWN': 945.0989944934845}, 'count': {'E_CAR': 1, 'UNKNOWN': 2}} {'distance': {'UNKNOWN': 155.63066751202888}, 'duration': {'UNKNOWN': 116.02340650558472}, 'count': {'UNKNOWN': 1}} {'distance': {'E_CAR': 7177.555954021382, 'UNKNOWN': 43.50518475446066}, 'duration': {'E_CAR': 1140.2288630008698, 'UNKNOWN': 175.48782801628113}, 'count': {'E_CAR': 1, 'UNKNOWN': 1}} {'distance': {'UNKNOWN': 846.2578386118126}, 'duration': {'UNKNOWN': 766.3598084449768}, 'count': {'UNKNOWN': 1}} {'distance': {'E_CAR': 104.02576498063684}, 'duration': {'E_CAR': 38.734825134277344}, 'count': {'E_CAR': 1}} {'distance': {'E_CAR': 8250.614829636044}, 'duration': {'E_CAR': 825.4048693180084}, 'count': {'E_CAR': 1}} {'distance': {'E_CAR': 6171.384206967509}, 'duration': {'E_CAR': 781.507465839386}, 'count': {'E_CAR': 1}} {'distance': {'E_CAR': 1065.2594223724116, 'UNKNOWN': 73.02336166659416}, 'duration': {'E_CAR': 491.0299062728882, 'UNKNOWN': 105.17022156715393}, 'count': {'E_CAR': 1, 'UNKNOWN': 1}} {'distance': {'E_CAR': 733.2246673403289}, 'duration': {'E_CAR': 845.3612954616547}, 'count': {'E_CAR': 1}} {'distance': {'E_CAR': 4275.13516142465}, 'duration': {'E_CAR': 541.7157530784607}, 'count': {'E_CAR': 1}} {'distance': {'E_CAR': 7391.707788417107}, 'duration': {'E_CAR': 611.8730540275574}, 'count': {'E_CAR': 1}} {'distance': {'E_CAR': 10035.89912694906}, 'duration': {'E_CAR': 1205.663957118988}, 'count': {'E_CAR': 1}} {'distance': {'E_CAR': 9085.234840541858}, 'duration': {'E_CAR': 3597.4890780448914}, 'count': {'E_CAR': 1}} ``` --- emission/analysis/userinput/matcher.py | 18 +++++++++++------- emission/core/wrapper/confirmedtrip.py | 1 + 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/emission/analysis/userinput/matcher.py b/emission/analysis/userinput/matcher.py index ee4365261..9263d6c79 100644 --- a/emission/analysis/userinput/matcher.py +++ b/emission/analysis/userinput/matcher.py @@ -193,12 +193,13 @@ def create_and_link_timeline(ts, timeline, last_confirmed_place): confirmed_places, confirmed_trips) return confirmed_tl -def get_section_summary(ts, cleaned_trip, section_key): +def get_section_summary(ts, cleaned_trip, section_key, mode_prop="sensed_mode"): """ Returns the proportions of the distance, duration and count for each mode in this trip. Note that sections are unimodal by definition. cleaned_trip: the cleaned trip object associated with the sections section_key: 'inferred_section' or 'cleaned_section' + mode_prop: the section property used as the basis for mode: 'sensed_mode' or 'ble_sensed_mode'. """ logging.debug(f"get_section_summary({cleaned_trip['_id']}, {section_key}) called") sections = esdt.get_sections_for_trip(key = section_key, @@ -207,12 +208,14 @@ def get_section_summary(ts, cleaned_trip, section_key): logging.warning("While getting section summary, section length = 0. This should never happen, but let's not crash if it does") return {"distance": {}, "duration": {}, "count": {}} sections_df = ts.to_data_df(section_key, sections) - cleaned_section_mapper = lambda sm: ecwm.MotionTypes(sm).name - inferred_section_mapper = lambda sm: ecwmp.PredictedModeTypes(sm).name - sel_section_mapper = cleaned_section_mapper \ - if section_key == "analysis/cleaned_section" else inferred_section_mapper - sections_df["sensed_mode_str"] = sections_df["sensed_mode"].apply(sel_section_mapper) - grouped_section_df = sections_df.groupby("sensed_mode_str") + if mode_prop == "ble_sensed_mode": + mapper = lambda bsm: bsm['baseMode'] if bsm is not None else ecwm.MotionTypes.UNKNOWN.name + elif section_key == "analysis/cleaned_section": + mapper = lambda sm: ecwm.MotionTypes(sm).name + else: + mapper = lambda sm: ecwmp.PredictedModeTypes(sm).name + sections_df[mode_prop + "_str"] = sections_df[mode_prop].apply(mapper) + grouped_section_df = sections_df.groupby(mode_prop + "_str") retVal = { "distance": grouped_section_df.distance.sum().to_dict(), "duration": grouped_section_df.duration.sum().to_dict(), @@ -233,6 +236,7 @@ def create_confirmed_entry(ts, tce, confirmed_key, input_key_list): tce["data"]["cleaned_trip"]) confirmed_object_data['inferred_section_summary'] = get_section_summary(ts, cleaned_trip, "analysis/inferred_section") confirmed_object_data['cleaned_section_summary'] = get_section_summary(ts, cleaned_trip, "analysis/cleaned_section") + confirmed_object_data['ble_sensed_summary'] = get_section_summary(ts, cleaned_trip, "analysis/inferred_section", mode_prop="ble_sensed_mode") elif (confirmed_key == esda.CONFIRMED_PLACE_KEY): confirmed_object_data["cleaned_place"] = tce.get_id() confirmed_object_data["user_input"] = \ diff --git a/emission/core/wrapper/confirmedtrip.py b/emission/core/wrapper/confirmedtrip.py index 5a67c89fa..9a83efb2c 100644 --- a/emission/core/wrapper/confirmedtrip.py +++ b/emission/core/wrapper/confirmedtrip.py @@ -19,6 +19,7 @@ class Confirmedtrip(ecwt.Trip): "expected_trip": ecwb.WrapperBase.Access.WORM, "inferred_section_summary": ecwb.WrapperBase.Access.WORM, "cleaned_section_summary": ecwb.WrapperBase.Access.WORM, + "ble_sensed_summary": ecwb.WrapperBase.Access.WORM, # the user input will have all `manual/*` entries # let's make that be somewhat flexible instead of hardcoding into the data model "user_input": ecwb.WrapperBase.Access.WORM,