Private
Public Access
1
0

added age records to ote-bests

This commit is contained in:
Sander Roosendaal
2017-12-13 15:37:52 +01:00
parent 098dbb9c4a
commit 451f153983
6 changed files with 431 additions and 13 deletions

View File

@@ -1101,7 +1101,8 @@ def interactive_agegroup_plot(df):
return script,div
def interactive_cpchart(rower,thedistances,thesecs,theavpower,
theworkouts,promember=0):
theworkouts,promember=0,
wcpower=[],wcdurations=[]):
message = 0
# plot tools
@@ -1167,11 +1168,23 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
)
# fitting the data to three parameter CP model
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
p0 = [500,350,10,8000]
wcpower = pd.Series(wcpower)
wcdurations = pd.Series(wcdurations)
# fitting WC data to three parameter CP model
if len(wcdurations)>=4:
p1wc, success = optimize.leastsq(errfunc, p0[:],
args = (wcdurations,wcpower))
else:
p1wc = None
# fitting the data to three parameter CP model
p1 = p0
if len(thesecs)>=4:
@@ -1184,6 +1197,21 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
fitt = pd.Series(10**(4*np.arange(100)/100.))
fitpower = fitfunc(p1,fitt)
if p1wc is not None:
fitpowerwc = 0.95*fitfunc(p1wc,fitt)
fitpowerexcellent = 0.7*fitfunc(p1wc,fitt)
fitpowergood = 0.6*fitfunc(p1wc,fitt)
fitpowerfair = 0.5*fitfunc(p1wc,fitt)
fitpoweraverage = 0.4*fitfunc(p1wc,fitt)
else:
fitpowerwc = 0*fitpower
fitpowerexcellent = 0*fitpower
fitpowergood = 0*fitpower
fitpowerfair = 0*fitpower
fitpoweraverage = 0*fitpower
message = ""
if len(fitpower[fitpower<0]) > 0:
@@ -1203,6 +1231,11 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
),
spm = 0*fitpower,
power = fitpower,
fitpowerwc = fitpowerwc,
fitpowerexcellent = fitpowerexcellent,
fitpowergood = fitpowergood,
fitpowerfair = fitpowerfair,
fitpoweraverage = fitpoweraverage,
fpace = nicepaceformat(fitp2),
)
)
@@ -1281,6 +1314,25 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
plot.line('duration','power',source=sourcepaul,legend="Paul's Law")
plot.line('duration','power',source=sourcecomplex,legend="CP Model",
color='green')
plot.line('duration','fitpowerwc',source=sourcecomplex,
legend="World Class",
color='Maroon',line_dash='dotted')
plot.line('duration','fitpowerexcellent',source=sourcecomplex,
legend="Excellent",
color='Purple',line_dash='dotted')
plot.line('duration','fitpowergood',source=sourcecomplex,
legend="Good",
color='Olive',line_dash='dotted')
plot.line('duration','fitpowerfair',source=sourcecomplex,
legend="Fair",
color='Gray',line_dash='dotted')
plot.line('duration','fitpoweraverage',source=sourcecomplex,
legend="Average",
color='SkyBlue',line_dash='dotted')
script, div = components(plot)

View File

