Add the ability to cache our deco state

We kept reduing all the deco calculations, including the previous dives
(if any) for each segment we add to the dive plan. This simply remembers
the last stage and then just adds to that.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Dirk Hohndel 2013-01-06 11:13:46 -08:00
parent c607f09f40
commit c8830ffe48
3 changed files with 60 additions and 8 deletions

44
deco.c
View file

@ -11,8 +11,11 @@
* deco_allowed_depth(tissues_tolerance, surface_pressure, dive, smooth) * deco_allowed_depth(tissues_tolerance, surface_pressure, dive, smooth)
* - ceiling based on lead tissue, surface pressure, 3m increments or smooth * - ceiling based on lead tissue, surface pressure, 3m increments or smooth
* set_gf(gflow, gfhigh) - set Buehlmann gradient factors * set_gf(gflow, gfhigh) - set Buehlmann gradient factors
* void cache_deco_state(tissue_tolerance, char **datap) - cache the relevant data allocate memory if needed
* double restore_deco_state(char *data) - restore the state and return the tissue_tolerance
*/ */
#include <math.h> #include <math.h>
#include <string.h>
#include "dive.h" #include "dive.h"
//! Option structure for Buehlmann decompression. //! Option structure for Buehlmann decompression.
@ -88,6 +91,7 @@ double tissue_he_sat[16];
double tissue_tolerated_ambient_pressure[16]; double tissue_tolerated_ambient_pressure[16];
int ci_pointing_to_guiding_tissue; int ci_pointing_to_guiding_tissue;
double gf_low_position_this_dive; double gf_low_position_this_dive;
#define TISSUE_ARRAY_SZ sizeof(tissue_n2_sat)
static double actual_gradient_limit(const struct dive_data *data) static double actual_gradient_limit(const struct dive_data *data)
{ {
@ -222,6 +226,46 @@ void clear_deco(double surface_pressure)
gf_low_position_this_dive = buehlmann_config.gf_low_position_min; gf_low_position_this_dive = buehlmann_config.gf_low_position_min;
} }
void cache_deco_state(double tissue_tolerance, char **cached_datap)
{
char *data = *cached_datap;
if (!data) {
data = malloc(3 * TISSUE_ARRAY_SZ + 2 * sizeof(double) + sizeof(int));
*cached_datap = data;
}
memcpy(data, tissue_n2_sat, TISSUE_ARRAY_SZ);
data += TISSUE_ARRAY_SZ;
memcpy(data, tissue_he_sat, TISSUE_ARRAY_SZ);
data += TISSUE_ARRAY_SZ;
memcpy(data, tissue_tolerated_ambient_pressure, TISSUE_ARRAY_SZ);
data += TISSUE_ARRAY_SZ;
memcpy(data, &gf_low_position_this_dive, sizeof(double));
data += sizeof(double);
memcpy(data, &tissue_tolerance, sizeof(double));
data += sizeof(double);
memcpy(data, &ci_pointing_to_guiding_tissue, sizeof(int));
}
double restore_deco_state(char *data)
{
double tissue_tolerance;
memcpy(tissue_n2_sat, data, TISSUE_ARRAY_SZ);
data += TISSUE_ARRAY_SZ;
memcpy(tissue_he_sat, data, TISSUE_ARRAY_SZ);
data += TISSUE_ARRAY_SZ;
memcpy(tissue_tolerated_ambient_pressure, data, TISSUE_ARRAY_SZ);
data += TISSUE_ARRAY_SZ;
memcpy(&gf_low_position_this_dive, data, sizeof(double));
data += sizeof(double);
memcpy(&tissue_tolerance, data, sizeof(double));
data += sizeof(double);
memcpy(&ci_pointing_to_guiding_tissue, data, sizeof(int));
return tissue_tolerance;
}
unsigned int deco_allowed_depth(double tissues_tolerance, double surface_pressure, struct dive *dive, gboolean smooth) unsigned int deco_allowed_depth(double tissues_tolerance, double surface_pressure, struct dive *dive, gboolean smooth)
{ {
unsigned int depth, multiples_of_3m; unsigned int depth, multiples_of_3m;

2
dive.h
View file

@ -577,6 +577,8 @@ extern void clear_deco(double surface_pressure);
extern void dump_tissues(void); extern void dump_tissues(void);
extern unsigned int deco_allowed_depth(double tissues_tolerance, double surface_pressure, struct dive *dive, gboolean smooth); extern unsigned int deco_allowed_depth(double tissues_tolerance, double surface_pressure, struct dive *dive, gboolean smooth);
extern void set_gf(double gflow, double gfhigh); extern void set_gf(double gflow, double gfhigh);
extern void cache_deco_state(double, char **datap);
extern double restore_deco_state(char *data);
struct divedatapoint { struct divedatapoint {
int time; int time;

View file

@ -11,7 +11,7 @@
int stoplevels[] = { 3000, 6000, 9000, 12000, 15000, 21000, 30000, 42000, 60000, 90000 }; int stoplevels[] = { 3000, 6000, 9000, 12000, 15000, 21000, 30000, 42000, 60000, 90000 };
/* returns the tissue tolerance at the end of this (partial) dive */ /* returns the tissue tolerance at the end of this (partial) dive */
double tissue_at_end(struct dive *dive) double tissue_at_end(struct dive *dive, char **cached_datap)
{ {
struct divecomputer *dc; struct divecomputer *dc;
struct sample *sample, *psample; struct sample *sample, *psample;
@ -20,11 +20,15 @@ double tissue_at_end(struct dive *dive)
if (!dive) if (!dive)
return 0.0; return 0.0;
tissue_tolerance = init_decompression(dive); if (*cached_datap) {
tissue_tolerance = restore_deco_state(*cached_datap);
} else {
tissue_tolerance = init_decompression(dive);
cache_deco_state(tissue_tolerance, cached_datap);
}
dc = &dive->dc; dc = &dive->dc;
if (!dc->samples) if (!dc->samples)
return 0.0; return tissue_tolerance;
psample = sample = dc->sample; psample = sample = dc->sample;
t0 = 0; t0 = 0;
for (i = 0; i < dc->samples; i++, sample++) { for (i = 0; i < dc->samples; i++, sample++) {
@ -41,7 +45,7 @@ double tissue_at_end(struct dive *dive)
} }
/* how many seconds until we can ascend to the next stop? */ /* how many seconds until we can ascend to the next stop? */
int time_at_last_depth(struct dive *dive, int next_stop) int time_at_last_depth(struct dive *dive, int next_stop, char **cached_data_p)
{ {
int depth; int depth;
double surface_pressure, tissue_tolerance; double surface_pressure, tissue_tolerance;
@ -51,7 +55,7 @@ int time_at_last_depth(struct dive *dive, int next_stop)
if (!dive) if (!dive)
return 0; return 0;
surface_pressure = dive->surface_pressure.mbar / 1000.0; surface_pressure = dive->surface_pressure.mbar / 1000.0;
tissue_tolerance = tissue_at_end(dive); tissue_tolerance = tissue_at_end(dive, cached_data_p);
sample = &dive->dc.sample[dive->dc.samples - 1]; sample = &dive->dc.sample[dive->dc.samples - 1];
depth = sample->depth.mm; depth = sample->depth.mm;
while (deco_allowed_depth(tissue_tolerance, surface_pressure, dive, 1) > next_stop) { while (deco_allowed_depth(tissue_tolerance, surface_pressure, dive, 1) > next_stop) {
@ -171,6 +175,7 @@ void plan(struct diveplan *diveplan)
int ceiling, depth, transitiontime; int ceiling, depth, transitiontime;
int stopidx; int stopidx;
double tissue_tolerance; double tissue_tolerance;
char *cached_data = NULL;
if (!diveplan->surface_pressure) if (!diveplan->surface_pressure)
diveplan->surface_pressure = 1013; diveplan->surface_pressure = 1013;
@ -183,7 +188,7 @@ void plan(struct diveplan *diveplan)
o2 = dive->cylinder[sample->sensor].gasmix.o2.permille; o2 = dive->cylinder[sample->sensor].gasmix.o2.permille;
he = dive->cylinder[sample->sensor].gasmix.he.permille; he = dive->cylinder[sample->sensor].gasmix.he.permille;
tissue_tolerance = tissue_at_end(dive); tissue_tolerance = tissue_at_end(dive, &cached_data);
ceiling = deco_allowed_depth(tissue_tolerance, diveplan->surface_pressure / 1000.0, dive, 1); ceiling = deco_allowed_depth(tissue_tolerance, diveplan->surface_pressure / 1000.0, dive, 1);
for (stopidx = 0; stopidx < sizeof(stoplevels) / sizeof(int); stopidx++) for (stopidx = 0; stopidx < sizeof(stoplevels) / sizeof(int); stopidx++)
@ -200,7 +205,7 @@ void plan(struct diveplan *diveplan)
dive = create_dive_from_plan(diveplan); dive = create_dive_from_plan(diveplan);
record_dive(dive); record_dive(dive);
} }
wait_time = time_at_last_depth(dive, stoplevels[stopidx - 1]); wait_time = time_at_last_depth(dive, stoplevels[stopidx - 1], &cached_data);
if (wait_time) if (wait_time)
plan_add_segment(diveplan, wait_time, stoplevels[stopidx], o2, he); plan_add_segment(diveplan, wait_time, stoplevels[stopidx], o2, he);
transitiontime = (stoplevels[stopidx] - stoplevels[stopidx - 1]) / 150; transitiontime = (stoplevels[stopidx] - stoplevels[stopidx - 1]) / 150;
@ -212,6 +217,7 @@ void plan(struct diveplan *diveplan)
stopidx--; stopidx--;
} }
/* now make the dive visible as last dive of the dive list */ /* now make the dive visible as last dive of the dive list */
free(cached_data);
report_dives(FALSE, FALSE); report_dives(FALSE, FALSE);
} }