otw cp stuff not finished
This commit is contained in:
1
rowers/.#views.py
Normal file
1
rowers/.#views.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
E408191@CZ27LT9RCGN72.7808:1496304801
|
||||||
@@ -425,7 +425,8 @@ class Workout(models.Model):
|
|||||||
summary = models.TextField(blank=True)
|
summary = models.TextField(blank=True)
|
||||||
privacy = models.CharField(default='visible',max_length=30,
|
privacy = models.CharField(default='visible',max_length=30,
|
||||||
choices=privacychoices)
|
choices=privacychoices)
|
||||||
|
rankingpiece = models.BooleanField(default=False,verbose_name='Ranking Piece')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
|
|
||||||
date = self.date
|
date = self.date
|
||||||
@@ -552,7 +553,7 @@ class WorkoutForm(ModelForm):
|
|||||||
duration = forms.TimeInput(format='%H:%M:%S.%f')
|
duration = forms.TimeInput(format='%H:%M:%S.%f')
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Workout
|
model = Workout
|
||||||
fields = ['name','date','starttime','duration','distance','workouttype','notes','privacy','boattype']
|
fields = ['name','date','starttime','duration','distance','workouttype','notes','privacy','rankingpiece','boattype']
|
||||||
widgets = {
|
widgets = {
|
||||||
'date': DateInput(),
|
'date': DateInput(),
|
||||||
'notes': forms.Textarea,
|
'notes': forms.Textarea,
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ def get_strava_workout(user,stravaid):
|
|||||||
return [workoutsummary,df]
|
return [workoutsummary,df]
|
||||||
|
|
||||||
# Generate Workout data for Strava (a TCX file)
|
# Generate Workout data for Strava (a TCX file)
|
||||||
def createstravaworkoutdata(w):
|
def createstravaworkoutdata(w,dozip=True):
|
||||||
filename = w.csvfilename
|
filename = w.csvfilename
|
||||||
|
|
||||||
row = rowingdata(filename)
|
row = rowingdata(filename)
|
||||||
@@ -256,18 +256,22 @@ def createstravaworkoutdata(w):
|
|||||||
newnotes = 'from '+w.workoutsource+' via rowsandall.com'
|
newnotes = 'from '+w.workoutsource+' via rowsandall.com'
|
||||||
|
|
||||||
row.exporttotcx(tcxfilename,notes=newnotes)
|
row.exporttotcx(tcxfilename,notes=newnotes)
|
||||||
gzfilename = tcxfilename+'.gz'
|
if dozip:
|
||||||
with file(tcxfilename,'rb') as inF:
|
gzfilename = tcxfilename+'.gz'
|
||||||
s = inF.read()
|
with file(tcxfilename,'rb') as inF:
|
||||||
with gzip.GzipFile(gzfilename,'wb') as outF:
|
s = inF.read()
|
||||||
outF.write(s)
|
with gzip.GzipFile(gzfilename,'wb') as outF:
|
||||||
|
outF.write(s)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.remove(tcxfilename)
|
os.remove(tcxfilename)
|
||||||
except WindowError:
|
except WindowError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return gzfilename,""
|
return gzfilename,""
|
||||||
|
|
||||||
|
else:
|
||||||
|
return tcxfilename,""
|
||||||
|
|
||||||
|
|
||||||
# Upload the TCX file to Strava and set the workout activity type
|
# Upload the TCX file to Strava and set the workout activity type
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ urlpatterns = [
|
|||||||
url(r'^workout/(?P<id>\d+)/export$',views.workout_export_view),
|
url(r'^workout/(?P<id>\d+)/export$',views.workout_export_view),
|
||||||
url(r'^workout/(?P<id>\d+)/comment$',views.workout_comment_view),
|
url(r'^workout/(?P<id>\d+)/comment$',views.workout_comment_view),
|
||||||
url(r'^workout/(?P<id>\d+)/emailtcx$',views.workout_tcxemail_view),
|
url(r'^workout/(?P<id>\d+)/emailtcx$',views.workout_tcxemail_view),
|
||||||
|
url(r'^workout/(?P<id>\d+)/emailgpx$',views.workout_gpxemail_view),
|
||||||
url(r'^workout/(?P<id>\d+)/emailcsv$',views.workout_csvemail_view),
|
url(r'^workout/(?P<id>\d+)/emailcsv$',views.workout_csvemail_view),
|
||||||
url(r'^workout/(?P<id>\d+)/csvtoadmin$',views.workout_csvtoadmin_view),
|
url(r'^workout/(?P<id>\d+)/csvtoadmin$',views.workout_csvtoadmin_view),
|
||||||
url(r'^workout/compare/(?P<id>\d+)/$',views.workout_comparison_list),
|
url(r'^workout/compare/(?P<id>\d+)/$',views.workout_comparison_list),
|
||||||
|
|||||||
348
rowers/views.py
348
rowers/views.py
@@ -1064,7 +1064,7 @@ def workout_tcxemail_view(request,id=0):
|
|||||||
raise Http404("Workout doesn't exist")
|
raise Http404("Workout doesn't exist")
|
||||||
if (checkworkoutuser(request.user,w)):
|
if (checkworkoutuser(request.user,w)):
|
||||||
try:
|
try:
|
||||||
tcxfile,tcxmessg = stravastuff.createstravaworkoutdata(w)
|
tcxfile,tcxmessg = stravastuff.createstravaworkoutdata(w,dozip=False)
|
||||||
if tcxfile == 0:
|
if tcxfile == 0:
|
||||||
message = "Something went wrong (TCX export) "+tcxmessg
|
message = "Something went wrong (TCX export) "+tcxmessg
|
||||||
messages.error(request,message)
|
messages.error(request,message)
|
||||||
@@ -1116,6 +1116,51 @@ def workout_tcxemail_view(request,id=0):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
# Export workout to GPX and send to user's email address
|
||||||
|
@login_required()
|
||||||
|
def workout_gpxemail_view(request,id=0):
|
||||||
|
message = ""
|
||||||
|
successmessage = ""
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
try:
|
||||||
|
w = Workout.objects.get(id=id)
|
||||||
|
except Workout.DoesNotExist:
|
||||||
|
raise Http404("Workout doesn't exist")
|
||||||
|
if (checkworkoutuser(request.user,w)):
|
||||||
|
filename = w.csvfilename
|
||||||
|
row = rdata(filename)
|
||||||
|
gpxfilename = filename[:-4]+'.gpx'
|
||||||
|
row.exporttogpx(gpxfilename)
|
||||||
|
if settings.DEBUG:
|
||||||
|
res = handle_sendemailtcx.delay(r.user.first_name,
|
||||||
|
r.user.last_name,
|
||||||
|
r.user.email,gpxfilename)
|
||||||
|
|
||||||
|
else:
|
||||||
|
res = queuehigh.enqueue(handle_sendemailtcx,r.user.first_name,
|
||||||
|
r.user.last_name,
|
||||||
|
r.user.email,gpxfilename)
|
||||||
|
|
||||||
|
successmessage = "The GPX file was sent to you per email"
|
||||||
|
messages.info(request,successmessage)
|
||||||
|
url = reverse(workout_export_view,
|
||||||
|
kwargs = {
|
||||||
|
'id':str(w.id),
|
||||||
|
})
|
||||||
|
|
||||||
|
response = HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
else:
|
||||||
|
message = "You are not allowed to export this workout"
|
||||||
|
messages.error(request,message)
|
||||||
|
url = reverse(workout_export_view,
|
||||||
|
kwargs = {
|
||||||
|
'id':str(w.id),
|
||||||
|
})
|
||||||
|
response = HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
# Get Workout CSV file and send it to user's email address
|
# Get Workout CSV file and send it to user's email address
|
||||||
@login_required()
|
@login_required()
|
||||||
def workout_csvemail_view(request,id=0):
|
def workout_csvemail_view(request,id=0):
|
||||||
@@ -2645,6 +2690,301 @@ def rankings_view(request,theuser=0,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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),
|
||||||
|
})
|
||||||
|
|
||||||
|
# Show ranking distances including predicted paces
|
||||||
|
@login_required()
|
||||||
|
def otwrankings_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))
|
||||||
|
|
||||||
|
thedistances = []
|
||||||
|
theworkouts = []
|
||||||
|
thesecs = []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
rankingdistances.sort()
|
||||||
|
rankingdurations.sort()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
theworkouts = Workout.objects.filter(user=r,rankingpiece=True,
|
||||||
|
workouttype='water',
|
||||||
|
startdatetime__gte=startdate,
|
||||||
|
startdatetime__lte=enddate)
|
||||||
|
|
||||||
|
|
||||||
|
# get all power data from database (plus workoutid)
|
||||||
|
theids = [w.id for w in theworkouts]
|
||||||
|
columns = ['power','workoutid','time']
|
||||||
|
df = dataprep.getsmallrowdata_db(columns,ids=theids)
|
||||||
|
|
||||||
|
dfgrouped = df.groupby(['workoutid'])
|
||||||
|
for id in theids:
|
||||||
|
tt = df['time']
|
||||||
|
|
||||||
|
for w in theworkouts:
|
||||||
|
|
||||||
|
thedistances.append(w.distance)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
thesecs = np.array(thesecs)
|
||||||
|
|
||||||
|
theavpower = 2.8*(thevelos**3)
|
||||||
|
|
||||||
|
|
||||||
|
# create interactive plot
|
||||||
|
if len(thedistances) !=0 :
|
||||||
|
res = interactive_cpchart(thedistances,thesecs,theavpower,
|
||||||
|
theworkouts,promember=promember)
|
||||||
|
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=value,hour=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:
|
for rankingduration in rankingdurations:
|
||||||
t = 3600.*rankingduration.hour
|
t = 3600.*rankingduration.hour
|
||||||
t += 60.*rankingduration.minute
|
t += 60.*rankingduration.minute
|
||||||
@@ -5187,6 +5527,11 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
|||||||
privacy = request.POST['privacy']
|
privacy = request.POST['privacy']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
privacy = Workout.objects.get(id=id).privacy
|
privacy = Workout.objects.get(id=id).privacy
|
||||||
|
try:
|
||||||
|
rankingpiece = form.cleaned_data['rankingpiece']
|
||||||
|
except KeyError:
|
||||||
|
rankingpiece =- Workout.objects.get(id=id).rankingpiece
|
||||||
|
|
||||||
startdatetime = (str(date) + ' ' + str(starttime))
|
startdatetime = (str(date) + ' ' + str(starttime))
|
||||||
startdatetime = datetime.datetime.strptime(startdatetime,
|
startdatetime = datetime.datetime.strptime(startdatetime,
|
||||||
"%Y-%m-%d %H:%M:%S")
|
"%Y-%m-%d %H:%M:%S")
|
||||||
@@ -5203,6 +5548,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
|||||||
row.distance = distance
|
row.distance = distance
|
||||||
row.boattype = boattype
|
row.boattype = boattype
|
||||||
row.privacy = privacy
|
row.privacy = privacy
|
||||||
|
row.rankingpiece = rankingpiece
|
||||||
try:
|
try:
|
||||||
row.save()
|
row.save()
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
|
|||||||
Reference in New Issue
Block a user