diff options
-rw-r--r-- | core/deco.c | 206 | ||||
-rw-r--r-- | core/deco.h | 3 | ||||
-rw-r--r-- | core/dive.h | 24 | ||||
-rw-r--r-- | core/divelist.c | 30 | ||||
-rw-r--r-- | core/divelist.h | 2 | ||||
-rw-r--r-- | core/planner.c | 118 | ||||
-rw-r--r-- | core/profile.c | 98 | ||||
-rw-r--r-- | core/profile.h | 2 | ||||
-rw-r--r-- | core/qthelper.h | 3 | ||||
-rw-r--r-- | qt-models/diveplannermodel.cpp | 37 | ||||
-rw-r--r-- | qt-models/diveplannermodel.h | 3 | ||||
-rw-r--r-- | qt-models/diveplotdatamodel.cpp | 4 | ||||
-rw-r--r-- | qt-models/diveplotdatamodel.h | 2 | ||||
-rw-r--r-- | tests/testplan.cpp | 52 |
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; |