From cace69a63db242f0524c6c02719463dedfc2f8b9 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 25 Nov 2020 18:35:40 +0100 Subject: [PATCH] adding fitscore --- rowers/dataprep.py | 71 ++++++++++++++++++++++++++++++++++++-- rowers/interactiveplots.py | 2 +- rowers/models.py | 17 ++++++--- rowers/utils.py | 5 +-- 4 files changed, 86 insertions(+), 9 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index c1cf63b0..843cbc06 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -6,7 +6,9 @@ from __future__ import unicode_literals # All the data preparation, data cleaning and data mangling should # be defined here from __future__ import unicode_literals, absolute_import -from rowers.models import Workout, Team +from rowers.models import ( + Workout, Team, CalcAgePerformance,C2WorldClassAgePerformance, + ) import pytz import collections @@ -23,7 +25,10 @@ from rowingdata import ( get_file_type, get_empower_rigging,get_empower_firmware ) -from rowers.tasks import handle_sendemail_unrecognized,handle_setcp +from rowers.tasks import ( + handle_sendemail_unrecognized,handle_setcp, + handle_getagegrouprecords + ) from rowers.tasks import handle_zip_file from pandas import DataFrame, Series @@ -1016,6 +1021,67 @@ def fetchcperg(rower,theworkouts): return cpdf +from rowers.datautils import p0 +from rowers.utils import calculate_age +from scipy import optimize + +def fitscore(rower,workout): + cpfile = 'media/cpdata_{id}.parquet.gz'.format(id=workout.id) + try: + df = pd.read_parquet(cpfile) + except: + df, delta, cpvalues = setcp(workout) + + age = calculate_age(rower.birthdate,today=workout.date) + agerecords = CalcAgePerformance.objects.filter( + age=age, + sex=rower.sex, + weightcategory = rower.weightcategory + ) + wcdurations = [] + wcpower = [] + for record in agerecords: + wcdurations.append(record.duration) + wcpower.append(record.power) + + if len(agerecords)==0: + durations = [1,4,10,20,30,60] + distances = [] + df2 = pd.DataFrame( + list( + C2WorldClassAgePerformance.objects.filter( + sex=rower.sex, + weightcategory=rower.weightcategory + ).values() + ) + ) + jsondf = df2.to_json() + job = myqueue(queue,handle_getagegrouprecords, + jsondf,distances,durations,age,rower.sex,rower.weightcategory) + + wcpower = pd.Series(wcpower) + wcdurations = pd.Series(wcdurations) + + fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3])) + errfunc = lambda pars,x,y: fitfunc(pars,x)-y + + if len(wcdurations)>4: + p1wc, success = optimize.leastsq(errfunc, p0[:],args=(wcdurations,wcpower)) + else: + factor = fitfunc(p0,wcdurations.mean()/wcpower.mean()) + p1wc = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] + success = 0 + + + times = df['delta'] + powers = df['cp'] + wcpowers = fitfunc(p1wc,times) + scores = 100.*powers/wcpowers + + indexmax = scores.idxmax() + + return scores.max(),df.loc[indexmax,'delta'] + def fetchcp_new(rower,workouts): data = [] @@ -3009,6 +3075,7 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True, return data + def workout_trimp(w): r = w.user diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index c95c88c6..088ea90c 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import colorsys from rowers.models import ( Workout, User, Rower, WorkoutForm,RowerForm, - GraphImage,GeoPolygon,GeoCourse,GeoPoint + GraphImage,GeoPolygon,GeoCourse,GeoPoint, ) from rowers.tasks import handle_setcp from rowingdata import rower as rrower diff --git a/rowers/models.py b/rowers/models.py index ed96081a..f38ccc04 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -265,15 +265,15 @@ def update_records(url=c2url,verbose=True): for nr,row in df.iterrows(): if 'm' in row['Record']: - df.ix[nr,'Distance'] = row['Record'][:-1] - df.ix[nr,'Duration'] = 60*row['Event'] + df.loc[nr,'Distance'] = row['Record'][:-1] + df.loc[nr,'Duration'] = 60*row['Event'] else: - df.ix[nr,'Distance'] = row['Event'] + df.loc[nr,'Distance'] = row['Event'] try: tobj = datetime.datetime.strptime(row['Record'],'%M:%S.%f') except ValueError: tobj = datetime.datetime.strptime(row['Record'],'%H:%M:%S.%f') - df.ix[nr,'Duration'] = 3600.*tobj.hour+60.*tobj.minute+tobj.second+tobj.microsecond/1.e6 + df.loc[nr,'Duration'] = 3600.*tobj.hour+60.*tobj.minute+tobj.second+tobj.microsecond/1.e6 for nr,row in df.iterrows(): try: @@ -334,6 +334,15 @@ class CalcAgePerformance(models.Model): class Meta: db_table = 'calcagegrouprecords' + def __str_(self): + stri = 'Calculated World Class Performance for {s}, {a}, {d} secs, {p} Watts'.format( + s = self.sex, + a = self.age, + d = self.duration, + p = self.power + ) + return stri + class PowerTimeFitnessMetric(models.Model): modechoices = ( ('rower','Rower'), diff --git a/rowers/utils.py b/rowers/utils.py index ce2a017f..cf76d3ca 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -323,8 +323,9 @@ def myqueue(queue,function,*args,**kwargs): from datetime import date -def calculate_age(born): - today = date.today() +def calculate_age(born,today=None): + if not today: + today = date.today() if born: return today.year - born.year - ((today.month, today.day) < (born.month, born.day)) else: