summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/deco.c206
-rw-r--r--core/deco.h3
-rw-r--r--core/dive.h24
-rw-r--r--core/divelist.c30
-rw-r--r--core/divelist.h2
-rw-r--r--core/planner.c118
-rw-r--r--core/profile.c98
-rw-r--r--core/profile.h2
-rw-r--r--core/qthelper.h3
-rw-r--r--qt-models/diveplannermodel.cpp37
-rw-r--r--qt-models/diveplannermodel.h3
-rw-r--r--qt-models/diveplotdatamodel.cpp4
-rw-r--r--qt-models/diveplotdatamodel.h2
-rw-r--r--tests/testplan.cpp52
14 files changed, 298 insertions, 286 deletions
diff --git a/core/deco.c b/core/deco.c
index 7a7325297..c104205d8 100644
--- a/core/deco.c
+++ b/core/deco.c
@@ -151,11 +151,7 @@ const double vpmb_conservatism_lvls[] = { 1.0, 1.05, 1.12, 1.22, 1.35 };
#define DECO_STOPS_MULTIPLIER_MM 3000.0
#define NITROGEN_FRACTION 0.79
-struct deco_state global_deco_state;
-
-struct deco_state *deco_state = &global_deco_state;
-
-#define TISSUE_ARRAY_SZ sizeof(deco_state->tissue_n2_sat)
+#define TISSUE_ARRAY_SZ sizeof(ds->tissue_n2_sat)
int sumx, sum1;
long sumxx;
@@ -194,9 +190,9 @@ double solve_cubic2(double B, double C)
// This is a simplified formula avoiding radii. It uses the fact that Boyle's law says
// pV = (G + P_amb) / G^3 is constant to solve for the new gradient G.
-double update_gradient(double next_stop_pressure, double first_gradient)
+double update_gradient(struct deco_state *ds, double next_stop_pressure, double first_gradient)
{
- double B = cube(first_gradient) / (deco_state->first_ceiling_pressure.mbar / 1000.0 + first_gradient);
+ double B = cube(first_gradient) / (ds->first_ceiling_pressure.mbar / 1000.0 + first_gradient);
double C = next_stop_pressure * B;
double new_gradient = solve_cubic2(B, C);
@@ -206,25 +202,25 @@ double update_gradient(double next_stop_pressure, double first_gradient)
return new_gradient;
}
-double vpmb_tolerated_ambient_pressure(double reference_pressure, int ci)
+double vpmb_tolerated_ambient_pressure(struct deco_state *ds, double reference_pressure, int ci)
{
double n2_gradient, he_gradient, total_gradient;
- if (reference_pressure >= deco_state->first_ceiling_pressure.mbar / 1000.0 || !deco_state->first_ceiling_pressure.mbar) {
- n2_gradient = deco_state->bottom_n2_gradient[ci];
- he_gradient = deco_state->bottom_he_gradient[ci];
+ if (reference_pressure >= ds->first_ceiling_pressure.mbar / 1000.0 || !ds->first_ceiling_pressure.mbar) {
+ n2_gradient = ds->bottom_n2_gradient[ci];
+ he_gradient = ds->bottom_he_gradient[ci];
} else {
- n2_gradient = update_gradient(reference_pressure, deco_state->bottom_n2_gradient[ci]);
- he_gradient = update_gradient(reference_pressure, deco_state->bottom_he_gradient[ci]);
+ n2_gradient = update_gradient(ds, reference_pressure, ds->bottom_n2_gradient[ci]);
+ he_gradient = update_gradient(ds, reference_pressure, ds->bottom_he_gradient[ci]);
}
- total_gradient = ((n2_gradient * deco_state->tissue_n2_sat[ci]) + (he_gradient * deco_state->tissue_he_sat[ci])) / (deco_state->tissue_n2_sat[ci] + deco_state->tissue_he_sat[ci]);
+ total_gradient = ((n2_gradient * ds->tissue_n2_sat[ci]) + (he_gradient * ds->tissue_he_sat[ci])) / (ds->tissue_n2_sat[ci] + ds->tissue_he_sat[ci]);
- return deco_state->tissue_n2_sat[ci] + deco_state->tissue_he_sat[ci] + vpmb_config.other_gases_pressure - total_gradient;
+ return ds->tissue_n2_sat[ci] + ds->tissue_he_sat[ci] + vpmb_config.other_gases_pressure - total_gradient;
}
-double tissue_tolerance_calc(const struct dive *dive, double pressure)
+double tissue_tolerance_calc(struct deco_state *ds, const struct dive *dive, double pressure)
{
int ci = -1;
double ret_tolerance_limit_ambient_pressure = 0.0;
@@ -235,8 +231,8 @@ double tissue_tolerance_calc(const struct dive *dive, double pressure)
double tissue_lowest_ceiling[16];
for (ci = 0; ci < 16; ci++) {
- deco_state->buehlmann_inertgas_a[ci] = ((buehlmann_N2_a[ci] * deco_state->tissue_n2_sat[ci]) + (buehlmann_He_a[ci] * deco_state->tissue_he_sat[ci])) / deco_state->tissue_inertgas_saturation[ci];
- deco_state->buehlmann_inertgas_b[ci] = ((buehlmann_N2_b[ci] * deco_state->tissue_n2_sat[ci]) + (buehlmann_He_b[ci] * deco_state->tissue_he_sat[ci])) / deco_state->tissue_inertgas_saturation[ci];
+ ds->buehlmann_inertgas_a[ci] = ((buehlmann_N2_a[ci] * ds->tissue_n2_sat[ci]) + (buehlmann_He_a[ci] * ds->tissue_he_sat[ci])) / ds->tissue_inertgas_saturation[ci];
+ ds->buehlmann_inertgas_b[ci] = ((buehlmann_N2_b[ci] * ds->tissue_n2_sat[ci]) + (buehlmann_He_b[ci] * ds->tissue_he_sat[ci])) / ds->tissue_inertgas_saturation[ci];
}
if (decoMode() != VPMB) {
@@ -244,32 +240,32 @@ double tissue_tolerance_calc(const struct dive *dive, double pressure)
/* tolerated = (tissue_inertgas_saturation - buehlmann_inertgas_a) * buehlmann_inertgas_b; */
- tissue_lowest_ceiling[ci] = (deco_state->buehlmann_inertgas_b[ci] * deco_state->tissue_inertgas_saturation[ci] - gf_low * deco_state->buehlmann_inertgas_a[ci] * deco_state->buehlmann_inertgas_b[ci]) /
- ((1.0 - deco_state->buehlmann_inertgas_b[ci]) * gf_low + deco_state->buehlmann_inertgas_b[ci]);
+ tissue_lowest_ceiling[ci] = (ds->buehlmann_inertgas_b[ci] * ds->tissue_inertgas_saturation[ci] - gf_low * ds->buehlmann_inertgas_a[ci] * ds->buehlmann_inertgas_b[ci]) /
+ ((1.0 - ds->buehlmann_inertgas_b[ci]) * gf_low + ds->buehlmann_inertgas_b[ci]);
if (tissue_lowest_ceiling[ci] > lowest_ceiling)
lowest_ceiling = tissue_lowest_ceiling[ci];
- if (lowest_ceiling > deco_state->gf_low_pressure_this_dive)
- deco_state->gf_low_pressure_this_dive = lowest_ceiling;
+ if (lowest_ceiling > ds->gf_low_pressure_this_dive)
+ ds->gf_low_pressure_this_dive = lowest_ceiling;
}
for (ci = 0; ci < 16; ci++) {
double tolerated;
- if ((surface / deco_state->buehlmann_inertgas_b[ci] + deco_state->buehlmann_inertgas_a[ci] - surface) * gf_high + surface <
- (deco_state->gf_low_pressure_this_dive / deco_state->buehlmann_inertgas_b[ci] + deco_state->buehlmann_inertgas_a[ci] - deco_state->gf_low_pressure_this_dive) * gf_low + deco_state->gf_low_pressure_this_dive)
- tolerated = (-deco_state->buehlmann_inertgas_a[ci] * deco_state->buehlmann_inertgas_b[ci] * (gf_high * deco_state->gf_low_pressure_this_dive - gf_low * surface) -
- (1.0 - deco_state->buehlmann_inertgas_b[ci]) * (gf_high - gf_low) * deco_state->gf_low_pressure_this_dive * surface +
- deco_state->buehlmann_inertgas_b[ci] * (deco_state->gf_low_pressure_this_dive - surface) * deco_state->tissue_inertgas_saturation[ci]) /
- (-deco_state->buehlmann_inertgas_a[ci] * deco_state->buehlmann_inertgas_b[ci] * (gf_high - gf_low) +
- (1.0 - deco_state->buehlmann_inertgas_b[ci]) * (gf_low * deco_state->gf_low_pressure_this_dive - gf_high * surface) +
- deco_state->buehlmann_inertgas_b[ci] * (deco_state->gf_low_pressure_this_dive - surface));
+ if ((surface / ds->buehlmann_inertgas_b[ci] + ds->buehlmann_inertgas_a[ci] - surface) * gf_high + surface <
+ (ds->gf_low_pressure_this_dive / ds->buehlmann_inertgas_b[ci] + ds->buehlmann_inertgas_a[ci] - ds->gf_low_pressure_this_dive) * gf_low + ds->gf_low_pressure_this_dive)
+ tolerated = (-ds->buehlmann_inertgas_a[ci] * ds->buehlmann_inertgas_b[ci] * (gf_high * ds->gf_low_pressure_this_dive - gf_low * surface) -
+ (1.0 - ds->buehlmann_inertgas_b[ci]) * (gf_high - gf_low) * ds->gf_low_pressure_this_dive * surface +
+ ds->buehlmann_inertgas_b[ci] * (ds->gf_low_pressure_this_dive - surface) * ds->tissue_inertgas_saturation[ci]) /
+ (-ds->buehlmann_inertgas_a[ci] * ds->buehlmann_inertgas_b[ci] * (gf_high - gf_low) +
+ (1.0 - ds->buehlmann_inertgas_b[ci]) * (gf_low * ds->gf_low_pressure_this_dive - gf_high * surface) +
+ ds->buehlmann_inertgas_b[ci] * (ds->gf_low_pressure_this_dive - surface));
else
tolerated = ret_tolerance_limit_ambient_pressure;
- deco_state->tolerated_by_tissue[ci] = tolerated;
+ ds->tolerated_by_tissue[ci] = tolerated;
if (tolerated >= ret_tolerance_limit_ambient_pressure) {
- deco_state->ci_pointing_to_guiding_tissue = ci;
+ ds->ci_pointing_to_guiding_tissue = ci;
ret_tolerance_limit_ambient_pressure = tolerated;
}
}
@@ -283,12 +279,12 @@ double tissue_tolerance_calc(const struct dive *dive, double pressure)
reference_pressure = ret_tolerance_limit_ambient_pressure;
ret_tolerance_limit_ambient_pressure = 0.0;
for (ci = 0; ci < 16; ci++) {
- double tolerated = vpmb_tolerated_ambient_pressure(reference_pressure, ci);
+ double tolerated = vpmb_tolerated_ambient_pressure(ds, reference_pressure, ci);
if (tolerated >= ret_tolerance_limit_ambient_pressure) {
- deco_state->ci_pointing_to_guiding_tissue = ci;
+ ds->ci_pointing_to_guiding_tissue = ci;
ret_tolerance_limit_ambient_pressure = tolerated;
}
- deco_state->tolerated_by_tissue[ci] = tolerated;
+ ds->tolerated_by_tissue[ci] = tolerated;
}
// We are doing ok if the gradient was computed within ten centimeters of the ceiling.
} while (fabs(ret_tolerance_limit_ambient_pressure - reference_pressure) > 0.01);
@@ -298,12 +294,12 @@ double tissue_tolerance_calc(const struct dive *dive, double pressure)
sumx += plot_depth;
sumxx += plot_depth * plot_depth;
double n2_gradient, he_gradient, total_gradient;
- n2_gradient = update_gradient(depth_to_bar(plot_depth, &displayed_dive), deco_state->bottom_n2_gradient[deco_state->ci_pointing_to_guiding_tissue]);
- he_gradient = update_gradient(depth_to_bar(plot_depth, &displayed_dive), deco_state->bottom_he_gradient[deco_state->ci_pointing_to_guiding_tissue]);
- total_gradient = ((n2_gradient * deco_state->tissue_n2_sat[deco_state->ci_pointing_to_guiding_tissue]) + (he_gradient * deco_state->tissue_he_sat[deco_state->ci_pointing_to_guiding_tissue]))
- / (deco_state->tissue_n2_sat[deco_state->ci_pointing_to_guiding_tissue] + deco_state->tissue_he_sat[deco_state->ci_pointing_to_guiding_tissue]);
+ n2_gradient = update_gradient(ds, depth_to_bar(plot_depth, &displayed_dive), ds->bottom_n2_gradient[ds->ci_pointing_to_guiding_tissue]);
+ he_gradient = update_gradient(ds, depth_to_bar(plot_depth, &displayed_dive), ds->bottom_he_gradient[ds->ci_pointing_to_guiding_tissue]);
+ total_gradient = ((n2_gradient * ds->tissue_n2_sat[ds->ci_pointing_to_guiding_tissue]) + (he_gradient * ds->tissue_he_sat[ds->ci_pointing_to_guiding_tissue]))
+ / (ds->tissue_n2_sat[ds->ci_pointing_to_guiding_tissue] + ds->tissue_he_sat[ds->ci_pointing_to_guiding_tissue]);
- double buehlmann_gradient = (1.0 / deco_state->buehlmann_inertgas_b[deco_state->ci_pointing_to_guiding_tissue] - 1.0) * depth_to_bar(plot_depth, &displayed_dive) + deco_state->buehlmann_inertgas_a[deco_state->ci_pointing_to_guiding_tissue];
+ double buehlmann_gradient = (1.0 / ds->buehlmann_inertgas_b[ds->ci_pointing_to_guiding_tissue] - 1.0) * depth_to_bar(plot_depth, &displayed_dive) + ds->buehlmann_inertgas_a[ds->ci_pointing_to_guiding_tissue];
double gf = (total_gradient - vpmb_config.other_gases_pressure) / buehlmann_gradient;
sumxy += gf * plot_depth;
sumy += gf;
@@ -362,17 +358,17 @@ double calc_surface_phase(double surface_pressure, double he_pressure, double n2
return 0;
}
-void vpmb_start_gradient()
+void vpmb_start_gradient(struct deco_state *ds)
{
int ci;
for (ci = 0; ci < 16; ++ci) {
- deco_state->initial_n2_gradient[ci] = deco_state->bottom_n2_gradient[ci] = 2.0 * (vpmb_config.surface_tension_gamma / vpmb_config.skin_compression_gammaC) * ((vpmb_config.skin_compression_gammaC - vpmb_config.surface_tension_gamma) / deco_state->n2_regen_radius[ci]);
- deco_state->initial_he_gradient[ci] = deco_state->bottom_he_gradient[ci] = 2.0 * (vpmb_config.surface_tension_gamma / vpmb_config.skin_compression_gammaC) * ((vpmb_config.skin_compression_gammaC - vpmb_config.surface_tension_gamma) / deco_state->he_regen_radius[ci]);
+ ds->initial_n2_gradient[ci] = ds->bottom_n2_gradient[ci] = 2.0 * (vpmb_config.surface_tension_gamma / vpmb_config.skin_compression_gammaC) * ((vpmb_config.skin_compression_gammaC - vpmb_config.surface_tension_gamma) / ds->n2_regen_radius[ci]);
+ ds->initial_he_gradient[ci] = ds->bottom_he_gradient[ci] = 2.0 * (vpmb_config.surface_tension_gamma / vpmb_config.skin_compression_gammaC) * ((vpmb_config.skin_compression_gammaC - vpmb_config.surface_tension_gamma) / ds->he_regen_radius[ci]);
}
}
-void vpmb_next_gradient(double deco_time, double surface_pressure)
+void vpmb_next_gradient(struct deco_state *ds, double deco_time, double surface_pressure)
{
int ci;
double n2_b, n2_c;
@@ -381,18 +377,18 @@ void vpmb_next_gradient(double deco_time, double surface_pressure)
deco_time /= 60.0;
for (ci = 0; ci < 16; ++ci) {
- desat_time = deco_time + calc_surface_phase(surface_pressure, deco_state->tissue_he_sat[ci], deco_state->tissue_n2_sat[ci], log(2.0) / buehlmann_He_t_halflife[ci], log(2.0) / buehlmann_N2_t_halflife[ci]);
+ desat_time = deco_time + calc_surface_phase(surface_pressure, ds->tissue_he_sat[ci], ds->tissue_n2_sat[ci], log(2.0) / buehlmann_He_t_halflife[ci], log(2.0) / buehlmann_N2_t_halflife[ci]);
- n2_b = deco_state->initial_n2_gradient[ci] + (vpmb_config.crit_volume_lambda * vpmb_config.surface_tension_gamma) / (vpmb_config.skin_compression_gammaC * desat_time);
- he_b = deco_state->initial_he_gradient[ci] + (vpmb_config.crit_volume_lambda * vpmb_config.surface_tension_gamma) / (vpmb_config.skin_compression_gammaC * desat_time);
+ n2_b = ds->initial_n2_gradient[ci] + (vpmb_config.crit_volume_lambda * vpmb_config.surface_tension_gamma) / (vpmb_config.skin_compression_gammaC * desat_time);
+ he_b = ds->initial_he_gradient[ci] + (vpmb_config.crit_volume_lambda * vpmb_config.surface_tension_gamma) / (vpmb_config.skin_compression_gammaC * desat_time);
- n2_c = vpmb_config.surface_tension_gamma * vpmb_config.surface_tension_gamma * vpmb_config.crit_volume_lambda * deco_state->max_n2_crushing_pressure[ci];
+ n2_c = vpmb_config.surface_tension_gamma * vpmb_config.surface_tension_gamma * vpmb_config.crit_volume_lambda * ds->max_n2_crushing_pressure[ci];
n2_c = n2_c / (vpmb_config.skin_compression_gammaC * vpmb_config.skin_compression_gammaC * desat_time);
- he_c = vpmb_config.surface_tension_gamma * vpmb_config.surface_tension_gamma * vpmb_config.crit_volume_lambda * deco_state->max_he_crushing_pressure[ci];
+ he_c = vpmb_config.surface_tension_gamma * vpmb_config.surface_tension_gamma * vpmb_config.crit_volume_lambda * ds->max_he_crushing_pressure[ci];
he_c = he_c / (vpmb_config.skin_compression_gammaC * vpmb_config.skin_compression_gammaC * desat_time);
- deco_state->bottom_n2_gradient[ci] = 0.5 * ( n2_b + sqrt(n2_b * n2_b - 4.0 * n2_c));
- deco_state->bottom_he_gradient[ci] = 0.5 * ( he_b + sqrt(he_b * he_b - 4.0 * he_c));
+ ds->bottom_n2_gradient[ci] = 0.5 * ( n2_b + sqrt(n2_b * n2_b - 4.0 * n2_c));
+ ds->bottom_he_gradient[ci] = 0.5 * ( he_b + sqrt(he_b * he_b - 4.0 * he_c));
}
}
@@ -418,18 +414,18 @@ double solve_cubic(double A, double B, double C)
}
-void nuclear_regeneration(double time)
+void nuclear_regeneration(struct deco_state *ds, double time)
{
time /= 60.0;
int ci;
double crushing_radius_N2, crushing_radius_He;
for (ci = 0; ci < 16; ++ci) {
//rm
- crushing_radius_N2 = 1.0 / (deco_state->max_n2_crushing_pressure[ci] / (2.0 * (vpmb_config.skin_compression_gammaC - vpmb_config.surface_tension_gamma)) + 1.0 / get_crit_radius_N2());
- crushing_radius_He = 1.0 / (deco_state->max_he_crushing_pressure[ci] / (2.0 * (vpmb_config.skin_compression_gammaC - vpmb_config.surface_tension_gamma)) + 1.0 / get_crit_radius_He());
+ crushing_radius_N2 = 1.0 / (ds->max_n2_crushing_pressure[ci] / (2.0 * (vpmb_config.skin_compression_gammaC - vpmb_config.surface_tension_gamma)) + 1.0 / get_crit_radius_N2());
+ crushing_radius_He = 1.0 / (ds->max_he_crushing_pressure[ci] / (2.0 * (vpmb_config.skin_compression_gammaC - vpmb_config.surface_tension_gamma)) + 1.0 / get_crit_radius_He());
//rs
- deco_state->n2_regen_radius[ci] = crushing_radius_N2 + (get_crit_radius_N2() - crushing_radius_N2) * (1.0 - exp (-time / vpmb_config.regeneration_time));
- deco_state->he_regen_radius[ci] = crushing_radius_He + (get_crit_radius_He() - crushing_radius_He) * (1.0 - exp (-time / vpmb_config.regeneration_time));
+ ds->n2_regen_radius[ci] = crushing_radius_N2 + (get_crit_radius_N2() - crushing_radius_N2) * (1.0 - exp (-time / vpmb_config.regeneration_time));
+ ds->he_regen_radius[ci] = crushing_radius_He + (get_crit_radius_He() - crushing_radius_He) * (1.0 - exp (-time / vpmb_config.regeneration_time));
}
}
@@ -450,7 +446,7 @@ double calc_inner_pressure(double crit_radius, double onset_tension, double curr
}
// Calculates the crushing pressure in the given moment. Updates crushing_onset_tension and critical radius if needed
-void calc_crushing_pressure(double pressure)
+void calc_crushing_pressure(struct deco_state *ds, double pressure)
{
int ci;
double gradient;
@@ -459,31 +455,31 @@ void calc_crushing_pressure(double pressure)
double n2_inner_pressure, he_inner_pressure;
for (ci = 0; ci < 16; ++ci) {
- gas_tension = deco_state->tissue_n2_sat[ci] + deco_state->tissue_he_sat[ci] + vpmb_config.other_gases_pressure;
+ gas_tension = ds->tissue_n2_sat[ci] + ds->tissue_he_sat[ci] + vpmb_config.other_gases_pressure;
gradient = pressure - gas_tension;
if (gradient <= vpmb_config.gradient_of_imperm) { // permeable situation
n2_crushing_pressure = he_crushing_pressure = gradient;
- deco_state->crushing_onset_tension[ci] = gas_tension;
+ ds->crushing_onset_tension[ci] = gas_tension;
}
else { // impermeable
- if (deco_state->max_ambient_pressure >= pressure)
+ if (ds->max_ambient_pressure >= pressure)
return;
- n2_inner_pressure = calc_inner_pressure(get_crit_radius_N2(), deco_state->crushing_onset_tension[ci], pressure);
- he_inner_pressure = calc_inner_pressure(get_crit_radius_He(), deco_state->crushing_onset_tension[ci], pressure);
+ n2_inner_pressure = calc_inner_pressure(get_crit_radius_N2(), ds->crushing_onset_tension[ci], pressure);
+ he_inner_pressure = calc_inner_pressure(get_crit_radius_He(), ds->crushing_onset_tension[ci], pressure);
n2_crushing_pressure = pressure - n2_inner_pressure;
he_crushing_pressure = pressure - he_inner_pressure;
}
- deco_state->max_n2_crushing_pressure[ci] = MAX(deco_state->max_n2_crushing_pressure[ci], n2_crushing_pressure);
- deco_state->max_he_crushing_pressure[ci] = MAX(deco_state->max_he_crushing_pressure[ci], he_crushing_pressure);
+ ds->max_n2_crushing_pressure[ci] = MAX(ds->max_n2_crushing_pressure[ci], n2_crushing_pressure);
+ ds->max_he_crushing_pressure[ci] = MAX(ds->max_he_crushing_pressure[ci], he_crushing_pressure);
}
- deco_state->max_ambient_pressure = MAX(pressure, deco_state->max_ambient_pressure);
+ ds->max_ambient_pressure = MAX(pressure, ds->max_ambient_pressure);
}
/* add period_in_seconds at the given pressure and gas to the deco calculation */
-void add_segment(double pressure, const struct gasmix *gasmix, int period_in_seconds, int ccpo2, const struct dive *dive, int sac)
+void add_segment(struct deco_state *ds, double pressure, const struct gasmix *gasmix, int period_in_seconds, int ccpo2, const struct dive *dive, int sac)
{
(void) sac;
int ci;
@@ -493,64 +489,64 @@ void add_segment(double pressure, const struct gasmix *gasmix, int period_in_sec
gasmix, (double) ccpo2 / 1000.0, dive->dc.divemode);
for (ci = 0; ci < 16; ci++) {
- double pn2_oversat = pressures.n2 - deco_state->tissue_n2_sat[ci];
- double phe_oversat = pressures.he - deco_state->tissue_he_sat[ci];
+ double pn2_oversat = pressures.n2 - ds->tissue_n2_sat[ci];
+ double phe_oversat = pressures.he - ds->tissue_he_sat[ci];
double n2_f = factor(period_in_seconds, ci, N2);
double he_f = factor(period_in_seconds, ci, HE);
double n2_satmult = pn2_oversat > 0 ? buehlmann_config.satmult : buehlmann_config.desatmult;
double he_satmult = phe_oversat > 0 ? buehlmann_config.satmult : buehlmann_config.desatmult;
- deco_state->tissue_n2_sat[ci] += n2_satmult * pn2_oversat * n2_f;
- deco_state->tissue_he_sat[ci] += he_satmult * phe_oversat * he_f;
- deco_state->tissue_inertgas_saturation[ci] = deco_state->tissue_n2_sat[ci] + deco_state->tissue_he_sat[ci];
+ ds->tissue_n2_sat[ci] += n2_satmult * pn2_oversat * n2_f;
+ ds->tissue_he_sat[ci] += he_satmult * phe_oversat * he_f;
+ ds->tissue_inertgas_saturation[ci] = ds->tissue_n2_sat[ci] + ds->tissue_he_sat[ci];
}
if(decoMode() == VPMB)
- calc_crushing_pressure(pressure);
+ calc_crushing_pressure(ds, pressure);
return;
}
-void dump_tissues()
+void dump_tissues(struct deco_state *ds)
{
int ci;
printf("N2 tissues:");
for (ci = 0; ci < 16; ci++)
- printf(" %6.3e", deco_state->tissue_n2_sat[ci]);
+ printf(" %6.3e", ds->tissue_n2_sat[ci]);
printf("\nHe tissues:");
for (ci = 0; ci < 16; ci++)
- printf(" %6.3e", deco_state->tissue_he_sat[ci]);
+ printf(" %6.3e", ds->tissue_he_sat[ci]);
printf("\n");
}
-void clear_vpmb_state() {
+void clear_vpmb_state(struct deco_state *ds) {
int ci;
for (ci = 0; ci < 16; ci++) {
- deco_state->max_n2_crushing_pressure[ci] = 0.0;
- deco_state->max_he_crushing_pressure[ci] = 0.0;
+ ds->max_n2_crushing_pressure[ci] = 0.0;
+ ds->max_he_crushing_pressure[ci] = 0.0;
}
- deco_state->max_ambient_pressure = 0;
- deco_state->first_ceiling_pressure.mbar = 0;
- deco_state->max_bottom_ceiling_pressure.mbar = 0;
+ ds->max_ambient_pressure = 0;
+ ds->first_ceiling_pressure.mbar = 0;
+ ds->max_bottom_ceiling_pressure.mbar = 0;
}
-void clear_deco(double surface_pressure)
+void clear_deco(struct deco_state *ds, double surface_pressure)
{
int ci;
- clear_vpmb_state();
+ clear_vpmb_state(ds);
for (ci = 0; ci < 16; ci++) {
- deco_state->tissue_n2_sat[ci] = (surface_pressure - ((in_planner() && (decoMode() == VPMB)) ? WV_PRESSURE_SCHREINER : WV_PRESSURE)) * N2_IN_AIR / 1000;
- deco_state->tissue_he_sat[ci] = 0.0;
- deco_state->max_n2_crushing_pressure[ci] = 0.0;
- deco_state->max_he_crushing_pressure[ci] = 0.0;
- deco_state->n2_regen_radius[ci] = get_crit_radius_N2();
- deco_state->he_regen_radius[ci] = get_crit_radius_He();
+ ds->tissue_n2_sat[ci] = (surface_pressure - ((in_planner() && (decoMode() == VPMB)) ? WV_PRESSURE_SCHREINER : WV_PRESSURE)) * N2_IN_AIR / 1000;
+ ds->tissue_he_sat[ci] = 0.0;
+ ds->max_n2_crushing_pressure[ci] = 0.0;
+ ds->max_he_crushing_pressure[ci] = 0.0;
+ ds->n2_regen_radius[ci] = get_crit_radius_N2();
+ ds->he_regen_radius[ci] = get_crit_radius_He();
}
- deco_state->gf_low_pressure_this_dive = surface_pressure;
- deco_state->gf_low_pressure_this_dive += buehlmann_config.gf_low_position_min;
- deco_state->max_ambient_pressure = 0.0;
+ ds->gf_low_pressure_this_dive = surface_pressure;
+ ds->gf_low_pressure_this_dive += buehlmann_config.gf_low_position_min;
+ ds->max_ambient_pressure = 0.0;
}
-void cache_deco_state(struct deco_state **cached_datap)
+void cache_deco_state(struct deco_state *src, struct deco_state **cached_datap)
{
struct deco_state *data = *cached_datap;
@@ -558,23 +554,23 @@ void cache_deco_state(struct deco_state **cached_datap)
data = malloc(sizeof(struct deco_state));
*cached_datap = data;
}
- *data = *deco_state;
+ *data = *src;
}
-void restore_deco_state(struct deco_state *data, bool keep_vpmb_state)
+void restore_deco_state(struct deco_state *data, struct deco_state *target, bool keep_vpmb_state)
{
if (keep_vpmb_state) {
int ci;
for (ci = 0; ci < 16; ci++) {
- data->bottom_n2_gradient[ci] = deco_state->bottom_n2_gradient[ci];
- data->bottom_he_gradient[ci] = deco_state->bottom_he_gradient[ci];
- data->initial_n2_gradient[ci] = deco_state->initial_n2_gradient[ci];
- data->initial_he_gradient[ci] = deco_state->initial_he_gradient[ci];
+ data->bottom_n2_gradient[ci] = target->bottom_n2_gradient[ci];
+ data->bottom_he_gradient[ci] = target->bottom_he_gradient[ci];
+ data->initial_n2_gradient[ci] = target->initial_n2_gradient[ci];
+ data->initial_he_gradient[ci] = target->initial_he_gradient[ci];
}
- data->first_ceiling_pressure = deco_state->first_ceiling_pressure;
- data->max_bottom_ceiling_pressure = deco_state->max_bottom_ceiling_pressure;
+ data->first_ceiling_pressure = target->first_ceiling_pressure;
+ data->max_bottom_ceiling_pressure = target->max_bottom_ceiling_pressure;
}
- *deco_state = *data;
+ *target = *data;
}
@@ -615,15 +611,15 @@ void set_vpmb_conservatism(short conservatism)
vpmb_config.conservatism = conservatism;
}
-double get_gf(double ambpressure_bar, const struct dive *dive)
+double get_gf(struct deco_state *ds, double ambpressure_bar, const struct dive *dive)
{
double surface_pressure_bar = get_surface_pressure_in_mbar(dive, true) / 1000.0;
double gf_low = buehlmann_config.gf_low;
double gf_high = buehlmann_config.gf_high;
double gf;
- if (deco_state->gf_low_pressure_this_dive > surface_pressure_bar)
+ if (ds->gf_low_pressure_this_dive > surface_pressure_bar)
gf = MAX((double)gf_low, (ambpressure_bar - surface_pressure_bar) /
- (deco_state->gf_low_pressure_this_dive - surface_pressure_bar) * (gf_low - gf_high) + gf_high);
+ (ds->gf_low_pressure_this_dive - surface_pressure_bar) * (gf_low - gf_high) + gf_high);
else
gf = gf_low;
return gf;
diff --git a/core/deco.h b/core/deco.h
index 581d2a791..075e7758c 100644
--- a/core/deco.h
+++ b/core/deco.h
@@ -7,11 +7,10 @@ extern "C" {
#endif
extern double buehlmann_N2_t_halflife[];
-extern struct deco_state *deco_state;
extern int deco_allowed_depth(double tissues_tolerance, double surface_pressure, struct dive *dive, bool smooth);
-double get_gf(double ambpressure_bar, const struct dive *dive);
+double get_gf(struct deco_state *ds, double ambpressure_bar, const struct dive *dive);
#ifdef __cplusplus
}
diff --git a/core/dive.h b/core/dive.h
index 81396d352..399feecb5 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -894,17 +894,17 @@ struct deco_state {
int deco_time;
};
-extern void add_segment(double pressure, const struct gasmix *gasmix, int period_in_seconds, int setpoint, const struct dive *dive, int sac);
-extern void clear_deco(double surface_pressure);
-extern void dump_tissues(void);
+extern void add_segment(struct deco_state *ds, double pressure, const struct gasmix *gasmix, int period_in_seconds, int setpoint, const struct dive *dive, int sac);
+extern void clear_deco(struct deco_state *ds, double surface_pressure);
+extern void dump_tissues(struct deco_state *ds);
extern void set_gf(short gflow, short gfhigh);
extern void set_vpmb_conservatism(short conservatism);
-extern void cache_deco_state(struct deco_state **datap);
-extern void restore_deco_state(struct deco_state *data, bool keep_vpmb_state);
-extern void nuclear_regeneration(double time);
-extern void vpmb_start_gradient();
-extern void vpmb_next_gradient(double deco_time, double surface_pressure);
-extern double tissue_tolerance_calc(const struct dive *dive, double pressure);
+extern void cache_deco_state(struct deco_state *source, struct deco_state **datap);
+extern void restore_deco_state(struct deco_state *data, struct deco_state *target, bool keep_vpmb_state);
+extern void nuclear_regeneration(struct deco_state *ds, double time);
+extern void vpmb_start_gradient(struct deco_state *ds);
+extern void vpmb_next_gradient(struct deco_state *ds, double deco_time, double surface_pressure);
+extern double tissue_tolerance_calc(struct deco_state *ds, const struct dive *dive, double pressure);
/* this should be converted to use our types */
struct divedatapoint {
@@ -940,9 +940,9 @@ struct decostop {
int depth;
int time;
};
-bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct decostop *decostoptable, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer);
-void calc_crushing_pressure(double pressure);
-void vpmb_start_gradient();
+bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, int timestep, struct decostop *decostoptable, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer);
+void calc_crushing_pressure(struct deco_state *ds, double pressure);
+void vpmb_start_gradient(struct deco_state *ds);
void clear_vpmb_state();
void printdecotable(struct decostop *table);
diff --git a/core/divelist.c b/core/divelist.c
index 58376eef9..0ae33153e 100644
--- a/core/divelist.c
+++ b/core/divelist.c
@@ -419,7 +419,7 @@ static int calculate_sac(struct dive *dive)
}
/* for now we do this based on the first divecomputer */
-static void add_dive_to_deco(struct dive *dive)
+static void add_dive_to_deco(struct deco_state *ds, struct dive *dive)
{
struct divecomputer *dc = &dive->dc;
struct gasmix *gasmix = NULL;
@@ -439,7 +439,7 @@ static void add_dive_to_deco(struct dive *dive)
for (j = t0; j < t1; j++) {
int depth = interpolate(psample->depth.mm, sample->depth.mm, j - t0, t1 - t0);
gasmix = get_gasmix(dive, dc, j, &ev, gasmix);
- add_segment(depth_to_bar(depth, dive), gasmix, 1, sample->setpoint.mbar, dive, dive->sac);
+ add_segment(ds, depth_to_bar(depth, dive), gasmix, 1, sample->setpoint.mbar, dive, dive->sac);
}
}
}
@@ -475,7 +475,9 @@ static struct gasmix air = { .o2.permille = O2_IN_AIR, .he.permille = 0 };
/* take into account previous dives until there is a 48h gap between dives */
/* return last surface time before this dive or dummy value of 48h */
/* return negative surface time if dives are overlapping */
-int init_decompression(struct dive *dive)
+/* The place you call this function is likely the place where you want
+ * to create the deco_state */
+int init_decompression(struct deco_state *ds, struct dive *dive)
{
int i, divenr = -1;
int surface_time = 48 * 60 * 60;
@@ -576,7 +578,7 @@ int init_decompression(struct dive *dive)
#if DECO_CALC_DEBUG & 2
printf("Init deco\n");
#endif
- clear_deco(surface_pressure);
+ clear_deco(ds, surface_pressure);
deco_init = true;
#if DECO_CALC_DEBUG & 2
printf("Tissues after init:\n");
@@ -591,21 +593,21 @@ int init_decompression(struct dive *dive)
#endif
return surface_time;
}
- add_segment(surface_pressure, &air, surface_time, 0, dive, prefs.decosac);
+ add_segment(ds, surface_pressure, &air, surface_time, 0, dive, prefs.decosac);
#if DECO_CALC_DEBUG & 2
printf("Tissues after surface intervall of %d:%02u:\n", FRACTION(surface_time, 60));
- dump_tissues();
+ dump_tissues(ds);
#endif
}
- add_dive_to_deco(pdive);
+ add_dive_to_deco(ds, pdive);
last_starttime = pdive->when;
last_endtime = dive_endtime(pdive);
- clear_vpmb_state();
+ clear_vpmb_state(ds);
#if DECO_CALC_DEBUG & 2
printf("Tissues after added dive #%d:\n", pdive->number);
- dump_tissues();
+ dump_tissues(ds);
#endif
}
@@ -615,10 +617,10 @@ int init_decompression(struct dive *dive)
#if DECO_CALC_DEBUG & 2
printf("Init deco\n");
#endif
- clear_deco(surface_pressure);
+ clear_deco(ds, surface_pressure);
#if DECO_CALC_DEBUG & 2
printf("Tissues after no previous dive, surface time set to 48h:\n");
- dump_tissues();
+ dump_tissues(ds);
#endif
}
else {
@@ -629,15 +631,15 @@ int init_decompression(struct dive *dive)
#endif
return surface_time;
}
- add_segment(surface_pressure, &air, surface_time, 0, dive, prefs.decosac);
+ add_segment(ds, surface_pressure, &air, surface_time, 0, dive, prefs.decosac);
#if DECO_CALC_DEBUG & 2
printf("Tissues after surface intervall of %d:%02u:\n", FRACTION(surface_time, 60));
- dump_tissues();
+ dump_tissues(ds);
#endif
}
// I do not dare to remove this call. We don't need the result but it might have side effects. Bummer.
- tissue_tolerance_calc(dive, surface_pressure);
+ tissue_tolerance_calc(ds, dive, surface_pressure);
return surface_time;
}
diff --git a/core/divelist.h b/core/divelist.h
index 44f0bf0b0..ed648793f 100644
--- a/core/divelist.h
+++ b/core/divelist.h
@@ -15,7 +15,7 @@ extern void update_cylinder_related_info(struct dive *);
extern void mark_divelist_changed(int);
extern int unsaved_changes(void);
extern void remove_autogen_trips(void);
-extern int init_decompression(struct dive *dive);
+extern int init_decompression(struct deco_state *ds, struct dive *dive);
/* divelist core logic functions */
extern void process_dives(bool imported, bool prefer_imported);
diff --git a/core/planner.c b/core/planner.c
index a137753b2..6aa5cc2f4 100644
--- a/core/planner.c
+++ b/core/planner.c
@@ -114,20 +114,20 @@ int get_gasidx(struct dive *dive, struct gasmix *mix)
return find_best_gasmix_match(mix, dive->cylinder, 0);
}
-void interpolate_transition(struct dive *dive, duration_t t0, duration_t t1, depth_t d0, depth_t d1, const struct gasmix *gasmix, o2pressure_t po2)
+void interpolate_transition(struct deco_state *ds, struct dive *dive, duration_t t0, duration_t t1, depth_t d0, depth_t d1, const struct gasmix *gasmix, o2pressure_t po2)
{
uint32_t j;
for (j = t0.seconds; j < t1.seconds; j++) {
int depth = interpolate(d0.mm, d1.mm, j - t0.seconds, t1.seconds - t0.seconds);
- add_segment(depth_to_bar(depth, dive), gasmix, 1, po2.mbar, dive, prefs.bottomsac);
+ add_segment(ds, depth_to_bar(depth, dive), gasmix, 1, po2.mbar, dive, prefs.bottomsac);
}
if (d1.mm > d0.mm)
- calc_crushing_pressure(depth_to_bar(d1.mm, &displayed_dive));
+ calc_crushing_pressure(ds, depth_to_bar(d1.mm, &displayed_dive));
}
/* returns the tissue tolerance at the end of this (partial) dive */
-int tissue_at_end(struct dive *dive, struct deco_state **cached_datap)
+int tissue_at_end(struct deco_state *ds, struct dive *dive, struct deco_state **cached_datap)
{
struct divecomputer *dc;
struct sample *sample, *psample;
@@ -140,10 +140,10 @@ int tissue_at_end(struct dive *dive, struct deco_state **cached_datap)
if (!dive)
return 0;
if (*cached_datap) {
- restore_deco_state(*cached_datap, true);
+ restore_deco_state(*cached_datap, ds, true);
} else {
- surface_interval = init_decompression(dive);
- cache_deco_state(cached_datap);
+ surface_interval = init_decompression(ds, dive);
+ cache_deco_state(ds, cached_datap);
}
dc = &dive->dc;
if (!dc->samples)
@@ -174,19 +174,19 @@ int tissue_at_end(struct dive *dive, struct deco_state **cached_datap)
*/
if ((decoMode() == VPMB) && (lastdepth.mm > sample->depth.mm)) {
pressure_t ceiling_pressure;
- nuclear_regeneration(t0.seconds);
- vpmb_start_gradient();
- ceiling_pressure.mbar = depth_to_mbar(deco_allowed_depth(tissue_tolerance_calc(dive,
+ nuclear_regeneration(ds, t0.seconds);
+ vpmb_start_gradient(ds);
+ ceiling_pressure.mbar = depth_to_mbar(deco_allowed_depth(tissue_tolerance_calc(ds, dive,
depth_to_bar(lastdepth.mm, dive)),
dive->surface_pressure.mbar / 1000.0,
dive,
1),
dive);
- if (ceiling_pressure.mbar > deco_state->max_bottom_ceiling_pressure.mbar)
- deco_state->max_bottom_ceiling_pressure.mbar = ceiling_pressure.mbar;
+ if (ceiling_pressure.mbar > ds->max_bottom_ceiling_pressure.mbar)
+ ds->max_bottom_ceiling_pressure.mbar = ceiling_pressure.mbar;
}
- interpolate_transition(dive, t0, t1, lastdepth, sample->depth, &gas, setpoint);
+ interpolate_transition(ds, dive, t0, t1, lastdepth, sample->depth, &gas, setpoint);
psample = sample;
t0 = t1;
}
@@ -556,7 +556,7 @@ void track_ascent_gas(int depth, cylinder_t *cylinder, int avg_depth, int bottom
}
// Determine whether ascending to the next stop will break the ceiling. Return true if the ascent is ok, false if it isn't.
-bool trial_ascent(int wait_time, int trial_depth, int stoplevel, int avg_depth, int bottom_time, struct gasmix *gasmix, int po2, double surface_pressure, struct dive *dive)
+bool trial_ascent(struct deco_state *ds, int wait_time, int trial_depth, int stoplevel, int avg_depth, int bottom_time, struct gasmix *gasmix, int po2, double surface_pressure, struct dive *dive)
{
bool clear_to_ascend = true;
@@ -565,15 +565,15 @@ bool trial_ascent(int wait_time, int trial_depth, int stoplevel, int avg_depth,
// For consistency with other VPM-B implementations, we should not start the ascent while the ceiling is
// deeper than the next stop (thus the offgasing during the ascent is ignored).
// However, we still need to make sure we don't break the ceiling due to on-gassing during ascent.
- cache_deco_state(&trial_cache);
+ cache_deco_state(ds, &trial_cache);
if (wait_time)
- add_segment(depth_to_bar(trial_depth, dive),
+ add_segment(ds, depth_to_bar(trial_depth, dive),
gasmix,
wait_time, po2, dive, prefs.decosac);
- if (decoMode() == VPMB && (deco_allowed_depth(tissue_tolerance_calc(dive,
- depth_to_bar(stoplevel, dive)),
- surface_pressure, dive, 1) > stoplevel)) {
- restore_deco_state(trial_cache, false);
+ if (decoMode() == VPMB && (deco_allowed_depth(tissue_tolerance_calc(ds, dive,depth_to_bar(stoplevel, dive)),
+ surface_pressure, dive, 1)
+ > stoplevel)) {
+ restore_deco_state(trial_cache, ds, false);
free(trial_cache);
return false;
}
@@ -582,10 +582,10 @@ bool trial_ascent(int wait_time, int trial_depth, int stoplevel, int avg_depth,
int deltad = ascent_velocity(trial_depth, avg_depth, bottom_time) * TIMESTEP;
if (deltad > trial_depth) /* don't test against depth above surface */
deltad = trial_depth;
- add_segment(depth_to_bar(trial_depth, dive),
+ add_segment(ds, depth_to_bar(trial_depth, dive),
gasmix,
TIMESTEP, po2, dive, prefs.decosac);
- if (deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(trial_depth, dive)),
+ if (deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(trial_depth, dive)),
surface_pressure, dive, 1) > trial_depth - deltad) {
/* We should have stopped */
clear_to_ascend = false;
@@ -593,7 +593,7 @@ bool trial_ascent(int wait_time, int trial_depth, int stoplevel, int avg_depth,
}
trial_depth -= deltad;
}
- restore_deco_state(trial_cache, false);
+ restore_deco_state(trial_cache, ds, false);
free(trial_cache);
return clear_to_ascend;
}
@@ -621,18 +621,18 @@ bool enough_gas(int current_cylinder)
* So we always test at the upper bundary, not in the middle!
*/
-int wait_until(struct dive *dive, int clock, int min, int leap, int stepsize, int depth, int target_depth, int avg_depth, int bottom_time, struct gasmix *gasmix, int po2, double surface_pressure)
+int wait_until(struct deco_state *ds, struct dive *dive, int clock, int min, int leap, int stepsize, int depth, int target_depth, int avg_depth, int bottom_time, struct gasmix *gasmix, int po2, double surface_pressure)
{
// Round min + leap up to the next multiple of stepsize
int upper = min + leap + stepsize - 1 - (min + leap - 1) % stepsize;
// Is the upper boundary too small?
- if (!trial_ascent(upper - clock, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure, dive))
- return wait_until(dive, clock, upper, leap, stepsize, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure);
+ if (!trial_ascent(ds, upper - clock, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure, dive))
+ return wait_until(ds, dive, clock, upper, leap, stepsize, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure);
if (upper - min <= stepsize)
return upper;
- return wait_until(dive, clock, min, leap / 2, stepsize, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure);
+ return wait_until(ds, dive, clock, min, leap / 2, stepsize, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure);
}
// Work out the stops. Return value is if there were any mandatory stops.
@@ -646,8 +646,9 @@ void printdecotable(struct decostop *table)
}
}
-bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct decostop *decostoptable, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer)
+bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, int timestep, struct decostop *decostoptable, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer)
{
+
int bottom_depth;
int bottom_gi;
int bottom_stopidx;
@@ -690,8 +691,8 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
if (!diveplan->surface_pressure)
diveplan->surface_pressure = SURFACE_PRESSURE;
dive->surface_pressure.mbar = diveplan->surface_pressure;
- clear_deco(dive->surface_pressure.mbar / 1000.0);
- deco_state->max_bottom_ceiling_pressure.mbar = deco_state->first_ceiling_pressure.mbar = 0;
+ clear_deco(ds, dive->surface_pressure.mbar / 1000.0);
+ ds->max_bottom_ceiling_pressure.mbar = ds->first_ceiling_pressure.mbar = 0;
create_dive_from_plan(diveplan, dive, is_planner);
// Do we want deco stop array in metres or feet?
@@ -730,6 +731,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
transitiontime = depth / 75; /* this still needs to be made configurable */
plan_add_segment(diveplan, transitiontime, 0, current_cylinder, po2, false);
create_dive_from_plan(diveplan, dive, is_planner);
+ unlock_planner();
return false;
}
@@ -761,21 +763,21 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
gi = gaschangenr - 1;
/* Set tissue tolerance and initial vpmb gradient at start of ascent phase */
- diveplan->surface_interval = tissue_at_end(dive, cached_datap);
- nuclear_regeneration(clock);
- vpmb_start_gradient();
+ diveplan->surface_interval = tissue_at_end(ds, dive, cached_datap);
+ nuclear_regeneration(ds, clock);
+ vpmb_start_gradient(ds);
if (decoMode() == RECREATIONAL) {
bool safety_stop = prefs.safetystop && max_depth >= 10000;
track_ascent_gas(depth, &dive->cylinder[current_cylinder], avg_depth, bottom_time, safety_stop);
// How long can we stay at the current depth and still directly ascent to the surface?
do {
- add_segment(depth_to_bar(depth, dive),
+ add_segment(ds, depth_to_bar(depth, dive),
&dive->cylinder[current_cylinder].gasmix,
timestep, po2, dive, prefs.bottomsac);
update_cylinder_pressure(dive, depth, depth, timestep, prefs.bottomsac, &dive->cylinder[current_cylinder], false);
clock += timestep;
- } while (trial_ascent(0, depth, 0, avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix,
+ } while (trial_ascent(ds, 0, depth, 0, avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix,
po2, diveplan->surface_pressure / 1000.0, dive) &&
enough_gas(current_cylinder));
@@ -816,6 +818,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
free(stoplevels);
free(gaschanges);
+ unlock_planner();
return false;
}
@@ -830,10 +833,10 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
}
// VPM-B or Buehlmann Deco
- tissue_at_end(dive, cached_datap);
+ tissue_at_end(ds, dive, cached_datap);
previous_deco_time = 100000000;
- deco_state->deco_time = 10000000;
- cache_deco_state(&bottom_cache); // Lets us make several iterations
+ ds->deco_time = 10000000;
+ cache_deco_state(ds, &bottom_cache); // Lets us make several iterations
bottom_depth = depth;
bottom_gi = gi;
bottom_gas = gas;
@@ -842,12 +845,12 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
//CVA
do {
decostopcounter = 0;
- is_final_plan = (decoMode() == BUEHLMANN) || (previous_deco_time - deco_state->deco_time < 10); // CVA time converges
- if (deco_state->deco_time != 10000000)
- vpmb_next_gradient(deco_state->deco_time, diveplan->surface_pressure / 1000.0);
+ is_final_plan = (decoMode() == BUEHLMANN) || (previous_deco_time - ds->deco_time < 10); // CVA time converges
+ if (ds->deco_time != 10000000)
+ vpmb_next_gradient(ds, ds->deco_time, diveplan->surface_pressure / 1000.0);
- previous_deco_time = deco_state->deco_time;
- restore_deco_state(bottom_cache, true);
+ previous_deco_time = ds->deco_time;
+ restore_deco_state(bottom_cache, ds, true);
depth = bottom_depth;
gi = bottom_gi;
@@ -857,14 +860,11 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
decodive = false;
first_stop_depth = 0;
stopidx = bottom_stopidx;
- deco_state->first_ceiling_pressure.mbar = depth_to_mbar(deco_allowed_depth(tissue_tolerance_calc(dive,
- depth_to_bar(depth, dive)),
- diveplan->surface_pressure / 1000.0,
- dive,
- 1),
- dive);
- if (deco_state->max_bottom_ceiling_pressure.mbar > deco_state->first_ceiling_pressure.mbar)
- deco_state->first_ceiling_pressure.mbar = deco_state->max_bottom_ceiling_pressure.mbar;
+ ds->first_ceiling_pressure.mbar = depth_to_mbar(
+ deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(depth, dive)), diveplan->surface_pressure / 1000.0, dive, 1),
+ dive);
+ if (ds->max_bottom_ceiling_pressure.mbar > ds->first_ceiling_pressure.mbar)
+ ds->first_ceiling_pressure.mbar = ds->max_bottom_ceiling_pressure.mbar;
last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time);
/* Always prefer the best_first_ascend_cylinder if it has the right gasmix.
@@ -893,7 +893,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
if (depth - deltad < stoplevels[stopidx])
deltad = depth - stoplevels[stopidx];
- add_segment(depth_to_bar(depth, dive),
+ add_segment(ds, depth_to_bar(depth, dive),
&dive->cylinder[current_cylinder].gasmix,
TIMESTEP, po2, dive, prefs.decosac);
last_segment_min_switch = false;
@@ -922,7 +922,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
if (current_cylinder != gaschanges[gi].gasidx) {
if (!prefs.switch_at_req_stop ||
- !trial_ascent(0, depth, stoplevels[stopidx - 1], avg_depth, bottom_time,
+ !trial_ascent(ds, 0, depth, stoplevels[stopidx - 1], avg_depth, bottom_time,
&dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, dive) || get_o2(&dive->cylinder[current_cylinder].gasmix) < 160) {
current_cylinder = gaschanges[gi].gasidx;
gas = dive->cylinder[current_cylinder].gasmix;
@@ -932,7 +932,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
#endif
/* Stop for the minimum duration to switch gas unless we switch to o2 */
if (!last_segment_min_switch && get_o2(&dive->cylinder[current_cylinder].gasmix) != 1000) {
- add_segment(depth_to_bar(depth, dive),
+ add_segment(ds, depth_to_bar(depth, dive),
&dive->cylinder[current_cylinder].gasmix,
prefs.min_switch_duration, po2, dive, prefs.decosac);
clock += prefs.min_switch_duration;
@@ -952,7 +952,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
/* Save the current state and try to ascend to the next stopdepth */
while (1) {
/* Check if ascending to next stop is clear, go back and wait if we hit the ceiling on the way */
- if (trial_ascent(0, depth, stoplevels[stopidx], avg_depth, bottom_time,
+ if (trial_ascent(ds, 0, depth, stoplevels[stopidx], avg_depth, bottom_time,
&dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, dive)) {
decostoptable[decostopcounter].depth = depth;
decostoptable[decostopcounter].time = 0;
@@ -986,7 +986,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
#endif
/* Stop for the minimum duration to switch gas unless we switch to o2 */
if (!last_segment_min_switch && get_o2(&dive->cylinder[current_cylinder].gasmix) != 1000) {
- add_segment(depth_to_bar(depth, dive),
+ add_segment(ds, depth_to_bar(depth, dive),
&dive->cylinder[current_cylinder].gasmix,
prefs.min_switch_duration, po2, dive, prefs.decosac);
clock += prefs.min_switch_duration;
@@ -995,7 +995,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
pendinggaschange = false;
}
- int new_clock = wait_until(dive, clock, clock, laststoptime * 2 + 1, timestep, depth, stoplevels[stopidx], avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0);
+ int new_clock = wait_until(ds, dive, clock, clock, laststoptime * 2 + 1, timestep, depth, stoplevels[stopidx], avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0);
laststoptime = new_clock - clock;
/* Finish infinite deco */
if (clock >= 48 * 3600 && depth >= 6000) {
@@ -1043,7 +1043,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
}
}
}
- add_segment(depth_to_bar(depth, dive), &dive->cylinder[stop_cylinder].gasmix,
+ add_segment(ds, depth_to_bar(depth, dive), &dive->cylinder[stop_cylinder].gasmix,
laststoptime, po2, dive, prefs.decosac);
last_segment_min_switch = false;
decostoptable[decostopcounter].depth = depth;
@@ -1066,7 +1066,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
* otherwise odd things can happen, such as CVA causing the final ascent to start *later*
* if the ascent rate is slower, which is completely nonsensical.
* Assume final ascent takes 20s, which is the time taken to ascend at 9m/min from 3m */
- deco_state->deco_time = clock - bottom_time - stoplevels[stopidx + 1] / last_ascend_rate + 20;
+ ds->deco_time = clock - bottom_time - stoplevels[stopidx + 1] / last_ascend_rate + 20;
} while (!is_final_plan);
decostoptable[decostopcounter].depth = 0;
diff --git a/core/profile.c b/core/profile.c
index 697ebe1c0..5a88e20c6 100644
--- a/core/profile.c
+++ b/core/profile.c
@@ -903,7 +903,7 @@ static void setup_gas_sensor_pressure(struct dive *dive, struct divecomputer *dc
#ifndef SUBSURFACE_MOBILE
/* calculate DECO STOP / TTS / NDL */
-static void calculate_ndl_tts(struct dive *dive, struct plot_data *entry, struct gasmix *gasmix, double surface_pressure)
+static void calculate_ndl_tts(struct deco_state *ds, struct dive *dive, struct plot_data *entry, struct gasmix *gasmix, double surface_pressure)
{
/* FIXME: This should be configurable */
/* ascent speed up to first deco stop */
@@ -916,8 +916,9 @@ static void calculate_ndl_tts(struct dive *dive, struct plot_data *entry, struct
const int time_stepsize = 60;
const int deco_stepsize = 3000;
/* at what depth is the current deco-step? */
- int next_stop = ROUND_UP(deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)),
- surface_pressure, dive, 1), deco_stepsize);
+ int next_stop = ROUND_UP(deco_allowed_depth(
+ tissue_tolerance_calc(ds, dive, depth_to_bar(entry->depth, dive)),
+ surface_pressure, dive, 1), deco_stepsize);
int ascent_depth = entry->depth;
/* at what time should we give up and say that we got enuff NDL? */
/* If iterating through a dive, entry->tts_calc needs to be reset */
@@ -931,10 +932,13 @@ static void calculate_ndl_tts(struct dive *dive, struct plot_data *entry, struct
return;
}
/* stop if the ndl is above max_ndl seconds, and call it plenty of time */
- while (entry->ndl_calc < MAX_PROFILE_DECO && deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, 1) <= 0) {
+ while (entry->ndl_calc < MAX_PROFILE_DECO &&
+ deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(entry->depth, dive)),
+ surface_pressure, dive, 1) <= 0
+ ) {
entry->ndl_calc += time_stepsize;
- add_segment(depth_to_bar(entry->depth, dive),
- gasmix, time_stepsize, entry->o2pressure.mbar, dive, prefs.bottomsac);
+ add_segment(ds, depth_to_bar(entry->depth, dive),
+ gasmix, time_stepsize, entry->o2pressure.mbar, dive, prefs.bottomsac);
}
/* we don't need to calculate anything else */
return;
@@ -945,9 +949,10 @@ static void calculate_ndl_tts(struct dive *dive, struct plot_data *entry, struct
/* Add segments for movement to stopdepth */
for (; ascent_depth > next_stop; ascent_depth -= ascent_mm_per_step, entry->tts_calc += ascent_s_per_step) {
- add_segment(depth_to_bar(ascent_depth, dive),
+ add_segment(ds, depth_to_bar(ascent_depth, dive),
gasmix, ascent_s_per_step, entry->o2pressure.mbar, dive, prefs.decosac);
- next_stop = ROUND_UP(deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(ascent_depth, dive)), surface_pressure, dive, 1), deco_stepsize);
+ next_stop = ROUND_UP(deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(ascent_depth, dive)),
+ surface_pressure, dive, 1), deco_stepsize);
}
ascent_depth = next_stop;
@@ -965,13 +970,13 @@ static void calculate_ndl_tts(struct dive *dive, struct plot_data *entry, struct
entry->tts_calc += time_stepsize;
if (entry->tts_calc > MAX_PROFILE_DECO)
break;
- add_segment(depth_to_bar(ascent_depth, dive),
+ add_segment(ds, depth_to_bar(ascent_depth, dive),
gasmix, time_stepsize, entry->o2pressure.mbar, dive, prefs.decosac);
- if (deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(ascent_depth,dive)), surface_pressure, dive, 1) <= next_stop) {
+ if (deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(ascent_depth,dive)), surface_pressure, dive, 1) <= next_stop) {
/* move to the next stop and add the travel between stops */
for (; ascent_depth > next_stop; ascent_depth -= ascent_mm_per_deco_step, entry->tts_calc += ascent_s_per_deco_step)
- add_segment(depth_to_bar(ascent_depth, dive),
+ add_segment(ds, depth_to_bar(ascent_depth, dive),
gasmix, ascent_s_per_deco_step, entry->o2pressure.mbar, dive, prefs.decosac);
ascent_depth = next_stop;
next_stop -= deco_stepsize;
@@ -981,26 +986,26 @@ static void calculate_ndl_tts(struct dive *dive, struct plot_data *entry, struct
/* Let's try to do some deco calculations.
*/
-void calculate_deco_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool print_mode)
+void calculate_deco_information(struct deco_state *ds, struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool print_mode)
{
int i, count_iteration = 0;
double surface_pressure = (dc->surface_pressure.mbar ? dc->surface_pressure.mbar : get_surface_pressure_in_mbar(dive, true)) / 1000.0;
bool first_iteration = true;
int prev_deco_time = 10000000, time_deep_ceiling = 0;
if (!in_planner())
- deco_state->deco_time = 0;
+ ds->deco_time = 0;
struct deco_state *cache_data_initial = NULL;
lock_planner();
/* For VPM-B outside the planner, cache the initial deco state for CVA iterations */
if (decoMode() == VPMB) {
- cache_deco_state(&cache_data_initial);
+ cache_deco_state(ds, &cache_data_initial);
}
/* For VPM-B outside the planner, iterate until deco time converges (usually one or two iterations after the initial)
* Set maximum number of iterations to 10 just in case */
- while ((abs(prev_deco_time - deco_state->deco_time) >= 30) && (count_iteration < 10)) {
+ while ((abs(prev_deco_time - ds->deco_time) >= 30) && (count_iteration < 10)) {
int last_ndl_tts_calc_time = 0, first_ceiling = 0, current_ceiling, last_ceiling, final_tts = 0 , time_clear_ceiling = 0;
if (decoMode() == VPMB)
- deco_state->first_ceiling_pressure.mbar = depth_to_mbar(first_ceiling, dive);
+ ds->first_ceiling_pressure.mbar = depth_to_mbar(first_ceiling, dive);
struct gasmix *gasmix = NULL;
struct event *ev = NULL;
@@ -1012,7 +1017,7 @@ void calculate_deco_information(struct dive *dive, struct divecomputer *dc, stru
gasmix = get_gasmix(dive, dc, t1, &ev, gasmix);
entry->ambpressure = depth_to_bar(entry->depth, dive);
- entry->gfline = get_gf(entry->ambpressure, dive) * (100.0 - AMB_PERCENTAGE) + AMB_PERCENTAGE;
+ entry->gfline = get_gf(ds, entry->ambpressure, dive) * (100.0 - AMB_PERCENTAGE) + AMB_PERCENTAGE;
if (t0 > t1) {
fprintf(stderr, "non-monotonous dive stamps %d %d\n", t0, t1);
int xchg = t1;
@@ -1023,7 +1028,7 @@ void calculate_deco_information(struct dive *dive, struct divecomputer *dc, stru
time_stepsize = t1 - t0;
for (j = t0 + time_stepsize; j <= t1; j += time_stepsize) {
int depth = interpolate(entry[-1].depth, entry[0].depth, j - t0, t1 - t0);
- add_segment(depth_to_bar(depth, dive),
+ add_segment(ds, depth_to_bar(depth, dive),
gasmix, time_stepsize, entry->o2pressure.mbar, dive, entry->sac);
if ((t1 - j < time_stepsize) && (j < t1))
time_stepsize = t1 - j;
@@ -1033,15 +1038,15 @@ void calculate_deco_information(struct dive *dive, struct divecomputer *dc, stru
} else {
/* Keep updating the VPM-B gradients until the start of the ascent phase of the dive. */
if (decoMode() == VPMB && last_ceiling >= first_ceiling && first_iteration == true) {
- nuclear_regeneration(t1);
- vpmb_start_gradient();
+ nuclear_regeneration(ds, t1);
+ vpmb_start_gradient(ds);
/* For CVA iterations, calculate next gradient */
if (!first_iteration || in_planner())
- vpmb_next_gradient(deco_state->deco_time, surface_pressure / 1000.0);
+ vpmb_next_gradient(ds, ds->deco_time, surface_pressure / 1000.0);
}
- entry->ceiling = deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, !prefs.calcceiling3m);
+ entry->ceiling = deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, !prefs.calcceiling3m);
if (prefs.calcceiling3m)
- current_ceiling = deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, true);
+ current_ceiling = deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, true);
else
current_ceiling = entry->ceiling;
last_ceiling = current_ceiling;
@@ -1051,16 +1056,16 @@ void calculate_deco_information(struct dive *dive, struct divecomputer *dc, stru
(time_deep_ceiling == t0 && entry->depth == (entry - 1)->depth)) {
time_deep_ceiling = t1;
first_ceiling = current_ceiling;
- deco_state->first_ceiling_pressure.mbar = depth_to_mbar(first_ceiling, dive);
+ ds->first_ceiling_pressure.mbar = depth_to_mbar(first_ceiling, dive);
if (first_iteration) {
- nuclear_regeneration(t1);
- vpmb_start_gradient();
+ nuclear_regeneration(ds, t1);
+ vpmb_start_gradient(ds);
/* For CVA calculations, deco time = dive time remaining is a good guess,
but we want to over-estimate deco_time for the first iteration so it
converges correctly, so add 30min*/
if (!in_planner())
- deco_state->deco_time = pi->maxtime - t1 + 1800;
- vpmb_next_gradient(deco_state->deco_time, surface_pressure / 1000.0);
+ ds->deco_time = pi->maxtime - t1 + 1800;
+ vpmb_next_gradient(ds, ds->deco_time, surface_pressure / 1000.0);
}
}
// Use the point where the ceiling clears as the end of deco phase for CVA calculations
@@ -1071,11 +1076,11 @@ void calculate_deco_information(struct dive *dive, struct divecomputer *dc, stru
}
}
for (j = 0; j < 16; j++) {
- double m_value = deco_state->buehlmann_inertgas_a[j] + entry->ambpressure / deco_state->buehlmann_inertgas_b[j];
- entry->ceilings[j] = deco_allowed_depth(deco_state->tolerated_by_tissue[j], surface_pressure, dive, 1);
- entry->percentages[j] = deco_state->tissue_inertgas_saturation[j] < entry->ambpressure ?
- lrint(deco_state->tissue_inertgas_saturation[j] / entry->ambpressure * AMB_PERCENTAGE) :
- lrint(AMB_PERCENTAGE + (deco_state->tissue_inertgas_saturation[j] - entry->ambpressure) / (m_value - entry->ambpressure) * (100.0 - AMB_PERCENTAGE));
+ double m_value = ds->buehlmann_inertgas_a[j] + entry->ambpressure / ds->buehlmann_inertgas_b[j];
+ entry->ceilings[j] = deco_allowed_depth(ds->tolerated_by_tissue[j], surface_pressure, dive, 1);
+ entry->percentages[j] = ds->tissue_inertgas_saturation[j] < entry->ambpressure ?
+ lrint(ds->tissue_inertgas_saturation[j] / entry->ambpressure * AMB_PERCENTAGE) :
+ lrint(AMB_PERCENTAGE + (ds->tissue_inertgas_saturation[j] - entry->ambpressure) / (m_value - entry->ambpressure) * (100.0 - AMB_PERCENTAGE));
}
/* should we do more calculations?
@@ -1097,39 +1102,39 @@ void calculate_deco_information(struct dive *dive, struct divecomputer *dc, stru
/* We are going to mess up deco state, so store it for later restore */
struct deco_state *cache_data = NULL;
- cache_deco_state(&cache_data);
- calculate_ndl_tts(dive, entry, gasmix, surface_pressure);
+ cache_deco_state(ds, &cache_data);
+ calculate_ndl_tts(ds, dive, entry, gasmix, surface_pressure);
if (decoMode() == VPMB && !in_planner() && i == pi->nr - 1)
final_tts = entry->tts_calc;
/* Restore "real" deco state for next real time step */
- restore_deco_state(cache_data, decoMode() == VPMB);
+ restore_deco_state(cache_data, ds, decoMode() == VPMB);
free(cache_data);
}
}
if (decoMode() == VPMB && !in_planner()) {
int this_deco_time;
- prev_deco_time = deco_state->deco_time;
+ prev_deco_time = ds->deco_time;
// Do we need to update deco_time?
if (final_tts > 0)
- deco_state->deco_time = last_ndl_tts_calc_time + final_tts - time_deep_ceiling;
+ ds->deco_time = last_ndl_tts_calc_time + final_tts - time_deep_ceiling;
else if (time_clear_ceiling > 0)
/* Consistent with planner, deco_time ends after ascending (20s @9m/min from 3m)
* at end of whole minute after clearing ceiling. The deepest ceiling when planning a dive
* comes typically 10-60s after the end of the bottom time, so add 20s to the calculated
* deco time. */
- deco_state->deco_time = ROUND_UP(time_clear_ceiling - time_deep_ceiling + 20, 60) + 20;
- vpmb_next_gradient(deco_state->deco_time, surface_pressure / 1000.0);
+ ds->deco_time = ROUND_UP(time_clear_ceiling - time_deep_ceiling + 20, 60) + 20;
+ vpmb_next_gradient(ds, ds->deco_time, surface_pressure / 1000.0);
final_tts = 0;
last_ndl_tts_calc_time = 0;
first_ceiling = 0;
first_iteration = false;
count_iteration ++;
- this_deco_time = deco_state->deco_time;
- restore_deco_state(cache_data_initial, true);
- deco_state->deco_time = this_deco_time;
+ this_deco_time = ds->deco_time;
+ restore_deco_state(cache_data_initial, ds, true);
+ ds->deco_time = this_deco_time;
} else {
// With Buhlmann iterating isn't needed. This makes the while condition false.
- prev_deco_time = deco_state->deco_time = 0;
+ prev_deco_time = ds->deco_time = 0;
}
}
free(cache_data_initial);
@@ -1299,7 +1304,8 @@ void create_plot_info_new(struct dive *dive, struct divecomputer *dc, struct plo
{
int o2, he, o2max;
#ifndef SUBSURFACE_MOBILE
- init_decompression(dive);
+ struct deco_state plot_deco_state;
+ init_decompression(&plot_deco_state, dive);
#endif
/* Create the new plot data */
free((void *)last_pi_entry_new);
@@ -1327,7 +1333,7 @@ void create_plot_info_new(struct dive *dive, struct divecomputer *dc, struct plo
fill_o2_values(dive, dc, pi); /* .. and insert the O2 sensor data having 0 values. */
calculate_sac(dive, dc, pi); /* Calculate sac */
#ifndef SUBSURFACE_MOBILE
- calculate_deco_information(dive, dc, pi, false); /* and ceiling information, using gradient factor values in Preferences) */
+ calculate_deco_information(&plot_deco_state, dive, dc, pi, false); /* and ceiling information, using gradient factor values in Preferences) */
#endif
calculate_gas_information_new(dive, dc, pi); /* Calculate gas partial pressures */
diff --git a/core/profile.h b/core/profile.h
index 1cbcd30fd..bf29362f3 100644
--- a/core/profile.h
+++ b/core/profile.h
@@ -75,7 +75,7 @@ void compare_samples(struct plot_data *e1, struct plot_data *e2, char *buf, int
struct plot_data *populate_plot_entries(struct dive *dive, struct divecomputer *dc, struct plot_info *pi);
struct plot_info *analyze_plot_info(struct plot_info *pi);
void create_plot_info_new(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool fast);
-void calculate_deco_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool print_mode);
+void calculate_deco_information(struct deco_state *ds, struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool print_mode);
struct plot_data *get_plot_details_new(struct plot_info *pi, int time, struct membuffer *);
/*
diff --git a/core/qthelper.h b/core/qthelper.h
index ac91fbc1e..d23695f7f 100644
--- a/core/qthelper.h
+++ b/core/qthelper.h
@@ -52,5 +52,6 @@ extern "C" int parse_seabear_header(const char *filename, char **params, int pnr
enum inertgas {N2, HE};
extern "C" double cache_value(int tissue, int timestep, enum inertgas gas);
extern "C" void cache_insert(int tissue, int timestep, enum inertgas gas, double value);
-
+extern "C" void lock_planner();
+extern "C" void unlock_planner();
#endif // QTHELPER_H
diff --git a/qt-models/diveplannermodel.cpp b/qt-models/diveplannermodel.cpp
index acf2d9c6f..153771c08 100644
--- a/qt-models/diveplannermodel.cpp
+++ b/qt-models/diveplannermodel.cpp
@@ -6,6 +6,7 @@
#include "core/planner.h"
#include "qt-models/models.h"
#include "core/device.h"
+#include "core/qthelper.h"
#include "core/subsurface-qt/SettingsObjectWrapper.h"
#include <QApplication>
#include <QTextDocument>
@@ -920,8 +921,9 @@ void DivePlannerPointsModel::createTemporaryPlan()
#endif
if (recalcQ() && !diveplan_empty(&diveplan)) {
struct decostop stoptable[60];
- plan(&diveplan, &displayed_dive, DECOTIMESTEP, stoptable, &cache, isPlanner(), false);
- QtConcurrent::run(this, &DivePlannerPointsModel::computeVariations);
+ struct deco_state plan_deco_state;
+ plan(&plan_deco_state, &diveplan, &displayed_dive, DECOTIMESTEP, stoptable, &cache, isPlanner(), false);
+ //QtConcurrent::run(this, &DivePlannerPointsModel::computeVariations, &ds_after_previous_dives);
emit calculatedPlanNotes();
}
// throw away the cache
@@ -952,6 +954,7 @@ struct divedatapoint * DivePlannerPointsModel::cloneDiveplan(struct diveplan *pl
divedatapoint *src, *last_segment;
divedatapoint **dp;
+ lock_planner();
src = diveplan.dp;
*plan_copy = diveplan;
dp = &plan_copy->dp;
@@ -964,8 +967,9 @@ struct divedatapoint * DivePlannerPointsModel::cloneDiveplan(struct diveplan *pl
(*dp) = NULL;
last_segment = plan_copy->dp;
- while (last_segment->next->next)
+ while (last_segment && last_segment->next && last_segment->next->next)
last_segment = last_segment->next;
+ unlock_planner();
return last_segment;
}
@@ -1003,8 +1007,9 @@ int DivePlannerPointsModel::analyzeVariations(struct decostop *min, struct decos
return (leftsum + rightsum) / 2;
}
-void DivePlannerPointsModel::computeVariations()
+void DivePlannerPointsModel::computeVariations(struct deco_state *ds)
{
+ return;
bool oldRecalc = setRecalc(false);
struct dive *dive = alloc_dive();
copy_dive(&displayed_dive, dive);
@@ -1015,47 +1020,47 @@ void DivePlannerPointsModel::computeVariations()
if(in_planner() && prefs.display_variations) {
int my_instance = ++instanceCounter;
- cache_deco_state(&save);
+ cache_deco_state(ds, &save);
cloneDiveplan(&plan_copy);
if (my_instance != instanceCounter)
return;
- plan(&plan_copy, dive, 1, original, &cache, true, false);
+ plan(ds, &plan_copy, dive, 1, original, &cache, true, false);
free_dps(&plan_copy);
- restore_deco_state(save, false);
+ restore_deco_state(save, ds, false);
last_segment = cloneDiveplan(&plan_copy);
last_segment->depth.mm += 1000;
last_segment->next->depth.mm += 1000;
if (my_instance != instanceCounter)
return;
- plan(&plan_copy, dive, 1, deeper, &cache, true, false);
+ plan(ds, &plan_copy, dive, 1, deeper, &cache, true, false);
free_dps(&plan_copy);
- restore_deco_state(save, false);
+ restore_deco_state(save, ds, false);
last_segment = cloneDiveplan(&plan_copy);
last_segment->depth.mm -= 1000;
last_segment->next->depth.mm -= 1000;
if (my_instance != instanceCounter)
return;
- plan(&plan_copy, dive, 1, shallower, &cache, true, false);
+ plan(ds, &plan_copy, dive, 1, shallower, &cache, true, false);
free_dps(&plan_copy);
- restore_deco_state(save, false);
+ restore_deco_state(save, ds, false);
last_segment = cloneDiveplan(&plan_copy);
last_segment->next->time += 60;
if (my_instance != instanceCounter)
return;
- plan(&plan_copy, dive, 1, longer, &cache, true, false);
+ plan(ds, &plan_copy, dive, 1, longer, &cache, true, false);
free_dps(&plan_copy);
- restore_deco_state(save, false);
+ restore_deco_state(save, ds, false);
last_segment = cloneDiveplan(&plan_copy);
last_segment->next->time -= 60;
if (my_instance != instanceCounter)
return;
- plan(&plan_copy, dive, 1, shorter, &cache, true, false);
+ plan(ds, &plan_copy, dive, 1, shorter, &cache, true, false);
free_dps(&plan_copy);
- restore_deco_state(save, false);
+ restore_deco_state(save, ds, false);
#ifdef SHOWSTOPVARIATIONS
printf("\n\n");
#endif
@@ -1083,7 +1088,7 @@ void DivePlannerPointsModel::createPlan(bool replanCopy)
//TODO: C-based function here?
struct decostop stoptable[60];
- plan(&diveplan, &displayed_dive, DECOTIMESTEP, stoptable, &cache, isPlanner(), true);
+ plan(&ds_after_previous_dives, &diveplan, &displayed_dive, DECOTIMESTEP, stoptable, &cache, isPlanner(), true);
free(cache);
if (!current_dive || displayed_dive.id != current_dive->id) {
// we were planning a new dive, not re-planning an existing on
diff --git a/qt-models/diveplannermodel.h b/qt-models/diveplannermodel.h
index a4fe35a65..0b714e608 100644
--- a/qt-models/diveplannermodel.h
+++ b/qt-models/diveplannermodel.h
@@ -115,7 +115,7 @@ private:
void createPlan(bool replanCopy);
struct diveplan diveplan;
struct divedatapoint *cloneDiveplan(struct diveplan *plan_copy);
- void computeVariations();
+ void computeVariations(struct deco_state *ds);
int analyzeVariations(struct decostop *min, struct decostop *mid, struct decostop *max, const char *unit);
Mode mode;
bool recalc;
@@ -124,6 +124,7 @@ private:
int tempGFHigh;
int tempGFLow;
int instanceCounter = 0;
+ struct deco_state ds_after_previous_dives;
};
#endif
diff --git a/qt-models/diveplotdatamodel.cpp b/qt-models/diveplotdatamodel.cpp
index 8cabd833e..ac6cf7cd8 100644
--- a/qt-models/diveplotdatamodel.cpp
+++ b/qt-models/diveplotdatamodel.cpp
@@ -231,8 +231,8 @@ void DivePlotDataModel::emitDataChanged()
void DivePlotDataModel::calculateDecompression()
{
struct divecomputer *dc = select_dc(&displayed_dive);
- init_decompression(&displayed_dive);
- calculate_deco_information(&displayed_dive, dc, &pInfo, false);
+ init_decompression(&plot_deco_state, &displayed_dive);
+ calculate_deco_information(&plot_deco_state, &displayed_dive, dc, &pInfo, false);
dataChanged(index(0, CEILING), index(pInfo.nr - 1, TISSUE_16));
}
#endif
diff --git a/qt-models/diveplotdatamodel.h b/qt-models/diveplotdatamodel.h
index b28dce685..4e0c63c2e 100644
--- a/qt-models/diveplotdatamodel.h
+++ b/qt-models/diveplotdatamodel.h
@@ -5,6 +5,7 @@
#include <QAbstractTableModel>
#include "core/display.h"
+#include "core/dive.h"
struct dive;
struct plot_data;
@@ -91,6 +92,7 @@ private:
struct plot_info pInfo;
int diveId;
unsigned int dcNr;
+ struct deco_state plot_deco_state;
};
#endif // DIVEPLOTDATAMODEL_H
diff --git a/tests/testplan.cpp b/tests/testplan.cpp
index 771b3e831..5ef7b7187 100644
--- a/tests/testplan.cpp
+++ b/tests/testplan.cpp
@@ -11,8 +11,8 @@
// testing the dive plan algorithm
struct decostop stoptable[60];
-extern bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct decostop *decostoptable, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer);
-extern struct deco_state *deco_state;
+struct deco_state test_deco_state;
+extern bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, int timestep, struct decostop *decostoptable, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer);
void setupPrefs()
{
copy_prefs(&default_prefs, &prefs);
@@ -363,7 +363,7 @@ void TestPlan::testMetric()
struct diveplan testPlan = {};
setupPlan(&testPlan);
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -403,7 +403,7 @@ void TestPlan::testImperial()
struct diveplan testPlan = {};
setupPlan(&testPlan);
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -443,7 +443,7 @@ void TestPlan::testVpmbMetric45m30minTx()
setupPlanVpmb45m30mTx(&testPlan);
setCurrentAppState("PlanDive");
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -456,7 +456,7 @@ void TestPlan::testVpmbMetric45m30minTx()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 108l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check benchmark run time of 141 minutes, and known Subsurface runtime of 139 minutes
//QVERIFY(compareDecoTime(displayed_dive.dc.duration.seconds, 141u * 60u + 20u, 139u * 60u + 20u));
}
@@ -473,7 +473,7 @@ void TestPlan::testVpmbMetric60m10minTx()
setupPlanVpmb60m10mTx(&testPlan);
setCurrentAppState("PlanDive");
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -486,7 +486,7 @@ void TestPlan::testVpmbMetric60m10minTx()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 162l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check benchmark run time of 141 minutes, and known Subsurface runtime of 139 minutes
//QVERIFY(compareDecoTime(displayed_dive.dc.duration.seconds, 141u * 60u + 20u, 139u * 60u + 20u));
}
@@ -503,7 +503,7 @@ void TestPlan::testVpmbMetric60m30minAir()
setupPlanVpmb60m30minAir(&testPlan);
setCurrentAppState("PlanDive");
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -516,7 +516,7 @@ void TestPlan::testVpmbMetric60m30minAir()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 180l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check benchmark run time of 141 minutes, and known Subsurface runtime of 139 minutes
QVERIFY(compareDecoTime(displayed_dive.dc.duration.seconds, 141u * 60u + 20u, 139u * 60u + 20u));
}
@@ -533,7 +533,7 @@ void TestPlan::testVpmbMetric60m30minEan50()
setupPlanVpmb60m30minEan50(&testPlan);
setCurrentAppState("PlanDive");
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -546,7 +546,7 @@ void TestPlan::testVpmbMetric60m30minEan50()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 155l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check first gas change to EAN50 at 21m
struct event *ev = displayed_dive.dc.events;
QVERIFY(ev != NULL);
@@ -569,7 +569,7 @@ void TestPlan::testVpmbMetric60m30minTx()
setupPlanVpmb60m30minTx(&testPlan);
setCurrentAppState("PlanDive");
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -582,7 +582,7 @@ void TestPlan::testVpmbMetric60m30minTx()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 159l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check first gas change to EAN50 at 21m
struct event *ev = displayed_dive.dc.events;
QVERIFY(ev != NULL);
@@ -605,7 +605,7 @@ void TestPlan::testVpmbMetric100m60min()
setupPlanVpmb100m60min(&testPlan);
setCurrentAppState("PlanDive");
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -618,7 +618,7 @@ void TestPlan::testVpmbMetric100m60min()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 157l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check first gas change to EAN50 at 21m
struct event *ev = displayed_dive.dc.events;
QVERIFY(ev != NULL);
@@ -647,7 +647,7 @@ void TestPlan::testVpmbMetricMultiLevelAir()
setupPlanVpmbMultiLevelAir(&testPlan);
setCurrentAppState("PlanDive");
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -660,7 +660,7 @@ void TestPlan::testVpmbMetricMultiLevelAir()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 101l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check benchmark run time of 167 minutes, and known Subsurface runtime of 169 minutes
QVERIFY(compareDecoTime(displayed_dive.dc.duration.seconds, 167u * 60u + 20u, 169u * 60u + 20u));
}
@@ -677,7 +677,7 @@ void TestPlan::testVpmbMetric100m10min()
setupPlanVpmb100m10min(&testPlan);
setCurrentAppState("PlanDive");
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -690,7 +690,7 @@ void TestPlan::testVpmbMetric100m10min()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 175l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check first gas change to EAN50 at 21m
struct event *ev = displayed_dive.dc.events;
QVERIFY(ev != NULL);
@@ -723,7 +723,7 @@ void TestPlan::testVpmbMetricRepeat()
setupPlanVpmb30m20min(&testPlan);
setCurrentAppState("PlanDive");
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -736,14 +736,14 @@ void TestPlan::testVpmbMetricRepeat()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 61l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check benchmark run time of 27 minutes, and known Subsurface runtime of 28 minutes
QVERIFY(compareDecoTime(displayed_dive.dc.duration.seconds, 27u * 60u + 20u, 27u * 60u + 20u));
int firstDiveRunTimeSeconds = displayed_dive.dc.duration.seconds;
setupPlanVpmb100mTo70m30min(&testPlan);
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -756,7 +756,7 @@ void TestPlan::testVpmbMetricRepeat()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 80l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check first gas change to 21/35 at 66m
struct event *ev = displayed_dive.dc.events;
QVERIFY(ev != NULL);
@@ -779,7 +779,7 @@ void TestPlan::testVpmbMetricRepeat()
QVERIFY(compareDecoTime(displayed_dive.dc.duration.seconds, 127u * 60u + 20u, 127u * 60u + 20u));
setupPlanVpmb30m20min(&testPlan);
- plan(&testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
+ plan(&test_deco_state, &testPlan, &displayed_dive, 60, stoptable, &cache, 1, 0);
#if DEBUG
free(displayed_dive.notes);
@@ -792,7 +792,7 @@ void TestPlan::testVpmbMetricRepeat()
while(!dp->minimum_gas.mbar && dp->next) dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 61l);
// print first ceiling
- printf("First ceiling %.1f m\n", (mbar_to_depth(deco_state->first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
+ printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &displayed_dive) * 0.001));
// check runtime is exactly the same as the first time
int finalDiveRunTimeSeconds = displayed_dive.dc.duration.seconds;