Localize global planner state

For UI responsiveness, we need to be able to run the planner in the background. This needs the
planner state to be localized (and we need to pass a pointer around).

In order to not let too many lines overrun (and to save typing in the future)
I have renamed instances of struct deco_state to ds. Yes this should have gone
to a separate commit but I accidentally commit --amend'ed it.

Computing of planner variations is temporarily disabled.

Unlock the planner when returning early

So we don't deadlock in add dive and recreational mode (which
use the planner without actually planning).

Signed-off-by: Robert C. Helling <helling@atdotde.de>
This commit is contained in:
Robert C. Helling 2017-11-22 20:42:33 +01:00
parent a9ceecc2e3
commit 8e21a65653
14 changed files with 298 additions and 286 deletions

View file

@ -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;

View file

@ -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
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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 */

View file

@ -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 *);
/*

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;