@@ -319,12 +319,26 @@ def calc_trimp(df,sex,hrmax,hrmin):
return trimp
def getagegroup2k(age,sex='male',weightcategory='hwt'):
df = pd.DataFrame(
list(
C2WorldClassAgePerformance.objects.filter(
sex=sex,
weightcategory=weightcategory
def getagegrouprecord(age,sex='male',weightcategory='hwt',
distance=2000,duration=None):
if not duration:
df = pd.DataFrame(
list(
C2WorldClassAgePerformance.objects.filter(
distance=distance,
sex=sex,
weightcategory=weightcategory
).values()
)
)
else:
duration=60*int(duration)
df = pd.DataFrame(
list(
C2WorldClassAgePerformance.objects.filter(
duration=duration,
sex=sex,
weightcategory=weightcategory
).values()
)
)

View File

@@ -0,0 +1 @@
E408191@CZ27LT9RCGN72.12348:1512983261

View File

@@ -160,6 +160,15 @@
{{ the_div|safe }}
<p>The dashed lines are based on the Concept2 rankings for your age, gender
and weight category. World class means within 5% of World Record in terms
of power. Excellent, Good, and Fair indicate the power levels of the top
10%, 25% and 50% of the Concept2 rankings. Average is taken
as being in the top 75%, given that the Concept2 rankings probably
represent the more competitive sub-group of all people who erg.
Please note that this is a prediction for people of exactly your age,
and your actual place in the Concept2 Ranking may be different.</p>
</div>
<div id="predictions" class="grid_12 alpha">
@@ -259,9 +268,7 @@
{% endif %}
</div>
{% if worldclasspower %}
World class 2k for your age, weight is {{ worldclasspower }} Watt
{% endif %}
</div>
{% endblock %}

View File

@@ -165,6 +165,12 @@ urlpatterns = [
url(r'^ote-bests/(?P<deltadays>\d+)$',views.rankings_view),
url(r'^ote-bests/$',views.rankings_view),
url(r'^(?P<theuser>\d+)/ote-bests/$',views.rankings_view),
url(r'^(?P<theuser>\d+)/ote-bests2/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.rankings_view),
url(r'^(?P<theuser>\d+)/ote-bests2/(?P<deltadays>\d+)$',views.rankings_view2),
url(r'^ote-bests2/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.rankings_view2),
url(r'^ote-bests2/(?P<deltadays>\d+)$',views.rankings_view2),
url(r'^ote-bests2/$',views.rankings_view2),
url(r'^(?P<theuser>\d+)/ote-bests2/$',views.rankings_view2),
url(r'^(?P<theuser>\d+)/otw-bests/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.otwrankings_view),
url(r'^(?P<theuser>\d+)/otw-bests/(?P<deltadays>\d+)$',views.otwrankings_view),
url(r'^otw-bests/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.otwrankings_view),

View File

@@ -3223,7 +3223,7 @@ def rankings_view(request,theuser=0,
r = getrower(request.user)
if r.birthdate:
age = calculate_age(r.birthdate)
worldclasspower = int(metrics.getagegroup2k(
worldclasspower = int(metrics.getagegrouprecord(
age,
sex=r.sex,
weightcategory=r.weightcategory
@@ -3507,6 +3507,344 @@ def rankings_view(request,theuser=0,
'teams':get_my_teams(request.user),
})
# Show ranking distances including predicted paces
@login_required()
def rankings_view2(request,theuser=0,
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now(),
deltadays=-1,
startdatestring="",
enddatestring=""):
if deltadays>0:
startdate = enddate-datetime.timedelta(days=int(deltadays))
if startdatestring != "":
startdate = iso8601.parse_date(startdatestring)
if enddatestring != "":
enddate = iso8601.parse_date(enddatestring)
if enddate < startdate:
s = enddate
enddate = startdate
startdate = s
if theuser == 0:
theuser = request.user.id
promember=0
if not request.user.is_anonymous():
r = getrower(request.user)
wcdurations = []
wcpower = []
if r.birthdate:
age = calculate_age(r.birthdate)
durations = [1,4,30,60]
distances = [100,500,1000,2000,5000,6000,10000,21097,42195]
print r.weightcategory,r.sex,age,'aap'
for distance in distances:
worldclasspower = metrics.getagegrouprecord(
age,
sex=r.sex,
distance=distance,
weightcategory=r.weightcategory
)
velo = (worldclasspower/2.8)**(1./3.)
duration = distance/velo
wcdurations.append(duration)
wcpower.append(worldclasspower)
for duration in durations:
worldclasspower = metrics.getagegrouprecord(
age,
sex=r.sex,
duration=duration,
weightcategory=r.weightcategory
)
wcdurations.append(60.*duration)
velo = (worldclasspower/2.8)**(1./3.)
distance = int(60*duration*velo)
wcpower.append(worldclasspower)
else:
worldclasspower = None
result = request.user.is_authenticated() and ispromember(request.user)
if result:
promember=1
# get all indoor rows in date range
# process form
if request.method == 'POST' and "daterange" in request.POST:
dateform = DateRangeForm(request.POST)
deltaform = DeltaDaysForm(request.POST)
if dateform.is_valid():
startdate = dateform.cleaned_data['startdate']
enddate = dateform.cleaned_data['enddate']
if startdate > enddate:
s = enddate
enddate = startdate
startdate = s
elif request.method == 'POST' and "datedelta" in request.POST:
deltaform = DeltaDaysForm(request.POST)
if deltaform.is_valid():
deltadays = deltaform.cleaned_data['deltadays']
if deltadays:
enddate = timezone.now()
startdate = enddate-datetime.timedelta(days=deltadays)
if startdate > enddate:
s = enddate
enddate = startdate
startdate = s
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
else:
dateform = DateRangeForm()
deltaform = DeltaDaysForm()
else:
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
deltaform = DeltaDaysForm()
# get all 2k (if any) - this rower, in date range
try:
r = getrower(theuser)
except Rower.DoesNotExist:
allergworkouts = []
r=0
try:
uu = User.objects.get(id=theuser)
except User.DoesNotExist:
uu = ''
# test to fix bug
startdate = datetime.datetime.combine(startdate,datetime.time())
enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
enddate = enddate+datetime.timedelta(days=1)
rankingdistances = [100,500,1000,2000,5000,6000,10000,21097,42195,100000]
rankingdurations = []
rankingdurations.append(datetime.time(minute=1))
rankingdurations.append(datetime.time(minute=4))
rankingdurations.append(datetime.time(minute=30))
rankingdurations.append(datetime.time(hour=1,minute=15))
rankingdurations.append(datetime.time(hour=1))
thedistances = []
theworkouts = []
thesecs = []
rankingdistances.sort()
rankingdurations.sort()
for rankingdistance in rankingdistances:
workouts = Workout.objects.filter(user=r,distance=rankingdistance,
workouttype__in=['rower','dynamic','slides'],
startdatetime__gte=startdate,
startdatetime__lte=enddate).order_by('duration')
if workouts:
thedistances.append(rankingdistance)
theworkouts.append(workouts[0])
timesecs = 3600*workouts[0].duration.hour
timesecs += 60*workouts[0].duration.minute
timesecs += workouts[0].duration.second
timesecs += 1.e-6*workouts[0].duration.microsecond
thesecs.append(timesecs)
for rankingduration in rankingdurations:
workouts = Workout.objects.filter(user=r,duration=rankingduration,
workouttype='rower',
startdatetime__gte=startdate,
startdatetime__lte=enddate).order_by('-distance')
if workouts:
thedistances.append(workouts[0].distance)
theworkouts.append(workouts[0])
timesecs = 3600*workouts[0].duration.hour
timesecs += 60*workouts[0].duration.minute
timesecs += workouts[0].duration.second
timesecs += 1.e-5*workouts[0].duration.microsecond
thesecs.append(timesecs)
thedistances = np.array(thedistances)
thesecs = np.array(thesecs)
thevelos = thedistances/thesecs
theavpower = 2.8*(thevelos**3)
# create interactive plot
if len(thedistances) !=0 :
res = interactive_cpchart(
r,thedistances,thesecs,theavpower,
theworkouts,promember=promember,
wcdurations=wcdurations,wcpower=wcpower
)
script = res[0]
div = res[1]
paulslope = res[2]
paulintercept = res[3]
p1 = res[4]
message = res[5]
else:
script = ''
div = '<p>No ranking pieces found.</p>'
paulslope = 1
paulintercept = 1
p1 = [1,1,1,1]
message = ""
if request.method == 'POST' and "piece" in request.POST:
form = PredictedPieceForm(request.POST)
if form.is_valid():
value = form.cleaned_data['value']
hourvalue,value = divmod(value,60)
if hourvalue >= 24:
hourvalue = 23
pieceunit = form.cleaned_data['pieceunit']
if pieceunit == 'd':
rankingdistances.append(value)
else:
rankingdurations.append(datetime.time(minute=int(value),hour=int(hourvalue)))
else:
form = PredictedPieceForm()
rankingdistances.sort()
rankingdurations.sort()
predictions = []
cpredictions = []
for rankingdistance in rankingdistances:
# Paul's model
p = paulslope*np.log10(rankingdistance)+paulintercept
velo = 500./p
t = rankingdistance/velo
pwr = 2.8*(velo**3)
a = {'distance':rankingdistance,
'duration':timedeltaconv(t),
'pace':timedeltaconv(p),
'power':int(pwr)}
predictions.append(a)
# CP model -
pwr2 = p1[0]/(1+t/p1[2])
pwr2 += p1[1]/(1+t/p1[3])
if pwr2 <= 0:
pwr2 = 50.
velo2 = (pwr2/2.8)**(1./3.)
if np.isnan(velo2) or velo2 <= 0:
velo2 = 1.0
t2 = rankingdistance/velo2
pwr3 = p1[0]/(1+t2/p1[2])
pwr3 += p1[1]/(1+t2/p1[3])
if pwr3 <= 0:
pwr3 = 50.
velo3 = (pwr3/2.8)**(1./3.)
if np.isnan(velo3) or velo3 <= 0:
velo3 = 1.0
t3 = rankingdistance/velo3
p3 = 500./velo3
a = {'distance':rankingdistance,
'duration':timedeltaconv(t3),
'pace':timedeltaconv(p3),
'power':int(pwr3)}
cpredictions.append(a)
for rankingduration in rankingdurations:
t = 3600.*rankingduration.hour
t += 60.*rankingduration.minute
t += rankingduration.second
t += rankingduration.microsecond/1.e6
# Paul's model
ratio = paulintercept/paulslope
u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/paulslope
d = 500*t*np.log(10.)
d = d/(paulslope*lambertw(u))
d = d.real
velo = d/t
p = 500./velo
pwr = 2.8*(velo**3)
a = {'distance':int(d),
'duration':timedeltaconv(t),
'pace':timedeltaconv(p),
'power':int(pwr)}
predictions.append(a)
# CP model
pwr = p1[0]/(1+t/p1[2])
pwr += p1[1]/(1+t/p1[3])
if pwr <= 0:
pwr = 50.
velo = (pwr/2.8)**(1./3.)
if np.isnan(velo) or velo <=0:
velo = 1.0
d = t*velo
p = 500./velo
a = {'distance':int(d),
'duration':timedeltaconv(t),
'pace':timedeltaconv(p),
'power':int(pwr)}
cpredictions.append(a)
messages.error(request,message)
return render(request, 'rankings.html',
{'rankingworkouts':theworkouts,
'interactiveplot':script,
'the_div':div,
'predictions':predictions,
'cpredictions':cpredictions,
'nrdata':len(thedistances),
'form':form,
'dateform':dateform,
'deltaform':deltaform,
'id': theuser,
'theuser':uu,
'startdate':startdate,
'enddate':enddate,
'teams':get_my_teams(request.user),
})
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_update_cp_view(request,id=0):
try: