diff options
author | Robert C. Helling <helling@atdotde.de> | 2017-11-22 20:42:33 +0100 |
---|---|---|
committer | Robert C. Helling <helling@atdotde.de> | 2017-11-25 20:13:01 +0100 |
commit | 8e21a65653514d9340ef45c9b9c53dfe5d280350 (patch) | |
tree | 2ada40567e25bc45035698748f368127b1cca199 /core/profile.c | |
parent | a9ceecc2e3646432d6688d04b592c48f9c63ae65 (diff) | |
download | subsurface-8e21a65653514d9340ef45c9b9c53dfe5d280350.tar.gz |
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>
Diffstat (limited to 'core/profile.c')
-rw-r--r-- | core/profile.c | 98 |
1 files changed, 52 insertions, 46 deletions
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 */ |