diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 16babd4a..727eaae3 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -430,6 +430,7 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower', delta,cpvalues,avgpower = datautils.getsinglecp(row.df) if utils.isbreakthrough(delta,cpvalues,r.p0,r.p1,r.p2,r.p3): isbreakthrough = True + res = datautils.updatecp(delta,cpvalues,r) dtavg = row.df['TimeStamp (sec)'].diff().mean() diff --git a/rowers/datautils.py b/rowers/datautils.py index 9118dc2c..7c1d9136 100644 --- a/rowers/datautils.py +++ b/rowers/datautils.py @@ -1,6 +1,88 @@ import pandas as pd import numpy as np from scipy.interpolate import griddata +from scipy import optimize + +def updatecp(delta,cpvalues,r): + cp2 = r.p0/(1+delta/r.p2) + cp2 += r.p1/(1+delta/r.p3) + + delta = delta.append(delta) + cp = cpvalues.append(cp2) + + powerdf = pd.DataFrame({ + 'Delta':delta, + 'CP':cp, + }) + + 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) + + + res = cpfit(powerdf) + p1 = res[0] + + r.p0 = p1[0] + r.p1 = p1[1] + r.p2 = p1[2] + r.p3 = p1[3] + + r.save() + + return 1 + +def cpfit(powerdf): + # Fit the data to thee parameter CP model + fitfunc = lambda pars,x: abs(pars[0])/(1+(x/abs(pars[2]))) + abs(pars[1])/(1+(x/abs(pars[3]))) + errfunc = lambda pars,x,y: fitfunc(pars,x)-y + + p0 = [500,350,10,8000] + + p1 = p0 + + thesecs = powerdf['Delta'] + theavpower = powerdf['CP'] + + if len(thesecs)>=4: + p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower)) + else: + factor = fitfunc(p0,thesecs.mean())/theavpower.mean() + p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] + + + p1 = [abs(p) for p in p1] + fitt = pd.Series(10**(4*np.arange(100)/100.)) + + fitpower = fitfunc(p1,fitt) + + fitpoints = fitfunc(p1,thesecs) + fitpoints0 = fitpoints.copy() + dd = fitpoints-theavpower + + ddmin = dd.min() + + frac = abs(ddmin)/fitpoints.mean() + + while frac>0.0001: + fitpoints = fitpoints*(fitpoints.mean()-ddmin)/(fitpoints.mean()) + dd = fitpoints-theavpower + ddmin = dd.min() + frac = abs(ddmin)/fitpoints.mean() + + ratio = fitpoints.mean()/fitpoints0.mean() + + return p1,fitt,fitpower,ratio + +def getlogarr(maxt): + maxlog10 = np.log10(maxt-5) + logarr = np.log10(5.)+np.arange(50)*maxlog10/50. + logarr = [int(10.**(la)) for la in logarr] + logarr = pd.Series(logarr) + logarr.drop_duplicates(keep='first',inplace=True) + + logarr = logarr.values + return logarr def getsinglecp(df): thesecs = df['TimeStamp (sec)'].max()-df['TimeStamp (sec)'].min() @@ -9,13 +91,7 @@ def getsinglecp(df): else: maxt = 1000. - maxlog10 = np.log10(maxt) - logarr = np.arange(50)*maxlog10/50. - logarr = [int(10.**(la)) for la in logarr] - logarr = pd.Series(logarr) - logarr.drop_duplicates(keep='first',inplace=True) - - logarr = logarr.values + logarr = getlogarr(maxt) dfnew = pd.DataFrame({ @@ -42,7 +118,7 @@ def getcp(dfgrouped,logarr): tmax = tt.max() if tmax > 500000: - newlen = int(tmax/5000.) + newlen = int(tmax/2000.) else: newlen = len(tt) if newlen < len(tt): diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 47c0009f..7200497e 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -55,6 +55,7 @@ import rowers.dataprep as dataprep from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima from utils import lbstoN +import datautils watermarkurl = "/static/img/logo7.png" watermarksource = ColumnDataSource(dict( @@ -618,29 +619,11 @@ def interactive_otwcpchart(powerdf,promember=0): # there is no Paul's law for OTW - # Fit the data to thee parameter CP model - fitfunc = lambda pars,x: abs(pars[0])/(1+(x/abs(pars[2]))) + abs(pars[1])/(1+(x/abs(pars[3]))) - errfunc = lambda pars,x,y: fitfunc(pars,x)-y - - p0 = [500,350,10,8000] - - p1 = p0 - thesecs = powerdf['Delta'] theavpower = powerdf['CP'] - - if len(thesecs)>=4: - p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower)) - else: - factor = fitfunc(p0,thesecs.mean())/theavpower.mean() - p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] - - - p1 = [abs(p) for p in p1] - fitt = pd.Series(10**(4*np.arange(100)/100.)) - - fitpower = fitfunc(p1,fitt) - + + p1,fitt,fitpower,ratio = datautils.cpfit(powerdf) + message = "" #if len(fitpower[fitpower<0]) > 0: # message = "CP model fit didn't give correct results" @@ -652,6 +635,7 @@ def interactive_otwcpchart(powerdf,promember=0): sourcecomplex = ColumnDataSource( data = dict( CP = fitpower, + CPmax = ratio*fitpower, duration = fitt, ftime = ftime ) @@ -690,6 +674,7 @@ def interactive_otwcpchart(powerdf,promember=0): hover.tooltips = OrderedDict([ ('Duration ','@ftime'), ('Power (W)','@CP{int}'), + ('Power (W) upper','@CPmax{int}'), ]) hover.mode = 'mouse' @@ -697,6 +682,9 @@ def interactive_otwcpchart(powerdf,promember=0): plot.line('duration','CP',source=sourcecomplex,legend="CP Model", color='green') + plot.line('duration','CPmax',source=sourcecomplex,legend="CP Model", + color='red') + script, div = components(plot) return [script,div,p1,message] diff --git a/rowers/models.py b/rowers/models.py index 2eb2ec3c..6922265f 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -232,7 +232,7 @@ class Rower(models.Model): ('hidden','Hidden'), ) - getemailnotifications = models.BooleanField(default=True, + getemailnotifications = models.BooleanField(default=False, verbose_name='Receive email notifications') rowerplan = models.CharField(default='basic',max_length=30, diff --git a/rowers/views.py b/rowers/views.py index 3ca3cffb..a47800b1 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -2931,15 +2931,7 @@ def otwrankings_view(request,theuser=0, maxt = 1000. - maxlog10 = np.log10(maxt) - logarr = np.arange(50)*maxlog10/50. - logarr = [int(10.**(la)) for la in logarr] - logarr = pd.Series(logarr) - logarr.drop_duplicates(keep='first',inplace=True) - - logarr = logarr.values - - + logarr = datautils.getlogarr(maxt) dfgrouped = df.groupby(['workoutid']) delta,cpvalue,avgpower = datautils.getcp(dfgrouped,logarr) @@ -8101,8 +8093,10 @@ def team_view(request,id=0): if inviteid: teams.send_invite_email(inviteid) successmessage = text + messages.info(request,successmessage) else: message = text + messages.error(request,message) elif request.user == t.manager: inviteform = TeamInviteForm()