Advertisement
Guest User

Untitled

a guest
Nov 16th, 2019
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.36 KB | None | 0 0
  1. def hrv_training_workflow(min_non_warmup_workout_time, athlete_id=1):
  2. '''
  3. Query db for oura hrv data, calculate rolling 7 day average, generate recommended workout and store in db.
  4. Once stored, continuously check if workout has been completed and fill in 'Compelted' field
  5. '''
  6.  
  7. session, engine = db_connect()
  8.  
  9. # Check if entire table is empty, if so the earliest hrv plan can start is after 30 days of hrv readings
  10. db_test = pd.read_sql(
  11. sql=session.query(hrvWorkoutStepLog).filter(hrvWorkoutStepLog.athlete_id == athlete_id).statement,
  12. con=engine, index_col='date')
  13.  
  14. if len(db_test) == 0:
  15. min_oura_date = session.query(func.min(ouraSleepSummary.report_date))[0][0]
  16. db_test.at[pd.to_datetime(min_oura_date + timedelta(29)), 'athlete_id'] = athlete_id
  17. db_test.at[pd.to_datetime(min_oura_date + timedelta(29)), 'hrv_workout_step'] = 0
  18. db_test.at[pd.to_datetime(min_oura_date + timedelta(29)), 'hrv_workout_step_desc'] = 'Low'
  19. db_test.at[pd.to_datetime(min_oura_date + timedelta(29)), 'completed'] = 0
  20. db_test.at[
  21. pd.to_datetime(min_oura_date + timedelta(
  22. 29)), 'rationale'] = 'This is the first date 30 day hrv thresholds could be calculated'
  23. db_insert(db_test, 'hrv_workout_step_log')
  24.  
  25. # Check if a step has already been inserted for today and if so check if workout has been completed yet
  26. todays_plan = session.query(hrvWorkoutStepLog).filter(hrvWorkoutStepLog.athlete_id == athlete_id,
  27. hrvWorkoutStepLog.date == datetime.today().date()).first()
  28.  
  29. if todays_plan:
  30. # If not yet "completed" keep checking throughout day
  31. if todays_plan.completed == 0:
  32. # If rest day, mark as completed
  33. if todays_plan.hrv_workout_step == 4 or todays_plan.hrv_workout_step == 5:
  34. todays_plan.completed = 1
  35. session.commit()
  36. else:
  37. workout = session.query(stravaSummary).filter(stravaSummary.start_day_local == datetime.today().date(),
  38. stravaSummary.elapsed_time > min_non_warmup_workout_time).first()
  39. if workout:
  40. todays_plan.completed = 1
  41. session.commit()
  42.  
  43. # If plan not yet created for today, create it
  44. else:
  45. hrv_df = pd.read_sql(sql=session.query(ouraSleepSummary.report_date, ouraSleepSummary.rmssd).statement,
  46. con=engine, index_col='report_date').sort_index(ascending=True)
  47.  
  48. # Wait for today's hrv to be loaded into cloud
  49. if hrv_df.index.max() == datetime.today().date(): # or (datetime.now() - timedelta(hours=12)) > pd.to_datetime(datetime.today().date()):
  50.  
  51. step_log_df = pd.read_sql(
  52. sql=session.query(hrvWorkoutStepLog.date, hrvWorkoutStepLog.hrv_workout_step,
  53. hrvWorkoutStepLog.completed).filter(
  54. hrvWorkoutStepLog.athlete_id == 1).statement,
  55. con=engine, index_col='date').sort_index(ascending=False)
  56.  
  57. step_log_df = step_log_df[step_log_df.index == step_log_df.index.max()]
  58.  
  59. # Store last step in variable for starting point in loop
  60. last_db_step = step_log_df['hrv_workout_step'].iloc[0]
  61.  
  62. # Resample to today
  63. step_log_df.at[pd.to_datetime(datetime.today().date()), 'hrv_workout_step'] = None
  64. step_log_df = step_log_df.set_index(pd.to_datetime(step_log_df.index))
  65. step_log_df = step_log_df.resample('D').mean()
  66. # Remove first row from df so it does not get re inserted into db
  67. step_log_df = step_log_df.iloc[1:]
  68.  
  69. # We already know there is no step for today from "current_step" parameter, so manually add today's date
  70. step_log_df.at[pd.to_datetime(datetime.today().date()), 'completed'] = 0
  71.  
  72. # Check if gap between today and max date in step log, if so merge in all workouts for 'completed' flag
  73. if step_log_df['completed'].isnull().values.any():
  74. workouts = pd.read_sql(
  75. sql=session.query(stravaSummary.start_day_local, stravaSummary.activity_id).filter(
  76. stravaSummary.elapsed_time > min_non_warmup_workout_time)
  77. .statement, con=engine,
  78. index_col='start_day_local')
  79. # Resample workouts to the per day level - just take max activity_id in case they were more than 1 workout for that day to avoid duplication of hrv data
  80. workouts = workouts.set_index(pd.to_datetime(workouts.index))
  81. workouts = workouts.resample('D').max()
  82. step_log_df = step_log_df.merge(workouts, how='left', left_index=True, right_index=True)
  83. # Completed = True if a workout (not just warmup) was done on that day or was a rest day
  84. for x in step_log_df.index:
  85. step_log_df.at[x, 'completed'] = 0 if np.isnan(step_log_df.at[x, 'activity_id']) else 1
  86.  
  87. # Generate row with yesterdays plan completions status for looping below through workout cycle logic
  88. step_log_df['completed_yesterday'] = step_log_df['completed'].shift(1)
  89.  
  90. # Drop historical rows that were used for 'yesterday calcs' so we are only working with todays data
  91. # step_log_df = step_log_df.iloc[1:]
  92.  
  93. # Calculate HRV metrics
  94. hrv_df.set_index(pd.to_datetime(hrv_df.index), inplace=True)
  95. hrv_df = hrv_df.resample('D').mean()
  96.  
  97. hrv_df['rmssd_7'] = hrv_df['rmssd'].rolling(7, min_periods=0).mean()
  98. hrv_df['rmssd_7_yesterday'] = hrv_df['rmssd_7'].shift(1)
  99. hrv_df['rmssd_30'] = hrv_df['rmssd'].rolling(30, min_periods=0).mean()
  100. hrv_df['stdev_rmssd_30_threshold'] = hrv_df['rmssd'].rolling(30, min_periods=0).std() * .5
  101. hrv_df['swc_upper'] = hrv_df['rmssd_30'] + hrv_df['stdev_rmssd_30_threshold']
  102. hrv_df['swc_lower'] = hrv_df['rmssd_30'] - hrv_df['stdev_rmssd_30_threshold']
  103. hrv_df['under_low_threshold'] = hrv_df['rmssd_7'] < hrv_df['swc_lower']
  104. hrv_df['under_low_threshold_yesterday'] = hrv_df['under_low_threshold'].shift(1)
  105. hrv_df['over_upper_threshold'] = hrv_df['rmssd_7'] > hrv_df['swc_upper']
  106. hrv_df['over_upper_threshold_yesterday'] = hrv_df['over_upper_threshold'].shift(1)
  107. for i in hrv_df.index:
  108. if hrv_df.at[i, 'under_low_threshold_yesterday'] == False and hrv_df.at[
  109. i, 'under_low_threshold'] == True:
  110. hrv_df.at[i, 'lower_threshold_crossed'] = True
  111. else:
  112. hrv_df.at[i, 'lower_threshold_crossed'] = False
  113. if hrv_df.at[i, 'over_upper_threshold_yesterday'] == False and hrv_df.at[
  114. i, 'over_upper_threshold'] == True:
  115. hrv_df.at[i, 'upper_threshold_crossed'] = True
  116. else:
  117. hrv_df.at[i, 'upper_threshold_crossed'] = False
  118. # Merge dfs
  119. df = pd.merge(step_log_df, hrv_df, how='left', right_index=True, left_index=True)
  120.  
  121. last_step = last_db_step
  122. for i in df.index:
  123. # Completed / Completed_yesterday could show erroneous data for rest days, as the 0 is brought in based off if a workout is found in strava summary
  124. df.at[i, 'completed_yesterday'] = 1 if last_step == 4 or last_step == 5 else df.at[
  125. i, 'completed_yesterday']
  126.  
  127. hrv_increase = df.at[i, 'rmssd_7'] >= df.at[i, 'rmssd_7_yesterday']
  128.  
  129. ### Low Threshold Exceptions ###
  130. # If lower threshold is crossed, switch to low intensity track
  131. if df.at[i, 'lower_threshold_crossed'] == True:
  132. current_step = 4
  133. rationale = '7 day HRV average crossed the 30 day baseline lower threshold.'
  134. dash_app.server.logger.debug('Lower threshold crossed. Setting current step = 4')
  135. # If we are below lower threshold, rest until back over threshold
  136. elif df.at[i, 'under_low_threshold'] == True:
  137. current_step = 5
  138. rationale = '7 day HRV average is under the 30 day baseline lower threshold.'
  139. dash_app.server.logger.debug('HRV is under threshold. Setting current step = 5')
  140.  
  141. ### Upper Threshold Exceptions ###
  142. # If upper threshold is crossed, switch to high intensity
  143. elif df.at[i, 'upper_threshold_crossed'] == True:
  144. current_step = 1
  145. rationale = '7 day HRV average crossed the 30 day baseline upper threshold.'
  146. dash_app.server.logger.debug('Upper threshold crossed. Setting current step = 1')
  147. # If we are above upper threshold, load high intensity until back under threshold
  148. elif df.at[i, 'over_upper_threshold'] == True:
  149. if hrv_increase:
  150. current_step = 1
  151. rationale = '7 day HRV average increased and is still over the 30 day baseline upper threshold.'
  152. else:
  153. current_step = 2
  154. rationale = "7 day HRV average decreased but is still over the 30 day baseline upper threshold."
  155. dash_app.server.logger.debug(
  156. 'HRV is above threshold. Setting current step = {}.'.format(current_step))
  157.  
  158. ### Missed Workout Exceptions ###
  159. # If workout was not completed yesterday but we are still within thresholds and current step is high/moderate go high if hrv increases, or stay on moderate if hrv decreases
  160. elif df.at[i, 'completed_yesterday'] == 0 and df.at[i, 'under_low_threshold'] == False and df.at[
  161. i, 'over_upper_threshold'] == False and (last_step == 1 or last_step == 2):
  162. if hrv_increase:
  163. current_step = 1
  164. rationale = "7 day HRV average increased and yesterday's workout was not completed."
  165. else:
  166. current_step = 2
  167. rationale = "7 day HRV average decreased and yesterday's workout was not completed."
  168. dash_app.server.logger.debug(
  169. 'No workout detected for previous day however still within thresholds. Maintaining last step = {}'.format(
  170. current_step))
  171. else:
  172. dash_app.server.logger.debug(
  173. 'No exceptions detected. Following the normal workout plan workflow.')
  174. rationale = '7 day HRV average is within the tresholds. Following the normal workout plan workflow.'
  175. # Workout workflow logic when no exceptions
  176. if last_step == 0:
  177. current_step = 1
  178. elif last_step == 1:
  179. current_step = 2 if hrv_increase else 6
  180. elif last_step == 2:
  181. current_step = 3
  182. elif last_step == 3:
  183. current_step = 1 if hrv_increase else 4
  184. elif last_step == 4:
  185. current_step = 6 if hrv_increase else 5
  186. elif last_step == 5:
  187. current_step = 6
  188. elif last_step == 6:
  189. current_step = 1 if hrv_increase else 4
  190.  
  191. df.at[i, 'completed'] = 1 if current_step == 4 or current_step == 5 else df.at[i, 'completed']
  192. df.at[i, 'hrv_workout_step'] = current_step
  193. last_step = current_step
  194.  
  195. df.at[i, 'rationale'] = rationale
  196.  
  197. df['athlete_id'] = athlete_id
  198. df['hrv_workout_step_desc'] = df['hrv_workout_step'].map(
  199. {0: 'Low', 1: 'High', 2: 'HIIT/MOD', 3: 'Low', 4: 'Rest', 5: 'Rest', 6: 'Low'})
  200.  
  201. # Insert into db
  202. df = df[['athlete_id', 'hrv_workout_step', 'hrv_workout_step_desc', 'completed', 'rationale']]
  203. db_insert(df, 'hrv_workout_step_log')
  204.  
  205. engine.dispose()
  206. session.close()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement