From 1cb9afba6f09a3e40f2e66b91b4d1e653c549e78 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 5 Feb 2025 18:51:13 +0100 Subject: [PATCH] updating rolling spm data --- rowers/dataprep.py | 50 ++++++++++++++++------ rowers/forms.py | 8 ++++ rowers/models.py | 2 +- rowers/templates/user_analysis_select.html | 3 +- rowers/views/analysisviews.py | 2 +- 5 files changed, 50 insertions(+), 15 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index aa7abed5..cf2896e2 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -810,7 +810,7 @@ def fetchcp_new(rower, workouts): -def update_rolling_cp(r, types, mode='water', dosend=False): +def update_rolling_cp(r, types, mode='water', metric='power', dosend=False): firstdate = tz.now()-datetime.timedelta(days=r.cprange) workouts = Workout.objects.filter( date__gte=firstdate, @@ -820,10 +820,17 @@ def update_rolling_cp(r, types, mode='water', dosend=False): delta, cp, cr, avgpower, workoutnames, urls = fetchcp_new(r, workouts) - powerdf = pl.DataFrame({ - 'Delta': delta, - 'CP': cp, - }) + if metric == 'power': + powerdf = pl.DataFrame({ + 'Delta': delta, + 'CP': cp, + }) + else: + powerdf = pl.DataFrame({ + 'Delta': delta, + 'CP': cr, + }) + powerdf = powerdf.filter(pl.col("CP")>0) powerdf = powerdf.fill_nan(None).drop_nulls().sort(["Delta", "CP"]) @@ -831,6 +838,8 @@ def update_rolling_cp(r, types, mode='water', dosend=False): if powerdf.is_empty(): return False + + res2 = datautils.cpfit(powerdf) p1 = res2[0] @@ -840,7 +849,7 @@ def update_rolling_cp(r, types, mode='water', dosend=False): pwr += p1[1]/(1+hourseconds/p1[3]) if len(powerdf) != 0: - if mode == 'water': + if mode == 'water' and metric == 'power': r.p0 = p1[0] r.p1 = p1[1] r.p2 = p1[2] @@ -849,8 +858,14 @@ def update_rolling_cp(r, types, mode='water', dosend=False): r.save() if dosend and pwr-5 > r.ftp*(100.-r.otwslack)/100. and r.getemailnotifications and not r.emailbounced: _ = myqueue(queuehigh, handle_sendemail_newftp,r,pwr,'water') - - else: + elif mode == 'water' and metric == 'spm': + r.r0 = p1[0] + r.r1 = p1[1] + r.r2 = p1[2] + r.r3 = p1[3] + r.crratio = res2[3] + r.save() + elif mode == 'erg' and metric == 'power': r.ep0 = p1[0] r.ep1 = p1[1] r.ep2 = p1[2] @@ -859,14 +874,23 @@ def update_rolling_cp(r, types, mode='water', dosend=False): r.save() if dosend and pwr-5 > r.ftp and r.getemailnotifications and not r.emailbounced: _ = myqueue(queuehigh, handle_sendemail_newftp,r,pwr,'water') + elif mode == 'erg' and metric == 'spm': + r.er0 = p1[0] + r.er1 = p1[1] + r.er2 = p1[2] + r.er3 = p1[3] + r.ecrratio = res2[3] + r.save() return True return False def initiate_cp(r): - _ = update_rolling_cp(r, otwtypes, 'water') - _ = update_rolling_cp(r, otetypes, 'erg') + _ = update_rolling_cp(r, otwtypes, mode='water', metric='power') + _ = update_rolling_cp(r, otetypes, mode='erg', metric='power') + _ = update_rolling_cp(r, otwtypes, mode='water', metric='spm') + _ = update_rolling_cp(r, otetypes, mode='erg', metric='spm') def split_workout(r, parent, splitsecond, splitmode): data, row = getrowdata_db(id=parent.id) @@ -1077,7 +1101,8 @@ def checkbreakthrough(w, r): try: res, btvalues, res2 = utils.isbreakthrough( delta, cpvalues, r.p0, r.p1, r.p2, r.p3, r.cpratio) - _ = update_rolling_cp(r, otwtypes, 'water') + _ = update_rolling_cp(r, otwtypes, mode='water') + _ = update_rolling_cp(r, otwtypes, mode='water', metric='spm') except ValueError: res = 0 res2 = 0 @@ -1086,7 +1111,8 @@ def checkbreakthrough(w, r): try: res, btvalues, res2 = utils.isbreakthrough( delta, cpvalues, r.ep0, r.ep1, r.ep2, r.ep3, r.ecpratio) - _ = update_rolling_cp(r, otetypes, 'erg') + _ = update_rolling_cp(r, otetypes, mode='erg') + _ = update_rolling_cp(r, otetypes, mode='erg', metric='spm') except ValueError: res = 0 res2 = 0 diff --git a/rowers/forms.py b/rowers/forms.py index a6a1c9d7..8ebd1804 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -1371,9 +1371,17 @@ class AnalysisChoiceForm(forms.Form): ('automatic', 'Critical Power Rolling Data') ) + crfitchoices = ( + ('data', 'Fit to Selected Workouts'), + ('automatic', 'Critical Stroke Rate Rolling Data') + ) + cpfit = forms.ChoiceField(choices=cpfitchoices, label='Model Fit', initial='data', required=False) + crfit = forms.ChoiceField(choices=crfitchoices, + label='Model Fit', initial='data', required=False) + cpoverlay = forms.BooleanField(initial=False, label='Overlay Gold Medal Performance', required=False) diff --git a/rowers/models.py b/rowers/models.py index ca4d864c..0d13f520 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -1114,7 +1114,7 @@ class Rower(models.Model): er1 = models.FloatField(default=1.0, verbose_name="erg CR r2") er2 = models.FloatField(default=1.0, verbose_name="erg CR r3") er3 = models.FloatField(default=1.0, verbose_name="erg CR r4") - ecpratio = models.FloatField(default=1.0, verbose_name="erg CP fit ratio") + ecrratio = models.FloatField(default=1.0, verbose_name="erg CR fit ratio") cprange = models.IntegerField(default=42, verbose_name="Range for calculation of breakthrough workouts and fitness (CP)", choices=cppresets) diff --git a/rowers/templates/user_analysis_select.html b/rowers/templates/user_analysis_select.html index 65722c5c..3ea46e5b 100644 --- a/rowers/templates/user_analysis_select.html +++ b/rowers/templates/user_analysis_select.html @@ -172,7 +172,8 @@ workmax.hide(); spmmin.hide(); spmmax.hide(); - cpfit.hide(); + cpfit.hide(); + crfit.hide(); cpoverlay.hide(); piece.hide(); trendline.hide(); diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 6b97f027..cab4ef79 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -816,7 +816,7 @@ def cpdata(workouts, options): def crdata(workouts, options): start = timezone.now() userid = options['userid'] - cpfit = options['cpfit'] + cpfit = options['crfit'] cpoverlay = options['cpoverlay'] u = User.objects.get(id=userid)