aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/planner.c67
1 files changed, 45 insertions, 22 deletions
diff --git a/core/planner.c b/core/planner.c
index 553e152fa..65bd5b488 100644
--- a/core/planner.c
+++ b/core/planner.c
@@ -558,7 +558,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 trial_depth, int stoplevel, int avg_depth, int bottom_time, struct gasmix *gasmix, int po2, double surface_pressure)
+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 clear_to_ascend = true;
@@ -568,9 +568,13 @@ bool trial_ascent(int trial_depth, int stoplevel, int avg_depth, int bottom_time
// 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);
- if (decoMode() == VPMB && (deco_allowed_depth(tissue_tolerance_calc(&displayed_dive,
- depth_to_bar(stoplevel, &displayed_dive)),
- surface_pressure, &displayed_dive, 1) > stoplevel)) {
+ if (wait_time)
+ add_segment(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);
free(trial_cache);
return false;
@@ -580,11 +584,11 @@ bool trial_ascent(int trial_depth, int stoplevel, int avg_depth, int bottom_time
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, &displayed_dive),
+ add_segment(depth_to_bar(trial_depth, dive),
gasmix,
- TIMESTEP, po2, &displayed_dive, prefs.decosac);
- if (deco_allowed_depth(tissue_tolerance_calc(&displayed_dive, depth_to_bar(trial_depth, &displayed_dive)),
- surface_pressure, &displayed_dive, 1) > trial_depth - deltad) {
+ TIMESTEP, po2, dive, prefs.decosac);
+ if (deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(trial_depth, dive)),
+ surface_pressure, dive, 1) > trial_depth - deltad) {
/* We should have stopped */
clear_to_ascend = false;
break;
@@ -613,6 +617,27 @@ bool enough_gas(int current_cylinder)
return true;
}
+/* Do a binary search for the time the ceiling is clear to ascent to target_depth.
+ * Minimal solution is min + 1, and the solution should be an integer multiple of stepsize.
+ * leap is a guess for the maximum but there is no guarantee that leap is an upper limit.
+ * 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)
+{
+ // Round min + leap up to the next multiple of stepsize
+ int upper = min + leap + stepsize - 1 - (min + leap - 1) % stepsize;
+ printf("clock: %d min: %d leap: %d, depth %d\n", clock / 60, min / 60, leap, depth);
+ // 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 (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);
+}
+
// Work out the stops. Return value is if there were any mandatory stops.
bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer)
@@ -648,6 +673,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
int error = 0;
bool decodive = false;
int first_stop_depth = 0;
+ int laststoptime = timestep;
set_gf(diveplan->gflow, diveplan->gfhigh, prefs.gf_low_at_maxdepth);
set_vpmb_conservatism(diveplan->vpmb_conservatism);
@@ -738,8 +764,8 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
timestep, po2, dive, prefs.bottomsac);
update_cylinder_pressure(dive, depth, depth, timestep, prefs.bottomsac, &dive->cylinder[current_cylinder], false);
clock += timestep;
- } while (trial_ascent(depth, 0, avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix,
- po2, diveplan->surface_pressure / 1000.0) &&
+ } while (trial_ascent(0, depth, 0, avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix,
+ po2, diveplan->surface_pressure / 1000.0, dive) &&
enough_gas(current_cylinder));
// We did stay one DECOTIMESTEP too many.
@@ -880,8 +906,8 @@ 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(depth, stoplevels[stopidx - 1], avg_depth, bottom_time,
- &dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0) || get_o2(&dive->cylinder[current_cylinder].gasmix) < 160) {
+ !trial_ascent(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;
#if DEBUG_PLAN & 16
@@ -909,8 +935,8 @@ 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(depth, stoplevels[stopidx], avg_depth, bottom_time,
- &dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0))
+ if (trial_ascent(0, depth, stoplevels[stopidx], avg_depth, bottom_time,
+ &dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, dive))
break; /* We did not hit the ceiling */
/* Add a minute of deco time and then try again */
@@ -947,14 +973,11 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
pendinggaschange = false;
}
- /* Deco stop should end when runtime is at a whole minute */
- int this_decotimestep;
- this_decotimestep = timestep - clock % timestep;
-
- add_segment(depth_to_bar(depth, dive),
- &dive->cylinder[current_cylinder].gasmix,
- this_decotimestep, po2, dive, prefs.decosac);
- clock += this_decotimestep;
+ int new_clock = wait_until(dive, clock, clock, laststoptime * 2, timestep, depth, stoplevels[stopidx], avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0);
+ add_segment(depth_to_bar(depth, dive), &dive->cylinder[current_cylinder].gasmix,
+ new_clock - clock, po2, dive, prefs.decosac);
+ laststoptime = new_clock - clock;
+ clock = new_clock;
/* Finish infinite deco */
if (clock >= 48 * 3600 && depth >= 6000) {
error = LONGDECO;