Merge branch 'release/v5.10'
This commit is contained in:
@@ -555,6 +555,71 @@ def fetchcp(rower,theworkouts,table='cpdata'):
|
|||||||
return [],[],avgpower2
|
return [],[],avgpower2
|
||||||
|
|
||||||
|
|
||||||
|
# create a new workout from manually entered data
|
||||||
|
def create_row_df(r,distance,duration,startdatetime,
|
||||||
|
title = 'Manually added workout',notes='',
|
||||||
|
workouttype='rower'):
|
||||||
|
|
||||||
|
|
||||||
|
nr_strokes = int(distance/10.)
|
||||||
|
|
||||||
|
unixstarttime = arrow.get(startdatetime).timestamp
|
||||||
|
|
||||||
|
totalseconds = duration.hour*3600.
|
||||||
|
totalseconds += duration.minute*60.
|
||||||
|
totalseconds += duration.second
|
||||||
|
totalseconds += duration.microsecond/1.e6
|
||||||
|
|
||||||
|
|
||||||
|
spm = 60.*nr_strokes/totalseconds
|
||||||
|
|
||||||
|
step = totalseconds/float(nr_strokes)
|
||||||
|
|
||||||
|
elapsed = np.arange(0,totalseconds+step,step)
|
||||||
|
|
||||||
|
dstep = distance/float(nr_strokes)
|
||||||
|
|
||||||
|
d = np.arange(0,distance+dstep,dstep)
|
||||||
|
|
||||||
|
unixtime = unixstarttime + elapsed
|
||||||
|
|
||||||
|
pace = 500.*totalseconds/distance
|
||||||
|
|
||||||
|
if workouttype in ['rower','slides','dynamic']:
|
||||||
|
velo = distance/totalseconds
|
||||||
|
power = 2.8*velo**3
|
||||||
|
else:
|
||||||
|
power = 0
|
||||||
|
|
||||||
|
df = pd.DataFrame({
|
||||||
|
'TimeStamp (sec)': unixtime,
|
||||||
|
' Horizontal (meters)': d,
|
||||||
|
' Cadence (stokes/min)': spm,
|
||||||
|
' Stroke500mPace (sec/500m)':pace,
|
||||||
|
' ElapsedTime (sec)':elapsed,
|
||||||
|
' Power (watts)':power,
|
||||||
|
})
|
||||||
|
|
||||||
|
timestr = strftime("%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
|
csvfilename = 'media/df_' + timestr + '.csv'
|
||||||
|
df[' ElapsedTime (sec)'] = df['TimeStamp (sec)']
|
||||||
|
|
||||||
|
row = rrdata(df=df)
|
||||||
|
|
||||||
|
row.write_csv(csvfilename, gzip = True)
|
||||||
|
|
||||||
|
id, message = save_workout_database(csvfilename, r,
|
||||||
|
title=title,
|
||||||
|
notes=notes,
|
||||||
|
dosmooth=False,
|
||||||
|
workouttype=workouttype,
|
||||||
|
consistencychecks=False,
|
||||||
|
totaltime=totalseconds)
|
||||||
|
|
||||||
|
return (id, message)
|
||||||
|
|
||||||
|
|
||||||
# Processes painsled CSV file to database
|
# Processes painsled CSV file to database
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
38
rowers/templates/manualadd.html
Normal file
38
rowers/templates/manualadd.html
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
{% load tz %}
|
||||||
|
|
||||||
|
|
||||||
|
{% get_current_timezone as TIME_ZONE %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="grid_12 alpha">
|
||||||
|
<h1>Add Workout Manually</h1>
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
{% if form.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form id="importantform"
|
||||||
|
enctype="multipart/form-data" action="" method="post">
|
||||||
|
<table width=100%>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div id="formbutton" class="grid_1 suffix_1 omega">
|
||||||
|
<input class="button green" type="submit" value="Save">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="images" class="grid_6 omega">
|
||||||
|
<p> </p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
232
rowers/templates/oterankings.html
Normal file
232
rowers/templates/oterankings.html
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{% include "monitorjobs.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block title %}Workouts{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||||
|
<script async="true" type="text/javascript">
|
||||||
|
Bokeh.set_log_level("info");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{ interactiveplot |safe }}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Set things up to resize the plot on a window resize. You can play with
|
||||||
|
// the arguments of resize_width_height() to change the plot's behavior.
|
||||||
|
var plot_resize_setup = function () {
|
||||||
|
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
|
||||||
|
var plot = Bokeh.index[plotid];
|
||||||
|
var plotresizer = function() {
|
||||||
|
// arguments: use width, use height, maintain aspect ratio
|
||||||
|
plot.resize_width_height(true, true, false);
|
||||||
|
};
|
||||||
|
window.addEventListener('resize', plotresizer);
|
||||||
|
plotresizer();
|
||||||
|
};
|
||||||
|
window.addEventListener('load', plot_resize_setup);
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
|
||||||
|
html, body {height: 100%; margin:5px;}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="title" class="grid_12 alpha">
|
||||||
|
<div class="grid_10 alpha">
|
||||||
|
{% if theuser %}
|
||||||
|
<h3>{{ theuser.first_name }}'s Ranking Pieces</h3>
|
||||||
|
{% else %}
|
||||||
|
<h3>{{ user.first_name }}'s Ranking Pieces</h3>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="grid_2 omega">
|
||||||
|
{% if user.is_authenticated and user|is_manager %}
|
||||||
|
<div class="grid_2 alpha dropdown">
|
||||||
|
<button class="grid_2 alpha button green small dropbtn">
|
||||||
|
Change Rower
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-content">
|
||||||
|
{% for member in user|team_members %}
|
||||||
|
{% if workouttype == 'water' %}
|
||||||
|
<a class="button green small" href="/rowers/{{ member.id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">{{ member.first_name }} {{ member.last_name }}</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="button green small" href="/rowers/{{ member.id }}/ote-ranking/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">{{ member.first_name }} {{ member.last_name }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="summary" class="grid_6 alpha">
|
||||||
|
<p>Summary for {{ theuser.first_name }} {{ theuser.last_name }}
|
||||||
|
between {{ startdate|date }} and {{ enddate|date }}</p>
|
||||||
|
|
||||||
|
<p>Direct link for other users:
|
||||||
|
{% if workouttype == 'water' %}
|
||||||
|
<a href="/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">https://rowsandall.com/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="/rowers/{{ id }}/ote-ranking/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">https://rowsandall.com/rowers/{{ id }}/ote-ranking/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>The table gives the efforts you marked as Ranking Piece.
|
||||||
|
The graph shows the best segments from those pieces, plotted as
|
||||||
|
average power (over the segment) vs the duration of the segment/
|
||||||
|
In other words: How long you can hold that power.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>When you change the date range, the algorithm calculates new
|
||||||
|
parameters in a background process. You may have to reload the
|
||||||
|
page to get an updated prediction.</p>
|
||||||
|
<p>At the bottom of the page, you will find predictions derived from the model.</p>
|
||||||
|
</div>
|
||||||
|
<div id="form" class="grid_6 omega">
|
||||||
|
<p>Use this form to select a different date range:</p>
|
||||||
|
<p>
|
||||||
|
Select start and end date for a date range:
|
||||||
|
<div class="grid_4 alpha">
|
||||||
|
|
||||||
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
|
|
||||||
|
<table>
|
||||||
|
{{ dateform.as_table }}
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
</div>
|
||||||
|
<div class="grid_2 omega">
|
||||||
|
<input name='daterange' class="button green" type="submit" value="Submit"> </form>
|
||||||
|
</div>
|
||||||
|
<div class="grid_4 alpha">
|
||||||
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
|
Or use the last {{ deltaform }} days.
|
||||||
|
</div>
|
||||||
|
<div class="grid_2 omega">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input name='datedelta' class="button green" type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="theplot" class="grid_12 alpha">
|
||||||
|
|
||||||
|
<h2>Critical Power Plot</h2>
|
||||||
|
|
||||||
|
{{ the_div|safe }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid_12 alpha">
|
||||||
|
|
||||||
|
<h2>Ranking Piece Results</h2>
|
||||||
|
|
||||||
|
{% if rankingworkouts %}
|
||||||
|
|
||||||
|
<table width="70%" class="listtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> Distance</th>
|
||||||
|
<th> Duration</th>
|
||||||
|
<th> Avg Power</th>
|
||||||
|
<th> Date</th>
|
||||||
|
<th> Avg HR </th>
|
||||||
|
<th> Max HR </th>
|
||||||
|
<th> Edit</th>
|
||||||
|
<tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for workout in rankingworkouts %}
|
||||||
|
<tr>
|
||||||
|
<td> {{ workout.distance }} m</td>
|
||||||
|
<td> {{ workout.duration |durationprint:"%H:%M:%S.%f" }} </td>
|
||||||
|
<td> {{ avgpower|lookup:workout.id }} W</td>
|
||||||
|
<td> {{ workout.date }} </td>
|
||||||
|
<td> {{ workout.averagehr }} </td>
|
||||||
|
<td> {{ workout.maxhr }} </td>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/workout/{{ workout.id }}/edit">{{ workout.name }}</a> </td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<p> No ranking workouts found </p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="predictions" class="grid_12 alpha">
|
||||||
|
<h2>Pace predictions for Ranking Pieces</h2>
|
||||||
|
|
||||||
|
<p>Add non-ranking piece using the form. The piece will be added in the prediction tables below. </p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="cpmodel" class="grid_6 alpha">
|
||||||
|
<table width="90%" class="listtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> Duration</th>
|
||||||
|
<th> Distance</th>
|
||||||
|
<th> Pace (upper)</th>
|
||||||
|
<th> Power </th>
|
||||||
|
<th> Power (upper)</th>
|
||||||
|
<tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for pred in cpredictions %}
|
||||||
|
<tr>
|
||||||
|
{% for key, value in pred.items %}
|
||||||
|
{% if key == "power" or key == "upper" %}
|
||||||
|
<td> {{ value }} W </td>
|
||||||
|
{% endif %}
|
||||||
|
{% if key == "duration" %}
|
||||||
|
<td> {{ value |deltatimeprint }} </td>
|
||||||
|
{% endif %}
|
||||||
|
{% if key == "distance" %}
|
||||||
|
<td> {{ value }} m </td>
|
||||||
|
{% endif %}
|
||||||
|
{% if key == 'pace' %}
|
||||||
|
<td> {{ value|paceprint }}</td>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid_3">
|
||||||
|
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||||
|
{{ form.value }} {{ form.pieceunit }}
|
||||||
|
|
||||||
|
{% csrf_token %}
|
||||||
|
</div>
|
||||||
|
<div class="grid_1">
|
||||||
|
minutes
|
||||||
|
</div>
|
||||||
|
<div class="grid_2 omega">
|
||||||
|
<input name="piece" class="button green"
|
||||||
|
action=""
|
||||||
|
type="submit" value="Add">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
|
|
||||||
<p>The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.</p>
|
<p>The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.</p>
|
||||||
|
|
||||||
<p>This page will evolve and try to give you guidance on where to improve.</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="form" class="grid_6 omega">
|
<div id="form" class="grid_6 omega">
|
||||||
<p>Use this form to select a different date range:</p>
|
<p>Use this form to select a different date range:</p>
|
||||||
@@ -138,6 +138,19 @@
|
|||||||
<p> No ranking workouts found </p>
|
<p> No ranking workouts found </p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<p>Missing your best pieces? Upload stroke data of any Concept2
|
||||||
|
ranking piece and they will be automatically added to this page.</p>
|
||||||
|
<p> Don't have stroke data for official Concept2 ranking pieces?
|
||||||
|
The <a href="/rowers/promembership">PRO membership</a> ranking piece functionality
|
||||||
|
allows you to include your best non ranking pieces and even use
|
||||||
|
parts of workouts for improved calculation accuracy.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Want to add race results but you don't have stroke data?
|
||||||
|
<a href="/rowers/addmanual">Click here.</a></p>
|
||||||
|
|
||||||
|
<p>Scroll down for the chart and pace predictions for ranking pieces.</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ urlpatterns = [
|
|||||||
url(r'^list-workouts/team/(?P<teamid>\d+)/$',views.workouts_view),
|
url(r'^list-workouts/team/(?P<teamid>\d+)/$',views.workouts_view),
|
||||||
url(r'^list-workouts/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.workouts_view),
|
url(r'^list-workouts/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.workouts_view),
|
||||||
url(r'^list-workouts/$',views.workouts_view),
|
url(r'^list-workouts/$',views.workouts_view),
|
||||||
|
url(r'^addmanual/$',views.addmanual_view),
|
||||||
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.team_comparison_select),
|
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.team_comparison_select),
|
||||||
url(r'^team-compare-select/team/(?P<teamid>\d+)/$',views.team_comparison_select),
|
url(r'^team-compare-select/team/(?P<teamid>\d+)/$',views.team_comparison_select),
|
||||||
url(r'^team-compare-select/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.team_comparison_select),
|
url(r'^team-compare-select/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.team_comparison_select),
|
||||||
|
|||||||
167
rowers/views.py
167
rowers/views.py
@@ -3096,6 +3096,82 @@ def histo(request,theuser=0,
|
|||||||
'teams':get_my_teams(request.user),
|
'teams':get_my_teams(request.user),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# add a workout manually
|
||||||
|
@login_required()
|
||||||
|
def addmanual_view(request):
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
# Form was submitted
|
||||||
|
form = WorkoutForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
# Get values from form
|
||||||
|
name = form.cleaned_data['name']
|
||||||
|
date = form.cleaned_data['date']
|
||||||
|
starttime = form.cleaned_data['starttime']
|
||||||
|
workouttype = form.cleaned_data['workouttype']
|
||||||
|
duration = form.cleaned_data['duration']
|
||||||
|
distance = form.cleaned_data['distance']
|
||||||
|
notes = form.cleaned_data['notes']
|
||||||
|
thetimezone = form.cleaned_data['timezone']
|
||||||
|
try:
|
||||||
|
boattype = request.POST['boattype']
|
||||||
|
except KeyError:
|
||||||
|
boattype = '1x'
|
||||||
|
try:
|
||||||
|
privacy = request.POST['privacy']
|
||||||
|
except KeyError:
|
||||||
|
privacy = 'visible'
|
||||||
|
try:
|
||||||
|
rankingpiece = form.cleaned_data['rankingpiece']
|
||||||
|
except KeyError:
|
||||||
|
rankingpiece =- Workout.objects.get(id=id).rankingpiece
|
||||||
|
|
||||||
|
startdatetime = (str(date) + ' ' + str(starttime))
|
||||||
|
startdatetime = datetime.datetime.strptime(startdatetime,
|
||||||
|
"%Y-%m-%d %H:%M:%S")
|
||||||
|
startdatetime = timezone.make_aware(startdatetime)
|
||||||
|
startdatetime = startdatetime.astimezone(
|
||||||
|
pytz.timezone(thetimezone)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
print name
|
||||||
|
id,message = dataprep.create_row_df(r,
|
||||||
|
distance,
|
||||||
|
duration,startdatetime,
|
||||||
|
title = name,
|
||||||
|
notes=notes,
|
||||||
|
workouttype=workouttype)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if message:
|
||||||
|
messages.error(request,message)
|
||||||
|
|
||||||
|
if id:
|
||||||
|
w = Workout.objects.get(id=id)
|
||||||
|
w.rankingpiece = rankingpiece
|
||||||
|
w.notes = notes
|
||||||
|
w.save()
|
||||||
|
messages.info(request,'New workout created')
|
||||||
|
|
||||||
|
|
||||||
|
initial = {
|
||||||
|
'workouttype':'rower',
|
||||||
|
'date':datetime.date.today(),
|
||||||
|
'starttime':timezone.now(),
|
||||||
|
'timezone':r.defaulttimezone,
|
||||||
|
'duration':datetime.timedelta(minutes=2),
|
||||||
|
'distance':500,
|
||||||
|
|
||||||
|
}
|
||||||
|
form = WorkoutForm(initial=initial)
|
||||||
|
|
||||||
|
return render(request,'manualadd.html',
|
||||||
|
{'form':form,
|
||||||
|
})
|
||||||
|
|
||||||
# Show ranking distances including predicted paces
|
# Show ranking distances including predicted paces
|
||||||
@login_required()
|
@login_required()
|
||||||
def rankings_view(request,theuser=0,
|
def rankings_view(request,theuser=0,
|
||||||
@@ -3779,6 +3855,8 @@ def oterankings_view(request,theuser=0,
|
|||||||
rankingdurations.append(datetime.time(hour=1))
|
rankingdurations.append(datetime.time(hour=1))
|
||||||
rankingdurations.append(datetime.time(hour=1,minute=15))
|
rankingdurations.append(datetime.time(hour=1,minute=15))
|
||||||
|
|
||||||
|
rankingdistances = [100,500,1000,2000,5000,6000,10000,21097,42195,100000]
|
||||||
|
|
||||||
thedistances = []
|
thedistances = []
|
||||||
theworkouts = []
|
theworkouts = []
|
||||||
thesecs = []
|
thesecs = []
|
||||||
@@ -3874,21 +3952,29 @@ def oterankings_view(request,theuser=0,
|
|||||||
form = PredictedPieceForm(request.POST)
|
form = PredictedPieceForm(request.POST)
|
||||||
clean = form.is_valid()
|
clean = form.is_valid()
|
||||||
value = form.cleaned_data['value']
|
value = form.cleaned_data['value']
|
||||||
hourvalue,value = divmod(value,60)
|
hourvalue,tvalue = divmod(value,60)
|
||||||
hourvalue = int(hourvalue)
|
hourvalue = int(hourvalue)
|
||||||
minutevalue = int(value)
|
minutevalue = int(tvalue)
|
||||||
value = int(60*(value-minutevalue))
|
tvalue = int(60*(tvalue-minutevalue))
|
||||||
if hourvalue >= 24:
|
if hourvalue >= 24:
|
||||||
hourvalue = 23
|
hourvalue = 23
|
||||||
rankingdurations.append(datetime.time(minute=minutevalue,
|
pieceunit = form.cleaned_data['pieceunit']
|
||||||
|
if pieceunit == 'd':
|
||||||
|
rankingdistances.append(value)
|
||||||
|
else:
|
||||||
|
rankingdurations.append(datetime.time(
|
||||||
|
minute=minutevalue,
|
||||||
hour=hourvalue,
|
hour=hourvalue,
|
||||||
second=value))
|
second=tvalue
|
||||||
|
))
|
||||||
else:
|
else:
|
||||||
form = PredictedPieceForm()
|
form = PredictedPieceForm()
|
||||||
|
|
||||||
|
|
||||||
cpredictions = []
|
cpredictions = []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for rankingduration in rankingdurations:
|
for rankingduration in rankingdurations:
|
||||||
t = 3600.*rankingduration.hour
|
t = 3600.*rankingduration.hour
|
||||||
t += 60.*rankingduration.minute
|
t += 60.*rankingduration.minute
|
||||||
@@ -3900,6 +3986,9 @@ def oterankings_view(request,theuser=0,
|
|||||||
pwr = p1[0]/(1+t/p1[2])
|
pwr = p1[0]/(1+t/p1[2])
|
||||||
pwr += p1[1]/(1+t/p1[3])
|
pwr += p1[1]/(1+t/p1[3])
|
||||||
|
|
||||||
|
velo = (pwr/2.8)**(1./3.)
|
||||||
|
p = 500./velo
|
||||||
|
d = t*velo
|
||||||
|
|
||||||
if pwr <= 0:
|
if pwr <= 0:
|
||||||
pwr = 50.
|
pwr = 50.
|
||||||
@@ -3912,16 +4001,78 @@ def oterankings_view(request,theuser=0,
|
|||||||
pwr2 = pwr
|
pwr2 = pwr
|
||||||
|
|
||||||
a = {
|
a = {
|
||||||
|
'distance':int(d),
|
||||||
'duration':timedeltaconv(t),
|
'duration':timedeltaconv(t),
|
||||||
'power':int(pwr),
|
'power':int(pwr),
|
||||||
'upper':int(pwr2)}
|
'upper':int(pwr2),
|
||||||
|
'pace':timedeltaconv(p)}
|
||||||
|
|
||||||
cpredictions.append(a)
|
cpredictions.append(a)
|
||||||
|
|
||||||
|
|
||||||
del form.fields["pieceunit"]
|
# initiation - get 10 min power, then use Paul's law
|
||||||
|
|
||||||
|
t_10 = 600.
|
||||||
|
power_10 = p1[0]/(1+t_10/p1[2])
|
||||||
|
power_10 += p1[1]/(1+t_10/p1[3])
|
||||||
|
|
||||||
|
velo_10 = (power_10/2.8)**(1./3.)
|
||||||
|
pace_10 = 500./velo_10
|
||||||
|
distance_10 = t_10*velo_10
|
||||||
|
|
||||||
|
paulslope = 5.
|
||||||
|
|
||||||
|
for rankingdistance in rankingdistances:
|
||||||
|
|
||||||
|
delta = paulslope * np.log(rankingdistance/distance_10)/np.log(2)
|
||||||
|
|
||||||
|
|
||||||
|
p = pace_10+delta
|
||||||
|
velo = 500./p
|
||||||
|
t = rankingdistance/velo
|
||||||
|
|
||||||
|
pwr2 = p1[0]/(1+t/p1[2])
|
||||||
|
pwr2 += p1[1]/(1+t/p1[3])
|
||||||
|
pwr2 *= ratio
|
||||||
|
|
||||||
|
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])
|
||||||
|
pwr3 *= ratio
|
||||||
|
|
||||||
|
|
||||||
|
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),
|
||||||
|
'power':'--',
|
||||||
|
'upper':int(pwr3),
|
||||||
|
'pace':timedeltaconv(p3)}
|
||||||
|
|
||||||
|
cpredictions.append(a)
|
||||||
|
|
||||||
|
# del form.fields["pieceunit"]
|
||||||
|
|
||||||
messages.error(request,message)
|
messages.error(request,message)
|
||||||
return render(request, 'otwrankings.html',
|
return render(request, 'oterankings.html',
|
||||||
{'rankingworkouts':theworkouts,
|
{'rankingworkouts':theworkouts,
|
||||||
'interactiveplot':script,
|
'interactiveplot':script,
|
||||||
'the_div':div,
|
'the_div':div,
|
||||||
|
|||||||
BIN
static/img/image.png
Normal file
BIN
static/img/image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
Reference in New Issue
Block a user