Private
Public Access
1
0

Merge branch 'feature/goldmedalscore' into develop

This commit is contained in:
Sander Roosendaal
2020-12-10 21:17:36 +01:00
10 changed files with 194 additions and 53 deletions
+77 -11
View File
@@ -8,6 +8,7 @@ from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import from __future__ import unicode_literals, absolute_import
from rowers.models import ( from rowers.models import (
Workout, Team, CalcAgePerformance,C2WorldClassAgePerformance, Workout, Team, CalcAgePerformance,C2WorldClassAgePerformance,
User
) )
import pytz import pytz
@@ -325,10 +326,13 @@ def workout_summary_to_df(
startdate=datetime.datetime(1970,1,1), startdate=datetime.datetime(1970,1,1),
enddate=timezone.now()+timezone.timedelta(days=1)): enddate=timezone.now()+timezone.timedelta(days=1)):
ws = Workout.objects.filter(user=rower).order_by("startdatetime") ws = Workout.objects.filter(
user=rower,date__gte=startdate,date__lte=enddate
).order_by("startdatetime")
types = [] types = []
names = [] names = []
ids = []
startdatetimes = [] startdatetimes = []
timezones = [] timezones = []
distances = [] distances = []
@@ -339,12 +343,19 @@ def workout_summary_to_df(
notes = [] notes = []
tcx_links = [] tcx_links = []
csv_links = [] csv_links = []
workout_links = []
goldstandards = []
goldstandarddurations = []
rscores = [] rscores = []
hrtss = []
trimps = [] trimps = []
rankingpieces = []
boattypes = []
for w in ws: for w in ws:
types.append(w.workouttype) types.append(w.workouttype)
names.append(w.name) names.append(w.name)
ids.append(encoder.encode_hex(w.id))
startdatetimes.append(w.startdatetime) startdatetimes.append(w.startdatetime)
timezones.append(w.timezone) timezones.append(w.timezone)
distances.append(w.distance) distances.append(w.distance)
@@ -352,6 +363,7 @@ def workout_summary_to_df(
weightcategories.append(w.weightcategory) weightcategories.append(w.weightcategory)
adaptivetypes.append(w.adaptiveclass) adaptivetypes.append(w.adaptiveclass)
weightvalues.append(w.weightvalue) weightvalues.append(w.weightvalue)
boattypes.append(w.boattype)
notes.append(w.notes) notes.append(w.notes)
tcx_link = SITE_URL+'/rowers/workout/{id}/emailtcx'.format( tcx_link = SITE_URL+'/rowers/workout/{id}/emailtcx'.format(
id=encoder.encode_hex(w.id) id=encoder.encode_hex(w.id)
@@ -361,25 +373,41 @@ def workout_summary_to_df(
id=encoder.encode_hex(w.id) id=encoder.encode_hex(w.id)
) )
csv_links.append(csv_link) csv_links.append(csv_link)
workout_link = SITE_URL+'/rowers/workout/{id}/'.format(
id=encoder.encode_hex(w.id)
)
workout_links.append(workout_link)
trimps.append(workout_trimp(w)[0]) trimps.append(workout_trimp(w)[0])
rscore = workout_rscore(w) rscore = workout_rscore(w)
rscores.append(int(rscore[0])) rscores.append(int(rscore[0]))
hrtss.append(int(w.hrtss))
goldstandard,goldstandardduration = workout_goldmedalstandard(w)
goldstandards.append(int(goldstandard))
goldstandarddurations.append(int(goldstandardduration))
rankingpieces.append(w.rankingpiece)
df = pd.DataFrame({ df = pd.DataFrame({
'name':names, 'ID': ids,
'date':startdatetimes, 'date':startdatetimes,
'name':names,
'link':workout_links,
'timezone':timezones, 'timezone':timezones,
'type':types, 'type':types,
'boat type':boattypes,
'distance (m)':distances, 'distance (m)':distances,
'duration ':durations, 'duration ':durations,
'ranking piece':rankingpieces,
'weight category':weightcategories, 'weight category':weightcategories,
'adaptive classification':adaptivetypes, 'adaptive classification':adaptivetypes,
'weight (kg)':weightvalues, 'weight (kg)':weightvalues,
'notes':notes,
'Stroke Data TCX':tcx_links, 'Stroke Data TCX':tcx_links,
'Stroke Data CSV':csv_links, 'Stroke Data CSV':csv_links,
'TRIMP Training Load':trimps, 'TRIMP Training Load':trimps,
'TSS Training Load':rscores, 'TSS Training Load':rscores,
'hrTSS Training Load':hrtss,
'GS':goldstandards,
'GS_secs':goldstandarddurations,
'notes':notes,
}) })
return df return df
@@ -1026,28 +1054,58 @@ from rowers.datautils import p0
from rowers.utils import calculate_age from rowers.utils import calculate_age
from scipy import optimize from scipy import optimize
def fitscore(rower,workout): def get_workoutsummaries(userid,startdate):
u = User.objects.get(id=userid)
r = u.rower
df = workout_summary_to_df(r,startdate=startdate)
df.drop(['Stroke Data TCX','Stroke Data CSV'],axis=1,inplace=True)
df = df.sort_values('date',ascending=False)
return df
def workout_goldmedalstandard(workout):
if workout.goldmedalstandard > 0:
return workout.goldmedalstandard,workout.goldmedalseconds
if workout.workouttype in rowtypes:
goldmedalstandard,goldmedalseconds = calculate_goldmedalstandard(workout.user,workout)
workout.goldmedalstandard = goldmedalstandard
workout.goldmedalseconds = goldmedalseconds
workout.save()
return goldmedalstandard, goldmedalseconds
else:
return 0,0
def calculate_goldmedalstandard(rower,workout):
cpfile = 'media/cpdata_{id}.parquet.gz'.format(id=workout.id) cpfile = 'media/cpdata_{id}.parquet.gz'.format(id=workout.id)
try: try:
df = pd.read_parquet(cpfile) df = pd.read_parquet(cpfile)
except: except:
df, delta, cpvalues = setcp(workout) df, delta, cpvalues = setcp(workout)
if df.empty:
df, delta, cpvalues = setcp(workout)
age = calculate_age(rower.birthdate,today=workout.date) age = calculate_age(rower.birthdate,today=workout.date)
agerecords = CalcAgePerformance.objects.filter( agerecords = CalcAgePerformance.objects.filter(
age=age, age=age,
sex=rower.sex, sex=rower.sex,
weightcategory = rower.weightcategory weightcategory = rower.weightcategory
) )
wcdurations = [] wcdurations = []
wcpower = [] wcpower = []
getrecords = len(agerecords) == 0
for record in agerecords: for record in agerecords:
if record.power > 0:
wcdurations.append(record.duration) wcdurations.append(record.duration)
wcpower.append(record.power) wcpower.append(record.power)
else:
getrecords = True
if len(agerecords)==0: if getrecords:
durations = [1,4,10,20,30,60] durations = [1,4,30,60]
distances = [] distances = [100,500,1000,2000,5000,6000,10000,21097,42195]
df2 = pd.DataFrame( df2 = pd.DataFrame(
list( list(
C2WorldClassAgePerformance.objects.filter( C2WorldClassAgePerformance.objects.filter(
@@ -1066,12 +1124,13 @@ def fitscore(rower,workout):
fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3])) 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 errfunc = lambda pars,x,y: fitfunc(pars,x)-y
if len(wcdurations)>4: if len(wcdurations)>=4:
p1wc, success = optimize.leastsq(errfunc, p0[:],args=(wcdurations,wcpower)) p1wc, success = optimize.leastsq(errfunc, p0[:],args=(wcdurations,wcpower))
else: else:
factor = fitfunc(p0,wcdurations.mean()/wcpower.mean()) factor = fitfunc(p0,wcdurations.mean()/wcpower.mean())
p1wc = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] p1wc = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]]
success = 0 success = 0
return 0,0
times = df['delta'] times = df['delta']
@@ -1079,11 +1138,12 @@ def fitscore(rower,workout):
wcpowers = fitfunc(p1wc,times) wcpowers = fitfunc(p1wc,times)
scores = 100.*powers/wcpowers scores = 100.*powers/wcpowers
try: try:
indexmax = scores.idxmax() indexmax = scores.idxmax()
delta = df.loc[indexmax,'delta'] delta = int(df.loc[indexmax,'delta'])
maxvalue = scores.max() maxvalue = scores.max()
except ValueError: except (ValueError,TypeError):
indexmax = 0 indexmax = 0
delta = 0 delta = 0
maxvalue = 0 maxvalue = 0
@@ -1127,7 +1187,6 @@ def setcp(workout,background=False):
return job.id return job.id
if not strokesdf.empty: if not strokesdf.empty:
totaltime = strokesdf['time'].max() totaltime = strokesdf['time'].max()
try: try:
@@ -1150,6 +1209,10 @@ def setcp(workout,background=False):
'id':workout.id, 'id':workout.id,
}) })
df.to_parquet(filename,engine='fastparquet',compression='GZIP') df.to_parquet(filename,engine='fastparquet',compression='GZIP')
goldmedalstandard, goldmedalduration = calculate_goldmedalstandard(workout.user,workout)
workout.goldmedalstandard = goldmedalstandard
workout.goldmedalduration = goldmedalduration
workout.save()
return df,delta,cpvalues return df,delta,cpvalues
return pd.DataFrame({'delta':[],'cp':[]}),pd.Series(),pd.Series() return pd.DataFrame({'delta':[],'cp':[]}),pd.Series(),pd.Series()
@@ -2580,7 +2643,10 @@ def read_df_sql(id):
rowdata,row = getrowdata(id=id) rowdata,row = getrowdata(id=id)
if rowdata and len(rowdata.df): if rowdata and len(rowdata.df):
data = dataprep(rowdata.df,id=id,bands=True,otwpower=True,barchart=True) data = dataprep(rowdata.df,id=id,bands=True,otwpower=True,barchart=True)
try:
df = pd.read_parquet(f) df = pd.read_parquet(f)
except OSError:
df = data
else: else:
df = pd.DataFrame() df = pd.DataFrame()
+1 -1
View File
@@ -768,7 +768,7 @@ class FitnessFitForm(forms.Form):
fitnesstest = forms.IntegerField(required=True,initial=20, fitnesstest = forms.IntegerField(required=True,initial=20,
label='Test Duration (minutes)') label='Test Duration (minutes)')
usefitscore = forms.BooleanField(required=False,initial=False, usegoldmedalstandard = forms.BooleanField(required=False,initial=False,
label='Use best performance against world class') label='Use best performance against world class')
kfitness = forms.IntegerField(initial=42,required=True, kfitness = forms.IntegerField(initial=42,required=True,
+42 -22
View File
@@ -25,7 +25,7 @@ import itertools
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation, Band from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation, Band
from rowers.utils import myqueue from rowers.utils import myqueue, totaltime_sec_to_string
import django_rq import django_rq
queue = django_rq.get_queue('default') queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low') queuelow = django_rq.get_queue('low')
@@ -102,39 +102,52 @@ import rowers.datautils as datautils
from pandas.core.groupby.groupby import DataError from pandas.core.groupby.groupby import DataError
def get_fitscore(workouts,kfitness): def build_goldmedalstandards(workouts,kfitness):
dates = [] dates = []
testpower = [] testpower = []
testduration = []
fatigues = [] fatigues = []
fitnesses = [] fitnesses = []
data = [] data = []
fitscores = [] goldmedalstandards = []
goldmedaldurations = []
ids = [] ids = []
for w in workouts: for w in workouts:
fitscore,fitnesstestsecs = dataprep.fitscore(w.user,w) goldmedalstandard,goldmedalseconds = dataprep.workout_goldmedalstandard(w)
ids.append(w.id) ids.append(w.id)
fitscores.append(fitscore) goldmedalstandards.append(goldmedalstandard)
goldmedaldurations.append(goldmedalseconds)
df = pd.DataFrame({'workout':ids,'fitscore':fitscores}) df = pd.DataFrame({
'workout':ids,
'goldmedalstandard':goldmedalstandards,
'goldmedalduration':goldmedaldurations,
})
for w in workouts: for w in workouts:
ids = [w.id for w in workouts.filter(date__gte=w.date-datetime.timedelta(days=kfitness), ids = [w.id for w in workouts.filter(date__gte=w.date-datetime.timedelta(days=kfitness),
date__lte=w.date)] date__lte=w.date)]
powerdf = df[df['workout'].isin(ids)] powerdf = df[df['workout'].isin(ids)]
powertest = powerdf['fitscore'].max() indexmax = powerdf['goldmedalstandard'].idxmax()
powertest = powerdf['goldmedalstandard'].max()
durationtest = powerdf.loc[indexmax,'goldmedalduration']
dates.append(datetime.datetime.combine(w.date,datetime.datetime.min.time())) dates.append(datetime.datetime.combine(w.date,datetime.datetime.min.time()))
testpower.append(powertest) testpower.append(powertest)
testduration.append(durationtest)
fatigues.append(np.nan) fatigues.append(np.nan)
fitnesses.append(np.nan) fitnesses.append(np.nan)
return dates, testpower, fatigues, fitnesses return dates, testpower, testduration, fatigues, fitnesses
def get_testpower(workouts,fitnesstestsecs,kfitness): def get_testpower(workouts,fitnesstestsecs,kfitness):
dates = [] dates = []
testpower = [] testpower = []
testduration = []
fatigues = [] fatigues = []
fitnesses = [] fitnesses = []
data = [] data = []
@@ -192,10 +205,11 @@ def get_testpower(workouts,fitnesstestsecs,kfitness):
dates.append(datetime.datetime.combine(w.date,datetime.datetime.min.time())) dates.append(datetime.datetime.combine(w.date,datetime.datetime.min.time()))
testpower.append(powertest) testpower.append(powertest)
testduration.append(fitnesstestsecs)
fatigues.append(np.nan) fatigues.append(np.nan)
fitnesses.append(np.nan) fitnesses.append(np.nan)
return dates,testpower,fatigues,fitnesses return dates,testpower, testduration,fatigues,fitnesses
@@ -1632,7 +1646,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
return [script,div,js_resources,css_resources] return [script,div,js_resources,css_resources]
def getfatigues( def getfatigues(
fatigues,fitnesses,dates,testpower, fatigues,fitnesses,dates,testpower,testduration,
startdate,enddate,user,metricchoice,kfatigue,kfitness): startdate,enddate,user,metricchoice,kfatigue,kfitness):
fatigue = 0 fatigue = 0
@@ -1685,8 +1699,9 @@ def getfatigues(
fitnesses.append(fitness) fitnesses.append(fitness)
dates.append(datetime.datetime.combine(date,datetime.datetime.min.time())) dates.append(datetime.datetime.combine(date,datetime.datetime.min.time()))
testpower.append(np.nan) testpower.append(np.nan)
testduration.append(np.nan)
return fatigues,fitnesses,dates,testpower,impulses return fatigues,fitnesses,dates,testpower,testduration,impulses
def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7, def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
metricchoice='trimp',doform=False,dofatigue=False): metricchoice='trimp',doform=False,dofatigue=False):
@@ -1699,6 +1714,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
fitnesses = [] fitnesses = []
dates = [] dates = []
testpower = [] testpower = []
testduration = []
modelchoice = 'coggan' modelchoice = 'coggan'
p0 = 0 p0 = 0
@@ -1707,11 +1723,10 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
fatigues,fitnesses,dates,testpower,testduration,impulses = getfatigues(fatigues,
fatigues,fitnesses,dates,testpower,impulses = getfatigues(fatigues,
fitnesses, fitnesses,
dates, dates,
testpower, testpower,testduration,
startdate,enddate, startdate,enddate,
user,metricchoice, user,metricchoice,
kfatigue,kfitness) kfatigue,kfitness)
@@ -1918,7 +1933,7 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
metricchoice='rscore', metricchoice='rscore',
k1=1,k2=1,p0=100, k1=1,k2=1,p0=100,
modelchoice='tsb', modelchoice='tsb',
usefitscore=False): usegoldmedalstandard=False):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
@@ -1929,12 +1944,12 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
fitnesstestsecs = fitnesstest*60 fitnesstestsecs = fitnesstest*60
df = pd.DataFrame() df = pd.DataFrame()
if not usefitscore: if not usegoldmedalstandard:
dates,testpower,fatigues,fitnesses = get_testpower( dates,testpower,testduration, fatigues,fitnesses = get_testpower(
workouts,fitnesstestsecs,kfitness workouts,fitnesstestsecs,kfitness
) )
else: else:
dates,testpower,fatigues,fitnesses = get_fitscore( dates,testpower, testduration,fatigues,fitnesses = build_goldmedalstandards(
workouts,kfitness workouts,kfitness
) )
# create CP data # create CP data
@@ -1942,6 +1957,7 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
df = pd.DataFrame({ df = pd.DataFrame({
'date':dates, 'date':dates,
'testpower':testpower, 'testpower':testpower,
'testduration':testduration,
'fatigue':fatigues, 'fatigue':fatigues,
'fitness':fitnesses, 'fitness':fitnesses,
}) })
@@ -1962,9 +1978,10 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
testpower = df['testpower'].values.tolist() testpower = df['testpower'].values.tolist()
fatigues = df['fatigue'].values.tolist() fatigues = df['fatigue'].values.tolist()
fitnesses = df['fitness'].values.tolist() fitnesses = df['fitness'].values.tolist()
testduration = df['testduration'].values.tolist()
fatigues,fitnesses,dates,testpower,impulses = getfatigues( fatigues,fitnesses,dates,testpower,testduration,impulses = getfatigues(
fatigues,fitnesses,dates,testpower, fatigues,fitnesses,dates,testpower,testduration,
startdate,enddate,user,metricchoice,kfatigue,kfitness startdate,enddate,user,metricchoice,kfatigue,kfitness
) )
@@ -1972,6 +1989,7 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
df = pd.DataFrame({ df = pd.DataFrame({
'date':dates, 'date':dates,
'testpower':testpower, 'testpower':testpower,
'testduration':testduration,
'fatigue':fatigues, 'fatigue':fatigues,
'fitness':fitnesses, 'fitness':fitnesses,
}) })
@@ -1997,6 +2015,7 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
source = ColumnDataSource( source = ColumnDataSource(
data = dict( data = dict(
testpower = df['testpower'], testpower = df['testpower'],
testduration = df['testduration'].apply(lambda x:totaltime_sec_to_string(x,shorten=True)),
date = df['date'], date = df['date'],
fdate = df['date'].map(lambda x: x.strftime('%d-%m-%Y')), fdate = df['date'].map(lambda x: x.strftime('%d-%m-%Y')),
fitness = df['fitness'], fitness = df['fitness'],
@@ -2051,7 +2070,7 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
formlabel = 'TSB' formlabel = 'TSB'
rightaxlabel = 'Coggan CTL/ATL/TSB' rightaxlabel = 'Coggan CTL/ATL/TSB'
if usefitscore: if usegoldmedalstandard:
legend_label = 'Test Score' legend_label = 'Test Score'
yaxlabel = 'Test Score' yaxlabel = 'Test Score'
else: else:
@@ -2106,7 +2125,8 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
hover = plot.select(dict(type=HoverTool)) hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([ hover.tooltips = OrderedDict([
(legend_label,'@testpower'), (legend_label,'@testpower{int}'),
('Test', '@testduration'),
('Date','@fdate'), ('Date','@fdate'),
(fitlabel,'@fitness'), (fitlabel,'@fitness'),
(fatiguelabel,'@fatigue'), (fatiguelabel,'@fatigue'),
+1
View File
@@ -2953,6 +2953,7 @@ class Workout(models.Model):
normv = models.FloatField(default=-1,blank=True) normv = models.FloatField(default=-1,blank=True)
normw = models.FloatField(default=-1,blank=True) normw = models.FloatField(default=-1,blank=True)
goldmedalstandard = models.FloatField(default=-1,blank=True,verbose_name='Gold Medal Standard') goldmedalstandard = models.FloatField(default=-1,blank=True,verbose_name='Gold Medal Standard')
goldmedalseconds = models.IntegerField(default=0,blank=True,verbose_name='Gold Medal Seconds')
rpe = models.IntegerField(default=0,blank=True,choices=rpechoices, rpe = models.IntegerField(default=0,blank=True,choices=rpechoices,
verbose_name='Rate of Perceived Exertion') verbose_name='Rate of Perceived Exertion')
+6 -1
View File
@@ -16,6 +16,7 @@ import json
from scipy import optimize from scipy import optimize
from scipy.signal import savgol_filter from scipy.signal import savgol_filter
from scipy.interpolate import griddata
import rowingdata import rowingdata
from rowingdata import make_cumvalues from rowingdata import make_cumvalues
@@ -333,7 +334,11 @@ def getagegrouprecord(age,sex='male',weightcategory='hwt',
power = 0.5*(np.abs(power)+power) power = 0.5*(np.abs(power)+power)
else: else:
power = 0 new_age = np.range([age])
ww = griddata(ages.values,
powers.values,
new_age,method='linear',rescale=True)
power = 0.5*(np.abs(power)+power)
else: else:
power = 0 power = 0
+7
View File
@@ -49,6 +49,13 @@
</table> </table>
</li> </li>
<li class="grid_2"> <li class="grid_2">
<p>Gold Medal Standard: For rowing workouts, the best performance, relative to world class rowers
of your age, gender and weight category,
found in this workout. This metric uses your power data over time and
compares them with the power that the best rowers of your age, gender and weight category
can hold over time.</p>
<p>Gold Medal Standard Duration: The time interval over which your best
performance in this workout was achieved.</p>
<p>rPower: Equivalent steady state power for the duration of the workout.</p> <p>rPower: Equivalent steady state power for the duration of the workout.</p>
<p>Heart Rate Drift: Comparing heart rate normalized for average power for the first and second half of the workout</p> <p>Heart Rate Drift: Comparing heart rate normalized for average power for the first and second half of the workout</p>
<p>TRIMP: TRaining IMPact. A way to combine duration and heart rate into a single number.</p> <p>TRIMP: TRaining IMPact. A way to combine duration and heart rate into a single number.</p>
+23 -1
View File
@@ -327,7 +327,10 @@ def calculate_age(born,today=None):
if not today: if not today:
today = date.today() today = date.today()
if born: if born:
try:
return today.year - born.year - ((today.month, today.day) < (born.month, born.day)) return today.year - born.year - ((today.month, today.day) < (born.month, born.day))
except AttributeError:
return None
else: else:
return None return None
@@ -373,7 +376,9 @@ def wavg(group, avg_name, weight_name):
except ZeroDivisionError: except ZeroDivisionError:
return d.mean() return d.mean()
def totaltime_sec_to_string(totaltime): def totaltime_sec_to_string(totaltime,shorten=False):
if np.isnan(totaltime):
return ''
hours = int(totaltime / 3600.) hours = int(totaltime / 3600.)
if hours > 23: if hours > 23:
message = 'Warning: The workout duration was longer than 23 hours. ' message = 'Warning: The workout duration was longer than 23 hours. '
@@ -397,12 +402,29 @@ def totaltime_sec_to_string(totaltime):
if not message: if not message:
message = 'Warning: there is something wrong with the workout duration' message = 'Warning: there is something wrong with the workout duration'
duration = ""
if not shorten:
duration = "{hours:02d}:{minutes:02d}:{seconds:02d}.{tenths}".format( duration = "{hours:02d}:{minutes:02d}:{seconds:02d}.{tenths}".format(
hours=hours, hours=hours,
minutes=minutes, minutes=minutes,
seconds=seconds, seconds=seconds,
tenths=tenths tenths=tenths
) )
else:
if hours != 0:
duration = "{hours}:{minutes:02d}:{seconds:02d}".format(
hours=hours,
minutes=minutes,
seconds=seconds,
tenths=tenths
)
else:
duration = "{minutes}:{seconds:02d}".format(
hours=hours,
minutes=minutes,
seconds=seconds,
tenths=tenths
)
return duration return duration
+4 -4
View File
@@ -1561,7 +1561,7 @@ def performancemanager_view(request,userid=0,mode='rower',
fitnesstest = 20 fitnesstest = 20
metricchoice = 'trimp' metricchoice = 'trimp'
modelchoice = 'tsb' modelchoice = 'tsb'
usefitscore = False usegoldmedalstandard = False
doform = therower.showfresh doform = therower.showfresh
dofatigue = therower.showfit dofatigue = therower.showfit
@@ -1647,7 +1647,7 @@ def fitness_from_cp_view(request,userid=0,mode='rower',
fitnesstest = 20 fitnesstest = 20
metricchoice = 'trimp' metricchoice = 'trimp'
modelchoice = 'tsb' modelchoice = 'tsb'
usefitscore = False usegoldmedalstandard = False
# temp fit parameters # temp fit parameters
k1 = 1 k1 = 1
@@ -1669,7 +1669,7 @@ def fitness_from_cp_view(request,userid=0,mode='rower',
k2 = form.cleaned_data['k2'] k2 = form.cleaned_data['k2']
p0 = form.cleaned_data['p0'] p0 = form.cleaned_data['p0']
modelchoice = form.cleaned_data['modelchoice'] modelchoice = form.cleaned_data['modelchoice']
usefitscore = form.cleaned_data['usefitscore'] usegoldmedalstandard = form.cleaned_data['usegoldmedalstandard']
else: else:
form = FitnessFitForm() form = FitnessFitForm()
@@ -1694,7 +1694,7 @@ def fitness_from_cp_view(request,userid=0,mode='rower',
metricchoice=metricchoice, metricchoice=metricchoice,
k1=k1,k2=k2,p0=p0, k1=k1,k2=k2,p0=p0,
modelchoice=modelchoice, modelchoice=modelchoice,
usefitscore=usefitscore, usegoldmedalstandard=usegoldmedalstandard,
) )
breadcrumbs = [ breadcrumbs = [
+3
View File
@@ -554,7 +554,10 @@ def getrequestplanrower(request,rowerid=0,userid=0,notpermanent=False):
if rowerid != 0: if rowerid != 0:
r = Rower.objects.get(id=rowerid) r = Rower.objects.get(id=rowerid)
elif userid != 0: elif userid != 0:
try:
u = User.objects.get(id=userid) u = User.objects.get(id=userid)
except User.DoesNotExist:
raise Http404("User does not exist")
r = getrower(u) r = getrower(u)
else: else:
r = getrower(request.user) r = getrower(request.user)
+17
View File
@@ -12,6 +12,7 @@ import rowers.mytypes as mytypes
import numpy import numpy
from rowers.mailprocessing import send_confirm from rowers.mailprocessing import send_confirm
import rowers.uploads as uploads import rowers.uploads as uploads
import rowers.utils as utils
from urllib.parse import urlparse, parse_qs from urllib.parse import urlparse, parse_qs
from json.decoder import JSONDecodeError from json.decoder import JSONDecodeError
@@ -3497,6 +3498,22 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
# Normalized power & TSS # Normalized power & TSS
tss,normp = dataprep.workout_rscore(w) tss,normp = dataprep.workout_rscore(w)
goldmedalstandard,goldmedalseconds = dataprep.workout_goldmedalstandard(w)
#if not np.isnan(goldmedalstandard) and goldmedalstandard > 0:
# otherstats['goldmedalstandard'] = {
# 'verbose_name': 'Gold Medal Standard',
# 'value': int(goldmedalstandard),
# 'unit': '%',
# }
#if not np.isnan(goldmedalseconds) and goldmedalseconds > 0:
# otherstats['goldmedalseconds'] = {
# 'verbose_name': 'Gold Medal Standard Duration',
# 'value': utils.totaltime_sec_to_string(goldmedalseconds,shorten=True),
# 'unit': '',
# }
if not np.isnan(tss) and tss != 0: if not np.isnan(tss) and tss != 0: