Merge branch 'release/v23.2.0'
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 235 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 179 KiB |
+155
-35
@@ -458,7 +458,7 @@ def calculate_goldmedalstandard(rower, workout, recurrance=True):
|
|||||||
if settings.TESTING:
|
if settings.TESTING:
|
||||||
background = False
|
background = False
|
||||||
if recurrance:
|
if recurrance:
|
||||||
df, delta, cpvalues = setcp(workout, background=background)
|
df, delta, cpvalues, cpvalues_spm = setcp(workout, background=background)
|
||||||
if df.is_empty():
|
if df.is_empty():
|
||||||
return 0, 0
|
return 0, 0
|
||||||
else:
|
else:
|
||||||
@@ -466,7 +466,7 @@ def calculate_goldmedalstandard(rower, workout, recurrance=True):
|
|||||||
|
|
||||||
|
|
||||||
if df.is_empty() and recurrance: # pragma: no cover
|
if df.is_empty() and recurrance: # pragma: no cover
|
||||||
df, delta, cpvalues = setcp(workout, recurrance=False, background=True)
|
df, delta, cpvalues, cpvalues_spm = setcp(workout, recurrance=False, background=True)
|
||||||
if df.is_empty():
|
if df.is_empty():
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
@@ -553,7 +553,10 @@ def setcp(workout, background=False, recurrance=True):
|
|||||||
# check dts
|
# check dts
|
||||||
tarr = datautils.getlogarr(4000)
|
tarr = datautils.getlogarr(4000)
|
||||||
if df['delta'][0] in tarr:
|
if df['delta'][0] in tarr:
|
||||||
return(df, df['delta'], df['cp'])
|
try:
|
||||||
|
return(df, df['delta'], df['cp'], df['cr'])
|
||||||
|
except KeyError:
|
||||||
|
return(df, df['delta'], df['cp'], 0*df['cp'])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
try:
|
try:
|
||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
@@ -565,7 +568,7 @@ def setcp(workout, background=False, recurrance=True):
|
|||||||
strokesdf = remove_nulls_pl(strokesdf)
|
strokesdf = remove_nulls_pl(strokesdf)
|
||||||
|
|
||||||
if strokesdf.is_empty():
|
if strokesdf.is_empty():
|
||||||
return pl.DataFrame({'delta': [], 'cp': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
return pl.DataFrame({'delta': [], 'cp': [], 'cr': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||||
|
|
||||||
totaltime = strokesdf['time'].max()
|
totaltime = strokesdf['time'].max()
|
||||||
maxt = totaltime/1000.
|
maxt = totaltime/1000.
|
||||||
@@ -580,7 +583,7 @@ def setcp(workout, background=False, recurrance=True):
|
|||||||
elif os.path.exists(csvfilename+'.gz'): # pragma: no cover
|
elif os.path.exists(csvfilename+'.gz'): # pragma: no cover
|
||||||
csvfile = csvfilename+'.gz'
|
csvfile = csvfilename+'.gz'
|
||||||
else: # pragma: no cover
|
else: # pragma: no cover
|
||||||
return pl.DataFrame({'delta': [], 'cp': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
return pl.DataFrame({'delta': [], 'cp': [], 'cr': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||||
csvfile = os.path.abspath(csvfile)
|
csvfile = os.path.abspath(csvfile)
|
||||||
|
|
||||||
with grpc.insecure_channel(
|
with grpc.insecure_channel(
|
||||||
@@ -593,7 +596,7 @@ def setcp(workout, background=False, recurrance=True):
|
|||||||
grpc.channel_ready_future(channel).result(timeout=10)
|
grpc.channel_ready_future(channel).result(timeout=10)
|
||||||
except grpc.FutureTimeoutError: # pragma: no cover
|
except grpc.FutureTimeoutError: # pragma: no cover
|
||||||
dologging('metrics.log','grpc channel time out in setcp')
|
dologging('metrics.log','grpc channel time out in setcp')
|
||||||
return pl.DataFrame({'delta': [], 'cp': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
return pl.DataFrame({'delta': [], 'cp': [], 'cr':[]}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||||
|
|
||||||
stub = metrics_pb2_grpc.MetricsStub(channel)
|
stub = metrics_pb2_grpc.MetricsStub(channel)
|
||||||
req = metrics_pb2.CPRequest(filename = csvfile, filetype = "CSV", tarr = logarr)
|
req = metrics_pb2.CPRequest(filename = csvfile, filetype = "CSV", tarr = logarr)
|
||||||
@@ -602,16 +605,18 @@ def setcp(workout, background=False, recurrance=True):
|
|||||||
response = stub.GetCP(req, timeout=60)
|
response = stub.GetCP(req, timeout=60)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
dologging('metrics.log', traceback.format_exc())
|
dologging('metrics.log', traceback.format_exc())
|
||||||
return pl.DataFrame({'delta': [], 'cp': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
return pl.DataFrame({'delta': [], 'cp': [], 'cr': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||||
|
|
||||||
delta = pl.Series(np.array(response.delta))
|
delta = pl.Series(np.array(response.delta))
|
||||||
cpvalues = pl.Series(np.array(response.power))
|
cpvalues = pl.Series(np.array(response.power))
|
||||||
powermean = response.avgpower
|
powermean = response.avgpower
|
||||||
|
spmvalues = pl.Series(np.array(response.spm))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
df = pl.DataFrame({
|
df = pl.DataFrame({
|
||||||
'delta': delta,
|
'delta': delta,
|
||||||
'cp': cpvalues,
|
'cp': cpvalues,
|
||||||
|
'cr': spmvalues,
|
||||||
'id': workout.id,
|
'id': workout.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -620,7 +625,7 @@ def setcp(workout, background=False, recurrance=True):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
dologging("metrics.log", "setcp: "+ str(e))
|
dologging("metrics.log", "setcp: "+ str(e))
|
||||||
return pl.DataFrame({'delta': [], 'cp': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
return pl.DataFrame({'delta': [], 'cp': [], 'cr': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||||
|
|
||||||
#df.to_parquet(filename, engine='fastparquet', compression='GZIP')
|
#df.to_parquet(filename, engine='fastparquet', compression='GZIP')
|
||||||
|
|
||||||
@@ -631,7 +636,7 @@ def setcp(workout, background=False, recurrance=True):
|
|||||||
workout.goldmedalduration = goldmedalduration
|
workout.goldmedalduration = goldmedalduration
|
||||||
workout.save()
|
workout.save()
|
||||||
|
|
||||||
return df, delta, cpvalues
|
return df, delta, cpvalues, spmvalues # pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -772,7 +777,7 @@ def fetchcp_new(rower, workouts):
|
|||||||
data = []
|
data = []
|
||||||
|
|
||||||
for workout in workouts:
|
for workout in workouts:
|
||||||
df, delta, cpvalues = setcp(workout)
|
df, delta, cpvalues, cpvalues_spm = setcp(workout)
|
||||||
df = df.drop('id')
|
df = df.drop('id')
|
||||||
df = df.with_columns((pl.lit(str(workout))).alias("workout"))
|
df = df.with_columns((pl.lit(str(workout))).alias("workout"))
|
||||||
df = df.with_columns((pl.lit(workout.url())).alias("url"))
|
df = df.with_columns((pl.lit(workout.url())).alias("url"))
|
||||||
@@ -780,7 +785,7 @@ def fetchcp_new(rower, workouts):
|
|||||||
data.append(df)
|
data.append(df)
|
||||||
|
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
return pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), 0, pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
return pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), 0, pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||||
if len(data) > 1:
|
if len(data) > 1:
|
||||||
df = pl.concat(data)
|
df = pl.concat(data)
|
||||||
|
|
||||||
@@ -791,16 +796,21 @@ def fetchcp_new(rower, workouts):
|
|||||||
pl.all().sort_by('cp').last(),
|
pl.all().sort_by('cp').last(),
|
||||||
])
|
])
|
||||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||||
return pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), 0, pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
return pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), 0, pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||||
|
|
||||||
df = df.filter(pl.col("cp")>20)
|
df = df.filter(pl.col("cp")>20)
|
||||||
|
|
||||||
return df['delta'], df['cp'], 0, df['workout'], df['url']
|
try:
|
||||||
|
testje = df['cr']
|
||||||
|
except KeyError:
|
||||||
|
return df['delta'], df['cp'], 0*df['cp'], 0, df['workout'], df['url']
|
||||||
|
|
||||||
|
return df['delta'], df['cp'], df['cr'], 0, df['workout'], df['url']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def update_rolling_cp(r, types, mode='water', dosend=False):
|
def update_rolling_cp(r, types, mode='water', metric='power', dosend=False):
|
||||||
firstdate = tz.now()-datetime.timedelta(days=r.cprange)
|
firstdate = tz.now()-datetime.timedelta(days=r.cprange)
|
||||||
workouts = Workout.objects.filter(
|
workouts = Workout.objects.filter(
|
||||||
date__gte=firstdate,
|
date__gte=firstdate,
|
||||||
@@ -808,12 +818,19 @@ def update_rolling_cp(r, types, mode='water', dosend=False):
|
|||||||
user=r
|
user=r
|
||||||
)
|
)
|
||||||
|
|
||||||
delta, cp, avgpower, workoutnames, urls = fetchcp_new(r, workouts)
|
delta, cp, cr, avgpower, workoutnames, urls = fetchcp_new(r, workouts)
|
||||||
|
|
||||||
|
if metric == 'power':
|
||||||
|
powerdf = pl.DataFrame({
|
||||||
|
'Delta': delta,
|
||||||
|
'CP': cp,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
powerdf = pl.DataFrame({
|
||||||
|
'Delta': delta,
|
||||||
|
'CP': cr,
|
||||||
|
})
|
||||||
|
|
||||||
powerdf = pl.DataFrame({
|
|
||||||
'Delta': delta,
|
|
||||||
'CP': cp,
|
|
||||||
})
|
|
||||||
|
|
||||||
powerdf = powerdf.filter(pl.col("CP")>0)
|
powerdf = powerdf.filter(pl.col("CP")>0)
|
||||||
powerdf = powerdf.fill_nan(None).drop_nulls().sort(["Delta", "CP"])
|
powerdf = powerdf.fill_nan(None).drop_nulls().sort(["Delta", "CP"])
|
||||||
@@ -821,6 +838,8 @@ def update_rolling_cp(r, types, mode='water', dosend=False):
|
|||||||
|
|
||||||
if powerdf.is_empty():
|
if powerdf.is_empty():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
res2 = datautils.cpfit(powerdf)
|
res2 = datautils.cpfit(powerdf)
|
||||||
p1 = res2[0]
|
p1 = res2[0]
|
||||||
@@ -830,7 +849,7 @@ def update_rolling_cp(r, types, mode='water', dosend=False):
|
|||||||
pwr += p1[1]/(1+hourseconds/p1[3])
|
pwr += p1[1]/(1+hourseconds/p1[3])
|
||||||
|
|
||||||
if len(powerdf) != 0:
|
if len(powerdf) != 0:
|
||||||
if mode == 'water':
|
if mode == 'water' and metric == 'power':
|
||||||
r.p0 = p1[0]
|
r.p0 = p1[0]
|
||||||
r.p1 = p1[1]
|
r.p1 = p1[1]
|
||||||
r.p2 = p1[2]
|
r.p2 = p1[2]
|
||||||
@@ -839,8 +858,14 @@ def update_rolling_cp(r, types, mode='water', dosend=False):
|
|||||||
r.save()
|
r.save()
|
||||||
if dosend and pwr-5 > r.ftp*(100.-r.otwslack)/100. and r.getemailnotifications and not r.emailbounced:
|
if dosend and pwr-5 > r.ftp*(100.-r.otwslack)/100. and r.getemailnotifications and not r.emailbounced:
|
||||||
_ = myqueue(queuehigh, handle_sendemail_newftp,r,pwr,'water')
|
_ = myqueue(queuehigh, handle_sendemail_newftp,r,pwr,'water')
|
||||||
|
elif mode == 'water' and metric == 'spm':
|
||||||
else:
|
r.r0 = p1[0]
|
||||||
|
r.r1 = p1[1]
|
||||||
|
r.r2 = p1[2]
|
||||||
|
r.r3 = p1[3]
|
||||||
|
r.crratio = res2[3]
|
||||||
|
r.save()
|
||||||
|
elif mode == 'erg' and metric == 'power':
|
||||||
r.ep0 = p1[0]
|
r.ep0 = p1[0]
|
||||||
r.ep1 = p1[1]
|
r.ep1 = p1[1]
|
||||||
r.ep2 = p1[2]
|
r.ep2 = p1[2]
|
||||||
@@ -849,14 +874,23 @@ def update_rolling_cp(r, types, mode='water', dosend=False):
|
|||||||
r.save()
|
r.save()
|
||||||
if dosend and pwr-5 > r.ftp and r.getemailnotifications and not r.emailbounced:
|
if dosend and pwr-5 > r.ftp and r.getemailnotifications and not r.emailbounced:
|
||||||
_ = myqueue(queuehigh, handle_sendemail_newftp,r,pwr,'water')
|
_ = myqueue(queuehigh, handle_sendemail_newftp,r,pwr,'water')
|
||||||
|
elif mode == 'erg' and metric == 'spm':
|
||||||
|
r.er0 = p1[0]
|
||||||
|
r.er1 = p1[1]
|
||||||
|
r.er2 = p1[2]
|
||||||
|
r.er3 = p1[3]
|
||||||
|
r.ecrratio = res2[3]
|
||||||
|
r.save()
|
||||||
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def initiate_cp(r):
|
def initiate_cp(r):
|
||||||
_ = update_rolling_cp(r, otwtypes, 'water')
|
_ = update_rolling_cp(r, otwtypes, mode='water', metric='power')
|
||||||
_ = update_rolling_cp(r, otetypes, 'erg')
|
_ = update_rolling_cp(r, otetypes, mode='erg', metric='power')
|
||||||
|
_ = update_rolling_cp(r, otwtypes, mode='water', metric='spm')
|
||||||
|
_ = update_rolling_cp(r, otetypes, mode='erg', metric='spm')
|
||||||
|
|
||||||
def split_workout(r, parent, splitsecond, splitmode):
|
def split_workout(r, parent, splitsecond, splitmode):
|
||||||
data, row = getrowdata_db(id=parent.id)
|
data, row = getrowdata_db(id=parent.id)
|
||||||
@@ -1061,13 +1095,14 @@ def checkbreakthrough(w, r):
|
|||||||
ishard = False
|
ishard = False
|
||||||
workouttype = w.workouttype
|
workouttype = w.workouttype
|
||||||
if workouttype in rowtypes:
|
if workouttype in rowtypes:
|
||||||
cpdf, delta, cpvalues = setcp(w)
|
cpdf, delta, cpvalues, cpvalues_spm = setcp(w)
|
||||||
if not cpdf.is_empty():
|
if not cpdf.is_empty():
|
||||||
if workouttype in otwtypes:
|
if workouttype in otwtypes:
|
||||||
try:
|
try:
|
||||||
res, btvalues, res2 = utils.isbreakthrough(
|
res, btvalues, res2 = utils.isbreakthrough(
|
||||||
delta, cpvalues, r.p0, r.p1, r.p2, r.p3, r.cpratio)
|
delta, cpvalues, r.p0, r.p1, r.p2, r.p3, r.cpratio)
|
||||||
_ = update_rolling_cp(r, otwtypes, 'water')
|
_ = update_rolling_cp(r, otwtypes, mode='water')
|
||||||
|
_ = update_rolling_cp(r, otwtypes, mode='water', metric='spm')
|
||||||
except ValueError:
|
except ValueError:
|
||||||
res = 0
|
res = 0
|
||||||
res2 = 0
|
res2 = 0
|
||||||
@@ -1076,7 +1111,8 @@ def checkbreakthrough(w, r):
|
|||||||
try:
|
try:
|
||||||
res, btvalues, res2 = utils.isbreakthrough(
|
res, btvalues, res2 = utils.isbreakthrough(
|
||||||
delta, cpvalues, r.ep0, r.ep1, r.ep2, r.ep3, r.ecpratio)
|
delta, cpvalues, r.ep0, r.ep1, r.ep2, r.ep3, r.ecpratio)
|
||||||
_ = update_rolling_cp(r, otetypes, 'erg')
|
_ = update_rolling_cp(r, otetypes, mode='erg')
|
||||||
|
_ = update_rolling_cp(r, otetypes, mode='erg', metric='spm')
|
||||||
except ValueError:
|
except ValueError:
|
||||||
res = 0
|
res = 0
|
||||||
res2 = 0
|
res2 = 0
|
||||||
@@ -1480,9 +1516,15 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
|||||||
r.running_wps = 400.
|
r.running_wps = 400.
|
||||||
r.save()
|
r.save()
|
||||||
|
|
||||||
|
if w.workouttype in otwtypes:
|
||||||
|
wps_avg = r.median_wps
|
||||||
|
elif w.workouttype in otetypes:
|
||||||
|
wps_avg = r.median_wps_erg
|
||||||
|
else:
|
||||||
|
wps_avg = 0
|
||||||
|
|
||||||
_ = myqueue(queuehigh, handle_calctrimp, w.id, f2,
|
_ = myqueue(queuehigh, handle_calctrimp, w.id, f2,
|
||||||
r.ftp, r.sex, r.hrftp, r.max, r.rest)
|
r.ftp, r.sex, r.hrftp, r.max, r.rest, wps_avg)
|
||||||
|
|
||||||
return (w.id, message)
|
return (w.id, message)
|
||||||
|
|
||||||
@@ -1771,8 +1813,15 @@ def new_workout_from_df(r, df,
|
|||||||
rpe=rpe,
|
rpe=rpe,
|
||||||
consistencychecks=False)
|
consistencychecks=False)
|
||||||
|
|
||||||
|
if workouttype in otwtypes:
|
||||||
|
wps_avg = r.median_wps
|
||||||
|
elif workouttype in otetypes:
|
||||||
|
wps_avg = r.median_wps_erg
|
||||||
|
else:
|
||||||
|
wps_avg = 0
|
||||||
|
|
||||||
_ = myqueue(queuehigh, handle_calctrimp, id, csvfilename,
|
_ = myqueue(queuehigh, handle_calctrimp, id, csvfilename,
|
||||||
r.ftp, r.sex, r.hrftp, r.max, r.rest)
|
r.ftp, r.sex, r.hrftp, r.max, r.rest, wps_avg)
|
||||||
|
|
||||||
return (id, message)
|
return (id, message)
|
||||||
|
|
||||||
@@ -1814,7 +1863,14 @@ def workout_trimp(w, reset=False):
|
|||||||
return 0, 100.*(w.averagehr/r.hrftp)*(w.duration.hour*60 + w.duration.minute)/60.
|
return 0, 100.*(w.averagehr/r.hrftp)*(w.duration.hour*60 + w.duration.minute)/60.
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
|
if w.workouttype in otwtypes:
|
||||||
|
wps_avg = r.median_wps
|
||||||
|
elif w.workouttype in otetypes:
|
||||||
|
wps_avg = r.median_wps_erg
|
||||||
|
else:
|
||||||
|
wps_avg = 0
|
||||||
|
|
||||||
ftp = float(r.ftp)
|
ftp = float(r.ftp)
|
||||||
_ = myqueue(
|
_ = myqueue(
|
||||||
queuehigh,
|
queuehigh,
|
||||||
@@ -1825,7 +1881,9 @@ def workout_trimp(w, reset=False):
|
|||||||
r.sex,
|
r.sex,
|
||||||
r.hrftp,
|
r.hrftp,
|
||||||
r.max,
|
r.max,
|
||||||
r.rest)
|
r.rest,
|
||||||
|
wps_avg,
|
||||||
|
)
|
||||||
return w.trimp, w.hrtss
|
return w.trimp, w.hrtss
|
||||||
elif w.trimp > -1 and not reset:
|
elif w.trimp > -1 and not reset:
|
||||||
return w.trimp, w.hrtss
|
return w.trimp, w.hrtss
|
||||||
@@ -1857,6 +1915,13 @@ def workout_trimp(w, reset=False):
|
|||||||
w.maxhr = maxhr
|
w.maxhr = maxhr
|
||||||
w.save()
|
w.save()
|
||||||
|
|
||||||
|
if w.workouttype in otwtypes:
|
||||||
|
wps_avg = r.median_wps
|
||||||
|
elif w.workouttype in otetypes:
|
||||||
|
wps_avg = r.median_wps_erg
|
||||||
|
else:
|
||||||
|
wps_avg = 0
|
||||||
|
|
||||||
_ = myqueue(
|
_ = myqueue(
|
||||||
queuehigh,
|
queuehigh,
|
||||||
handle_calctrimp,
|
handle_calctrimp,
|
||||||
@@ -1866,7 +1931,8 @@ def workout_trimp(w, reset=False):
|
|||||||
r.sex,
|
r.sex,
|
||||||
r.hrftp,
|
r.hrftp,
|
||||||
r.max,
|
r.max,
|
||||||
r.rest)
|
r.rest,
|
||||||
|
wps_avg,)
|
||||||
|
|
||||||
trimp = 0
|
trimp = 0
|
||||||
averagehr = 0
|
averagehr = 0
|
||||||
@@ -1877,6 +1943,45 @@ def workout_trimp(w, reset=False):
|
|||||||
|
|
||||||
return trimp, averagehr
|
return trimp, averagehr
|
||||||
|
|
||||||
|
def workout_spmtss(w, reset=False):
|
||||||
|
if w.spmtss > -1 and not reset:
|
||||||
|
return w.spmtss
|
||||||
|
|
||||||
|
if get_existing_job(w):
|
||||||
|
return 0, 0
|
||||||
|
|
||||||
|
r = w.user
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if w.workouttype in otwtypes:
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
|
if r.hrftp == 0:
|
||||||
|
hrftp = (r.an+r.tr)/2.
|
||||||
|
r.hrftp = int(hrftp)
|
||||||
|
r.save()
|
||||||
|
|
||||||
|
if w.workouttype in otwtypes:
|
||||||
|
wps_avg = r.median_wps
|
||||||
|
elif w.workouttype in otetypes:
|
||||||
|
wps_avg = r.median_wps_erg
|
||||||
|
else:
|
||||||
|
wps_avg = 0
|
||||||
|
|
||||||
|
_ = myqueue(
|
||||||
|
queuehigh,
|
||||||
|
handle_calctrimp,
|
||||||
|
w.id,
|
||||||
|
w.csvfilename,
|
||||||
|
ftp,
|
||||||
|
r.sex,
|
||||||
|
r.hrftp,
|
||||||
|
r.max,
|
||||||
|
r.rest,
|
||||||
|
wps_avg,)
|
||||||
|
|
||||||
|
return w.spmtss
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def workout_rscore(w, reset=False):
|
def workout_rscore(w, reset=False):
|
||||||
dologging('metrics.log','Workout_rscore for {w} {id}, {reset}'.format(
|
dologging('metrics.log','Workout_rscore for {w} {id}, {reset}'.format(
|
||||||
@@ -1906,6 +2011,13 @@ def workout_rscore(w, reset=False):
|
|||||||
r.save()
|
r.save()
|
||||||
|
|
||||||
dologging('metrics.log','Queueing an asynchronous task')
|
dologging('metrics.log','Queueing an asynchronous task')
|
||||||
|
|
||||||
|
if w.workouttype in otwtypes:
|
||||||
|
wps_avg = r.median_wps
|
||||||
|
elif w.workouttype in otetypes:
|
||||||
|
wps_avg = r.median_wps_erg
|
||||||
|
else:
|
||||||
|
wps_avg = 0
|
||||||
|
|
||||||
_ = myqueue(
|
_ = myqueue(
|
||||||
queuehigh,
|
queuehigh,
|
||||||
@@ -1916,7 +2028,8 @@ def workout_rscore(w, reset=False):
|
|||||||
r.sex,
|
r.sex,
|
||||||
r.hrftp,
|
r.hrftp,
|
||||||
r.max,
|
r.max,
|
||||||
r.rest)
|
r.rest,
|
||||||
|
wps_avg,)
|
||||||
|
|
||||||
return w.rscore, w.normp
|
return w.rscore, w.normp
|
||||||
|
|
||||||
@@ -1938,6 +2051,13 @@ def workout_normv(w, pp=4.0):
|
|||||||
r.hrftp = int(hrftp)
|
r.hrftp = int(hrftp)
|
||||||
r.save()
|
r.save()
|
||||||
|
|
||||||
|
if w.workouttype in otwtypes:
|
||||||
|
wps_avg = r.median_wps
|
||||||
|
elif w.workouttype in otetypes:
|
||||||
|
wps_avg = r.median_wps_erg
|
||||||
|
else:
|
||||||
|
wps_avg = 0
|
||||||
|
|
||||||
_ = myqueue(
|
_ = myqueue(
|
||||||
queuehigh,
|
queuehigh,
|
||||||
handle_calctrimp,
|
handle_calctrimp,
|
||||||
@@ -1947,6 +2067,6 @@ def workout_normv(w, pp=4.0):
|
|||||||
r.sex,
|
r.sex,
|
||||||
r.hrftp,
|
r.hrftp,
|
||||||
r.max,
|
r.max,
|
||||||
r.rest)
|
r.rest, wps_avg)
|
||||||
|
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|||||||
+4
-1
@@ -84,7 +84,10 @@ def cpfit(powerdf, fraclimit=0.0001, nmax=1000):
|
|||||||
p1 = p0
|
p1 = p0
|
||||||
|
|
||||||
thesecs = powerdf['Delta'].to_numpy()
|
thesecs = powerdf['Delta'].to_numpy()
|
||||||
theavpower = powerdf['CP'].to_numpy()
|
try:
|
||||||
|
theavpower = powerdf['CP'].to_numpy()
|
||||||
|
except: # pragma: no cover
|
||||||
|
theavpower = powerdf['CR'].to_numpy()
|
||||||
|
|
||||||
|
|
||||||
if len(thesecs) >= 4:
|
if len(thesecs) >= 4:
|
||||||
|
|||||||
@@ -1299,6 +1299,7 @@ analysischoices = (
|
|||||||
('stats', 'Statistics'),
|
('stats', 'Statistics'),
|
||||||
('compare', 'Compare'),
|
('compare', 'Compare'),
|
||||||
('cp', 'CP chart'),
|
('cp', 'CP chart'),
|
||||||
|
('cr', 'CR chart'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -1370,9 +1371,17 @@ class AnalysisChoiceForm(forms.Form):
|
|||||||
('automatic', 'Critical Power Rolling Data')
|
('automatic', 'Critical Power Rolling Data')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
crfitchoices = (
|
||||||
|
('data', 'Fit to Selected Workouts'),
|
||||||
|
('automatic', 'Critical Stroke Rate Rolling Data')
|
||||||
|
)
|
||||||
|
|
||||||
cpfit = forms.ChoiceField(choices=cpfitchoices,
|
cpfit = forms.ChoiceField(choices=cpfitchoices,
|
||||||
label='Model Fit', initial='data', required=False)
|
label='Model Fit', initial='data', required=False)
|
||||||
|
|
||||||
|
crfit = forms.ChoiceField(choices=crfitchoices,
|
||||||
|
label='Model Fit', initial='data', required=False)
|
||||||
|
|
||||||
cpoverlay = forms.BooleanField(initial=False,
|
cpoverlay = forms.BooleanField(initial=False,
|
||||||
label='Overlay Gold Medal Performance',
|
label='Overlay Gold Medal Performance',
|
||||||
required=False)
|
required=False)
|
||||||
|
|||||||
@@ -1113,6 +1113,75 @@ def interactive_otwcpchart(powerdf, promember=0, rowername="", r=None,
|
|||||||
return [script, div, p1, ratio, message]
|
return [script, div, p1, ratio, message]
|
||||||
|
|
||||||
|
|
||||||
|
def interactive_otwcrchart(powerdf, promember=0, rowername="", r=None,
|
||||||
|
cpfit='data',
|
||||||
|
title='', type='water'):
|
||||||
|
|
||||||
|
powerdf2 = powerdf.filter((pl.col("Delta") > 0) & (pl.col("CR") > 0))
|
||||||
|
|
||||||
|
# plot tools
|
||||||
|
if (promember == 1): # pragma: no cover
|
||||||
|
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
else:
|
||||||
|
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
|
||||||
|
x_axis_type = 'log'
|
||||||
|
|
||||||
|
deltas = powerdf2['Delta'].apply(lambda x: timedeltaconv(x))
|
||||||
|
powerdf2 = powerdf2.with_columns(
|
||||||
|
ftime = deltas.apply(lambda x: strfdelta(x)),
|
||||||
|
Deltaminutes = pl.col("Delta")/60.
|
||||||
|
)
|
||||||
|
|
||||||
|
# there is no Paul's law for OTW
|
||||||
|
|
||||||
|
thesecs = powerdf2['Delta']
|
||||||
|
theavpower = powerdf2['CR']
|
||||||
|
|
||||||
|
p1, fitt, fitpower, ratio = datautils.cpfit(powerdf2)
|
||||||
|
if cpfit == 'automatic' and r is not None:
|
||||||
|
if type == 'water':
|
||||||
|
p1 = [r.r0, r.r1, r.r2, r.r3]
|
||||||
|
ratio = r.cpratio
|
||||||
|
elif type == 'erg': # pragma: no cover
|
||||||
|
p1 = [r.er0, r.er1, r.er2, r.er3]
|
||||||
|
ratio = r.ecrratio
|
||||||
|
|
||||||
|
def fitfunc(pars, x):
|
||||||
|
return abs(pars[0])/(1+(x/abs(pars[2]))) + abs(pars[1])/(1+(x/abs(pars[3])))
|
||||||
|
|
||||||
|
fitpower = fitfunc(p1, fitt)
|
||||||
|
|
||||||
|
message = ""
|
||||||
|
# if len(fitpower[fitpower<0]) > 0:
|
||||||
|
# message = "CP model fit didn't give correct results"
|
||||||
|
|
||||||
|
deltas = fitt.apply(lambda x: timedeltaconv(x))
|
||||||
|
ftime = niceformat(deltas)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fit_data = pl.DataFrame(dict(
|
||||||
|
CR=fitpower,
|
||||||
|
CRmax=ratio*fitpower,
|
||||||
|
duration=fitt/60.,
|
||||||
|
ftime=ftime,
|
||||||
|
))
|
||||||
|
|
||||||
|
if not title:
|
||||||
|
title = "Critical StrokeRate for "+rowername
|
||||||
|
|
||||||
|
chart_dict = {
|
||||||
|
'data': powerdf2.to_dicts(),
|
||||||
|
'fitdata': fit_data.to_dicts(),
|
||||||
|
'title': title,
|
||||||
|
}
|
||||||
|
|
||||||
|
script, div = get_chart("/cr", chart_dict)
|
||||||
|
|
||||||
|
return [script, div, p1, ratio, message]
|
||||||
|
|
||||||
|
|
||||||
def interactive_agegroup_plot(df, distance=2000, duration=None,
|
def interactive_agegroup_plot(df, distance=2000, duration=None,
|
||||||
sex='male', weightcategory='hwt'):
|
sex='male', weightcategory='hwt'):
|
||||||
|
|
||||||
|
|||||||
@@ -1104,6 +1104,18 @@ class Rower(models.Model):
|
|||||||
ep3 = models.FloatField(default=1.0, verbose_name="erg CP p4")
|
ep3 = models.FloatField(default=1.0, verbose_name="erg CP p4")
|
||||||
ecpratio = models.FloatField(default=1.0, verbose_name="erg CP fit ratio")
|
ecpratio = models.FloatField(default=1.0, verbose_name="erg CP fit ratio")
|
||||||
|
|
||||||
|
r0 = models.FloatField(default=1.0, verbose_name="CR r1")
|
||||||
|
r1 = models.FloatField(default=1.0, verbose_name="CR r2")
|
||||||
|
r2 = models.FloatField(default=1.0, verbose_name="CR r3")
|
||||||
|
r3 = models.FloatField(default=1.0, verbose_name="CR r4")
|
||||||
|
crratio = models.FloatField(default=1.0, verbose_name="CR fit ratio")
|
||||||
|
|
||||||
|
er0 = models.FloatField(default=1.0, verbose_name="erg CR r1")
|
||||||
|
er1 = models.FloatField(default=1.0, verbose_name="erg CR r2")
|
||||||
|
er2 = models.FloatField(default=1.0, verbose_name="erg CR r3")
|
||||||
|
er3 = models.FloatField(default=1.0, verbose_name="erg CR r4")
|
||||||
|
ecrratio = models.FloatField(default=1.0, verbose_name="erg CR fit ratio")
|
||||||
|
|
||||||
cprange = models.IntegerField(default=42, verbose_name="Range for calculation of breakthrough workouts and fitness (CP)",
|
cprange = models.IntegerField(default=42, verbose_name="Range for calculation of breakthrough workouts and fitness (CP)",
|
||||||
choices=cppresets)
|
choices=cppresets)
|
||||||
|
|
||||||
@@ -3746,6 +3758,7 @@ class Workout(models.Model):
|
|||||||
trimp = models.IntegerField(default=-1, blank=True)
|
trimp = models.IntegerField(default=-1, blank=True)
|
||||||
rscore = models.IntegerField(default=-1, blank=True)
|
rscore = models.IntegerField(default=-1, blank=True)
|
||||||
hrtss = models.IntegerField(default=-1, blank=True)
|
hrtss = models.IntegerField(default=-1, blank=True)
|
||||||
|
spmtss = models.IntegerField(default=-1, blank=True)
|
||||||
normp = models.IntegerField(default=-1, blank=True)
|
normp = models.IntegerField(default=-1, blank=True)
|
||||||
normv = models.FloatField(default=-1, blank=True)
|
normv = models.FloatField(default=-1, blank=True)
|
||||||
normw = models.FloatField(default=-1, blank=True)
|
normw = models.FloatField(default=-1, blank=True)
|
||||||
|
|||||||
@@ -1,12 +1,22 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# NO CHECKED-IN PROTOBUF GENCODE
|
||||||
# source: rowing-workout-metrics.proto
|
# source: rowing-workout-metrics.proto
|
||||||
# Protobuf Python Version: 4.25.1
|
# Protobuf Python Version: 5.29.0
|
||||||
"""Generated protocol buffer code."""
|
"""Generated protocol buffer code."""
|
||||||
from google.protobuf import descriptor as _descriptor
|
from google.protobuf import descriptor as _descriptor
|
||||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||||
|
from google.protobuf import runtime_version as _runtime_version
|
||||||
from google.protobuf import symbol_database as _symbol_database
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
from google.protobuf.internal import builder as _builder
|
from google.protobuf.internal import builder as _builder
|
||||||
|
_runtime_version.ValidateProtobufRuntimeVersion(
|
||||||
|
_runtime_version.Domain.PUBLIC,
|
||||||
|
5,
|
||||||
|
29,
|
||||||
|
0,
|
||||||
|
'',
|
||||||
|
'rowing-workout-metrics.proto'
|
||||||
|
)
|
||||||
# @@protoc_insertion_point(imports)
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
_sym_db = _symbol_database.Default()
|
_sym_db = _symbol_database.Default()
|
||||||
@@ -14,22 +24,22 @@ _sym_db = _symbol_database.Default()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1crowing-workout-metrics.proto\x12\x16rowing_workout_metrics\"p\n\x15WorkoutMetricsRequest\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x0b\n\x03sex\x18\x02 \x01(\t\x12\x0b\n\x03\x66tp\x18\x03 \x01(\x01\x12\r\n\x05hrftp\x18\x04 \x01(\x01\x12\r\n\x05hrmax\x18\x05 \x01(\x01\x12\r\n\x05hrmin\x18\x06 \x01(\x01\"p\n\x16WorkoutMetricsResponse\x12\x0b\n\x03tss\x18\x01 \x01(\x01\x12\r\n\x05normp\x18\x02 \x01(\x01\x12\r\n\x05trimp\x18\x03 \x01(\x01\x12\r\n\x05hrtss\x18\x04 \x01(\x01\x12\r\n\x05normv\x18\x05 \x01(\x01\x12\r\n\x05normw\x18\x06 \x01(\x01\"=\n\tCPRequest\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x10\n\x08\x66iletype\x18\x02 \x01(\t\x12\x0c\n\x04tarr\x18\x03 \x03(\x01\"<\n\nCPResponse\x12\r\n\x05\x64\x65lta\x18\x01 \x03(\x01\x12\r\n\x05power\x18\x02 \x03(\x01\x12\x10\n\x08\x61vgpower\x18\x03 \x01(\x01\x32\xc7\x01\n\x07Metrics\x12l\n\x0b\x43\x61lcMetrics\x12-.rowing_workout_metrics.WorkoutMetricsRequest\x1a..rowing_workout_metrics.WorkoutMetricsResponse\x12N\n\x05GetCP\x12!.rowing_workout_metrics.CPRequest\x1a\".rowing_workout_metrics.CPResponseB\x1aZ\x18./rowing-workout-metricsb\x06proto3')
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1crowing-workout-metrics.proto\x12\x16rowing_workout_metrics\"\x80\x01\n\x15WorkoutMetricsRequest\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x0b\n\x03sex\x18\x02 \x01(\t\x12\x0b\n\x03\x66tp\x18\x03 \x01(\x01\x12\r\n\x05hrftp\x18\x04 \x01(\x01\x12\r\n\x05hrmax\x18\x05 \x01(\x01\x12\r\n\x05hrmin\x18\x06 \x01(\x01\x12\x0e\n\x06wpsavg\x18\x07 \x01(\x01\"\x80\x01\n\x16WorkoutMetricsResponse\x12\x0b\n\x03tss\x18\x01 \x01(\x01\x12\r\n\x05normp\x18\x02 \x01(\x01\x12\r\n\x05trimp\x18\x03 \x01(\x01\x12\r\n\x05hrtss\x18\x04 \x01(\x01\x12\r\n\x05normv\x18\x05 \x01(\x01\x12\r\n\x05normw\x18\x06 \x01(\x01\x12\x0e\n\x06spmtss\x18\x07 \x01(\x01\"=\n\tCPRequest\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x10\n\x08\x66iletype\x18\x02 \x01(\t\x12\x0c\n\x04tarr\x18\x03 \x03(\x01\"I\n\nCPResponse\x12\r\n\x05\x64\x65lta\x18\x01 \x03(\x01\x12\r\n\x05power\x18\x02 \x03(\x01\x12\x10\n\x08\x61vgpower\x18\x03 \x01(\x01\x12\x0b\n\x03spm\x18\x04 \x03(\x01\x32\xc7\x01\n\x07Metrics\x12l\n\x0b\x43\x61lcMetrics\x12-.rowing_workout_metrics.WorkoutMetricsRequest\x1a..rowing_workout_metrics.WorkoutMetricsResponse\x12N\n\x05GetCP\x12!.rowing_workout_metrics.CPRequest\x1a\".rowing_workout_metrics.CPResponseB\x1aZ\x18./rowing-workout-metricsb\x06proto3')
|
||||||
|
|
||||||
_globals = globals()
|
_globals = globals()
|
||||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'rowing_workout_metrics_pb2', _globals)
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'rowing_workout_metrics_pb2', _globals)
|
||||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
if not _descriptor._USE_C_DESCRIPTORS:
|
||||||
_globals['DESCRIPTOR']._options = None
|
_globals['DESCRIPTOR']._loaded_options = None
|
||||||
_globals['DESCRIPTOR']._serialized_options = b'Z\030./rowing-workout-metrics'
|
_globals['DESCRIPTOR']._serialized_options = b'Z\030./rowing-workout-metrics'
|
||||||
_globals['_WORKOUTMETRICSREQUEST']._serialized_start=56
|
_globals['_WORKOUTMETRICSREQUEST']._serialized_start=57
|
||||||
_globals['_WORKOUTMETRICSREQUEST']._serialized_end=168
|
_globals['_WORKOUTMETRICSREQUEST']._serialized_end=185
|
||||||
_globals['_WORKOUTMETRICSRESPONSE']._serialized_start=170
|
_globals['_WORKOUTMETRICSRESPONSE']._serialized_start=188
|
||||||
_globals['_WORKOUTMETRICSRESPONSE']._serialized_end=282
|
_globals['_WORKOUTMETRICSRESPONSE']._serialized_end=316
|
||||||
_globals['_CPREQUEST']._serialized_start=284
|
_globals['_CPREQUEST']._serialized_start=318
|
||||||
_globals['_CPREQUEST']._serialized_end=345
|
_globals['_CPREQUEST']._serialized_end=379
|
||||||
_globals['_CPRESPONSE']._serialized_start=347
|
_globals['_CPRESPONSE']._serialized_start=381
|
||||||
_globals['_CPRESPONSE']._serialized_end=407
|
_globals['_CPRESPONSE']._serialized_end=454
|
||||||
_globals['_METRICS']._serialized_start=410
|
_globals['_METRICS']._serialized_start=457
|
||||||
_globals['_METRICS']._serialized_end=609
|
_globals['_METRICS']._serialized_end=656
|
||||||
# @@protoc_insertion_point(module_scope)
|
# @@protoc_insertion_point(module_scope)
|
||||||
|
|||||||
@@ -1,9 +1,29 @@
|
|||||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||||
"""Client and server classes corresponding to protobuf-defined services."""
|
"""Client and server classes corresponding to protobuf-defined services."""
|
||||||
import grpc
|
import grpc
|
||||||
|
import warnings
|
||||||
|
|
||||||
import rowers.rowing_workout_metrics_pb2 as rowing__workout__metrics__pb2
|
import rowers.rowing_workout_metrics_pb2 as rowing__workout__metrics__pb2
|
||||||
|
|
||||||
|
GRPC_GENERATED_VERSION = '1.70.0'
|
||||||
|
GRPC_VERSION = grpc.__version__
|
||||||
|
_version_not_supported = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
from grpc._utilities import first_version_is_lower
|
||||||
|
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
||||||
|
except ImportError:
|
||||||
|
_version_not_supported = True
|
||||||
|
|
||||||
|
if _version_not_supported:
|
||||||
|
raise RuntimeError(
|
||||||
|
f'The grpc package installed is at version {GRPC_VERSION},'
|
||||||
|
+ f' but the generated code in rowing_workout_metrics_pb2_grpc.py depends on'
|
||||||
|
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
|
||||||
|
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
|
||||||
|
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MetricsStub(object):
|
class MetricsStub(object):
|
||||||
"""OTW-metrics service definition
|
"""OTW-metrics service definition
|
||||||
@@ -19,12 +39,12 @@ class MetricsStub(object):
|
|||||||
'/rowing_workout_metrics.Metrics/CalcMetrics',
|
'/rowing_workout_metrics.Metrics/CalcMetrics',
|
||||||
request_serializer=rowing__workout__metrics__pb2.WorkoutMetricsRequest.SerializeToString,
|
request_serializer=rowing__workout__metrics__pb2.WorkoutMetricsRequest.SerializeToString,
|
||||||
response_deserializer=rowing__workout__metrics__pb2.WorkoutMetricsResponse.FromString,
|
response_deserializer=rowing__workout__metrics__pb2.WorkoutMetricsResponse.FromString,
|
||||||
)
|
_registered_method=True)
|
||||||
self.GetCP = channel.unary_unary(
|
self.GetCP = channel.unary_unary(
|
||||||
'/rowing_workout_metrics.Metrics/GetCP',
|
'/rowing_workout_metrics.Metrics/GetCP',
|
||||||
request_serializer=rowing__workout__metrics__pb2.CPRequest.SerializeToString,
|
request_serializer=rowing__workout__metrics__pb2.CPRequest.SerializeToString,
|
||||||
response_deserializer=rowing__workout__metrics__pb2.CPResponse.FromString,
|
response_deserializer=rowing__workout__metrics__pb2.CPResponse.FromString,
|
||||||
)
|
_registered_method=True)
|
||||||
|
|
||||||
|
|
||||||
class MetricsServicer(object):
|
class MetricsServicer(object):
|
||||||
@@ -60,6 +80,7 @@ def add_MetricsServicer_to_server(servicer, server):
|
|||||||
generic_handler = grpc.method_handlers_generic_handler(
|
generic_handler = grpc.method_handlers_generic_handler(
|
||||||
'rowing_workout_metrics.Metrics', rpc_method_handlers)
|
'rowing_workout_metrics.Metrics', rpc_method_handlers)
|
||||||
server.add_generic_rpc_handlers((generic_handler,))
|
server.add_generic_rpc_handlers((generic_handler,))
|
||||||
|
server.add_registered_method_handlers('rowing_workout_metrics.Metrics', rpc_method_handlers)
|
||||||
|
|
||||||
|
|
||||||
# This class is part of an EXPERIMENTAL API.
|
# This class is part of an EXPERIMENTAL API.
|
||||||
@@ -78,11 +99,21 @@ class Metrics(object):
|
|||||||
wait_for_ready=None,
|
wait_for_ready=None,
|
||||||
timeout=None,
|
timeout=None,
|
||||||
metadata=None):
|
metadata=None):
|
||||||
return grpc.experimental.unary_unary(request, target, '/rowing_workout_metrics.Metrics/CalcMetrics',
|
return grpc.experimental.unary_unary(
|
||||||
|
request,
|
||||||
|
target,
|
||||||
|
'/rowing_workout_metrics.Metrics/CalcMetrics',
|
||||||
rowing__workout__metrics__pb2.WorkoutMetricsRequest.SerializeToString,
|
rowing__workout__metrics__pb2.WorkoutMetricsRequest.SerializeToString,
|
||||||
rowing__workout__metrics__pb2.WorkoutMetricsResponse.FromString,
|
rowing__workout__metrics__pb2.WorkoutMetricsResponse.FromString,
|
||||||
options, channel_credentials,
|
options,
|
||||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
channel_credentials,
|
||||||
|
insecure,
|
||||||
|
call_credentials,
|
||||||
|
compression,
|
||||||
|
wait_for_ready,
|
||||||
|
timeout,
|
||||||
|
metadata,
|
||||||
|
_registered_method=True)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def GetCP(request,
|
def GetCP(request,
|
||||||
@@ -95,8 +126,18 @@ class Metrics(object):
|
|||||||
wait_for_ready=None,
|
wait_for_ready=None,
|
||||||
timeout=None,
|
timeout=None,
|
||||||
metadata=None):
|
metadata=None):
|
||||||
return grpc.experimental.unary_unary(request, target, '/rowing_workout_metrics.Metrics/GetCP',
|
return grpc.experimental.unary_unary(
|
||||||
|
request,
|
||||||
|
target,
|
||||||
|
'/rowing_workout_metrics.Metrics/GetCP',
|
||||||
rowing__workout__metrics__pb2.CPRequest.SerializeToString,
|
rowing__workout__metrics__pb2.CPRequest.SerializeToString,
|
||||||
rowing__workout__metrics__pb2.CPResponse.FromString,
|
rowing__workout__metrics__pb2.CPResponse.FromString,
|
||||||
options, channel_credentials,
|
options,
|
||||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
channel_credentials,
|
||||||
|
insecure,
|
||||||
|
call_credentials,
|
||||||
|
compression,
|
||||||
|
wait_for_ready,
|
||||||
|
timeout,
|
||||||
|
metadata,
|
||||||
|
_registered_method=True)
|
||||||
|
|||||||
+10
-1
@@ -1639,6 +1639,7 @@ def handle_calctrimp(id,
|
|||||||
hrftp,
|
hrftp,
|
||||||
hrmax,
|
hrmax,
|
||||||
hrmin,
|
hrmin,
|
||||||
|
wps_avg,
|
||||||
debug=False, **kwargs):
|
debug=False, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
@@ -1648,6 +1649,7 @@ def handle_calctrimp(id,
|
|||||||
hrtss = 0
|
hrtss = 0
|
||||||
normv = 0
|
normv = 0
|
||||||
normw = 0
|
normw = 0
|
||||||
|
spmtss = 0
|
||||||
|
|
||||||
# check what the real file name is
|
# check what the real file name is
|
||||||
if os.path.exists(csvfilename):
|
if os.path.exists(csvfilename):
|
||||||
@@ -1680,6 +1682,7 @@ def handle_calctrimp(id,
|
|||||||
hrftp=hrftp,
|
hrftp=hrftp,
|
||||||
hrmax=hrmax,
|
hrmax=hrmax,
|
||||||
hrmin=hrmin,
|
hrmin=hrmin,
|
||||||
|
wpsavg=wps_avg,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
response = stub.CalcMetrics(req, timeout=60)
|
response = stub.CalcMetrics(req, timeout=60)
|
||||||
@@ -1693,13 +1696,15 @@ def handle_calctrimp(id,
|
|||||||
normv = response.normv
|
normv = response.normv
|
||||||
normw = response.normw
|
normw = response.normw
|
||||||
hrtss = response.hrtss
|
hrtss = response.hrtss
|
||||||
dologging('metrics.log','File {csvfile}. Got tss {tss}, normp {normp} trimp {trimp} normv {normv} normw {normw} hrtss {hrtss}'.format(
|
spmtss = response.spmtss
|
||||||
|
dologging('metrics.log','File {csvfile}. Got tss {tss}, normp {normp} trimp {trimp} normv {normv} normw {normw} hrtss {hrtss} spmtss {spmtss}'.format(
|
||||||
tss = tss,
|
tss = tss,
|
||||||
normp = normp,
|
normp = normp,
|
||||||
trimp = trimp,
|
trimp = trimp,
|
||||||
normv = normv,
|
normv = normv,
|
||||||
normw = normw,
|
normw = normw,
|
||||||
hrtss = hrtss,
|
hrtss = hrtss,
|
||||||
|
spmtss = spmtss,
|
||||||
csvfile=csvfile,
|
csvfile=csvfile,
|
||||||
))
|
))
|
||||||
|
|
||||||
@@ -1740,6 +1745,9 @@ def handle_calctrimp(id,
|
|||||||
if hrtss > 1000: # pragma: no cover
|
if hrtss > 1000: # pragma: no cover
|
||||||
hrtss = 0
|
hrtss = 0
|
||||||
|
|
||||||
|
if spmtss > 1000: # pragma: no cover
|
||||||
|
spmtss = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
workout = Workout.objects.get(id=id)
|
workout = Workout.objects.get(id=id)
|
||||||
except Workout.DoesNotExist: # pragma: no cover
|
except Workout.DoesNotExist: # pragma: no cover
|
||||||
@@ -1752,6 +1760,7 @@ def handle_calctrimp(id,
|
|||||||
workout.hrtss = int(hrtss)
|
workout.hrtss = int(hrtss)
|
||||||
workout.normv = normv
|
workout.normv = normv
|
||||||
workout.normw = normw
|
workout.normw = normw
|
||||||
|
workout.spmtss = int(spmtss)
|
||||||
workout.save()
|
workout.save()
|
||||||
dologging('metrics.log','Saving to workout {id} {obscure}'.format(
|
dologging('metrics.log','Saving to workout {id} {obscure}'.format(
|
||||||
id = id,
|
id = id,
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
{{ the_div|safe }}
|
||||||
|
<p>
|
||||||
|
<table width="100%" class="listtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> Duration</th>
|
||||||
|
<th> Stroke Estimate 1</th>
|
||||||
|
<th> Stroke Estimate 2</th>
|
||||||
|
<tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>{{ duration }}</td>
|
||||||
|
<td>{{ power }}</td>
|
||||||
|
<td>{{ upper }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
@@ -124,13 +124,13 @@
|
|||||||
<script>
|
<script>
|
||||||
// script for chart options form
|
// script for chart options form
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|
||||||
// Get the form fields and hidden div
|
// Get the form fields and hidden div
|
||||||
var functionfield = $("#id_function");
|
var functionfield = $("#id_function");
|
||||||
var plotfield = $("#id_plotfield").parent().parent();
|
var plotfield = $("#id_plotfield").parent().parent();
|
||||||
var x_param = $("#id_xparam").parent().parent();
|
var x_param = $("#id_xparam").parent().parent();
|
||||||
var y_param = $("#id_yparam").parent().parent();
|
var y_param = $("#id_yparam").parent().parent();
|
||||||
|
|
||||||
var groupby = $("#id_groupby").parent().parent();
|
var groupby = $("#id_groupby").parent().parent();
|
||||||
var binsize = $("#id_binsize").parent().parent();
|
var binsize = $("#id_binsize").parent().parent();
|
||||||
var errorbars = $("#id_ploterrorbars").parent().parent();
|
var errorbars = $("#id_ploterrorbars").parent().parent();
|
||||||
@@ -139,17 +139,18 @@
|
|||||||
var spmmax = $("#id_spmmax").parent().parent();
|
var spmmax = $("#id_spmmax").parent().parent();
|
||||||
var workmin = $("#id_workmin").parent().parent();
|
var workmin = $("#id_workmin").parent().parent();
|
||||||
var workmax = $("#id_workmax").parent().parent();
|
var workmax = $("#id_workmax").parent().parent();
|
||||||
|
|
||||||
var xaxis = $("#id_xaxis").parent().parent();
|
var xaxis = $("#id_xaxis").parent().parent();
|
||||||
var yaxis1 = $("#id_yaxis1").parent().parent();
|
var yaxis1 = $("#id_yaxis1").parent().parent();
|
||||||
var yaxis2 = $("#id_yaxis2").parent().parent();
|
var yaxis2 = $("#id_yaxis2").parent().parent();
|
||||||
var plottype = $("#id_plottype").parent().parent();
|
var plottype = $("#id_plottype").parent().parent();
|
||||||
|
|
||||||
var reststrokes = $("#id_includereststrokes").parent().parent();
|
var reststrokes = $("#id_includereststrokes").parent().parent();
|
||||||
var trendline = $("#id_trendline").parent().parent();
|
var trendline = $("#id_trendline").parent().parent();
|
||||||
var piece = $("#id_piece").parent().parent();
|
var piece = $("#id_piece").parent().parent();
|
||||||
var cpfit = $("#id_cpfit").parent().parent();
|
var cpfit = $("#id_cpfit").parent().parent();
|
||||||
var cpoverlay = $("#id_cpoverlay").parent().parent();
|
var crfit = $("#id_crfit").parent().parent();
|
||||||
|
var cpoverlay = $("#id_cpoverlay").parent().parent();
|
||||||
|
|
||||||
|
|
||||||
// Hide the fields.
|
// Hide the fields.
|
||||||
@@ -166,15 +167,16 @@
|
|||||||
yaxis1.hide();
|
yaxis1.hide();
|
||||||
yaxis2.hide();
|
yaxis2.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
// reststrokes.hide();
|
// reststrokes.hide();
|
||||||
workmin.hide();
|
workmin.hide();
|
||||||
workmax.hide();
|
workmax.hide();
|
||||||
spmmin.hide();
|
spmmin.hide();
|
||||||
spmmax.hide();
|
spmmax.hide();
|
||||||
cpfit.hide();
|
cpfit.hide();
|
||||||
cpoverlay.hide();
|
crfit.hide();
|
||||||
piece.hide();
|
cpoverlay.hide();
|
||||||
trendline.hide();
|
piece.hide();
|
||||||
|
trendline.hide();
|
||||||
|
|
||||||
if (functionfield.val() == 'boxplot') {
|
if (functionfield.val() == 'boxplot') {
|
||||||
plotfield.show();
|
plotfield.show();
|
||||||
@@ -214,11 +216,16 @@
|
|||||||
reststrokes.show();
|
reststrokes.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (functionfield.val() == 'cp') {
|
if (functionfield.val() == 'cp') {
|
||||||
cpfit.show();
|
cpfit.show();
|
||||||
piece.show();
|
piece.show();
|
||||||
cpoverlay.show();
|
cpoverlay.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (functionfield.val() == 'cr') {
|
||||||
|
crfit.show();
|
||||||
|
piece.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Setup an event listener for when the state of the
|
// Setup an event listener for when the state of the
|
||||||
@@ -241,15 +248,16 @@
|
|||||||
palette.hide();
|
palette.hide();
|
||||||
binsize.hide();
|
binsize.hide();
|
||||||
errorbars.hide();
|
errorbars.hide();
|
||||||
trendline.hide();
|
trendline.hide();
|
||||||
xaxis.hide();
|
xaxis.hide();
|
||||||
yaxis1.hide();
|
yaxis1.hide();
|
||||||
yaxis2.hide();
|
yaxis2.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
reststrokes.show();
|
reststrokes.show();
|
||||||
cpfit.hide();
|
cpfit.hide();
|
||||||
cpoverlay.hide();
|
crfit.hide();
|
||||||
piece.hide();
|
cpoverlay.hide();
|
||||||
|
piece.hide();
|
||||||
}
|
}
|
||||||
else if (Value=='histo') {
|
else if (Value=='histo') {
|
||||||
plotfield.show();
|
plotfield.show();
|
||||||
@@ -262,16 +270,17 @@
|
|||||||
groupby.hide();
|
groupby.hide();
|
||||||
palette.hide();
|
palette.hide();
|
||||||
binsize.hide();
|
binsize.hide();
|
||||||
trendline.hide();
|
trendline.hide();
|
||||||
errorbars.hide();
|
errorbars.hide();
|
||||||
xaxis.hide();
|
xaxis.hide();
|
||||||
yaxis1.hide();
|
yaxis1.hide();
|
||||||
yaxis2.hide();
|
yaxis2.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
reststrokes.show();
|
reststrokes.show();
|
||||||
cpfit.hide();
|
cpfit.hide();
|
||||||
cpoverlay.hide();
|
crfit.hide();
|
||||||
piece.hide();
|
cpoverlay.hide();
|
||||||
|
piece.hide();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (Value=='trendflex') {
|
else if (Value=='trendflex') {
|
||||||
@@ -284,17 +293,18 @@
|
|||||||
spmmin.show();
|
spmmin.show();
|
||||||
spmmax.show();
|
spmmax.show();
|
||||||
workmin.show();
|
workmin.show();
|
||||||
trendline.hide();
|
trendline.hide();
|
||||||
workmax.show();
|
workmax.show();
|
||||||
plotfield.hide();
|
plotfield.hide();
|
||||||
xaxis.hide();
|
xaxis.hide();
|
||||||
yaxis1.hide();
|
yaxis1.hide();
|
||||||
yaxis2.hide();
|
yaxis2.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
reststrokes.show();
|
reststrokes.show();
|
||||||
cpfit.hide();
|
cpfit.hide();
|
||||||
cpoverlay.hide();
|
crfit.hide();
|
||||||
piece.hide();
|
cpoverlay.hide();
|
||||||
|
piece.hide();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (Value=='flexall') {
|
else if (Value=='flexall') {
|
||||||
@@ -305,7 +315,7 @@
|
|||||||
y_param.hide();
|
y_param.hide();
|
||||||
groupby.hide();
|
groupby.hide();
|
||||||
spmmin.hide();
|
spmmin.hide();
|
||||||
trendline.show();
|
trendline.show();
|
||||||
spmmax.hide();
|
spmmax.hide();
|
||||||
workmin.hide();
|
workmin.hide();
|
||||||
workmax.hide();
|
workmax.hide();
|
||||||
@@ -314,10 +324,11 @@
|
|||||||
binsize.hide();
|
binsize.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
errorbars.hide();
|
errorbars.hide();
|
||||||
reststrokes.show();
|
reststrokes.show();
|
||||||
cpfit.hide();
|
cpfit.hide();
|
||||||
cpoverlay.hide();
|
crfit.hide();
|
||||||
piece.hide();
|
cpoverlay.hide();
|
||||||
|
piece.hide();
|
||||||
}
|
}
|
||||||
else if (Value=='stats') {
|
else if (Value=='stats') {
|
||||||
xaxis.hide();
|
xaxis.hide();
|
||||||
@@ -331,11 +342,12 @@
|
|||||||
binsize.hide();
|
binsize.hide();
|
||||||
errorbars.hide();
|
errorbars.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
trendline.hide();
|
trendline.hide();
|
||||||
reststrokes.show();
|
reststrokes.show();
|
||||||
cpfit.hide();
|
cpfit.hide();
|
||||||
cpoverlay.hide();
|
crfit.hide();
|
||||||
piece.hide();
|
cpoverlay.hide();
|
||||||
|
piece.hide();
|
||||||
}
|
}
|
||||||
else if (Value=='compare') {
|
else if (Value=='compare') {
|
||||||
xaxis.show();
|
xaxis.show();
|
||||||
@@ -350,18 +362,19 @@
|
|||||||
workmax.hide();
|
workmax.hide();
|
||||||
plotfield.hide();
|
plotfield.hide();
|
||||||
palette.hide();
|
palette.hide();
|
||||||
trendline.hide();
|
trendline.hide();
|
||||||
binsize.hide();
|
binsize.hide();
|
||||||
plottype.show();
|
plottype.show();
|
||||||
errorbars.hide();
|
errorbars.hide();
|
||||||
piece.hide();
|
piece.hide();
|
||||||
cpfit.hide();
|
cpfit.hide();
|
||||||
cpoverlay.hide();
|
crfit.hide();
|
||||||
reststrokes.show();
|
cpoverlay.hide();
|
||||||
|
reststrokes.show();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (Value=='cp') {
|
else if (Value=='cp') {
|
||||||
plotfield.hide();
|
plotfield.hide();
|
||||||
spmmin.hide();
|
spmmin.hide();
|
||||||
spmmax.hide();
|
spmmax.hide();
|
||||||
@@ -369,7 +382,7 @@
|
|||||||
workmax.hide();
|
workmax.hide();
|
||||||
x_param.hide();
|
x_param.hide();
|
||||||
y_param.hide();
|
y_param.hide();
|
||||||
trendline.hide();
|
trendline.hide();
|
||||||
groupby.hide();
|
groupby.hide();
|
||||||
palette.hide();
|
palette.hide();
|
||||||
binsize.hide();
|
binsize.hide();
|
||||||
@@ -378,10 +391,34 @@
|
|||||||
yaxis1.hide();
|
yaxis1.hide();
|
||||||
yaxis2.hide();
|
yaxis2.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
reststrokes.hide();
|
reststrokes.hide();
|
||||||
cpfit.show();
|
cpfit.show();
|
||||||
cpoverlay.hide();
|
crfit.hide();
|
||||||
piece.show();
|
cpoverlay.hide();
|
||||||
|
piece.show();
|
||||||
|
}
|
||||||
|
else if (Value=='cr') {
|
||||||
|
plotfield.hide();
|
||||||
|
spmmin.hide();
|
||||||
|
spmmax.hide();
|
||||||
|
workmin.hide();
|
||||||
|
workmax.hide();
|
||||||
|
x_param.hide();
|
||||||
|
y_param.hide();
|
||||||
|
trendline.hide();
|
||||||
|
groupby.hide();
|
||||||
|
palette.hide();
|
||||||
|
binsize.hide();
|
||||||
|
errorbars.hide();
|
||||||
|
xaxis.hide();
|
||||||
|
yaxis1.hide();
|
||||||
|
yaxis2.hide();
|
||||||
|
plottype.hide();
|
||||||
|
reststrokes.hide();
|
||||||
|
cpfit.hide();
|
||||||
|
crfit.show();
|
||||||
|
cpoverlay.hide();
|
||||||
|
piece.show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
<p>TRIMP: TRaining IMPact. A way to combine duration and heart rate into a single number.</p>
|
<p>TRIMP: TRaining IMPact. A way to combine duration and heart rate into a single number.</p>
|
||||||
<p>rScore: Score based on rPower and workout duration to estimate training effect</p>
|
<p>rScore: Score based on rPower and workout duration to estimate training effect</p>
|
||||||
<p>rScore (HR): Score based on heart rate, designed to give values comparable to rScore. Used instead of rScore for workouts without power data.</p>
|
<p>rScore (HR): Score based on heart rate, designed to give values comparable to rScore. Used instead of rScore for workouts without power data.</p>
|
||||||
|
<p>rScore (SPM): Score based on stroke rate, designed to give values comparable to rScore. Used instead of rScore for workouts without power or heart rate data.</p>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ class AsyncTaskTests(TestCase):
|
|||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
def test_handle_calctrimp(self, mocked_sqlalchemy):
|
def test_handle_calctrimp(self, mocked_sqlalchemy):
|
||||||
result = get_random_file()
|
result = get_random_file()
|
||||||
res = tasks.handle_calctrimp(1,result['filename'],200,'male',160,90,52)
|
res = tasks.handle_calctrimp(1,result['filename'],200,'male',160,90,52,400)
|
||||||
self.assertEqual(res,1)
|
self.assertEqual(res,1)
|
||||||
|
|
||||||
@patch('rowers.tasks.EmailMessage',side_effect=MockEmailMessage)
|
@patch('rowers.tasks.EmailMessage',side_effect=MockEmailMessage)
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -294,6 +294,8 @@ def analysis_new(request,
|
|||||||
df = comparisondata(tw, options)
|
df = comparisondata(tw, options)
|
||||||
elif function == 'cp': # pragma: no cover
|
elif function == 'cp': # pragma: no cover
|
||||||
df = cpdata(tw, options)
|
df = cpdata(tw, options)
|
||||||
|
elif function == 'cr': # pragma: no cover
|
||||||
|
df = crdata(tw, options)
|
||||||
options['savedata'] = False
|
options['savedata'] = False
|
||||||
request.session['options'] = options
|
request.session['options'] = options
|
||||||
try:
|
try:
|
||||||
@@ -661,7 +663,7 @@ def cpdata(workouts, options):
|
|||||||
r = u.rower
|
r = u.rower
|
||||||
|
|
||||||
|
|
||||||
delta, cpvalue, avgpower, workoutnames, urls = dataprep.fetchcp_new(
|
delta, cpvalue, crvalue, avgpower, workoutnames, urls = dataprep.fetchcp_new(
|
||||||
r, workouts)
|
r, workouts)
|
||||||
|
|
||||||
powerdf = pl.DataFrame({
|
powerdf = pl.DataFrame({
|
||||||
@@ -811,6 +813,139 @@ def cpdata(workouts, options):
|
|||||||
|
|
||||||
return (script, html_content)
|
return (script, html_content)
|
||||||
|
|
||||||
|
def crdata(workouts, options):
|
||||||
|
start = timezone.now()
|
||||||
|
userid = options['userid']
|
||||||
|
cpfit = options['crfit']
|
||||||
|
cpoverlay = options['cpoverlay']
|
||||||
|
|
||||||
|
u = User.objects.get(id=userid)
|
||||||
|
r = u.rower
|
||||||
|
|
||||||
|
|
||||||
|
delta, cpvalue, crvalue, avgpower, workoutnames, urls = dataprep.fetchcp_new(
|
||||||
|
r, workouts)
|
||||||
|
|
||||||
|
powerdf = pl.DataFrame({
|
||||||
|
'Delta': delta,
|
||||||
|
'CR': crvalue,
|
||||||
|
'workout': workoutnames,
|
||||||
|
'url': urls,
|
||||||
|
})
|
||||||
|
|
||||||
|
savedata = options.get('savedata',False)
|
||||||
|
if savedata: # pragma: no cover
|
||||||
|
return powerdf.to_pandas()
|
||||||
|
|
||||||
|
if powerdf.is_empty(): # pragma: no cover
|
||||||
|
return('', '<p>No valid data found</p>')
|
||||||
|
|
||||||
|
|
||||||
|
powerdf = powerdf.lazy().filter(pl.col("CR")>0)
|
||||||
|
powerdf = powerdf.sort(["Delta", "CR"], descending=[False, True])
|
||||||
|
powerdf = powerdf.unique(subset="Delta", keep="first")
|
||||||
|
powerdf = powerdf.fill_nan(None).drop_nulls()
|
||||||
|
powerdf = powerdf.collect()
|
||||||
|
|
||||||
|
rowername = r.user.first_name+" "+r.user.last_name
|
||||||
|
|
||||||
|
wcdurations = []
|
||||||
|
wcpower = []
|
||||||
|
|
||||||
|
if len(powerdf) != 0:
|
||||||
|
datefirst = pd.Series(w.date for w in workouts).min()
|
||||||
|
datelast = pd.Series(w.date for w in workouts).max()
|
||||||
|
title = 'Critical Stroke Rate chart for {name}, from {d1} to {d2}'.format(
|
||||||
|
name=rowername,
|
||||||
|
d1=datefirst,
|
||||||
|
d2=datelast,
|
||||||
|
)
|
||||||
|
wtype = 'water'
|
||||||
|
if workouts[0].workouttype in mytypes.otetypes: # pragma: no cover
|
||||||
|
wtype = 'erg'
|
||||||
|
if workouts[0].workouttype == 'bikeerg': # pragma: no cover
|
||||||
|
# for Mike
|
||||||
|
wtype = 'erg'
|
||||||
|
|
||||||
|
|
||||||
|
res = interactive_otwcrchart(powerdf, promember=True, rowername=rowername, r=r,
|
||||||
|
cpfit=cpfit, title=title, type=wtype,)
|
||||||
|
|
||||||
|
script = res[0]
|
||||||
|
div = res[1]
|
||||||
|
p1 = res[2]
|
||||||
|
ratio = res[3]
|
||||||
|
else: # pragma: no cover
|
||||||
|
script = ''
|
||||||
|
div = '<p>No ranking pieces found.</p>'
|
||||||
|
p1 = [1, 1, 1, 1]
|
||||||
|
ratio = 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
minutes = options['piece']
|
||||||
|
if minutes != 0:
|
||||||
|
# minutes = 77
|
||||||
|
try:
|
||||||
|
hourvalue, tvalue = divmod(minutes, 60)
|
||||||
|
except: # pragma: no cover
|
||||||
|
hourvalue = 0
|
||||||
|
tvalue = minutes
|
||||||
|
# hourvalue = 1, tvalue = 17
|
||||||
|
try:
|
||||||
|
hourvalue = int(hourvalue)
|
||||||
|
except TypeError: # pragma: no cover
|
||||||
|
hourvalue = 0
|
||||||
|
try:
|
||||||
|
minutevalue = int(tvalue)
|
||||||
|
except TypeError: # pragma: no cover
|
||||||
|
minutevalue = 0
|
||||||
|
|
||||||
|
tvalue = int(60*(tvalue-minutevalue))
|
||||||
|
|
||||||
|
if hourvalue >= 24: # pragma: no cover
|
||||||
|
hourvalue = 23
|
||||||
|
pieceduration = datetime.time(
|
||||||
|
minute=minutevalue,
|
||||||
|
hour=hourvalue,
|
||||||
|
second=tvalue,
|
||||||
|
)
|
||||||
|
|
||||||
|
pieceseconds = 3600.*pieceduration.hour+60. * \
|
||||||
|
pieceduration.minute+pieceduration.second
|
||||||
|
# CP model
|
||||||
|
pwr = p1[0]/(1+pieceseconds/p1[2])
|
||||||
|
pwr += p1[1]/(1+pieceseconds/p1[3])
|
||||||
|
|
||||||
|
if pwr <= 0: # pragma: no cover
|
||||||
|
pwr = 50.
|
||||||
|
|
||||||
|
if not np.isnan(pwr):
|
||||||
|
try:
|
||||||
|
pwr2 = pwr*ratio
|
||||||
|
except: # pragma: no cover
|
||||||
|
pwr2 = pwr
|
||||||
|
|
||||||
|
duration = timedeltaconv(pieceseconds)
|
||||||
|
power = int(pwr)
|
||||||
|
upper = int(pwr2)
|
||||||
|
else: # pragma: no cover
|
||||||
|
duration = timedeltaconv(0)
|
||||||
|
power = 0
|
||||||
|
upper = 0
|
||||||
|
|
||||||
|
htmly = env.get_template('otwcr.html')
|
||||||
|
html_content = htmly.render({
|
||||||
|
'script': script,
|
||||||
|
'the_div': div,
|
||||||
|
'duration': duration,
|
||||||
|
'power': power,
|
||||||
|
'upper': upper,
|
||||||
|
})
|
||||||
|
|
||||||
|
return (script, html_content)
|
||||||
|
|
||||||
|
|
||||||
def statsdata(workouts, options):
|
def statsdata(workouts, options):
|
||||||
#try:
|
#try:
|
||||||
@@ -1063,6 +1198,8 @@ def analysis_view_data(request, userid=0):
|
|||||||
script, div = comparisondata(workouts, options)
|
script, div = comparisondata(workouts, options)
|
||||||
elif function == 'cp': # pragma: no cover
|
elif function == 'cp': # pragma: no cover
|
||||||
script, div = cpdata(workouts, options)
|
script, div = cpdata(workouts, options)
|
||||||
|
elif function == 'cr': # pragma: no cover
|
||||||
|
script, div = crdata(workouts, options)
|
||||||
else: # pragma: no cover
|
else: # pragma: no cover
|
||||||
script = ''
|
script = ''
|
||||||
div = 'Unknown analysis functions'
|
div = 'Unknown analysis functions'
|
||||||
|
|||||||
@@ -1035,8 +1035,15 @@ def strokedatajson_v2(request, id):
|
|||||||
datadf = dataprep.dataplep(
|
datadf = dataprep.dataplep(
|
||||||
rowdata, id=row.id, bands=True, barchart=True, otwpower=True, empower=True)
|
rowdata, id=row.id, bands=True, barchart=True, otwpower=True, empower=True)
|
||||||
|
|
||||||
|
if row.workouttype in mytypes.otwtypes:
|
||||||
|
wps_avg = r.median_wps
|
||||||
|
elif row.workouttype in mytypes.ergtypes:
|
||||||
|
wps_avg = r.median_wps_erg
|
||||||
|
else:
|
||||||
|
wps_avg = 0
|
||||||
|
|
||||||
_ = myqueue(queuehigh, handle_calctrimp, row.id,
|
_ = myqueue(queuehigh, handle_calctrimp, row.id,
|
||||||
row.csvfilename, r.ftp, r.sex, r.hrftp, r.max, r.rest)
|
row.csvfilename, r.ftp, r.sex, r.hrftp, r.max, r.rest, wps_avg)
|
||||||
|
|
||||||
isbreakthrough, ishard = dataprep.checkbreakthrough(row, r)
|
isbreakthrough, ishard = dataprep.checkbreakthrough(row, r)
|
||||||
|
|
||||||
|
|||||||
@@ -3758,6 +3758,9 @@ def workout_stats_view(request, id=0, message="", successmessage=""):
|
|||||||
# TRIMP
|
# TRIMP
|
||||||
trimp, hrtss = dataprep.workout_trimp(w)
|
trimp, hrtss = dataprep.workout_trimp(w)
|
||||||
|
|
||||||
|
# SPMTSS
|
||||||
|
spmtss = dataprep.workout_spmtss(w)
|
||||||
|
|
||||||
otherstats['trimp'] = {
|
otherstats['trimp'] = {
|
||||||
'verbose_name': 'TRIMP',
|
'verbose_name': 'TRIMP',
|
||||||
'value': int(trimp),
|
'value': int(trimp),
|
||||||
@@ -3770,6 +3773,12 @@ def workout_stats_view(request, id=0, message="", successmessage=""):
|
|||||||
'unit': ''
|
'unit': ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
otherstats['spmScore'] = {
|
||||||
|
'verbose_name': 'rScore (SPM)',
|
||||||
|
'value': int(spmtss),
|
||||||
|
'unit': ''
|
||||||
|
}
|
||||||
|
|
||||||
return render(request,
|
return render(request,
|
||||||
'workoutstats.html',
|
'workoutstats.html',
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user