diff --git a/rowers/.#views.py b/rowers/.#views.py new file mode 100644 index 00000000..f675534b --- /dev/null +++ b/rowers/.#views.py @@ -0,0 +1 @@ +E408191@CZ27LT9RCGN72.344848:1509049169 \ No newline at end of file diff --git a/rowers/dataprep.py b/rowers/dataprep.py index e51e6631..04fe66ff 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -473,21 +473,37 @@ def updatecpdata_sql(rower_id,delta,cp,table='cpdata',distance=[]): engine.dispose() -def runcpupdate(rower): +def runcpupdate(rower,type='water'): startdate = timezone.now()-datetime.timedelta(days=365) enddate = timezone.now()+datetime.timedelta(days=5) - theworkouts = Workout.objects.filter(user=rower,rankingpiece=True, - workouttype='water', - startdatetime__gte=startdate, - startdatetime__lte=enddate) + if type == 'water': + theworkouts = Workout.objects.filter( + user=rower,rankingpiece=True, + workouttype='water', + startdatetime__gte=startdate, + startdatetime__lte=enddate + ) + table = 'cpdata' + else: + theworkouts = Workout.objects.filter( + user=rower,rankingpiece=True, + workouttype__in=[ + 'rower', + 'dynamic', + 'slides' + ], + startdatetime__gte=startdate, + startdatetime__lte=enddate + ) + table = 'cpergdata' theids = [w.id for w in theworkouts] if settings.DEBUG: - res = handle_updatecp.delay(rower.id,theids,debug=True) + res = handle_updatecp.delay(rower.id,theids,debug=True,table=table) else: - res = queue.enqueue(handle_updatecp,rower.id,theids) + res = queue.enqueue(handle_updatecp,rower.id,theids,table=table) def fetchcperg(rower,theworkouts): theids = [int(w.id) for w in theworkouts] @@ -502,24 +518,29 @@ def fetchcperg(rower,theworkouts): return cpdf -def fetchcp(rower,theworkouts): +def fetchcp(rower,theworkouts,table='cpdata'): # get all power data from database (plus workoutid) theids = [int(w.id) for w in theworkouts] columns = ['power','workoutid','time'] df = getsmallrowdata_db(columns,ids=theids) + if df.empty: + avgpower2 = {} + for id in theids: + avgpower2[id] = 0 + return pd.Series([]),pd.Series([]),avgpower2 dfgrouped = df.groupby(['workoutid']) avgpower2 = dict(dfgrouped.mean()['power'].astype(int)) - cpdf = getcpdata_sql(rower.id) + cpdf = getcpdata_sql(rower.id,table=table) if not cpdf.empty: return cpdf['delta'],cpdf['cp'],avgpower2 else: if settings.DEBUG: - res = handle_updatecp.delay(rower.id,theids,debug=True) + res = handle_updatecp.delay(rower.id,theids,debug=True,table=table) else: - res = queue.enqueue(handle_updatecp,rower.id,theids) + res = queue.enqueue(handle_updatecp,rower.id,theids,table=table) return [],[],avgpower2 diff --git a/rowers/models.py b/rowers/models.py index 1b233404..bfc190cc 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -653,6 +653,20 @@ class cpdata(models.Model): index_together = ['user'] app_label = 'rowers' + +# Storing data for the OTW CP chart +class cpergdata(models.Model): + delta = models.IntegerField(default=0) + cp = models.FloatField(default=0) + user = models.IntegerField(default=0) + + class Meta: + db_table = 'cpergdata' + index_together = ['user'] + app_label = 'rowers' + + + # Storing data for the OTW CP chart class ergcpdata(models.Model): delta = models.IntegerField(default=0) diff --git a/rowers/tasks.py b/rowers/tasks.py index 372dc1cb..bbb3c88f 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -420,7 +420,7 @@ def handle_updateergcp(rower_id,workoutfilenames,debug=False): @app.task -def handle_updatecp(rower_id,workoutids,debug=False): +def handle_updatecp(rower_id,workoutids,debug=False,table='cpdata'): columns = ['power','workoutid','time'] df = getsmallrowdata_db(columns,ids=workoutids,debug=debug) dfgrouped = df.groupby(['workoutid']) @@ -435,7 +435,7 @@ def handle_updatecp(rower_id,workoutids,debug=False): delta,cpvalue,avgpower = datautils.getcp(dfgrouped,logarr) - updatecpdata_sql(rower_id,delta,cpvalue,debug=debug) + updatecpdata_sql(rower_id,delta,cpvalue,debug=debug,table=table) return 1 diff --git a/rowers/templates/analysis.html b/rowers/templates/analysis.html index 6fa3f882..4c8d41da 100644 --- a/rowers/templates/analysis.html +++ b/rowers/templates/analysis.html @@ -92,7 +92,7 @@ {% endif %}
- Analyse power vs piece duration to make predictions. + Analyse power vs piece duration to make predictions. For On-The-Water rowing.
+ {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + OTE Ranking Pieces + {% else %} + OTE Ranking Pieces + {% endif %} +
++ Analyse power vs piece duration to make predictions, for erg pieces. +
+No ranking pieces found.
' + paulslope = 1 + paulintercept = 1 + p1 = [1,1,1,1] + message = "" + + + if request.method == 'POST' and "piece" in request.POST: + form = PredictedPieceForm(request.POST) + clean = form.is_valid() + value = form.cleaned_data['value'] + hourvalue,value = divmod(value,60) + hourvalue = int(hourvalue) + minutevalue = int(value) + value = int(60*(value-minutevalue)) + if hourvalue >= 24: + hourvalue = 23 + rankingdurations.append(datetime.time(minute=minutevalue, + hour=hourvalue, + second=value)) + else: + form = PredictedPieceForm() + + + cpredictions = [] + + for rankingduration in rankingdurations: + t = 3600.*rankingduration.hour + t += 60.*rankingduration.minute + t += rankingduration.second + t += rankingduration.microsecond/1.e6 + + + # CP model + pwr = p1[0]/(1+t/p1[2]) + pwr += p1[1]/(1+t/p1[3]) + + + if pwr <= 0: + pwr = 50. + + + if not np.isnan(pwr): + try: + pwr2 = pwr*ratio + except: + pwr2 = pwr + + a = { + 'duration':timedeltaconv(t), + 'power':int(pwr), + 'upper':int(pwr2)} + cpredictions.append(a) + + + del form.fields["pieceunit"] + + messages.error(request,message) + return render(request, 'otwrankings.html', + {'rankingworkouts':theworkouts, + 'interactiveplot':script, + 'the_div':div, + 'cpredictions':cpredictions, + 'avgpower':avgpower, + 'form':form, + 'dateform':dateform, + 'deltaform':deltaform, + 'id': theuser, + 'theuser':uu, + 'startdate':startdate, + 'enddate':enddate, + 'teams':get_my_teams(request.user), + }) +# Show ranking distances including predicted paces +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) +def oterankings_view(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 = Rower.objects.get(user=request.user) + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 + + # get all OTW 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 = Rower.objects.get(user=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) + + + 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)) + rankingdurations.append(datetime.time(hour=1,minute=15)) + + thedistances = [] + theworkouts = [] + thesecs = [] + + theworkouts = Workout.objects.filter(user=r,rankingpiece=True, + workouttype__in=[ + 'rower', + 'dynamic', + 'slides' + ], + startdatetime__gte=startdate, + startdatetime__lte=enddate) + + + delta,cpvalue,avgpower = dataprep.fetchcp( + r,theworkouts,table='cpergdata' + ) + + powerdf = pd.DataFrame({ + 'Delta':delta, + 'CP':cpvalue, + }) + + if powerdf.empty: + messages.info(request,'Your calculations are running in the background. Please reload this page.') + + powerdf = powerdf[powerdf['CP']>0] + powerdf.dropna(axis=0,inplace=True) + powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True) + powerdf.drop_duplicates(subset='Delta',keep='first',inplace=True) + + # create interactive plot if len(powerdf) !=0 : res = interactive_otwcpchart(powerdf,promember=promember) @@ -6630,7 +6852,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): successmessage = "Changes saved" if rankingpiece: - dataprep.runcpupdate(row.user) + dataprep.runcpupdate(row.user,type=row.workouttype) messages.info(request,successmessage) url = reverse(workout_edit_view,