Private
Public Access
1
0

using async job to calculate predicted age records and store in db

This commit is contained in:
Sander Roosendaal
2018-01-06 13:33:59 +01:00
parent 89b0a4f61f
commit bdf4546a29
7 changed files with 4062 additions and 3879 deletions

View File

@@ -582,7 +582,53 @@ def deletecpdata_sql(rower_id,table='cpdata',debug=False):
conn.close() conn.close()
engine.dispose() engine.dispose()
def delete_agegroup_db(age,sex,weightcategory,debug=False):
if debug:
engine = create_engine(database_url_debug, echo=False)
else:
engine = create_engine(database_url, echo=False)
query = sa.text('DELETE from {table} WHERE age={age} and weightcategory = {weightcategory} and sex={sex};'.format(
sex=sex,
age=age,
weightcategory=weightcategory,
table='calcagegrouprecords'
))
with engine.connect() as conn, conn.begin():
try:
result = conn.execute(query)
except:
print "Database locked"
conn.close()
engine.dispose()
def update_agegroup_db(age,sex,weightcategory,wcdurations,wcpower,
debug=False):
delete_agegroup_db(age,sex,weightcategory,debug=debug)
df = pd.DataFrame(
{
'duration':wcdurations,
'power':wcpower,
}
)
df['sex'] = sex
df['age'] = age
df['weightcategory'] = weightcategory
if debug:
engine = create_engine(database_url_debug, echo=False)
else:
engine = create_engine(database_url, echo=False)
table = 'calcagegrouprecords'
with engine.connect() as conn, conn.begin():
df.to_sql(table, engine, if_exists='append', index=False)
conn.close()
engine.dispose()
def updatecpdata_sql(rower_id,delta,cp,table='cpdata',distance=pd.Series([]),debug=False): def updatecpdata_sql(rower_id,delta,cp,table='cpdata',distance=pd.Series([]),debug=False):
deletecpdata_sql(rower_id,table=table,debug=debug) deletecpdata_sql(rower_id,table=table,debug=debug)

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@ import numpy as np
from models import C2WorldClassAgePerformance from models import C2WorldClassAgePerformance
import pandas as pd import pandas as pd
from scipy import optimize from scipy import optimize
from django.utils import timezone
rowingmetrics = ( rowingmetrics = (
('time',{ ('time',{
@@ -321,28 +322,36 @@ def calc_trimp(df,sex,hrmax,hrmin):
return trimp return trimp
def getagegrouprecord(age,sex='male',weightcategory='hwt', def getagegrouprecord(age,sex='male',weightcategory='hwt',
distance=2000,duration=None): distance=2000,duration=None,indf=pd.DataFrame()):
if not duration:
df = pd.DataFrame( if not indf.empty:
list( if not duration:
C2WorldClassAgePerformance.objects.filter( df = indf[indf['distance'] == distance]
distance=distance, else:
sex=sex, duration = 60*int(duration)
weightcategory=weightcategory df = indf[indf['duration'] == duration]
).values()
)
)
else: else:
duration=60*int(duration) if not duration:
df = pd.DataFrame( df = pd.DataFrame(
list( list(
C2WorldClassAgePerformance.objects.filter( C2WorldClassAgePerformance.objects.filter(
duration=duration, distance=distance,
sex=sex, sex=sex,
weightcategory=weightcategory weightcategory=weightcategory
).values() ).values()
)
)
else:
duration=60*int(duration)
df = pd.DataFrame(
list(
C2WorldClassAgePerformance.objects.filter(
duration=duration,
sex=sex,
weightcategory=weightcategory
).values()
)
) )
)
if not df.empty: if not df.empty:
ages = df['age'] ages = df['age']

View File

@@ -214,7 +214,34 @@ def update_records(url=c2url):
except: except:
print record print record
class CalcAgePerformance(models.Model):
weightcategories = (
('hwt','heavy-weight'),
('lwt','light-weight'),
)
sexcategories = (
('male','male'),
('female','female'),
)
weightcategory = models.CharField(default="hwt",
max_length=30,
choices=weightcategories)
sex = models.CharField(default="female",
max_length=30,
choices=sexcategories)
age = models.IntegerField(default=19,verbose_name="Age")
duration = models.FloatField(default=1,blank=True)
power = models.IntegerField(default=200)
class Meta:
db_table = 'calcagegrouprecords'
class C2WorldClassAgePerformance(models.Model): class C2WorldClassAgePerformance(models.Model):
weightcategories = ( weightcategories = (
('hwt','heavy-weight'), ('hwt','heavy-weight'),

View File

@@ -6,6 +6,8 @@ import gzip
import shutil import shutil
import numpy as np import numpy as np
from scipy import optimize
import rowingdata import rowingdata
from rowingdata import rowingdata as rdata from rowingdata import rowingdata as rdata
@@ -28,7 +30,8 @@ from utils import deserialize_list
from rowers.dataprepnodjango import ( from rowers.dataprepnodjango import (
update_strokedata, new_workout_from_file, update_strokedata, new_workout_from_file,
getsmallrowdata_db, updatecpdata_sql getsmallrowdata_db, updatecpdata_sql,
update_agegroup_db,
) )
from django.core.mail import send_mail, EmailMessage from django.core.mail import send_mail, EmailMessage
@@ -46,6 +49,96 @@ import longtask
def add(x, y): def add(x, y):
return x + y return x + y
def getagegrouprecord(age,sex='male',weightcategory='hwt',
distance=2000,duration=None,indf=pd.DataFrame()):
if not duration:
df = indf[indf['distance'] == distance]
else:
duration = 60*int(duration)
df = indf[indf['duration'] == duration]
if not df.empty:
ages = df['age']
powers = df['power']
#poly_coefficients = np.polyfit(ages,powers,6)
fitfunc = lambda pars, x: np.abs(pars[0])*(1-x/max(120,pars[1]))-np.abs(pars[2])*np.exp(-x/np.abs(pars[3]))+np.abs(pars[4])*(np.sin(np.pi*x/max(50,pars[5])))
errfunc = lambda pars, x,y: fitfunc(pars,x)-y
p0 = [700,120,700,10,100,100]
p1, success = optimize.leastsq(errfunc,p0[:],
args = (ages,powers))
if success:
power = fitfunc(p1, float(age))
#power = np.polyval(poly_coefficients,age)
power = 0.5*(np.abs(power)+power)
else:
power = 0
else:
power = 0
return power
@app.task(bind=True)
def handle_getagegrouprecords(self,
df,
distances,durations,
age,sex,weightcategory,
**kwargs):
wcdurations = []
wcpower = []
if 'debug' in kwargs:
debug = kwargs['debug']
else:
debug = False
df = pd.read_json(df)
for distance in distances:
worldclasspower = getagegrouprecord(
age,
sex=sex,
distance=distance,
weightcategory=weightcategory,indf=df,
)
velo = (worldclasspower/2.8)**(1./3.)
try:
duration = distance/velo
wcdurations.append(duration)
wcpower.append(worldclasspower)
except ZeroDivisionError:
pass
for duration in durations:
worldclasspower = getagegrouprecord(
age,
sex=sex,
duration=duration,
weightcategory=weightcategory,indf=df
)
try:
velo = (worldclasspower/2.8)**(1./3.)
distance = int(60*duration*velo)
wcdurations.append(60.*duration)
wcpower.append(worldclasspower)
except ValueError:
pass
update_agegroup_db(age,sex,weightcategory,wcdurations,wcpower,
debug=debug)
return 1
@app.task(bind=True) @app.task(bind=True)
def long_test_task(self,aantal,debug=False,job=None,session_key=None): def long_test_task(self,aantal,debug=False,job=None,session_key=None):

View File

@@ -9,21 +9,6 @@
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'> src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
</script> </script>
<script>
$(function($) {
console.log('loading script');
console.log('{{ recalc }}');
if ('{{ recalc }}' == 'True') {
theurl = '/rowers/ajax_agegroup/{{ age }}/{{ weightcategory }}/{{ sex }}/{{ user.id }}'
console.log(theurl);
$.getJSON(window.location.protocol + '//'+window.location.host + theurl, function(json) {
location.reload();
});
} else {
console.log('No need to reload');
}
});
</script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View File

@@ -56,6 +56,7 @@ from rowers.models import (
RowerPowerZonesForm,AccountRowerForm,UserForm,StrokeData, RowerPowerZonesForm,AccountRowerForm,UserForm,StrokeData,
Team,TeamForm,TeamInviteForm,TeamInvite,TeamRequest, Team,TeamForm,TeamInviteForm,TeamInvite,TeamRequest,
WorkoutComment,WorkoutCommentForm,RowerExportForm, WorkoutComment,WorkoutCommentForm,RowerExportForm,
CalcAgePerformance
) )
from rowers.models import FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement from rowers.models import FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement
from rowers.metrics import rowingmetrics,defaultfavoritecharts from rowers.metrics import rowingmetrics,defaultfavoritecharts
@@ -108,7 +109,7 @@ from rowers.tasks import (
handle_sendemail_unrecognized,handle_sendemailnewcomment, handle_sendemail_unrecognized,handle_sendemailnewcomment,
handle_sendemailnewresponse, handle_updatedps, handle_sendemailnewresponse, handle_updatedps,
handle_updatecp,long_test_task,long_test_task2, handle_updatecp,long_test_task,long_test_task2,
handle_zip_file handle_zip_file,handle_getagegrouprecords
) )
from scipy.signal import savgol_filter from scipy.signal import savgol_filter
@@ -284,6 +285,7 @@ verbose_job_status = {
'updatecp': 'Critical Power Calculation for Ergometer Workouts', 'updatecp': 'Critical Power Calculation for Ergometer Workouts',
'updatecpwater': 'Critical Power Calculation for OTW Workouts', 'updatecpwater': 'Critical Power Calculation for OTW Workouts',
'otwsetpower': 'Rowing Physics OTW Power Calculation', 'otwsetpower': 'Rowing Physics OTW Power Calculation',
'agegrouprecords': 'Calculate age group records',
'make_plot': 'Create static chart', 'make_plot': 'Create static chart',
'long_test_task': 'Long Test Task', 'long_test_task': 'Long Test Task',
'long_test_task2': 'Long Test Task 2', 'long_test_task2': 'Long Test Task 2',
@@ -3526,51 +3528,28 @@ def ajax_agegrouprecords(request,
wcpower = [] wcpower = []
durations = [1,4,30,60] durations = [1,4,30,60]
distances = [100,500,1000,2000,5000,6000,10000,21097,42195] distances = [100,500,1000,2000,5000,6000,10000,21097,42195]
for distance in distances:
worldclasspower = metrics.getagegrouprecord( df = pd.DataFrame(
age, list(
sex=sex, C2WorldClassAgePerformance.objects.filter(
distance=distance,
weightcategory=weightcategory
)
velo = (worldclasspower/2.8)**(1./3.)
try:
duration = distance/velo
wcdurations.append(duration)
wcpower.append(worldclasspower)
except ZeroDivisionError:
pass
for duration in durations:
worldclasspower = metrics.getagegrouprecord(
age,
sex=sex, sex=sex,
duration=duration,
weightcategory=weightcategory weightcategory=weightcategory
) ).values()
try: )
velo = (worldclasspower/2.8)**(1./3.) )
distance = int(60*duration*velo)
wcdurations.append(60.*duration)
wcpower.append(worldclasspower)
except ValueError:
pass
options = {} jsondf = df.to_json()
options['wcpower'] = wcpower
options['wcdurations'] = wcdurations
thenowtime = timezone.now().isoformat()
options['lastupdated'] = thenowtime
options['userid'] = userid
request.session['options'] = options job = myqueue(queue,
handle_getagegrouprecords,
jsondf,distances,durations,age,sex,weightcategory,
)
return JSONResponse( return JSONResponse(
{ {
'wcdurations': wcdurations, 'job':job.id
'wcpower': wcpower,
'lastupdated': thenowtime,
} }
) )
@@ -3636,6 +3615,7 @@ def rankings_view2(request,theuser=0,
recalc = False recalc = False
if str(userid) != str(theuser) or deltatime_seconds > 3600: if str(userid) != str(theuser) or deltatime_seconds > 3600:
recalc = True recalc = True
options['lastupdated'] = arrow.utcnow().isoformat()
else: else:
recalc = False recalc = False
@@ -3647,6 +3627,23 @@ def rankings_view2(request,theuser=0,
worldclasspower = None worldclasspower = None
age = 0 age = 0
agerecords = CalcAgePerformance.objects.filter(
age = age,
sex = r.sex,
weightcategory = r.weightcategory)
print len(agerecords),'aap'
if len(agerecords) == 0:
recalc = True
wcpower = []
wcduration = []
else:
wcdurations = []
wcpower = []
for record in agerecords:
wcdurations.append(record.duration)
wcpower.append(record.power)
options['wcpower'] = wcpower options['wcpower'] = wcpower
options['wcdurations'] = wcdurations options['wcdurations'] = wcdurations
if theuser: if theuser:
@@ -3914,6 +3911,32 @@ def rankings_view2(request,theuser=0,
'power':int(pwr)} 'power':int(pwr)}
cpredictions.append(a) cpredictions.append(a)
if recalc:
wcdurations = []
wcpower = []
durations = [1,4,30,60]
distances = [100,500,1000,2000,5000,6000,10000,21097,42195]
df = pd.DataFrame(
list(
C2WorldClassAgePerformance.objects.filter(
sex=r.sex,
weightcategory=r.weightcategory
).values()
)
)
jsondf = df.to_json()
job = myqueue(queue,
handle_getagegrouprecords,
jsondf,distances,durations,age,r.sex,r.weightcategory)
try:
request.session['async_tasks'] += [(job.id,'agegrouprecords')]
except KeyError:
request.session['async_tasks'] = [(job.id,'agegrouprecords')]
messages.error(request,message) messages.error(request,message)
return render(request, 'rankings.html', return render(request, 'rankings.html',