using async job to calculate predicted age records and store in db
This commit is contained in:
@@ -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
@@ -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']
|
||||||
|
|||||||
@@ -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'),
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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 %}
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
Reference in New Issue
Block a user