diff options
-rw-r--r-- | Documentation/user-manual_es.txt | 75 | ||||
-rw-r--r-- | profile-widget/profilewidget2.cpp | 32 | ||||
-rw-r--r-- | profile-widget/profilewidget2.h | 2 | ||||
-rw-r--r-- | subsurface-core/deco.c | 4 | ||||
-rw-r--r-- | subsurface-core/file.c | 3 | ||||
-rw-r--r-- | subsurface-core/parse-xml.c | 56 | ||||
-rw-r--r-- | subsurface-core/profile.c | 183 |
7 files changed, 239 insertions, 116 deletions
diff --git a/Documentation/user-manual_es.txt b/Documentation/user-manual_es.txt index a8cd4c267..8c9490638 100644 --- a/Documentation/user-manual_es.txt +++ b/Documentation/user-manual_es.txt @@ -6,7 +6,7 @@ // :revnumber: 4.5 // :revdate: October 2015 :icons: -:toc: +:toc2: :toc-placement: manual :numbered: :ascii-ids: @@ -24,7 +24,7 @@ Pedro Neves Bienvenido como usuario de _Subsurface_, un avanzado programa de registro de inmersiones con extensa infraestructura para describir, organizar e -interpretarbuceos en apnea o con botella. _Subsurface_ ofrece muchas ventajas +interpretar buceos en apnea o con botella. _Subsurface_ ofrece muchas ventajas sobre otras soluciones de software similares: - ¿Necesitas una forma flexible de registrar inmersiones usando equipo @@ -65,14 +65,31 @@ Buceadores profesionales. toc::[] -[[S_UserSurvey]] Utilizar este manual -------------------- Cuando se abre desde dentro de _Subsurface_ este manual no tiene controles -externos. Sin embargo, una función _BUSCAR_ es importante. Se activa pulsando -control-F en el teclado. Aparecerá una ventana de texto al pié de la ventana. -Utilízala para buscar cualquier término en el manual. +externos para paginar o seleccionar páginas anteriores, sin embargo se +proporcionan dos utilidades: + +- La función _BUSCAR_ se activa pulsando control-F o command-F en el teclado. +Aparecerá una ventana de texto al pié de la ventana (ver imagen a continuación). +Por ejemplo, si se tecleó la palabra "_lastre_" en la casilla de búsqueda, se +buscará esta palabra por todo el manual. A la derecha de la casilla de texto +hay dos flechas, una hacia arriba y otra hacia abajo. Pulsándolas se irá a la +anterior o posterior aparición de la palabra buscada. + +image::images/usermanualfunctions.jpg["User manual functions",align="center"] + +- _LINK ANTERIOR/POSTERIOR_. Se puede navegar entre links (palabras resaltadas +que permiten saltar a secciones específicas del manual) haciendo clic-derecho +en el texto. Esto muestra un menú contextual que permite navegar a links +del manual visitados anteriormente (ver imagen anterior). Por ejemplo, si se +ha seleccionado un link del manual, la opción _Atrás_ muestra el texto del +último link seleccionado. A la inversa, la opción _Adelante_ permite saltar +al texto visitado antes de usar la opción _Atrás_. La opción _Recargar_ hace +que se recargue el manual completo en la ventana. +[[S_UserSurvey]] La Encuesta de Usuarios ----------------------- Para poder desarrollar _Subsurface_ de una forma que sirva a sus usuarios de la @@ -509,8 +526,12 @@ _Limpiar_ y efectúa una nueva búsqueda utilizando el botón _Buscar_. Si _Subsurface_ "ve" el ordenador de buceo, la línea de la lista contendrá el nombre del dispositivo, su dirección y su estado de emparejamiento. Si el dispositivo no está emparejado y tiene un fondo rojo, se puede abrir un menú -contextual seleccionando su línea y pulsando clic-derecho. Pulsa el -botón _Emparejar_ y espera a que se complete la tarea. +contextual seleccionando su línea y pulsando clic-derecho. +Pulsa el botón _Emparejar_ y espera a que se complete la tarea. Si este +ordenador de buceo se está emparejando con _Subsurface_ por primera vez, es +posible que se requiera una clave o número PIN. La clave más utilizada suele +ser 0000, y funciona para el Shearwater Petrel. En caso necesario, consulta el +manual de usuario del ordenador de buceo. **** [icon="images/icons/important.png"] @@ -543,7 +564,11 @@ image::images/DC_import_Bluetooth_Windows.png["FIGURE: Descarga Bluetooth en Win En plataformas Windows no está disponible la _sección de detalles de los dispositivos Bluetooth_. Para iniciar correctamente un escaneo pulsando el botón _Buscar_ , comprueba que el dispositivo _Bluetooth_ del ordenador con -_Subsurface_ está activado. +_Subsurface_ está activado seleccionando el ordenador de la lista de +dispositivos Bluetooth disponibles (ver imagen anterior). Si se accede por +primera vez al ordenador de buceo con _Subsurface_, es posible que se +requiera una clave/PIN. Introduce el recomendado en el manual de ordenador +de buceo. A menudo es correcto un pin 0000. El paso del emparejado se efectúa de forma automática durante el proceso de descarga. Si los dispositivos no se han @@ -559,7 +584,8 @@ proceso. Hay que tener en cuenta que, actualmente, _Subsurface_ solo funciona con adaptadores Bluetooth locales que usen Microsoft Bluetooth Stack. Si el dispositivo local usa drivers _Widcomm_, _Stonestreet One Bluetopia Bluetooth_ o -_BlueSolei_ no funcionará. +_BlueSolei_ no funcionará, sin embargo, los receptores de estos fabricantes +que usen el Microsoft Bluetooth Stack sí funcionarán. Un mensaje de aviso en la parte inferior izquierda de la _Selección de dispositivos Bluetooth remotos_ muestra detalles del estado actual del agente @@ -1966,10 +1992,10 @@ oxígeno (OTU) en las que se ha incurrido. [icon="images/icons/info.jpg"] [NOTE] -Consumo de gas y cálculos de CAS _Subsurface_ calcula el CAS y el consumo de gas +Consumo de gas y cálculos de CAS: _Subsurface_ calcula el CAS y el consumo de gas teniendo en cuenta la incompresibilidad de los gases, particularmente a presiones en las botellas superiores a 200 bar, haciéndolos más precisos. Los -usuarios deberían consultar el xref:SAC_CALCULATION[Apéndice_D] para más información. +usuarios deberían consultar el xref:SAC_CALCULATION[Apéndice F] para más información. [[S_ExtraDataTab]] === La pestaña *Otros datos* (para inmersiones individuales) @@ -2265,6 +2291,20 @@ máxima de 1.4 en la sección *Preferencias*. Por debajo de la PMO existe un riesgo muy elevado de exposición a los peligros asociados con la toxicidad del oxígeno. +[icon="images/icons/NDL.jpg"] +[NOTE] +Activar este botón hace que el recuadro Información muestre, bien el *Límite +de no descompresión (LND)* o el **Tiempo total hasta superficie (TTS)*. El +LND es el tiempo que un buzo puede permanecer sumergido a la profundidad actual +sin requerir descompresión (esto es, sin que aparezca un techo para el ascenso). +Una vez que se ha excedido el LND y se requiere descompresión, el TTS incluirá +el total de minutos requeridos antes de que el buceador pueda salir a superficie. +El TTS incluye el tiempo de ascenso y las paradas de descompresión. Se calcula +suponiendo que se usa el gas actual. Incluso si el perfil incluye varios +cambios de gas, el TTS en un momento dado de la inmersión se habrá calculado +con el gas en uso en ese momento. Para TTS superiores a 2 horas, no se calcula +con precisión y simplemente se indica _TTS > 2h_. + [icon="images/icons/SAC.jpg"] [NOTE] Activar este botón hace que el Recuadro de información muestre el *Consumo de @@ -3787,7 +3827,7 @@ conectarse y se debería poder importar las inmersiones. [icon="images/icons/bluetooth.jpg"] [NOTE] Para ordenadores de buceo que se comunican por bluetooth como el Heinrichs -Weikamp Frog o el Shearwater Predator y Petrel hay un procedimiento distinto +Weikamp Frog o el Shearwater Predator, Petrel y Nerd hay un procedimiento distinto para localizar los nombres de dispositivo con los que se comunicará _Subsurface_. En general consiste en estos pasos: @@ -3795,7 +3835,7 @@ _Subsurface_. En general consiste en estos pasos: modo Upload* Para emparejar el ordenador de buceo, consulta la guía de usuario del -fabricante. Si se está usando un Shearwater Predator/Petrel, hay que seleccionar +fabricante. Si se está usando un Shearwater Predator/Petrel/Nerd, hay que seleccionar _Dive Log → Upload Log_ y esperar al mensaje _Wait PC_. * *Emparejar el PC con _Subsurface_ con el ordenador de buceo.* @@ -3850,7 +3890,7 @@ Se trata esencialmente de un proceso en tres pasos. - Descargar las inmersiones con _Subsurface_ Asegurarse de que el ordenador de buceo está en modo "upload". En el _Petrel_ -y _Petrel 2_, navega por el menú, selecciona 'Dive Log', luego 'Upload log'. En +y _Petrel 2_ y _Nerd_, navega por el menú, selecciona 'Dive Log', luego 'Upload log'. En la pantalla se leerá 'Initializing', luego 'Wait PC 3:00' e iniciará una cuenta atrás. Una vez que la conexión esté establecida, en la pantalla se leerá 'Wait CMD ...' y la cuenta atrás seguirá. Cuando se descargue la inmersión a @@ -3964,8 +4004,9 @@ Si se omite el canal, se asume el 1. Basándonos en un número limitado de informaciones de usuarios el canal apropiado para el ordenador de buceo, probablemente sea: -- _Shearwater Petrel 2_: channel 5 - _Shearwater Petrel 1_: channel 1 +- _Shearwater Petrel 2_: channel 5 +- _Shearwater Nerd_: channel 5 - _Heinrichs-Weikamp OSTC Sport_: channel 1 P.e. para conectar un _Shearwater Petrel 2_, ajusta el ordenador de buceo a @@ -4106,7 +4147,7 @@ capa de deco en el *Perfil deinmersión* de _Subsurface_ pero fíjate que la deco calculada por _Subsurface_ diferirá con toda probabilidad de la que mostraría el xDEEP BLACK. -=== Importar del Shearwater Predator/Petrel usando Bluetooth +=== Importar del Shearwater Predator/Petrel/Nerd usando Bluetooth [icon="images/icons/predator.jpg"] [NOTE] diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index 8ff8e8669..653818556 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -87,7 +87,7 @@ ProfileWidget2::ProfileWidget2(QWidget *parent) : QGraphicsView(parent), gasPressureItem(new DiveGasPressureItem()), diveComputerText(new DiveTextItem()), diveCeiling(new DiveCalculatedCeiling()), - gradientFactor(new DiveTextItem()), + decoModelParameters(new DiveTextItem()), reportedCeiling(new DiveReportedCeiling()), pn2GasItem(new PartialPressureGasItem()), pheGasItem(new PartialPressureGasItem()), @@ -204,7 +204,7 @@ void ProfileWidget2::addItemsToScene() diveComputerText->setData(SUBSURFACE_OBJ_DATA, SUBSURFACE_OBJ_DC_TEXT); scene()->addItem(diveComputerText); scene()->addItem(diveCeiling); - scene()->addItem(gradientFactor); + scene()->addItem(decoModelParameters); scene()->addItem(reportedCeiling); scene()->addItem(pn2GasItem); scene()->addItem(pheGasItem); @@ -288,11 +288,11 @@ void ProfileWidget2::setupItemOnScene() rulerItem->setAxis(timeAxis, profileYAxis); tankItem->setHorizontalAxis(timeAxis); - // show the gradient factor at the top in the center - gradientFactor->setY(0); - gradientFactor->setX(50); - gradientFactor->setBrush(getColor(PRESSURE_TEXT)); - gradientFactor->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); + // show the deco model parameters at the top in the center + decoModelParameters->setY(0); + decoModelParameters->setX(50); + decoModelParameters->setBrush(getColor(PRESSURE_TEXT)); + decoModelParameters->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); setupItem(reportedCeiling, timeAxis, profileYAxis, dataModel, DivePlotDataModel::CEILING, DivePlotDataModel::TIME, 1); setupItem(diveCeiling, timeAxis, profileYAxis, dataModel, DivePlotDataModel::CEILING, DivePlotDataModel::TIME, 1); @@ -509,7 +509,10 @@ void ProfileWidget2::plotDive(struct dive *d, bool force) // this copies the dive and makes copies of all the relevant additional data copy_dive(d, &displayed_dive); - gradientFactor->setText(QString("GF %1/%2").arg(prefs.gflow).arg(prefs.gfhigh)); + if (prefs.deco_mode == VPMB) + decoModelParameters->setText(QString("VPM-B +%1").arg(prefs.conservatism_level)); + else + decoModelParameters->setText(QString("GF %1/%2").arg(prefs.gflow).arg(prefs.gfhigh)); } else { DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); plannerModel->createTemporaryPlan(); @@ -518,7 +521,10 @@ void ProfileWidget2::plotDive(struct dive *d, bool force) plannerModel->deleteTemporaryPlan(); return; } - gradientFactor->setText(QString("GF %1/%2").arg(diveplan.gflow).arg(diveplan.gfhigh)); + if (prefs.deco_mode == VPMB) + decoModelParameters->setText(QString("VPM-B +%1").arg(prefs.conservatism_level)); + else + decoModelParameters->setText(QString("GF %1/%2").arg(prefs.gflow).arg(prefs.gfhigh)); } // special handling for the first time we display things @@ -926,7 +932,7 @@ void ProfileWidget2::setEmptyState() toolTipItem->setVisible(false); diveComputerText->setVisible(false); diveCeiling->setVisible(false); - gradientFactor->setVisible(false); + decoModelParameters->setVisible(false); reportedCeiling->setVisible(false); rulerItem->setVisible(false); tankItem->setVisible(false); @@ -1053,7 +1059,7 @@ void ProfileWidget2::setProfileState() diveComputerText->setPos(itemPos.dcLabel.on); diveCeiling->setVisible(prefs.calcceiling); - gradientFactor->setVisible(prefs.calcceiling); + decoModelParameters->setVisible(prefs.calcceiling); reportedCeiling->setVisible(prefs.dcceiling); if (prefs.calcalltissues) { @@ -1131,7 +1137,7 @@ void ProfileWidget2::setAddState() /* show the same stuff that the profile shows. */ currentState = ADD; /* enable the add state. */ diveCeiling->setVisible(true); - gradientFactor->setVisible(true); + decoModelParameters->setVisible(true); setBackgroundBrush(QColor("#A7DCFF")); } @@ -1165,7 +1171,7 @@ void ProfileWidget2::setPlanState() /* show the same stuff that the profile shows. */ currentState = PLAN; /* enable the add state. */ diveCeiling->setVisible(true); - gradientFactor->setVisible(true); + decoModelParameters->setVisible(true); setBackgroundBrush(QColor("#D7E3EF")); } diff --git a/profile-widget/profilewidget2.h b/profile-widget/profilewidget2.h index f11ec5be1..ce3fda083 100644 --- a/profile-widget/profilewidget2.h +++ b/profile-widget/profilewidget2.h @@ -170,7 +170,7 @@ private: QList<DiveEventItem *> eventItems; DiveTextItem *diveComputerText; DiveCalculatedCeiling *diveCeiling; - DiveTextItem *gradientFactor; + DiveTextItem *decoModelParameters; QList<DiveCalculatedTissue *> allTissues; DiveReportedCeiling *reportedCeiling; PartialPressureGasItem *pn2GasItem; diff --git a/subsurface-core/deco.c b/subsurface-core/deco.c index 86acc0351..506d8b58f 100644 --- a/subsurface-core/deco.c +++ b/subsurface-core/deco.c @@ -244,7 +244,7 @@ double tissue_tolerance_calc(const struct dive *dive, double pressure) double lowest_ceiling = 0.0; double tissue_lowest_ceiling[16]; - if (prefs.deco_mode != VPMB || !in_planner()) { + if (prefs.deco_mode != VPMB) { for (ci = 0; ci < 16; ci++) { tissue_inertgas_saturation[ci] = tissue_n2_sat[ci] + tissue_he_sat[ci]; buehlmann_inertgas_a[ci] = ((buehlmann_N2_a[ci] * tissue_n2_sat[ci]) + (buehlmann_He_a[ci] * tissue_he_sat[ci])) / tissue_inertgas_saturation[ci]; @@ -509,7 +509,7 @@ void add_segment(double pressure, const struct gasmix *gasmix, int period_in_sec tissue_n2_sat[ci] += n2_satmult * pn2_oversat * n2_f; tissue_he_sat[ci] += he_satmult * phe_oversat * he_f; } - if(prefs.deco_mode == VPMB && in_planner()) + if(prefs.deco_mode == VPMB) calc_crushing_pressure(pressure); return; } diff --git a/subsurface-core/file.c b/subsurface-core/file.c index c4032c1f2..0263da457 100644 --- a/subsurface-core/file.c +++ b/subsurface-core/file.c @@ -105,6 +105,9 @@ int try_to_open_zip(const char *filename, struct memblock *mem) success++; } subsurface_zip_close(zip); + + if (!success) + return report_error(translate("gettextFromC", "No dives in the input file '%s'"), filename); } return success; } diff --git a/subsurface-core/parse-xml.c b/subsurface-core/parse-xml.c index 3d86222b9..93ce74305 100644 --- a/subsurface-core/parse-xml.c +++ b/subsurface-core/parse-xml.c @@ -1398,32 +1398,36 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; if (MATCH("visibility.dive", get_rating, &dive->visibility)) return; - if (MATCH("size.cylinder", cylindersize, &dive->cylinder[cur_cylinder_index].type.size)) - return; - if (MATCH("workpressure.cylinder", pressure, &dive->cylinder[cur_cylinder_index].type.workingpressure)) - return; - if (MATCH("description.cylinder", utf8_string, &dive->cylinder[cur_cylinder_index].type.description)) - return; - if (MATCH("start.cylinder", pressure, &dive->cylinder[cur_cylinder_index].start)) - return; - if (MATCH("end.cylinder", pressure, &dive->cylinder[cur_cylinder_index].end)) - return; - if (MATCH("use.cylinder", cylinder_use, &dive->cylinder[cur_cylinder_index].cylinder_use)) - return; - if (MATCH("description.weightsystem", utf8_string, &dive->weightsystem[cur_ws_index].description)) - return; - if (MATCH("weight.weightsystem", weight, &dive->weightsystem[cur_ws_index].weight)) - return; - if (MATCH("weight", weight, &dive->weightsystem[cur_ws_index].weight)) - return; - if (MATCH("o2", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2)) - return; - if (MATCH("o2percent", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2)) - return; - if (MATCH("n2", gasmix_nitrogen, &dive->cylinder[cur_cylinder_index].gasmix)) - return; - if (MATCH("he", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.he)) - return; + if (cur_ws_index < MAX_WEIGHTSYSTEMS) { + if (MATCH("description.weightsystem", utf8_string, &dive->weightsystem[cur_ws_index].description)) + return; + if (MATCH("weight.weightsystem", weight, &dive->weightsystem[cur_ws_index].weight)) + return; + if (MATCH("weight", weight, &dive->weightsystem[cur_ws_index].weight)) + return; + } + if (cur_cylinder_index < MAX_CYLINDERS) { + if (MATCH("size.cylinder", cylindersize, &dive->cylinder[cur_cylinder_index].type.size)) + return; + if (MATCH("workpressure.cylinder", pressure, &dive->cylinder[cur_cylinder_index].type.workingpressure)) + return; + if (MATCH("description.cylinder", utf8_string, &dive->cylinder[cur_cylinder_index].type.description)) + return; + if (MATCH("start.cylinder", pressure, &dive->cylinder[cur_cylinder_index].start)) + return; + if (MATCH("end.cylinder", pressure, &dive->cylinder[cur_cylinder_index].end)) + return; + if (MATCH("use.cylinder", cylinder_use, &dive->cylinder[cur_cylinder_index].cylinder_use)) + return; + if (MATCH("o2", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2)) + return; + if (MATCH("o2percent", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2)) + return; + if (MATCH("n2", gasmix_nitrogen, &dive->cylinder[cur_cylinder_index].gasmix)) + return; + if (MATCH("he", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.he)) + return; + } if (MATCH("air.divetemperature", temperature, &dive->airtemp)) return; if (MATCH("water.divetemperature", temperature, &dive->watertemp)) diff --git a/subsurface-core/profile.c b/subsurface-core/profile.c index d39133c21..edba51ebd 100644 --- a/subsurface-core/profile.c +++ b/subsurface-core/profile.c @@ -28,6 +28,9 @@ unsigned int dc_number = 0; static struct plot_data *last_pi_entry_new = NULL; void populate_pressure_information(struct dive *, struct divecomputer *, struct plot_info *, int); +extern bool in_planner(); +extern pressure_t first_ceiling_pressure; + #ifdef DEBUG_PI /* debugging tool - not normally used */ static void dump_pi(struct plot_info *pi) @@ -866,6 +869,8 @@ static void calculate_ndl_tts(struct plot_data *entry, struct dive *dive, double int ascent_depth = entry->depth; /* at what time should we give up and say that we got enuff NDL? */ int cylinderindex = entry->cylinderindex; + /* If iterating through a dive, entry->tts_calc needs to be reset */ + entry->tts_calc = 0; /* If we don't have a ceiling yet, calculate ndl. Don't try to calculate * a ndl for lower values than 3m it would take forever */ @@ -927,69 +932,133 @@ static void calculate_ndl_tts(struct plot_data *entry, struct dive *dive, double */ void calculate_deco_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool print_mode) { - int i; + 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; int last_ndl_tts_calc_time = 0; - for (i = 1; i < pi->nr; i++) { - struct plot_data *entry = pi->entry + i; - int j, t0 = (entry - 1)->sec, t1 = entry->sec; - int time_stepsize = 20; - - entry->ambpressure = depth_to_bar(entry->depth, dive); - entry->gfline = MAX((double)prefs.gflow, (entry->ambpressure - surface_pressure) / (gf_low_pressure_this_dive - surface_pressure) * - (prefs.gflow - prefs.gfhigh) + - prefs.gfhigh) * - (100.0 - AMB_PERCENTAGE) / 100.0 + AMB_PERCENTAGE; - if (t0 > t1) { - fprintf(stderr, "non-monotonous dive stamps %d %d\n", t0, t1); - int xchg = t1; - t1 = t0; - t0 = xchg; - } - if (t0 != t1 && t1 - t0 < time_stepsize) - 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), - &dive->cylinder[entry->cylinderindex].gasmix, time_stepsize, entry->o2pressure.mbar, dive, entry->sac); - if ((t1 - j < time_stepsize) && (j < t1)) - time_stepsize = t1 - j; - } - if (t0 == t1) - entry->ceiling = (entry - 1)->ceiling; - else - entry->ceiling = deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, !prefs.calcceiling3m); - for (j = 0; j < 16; j++) { - double m_value = buehlmann_inertgas_a[j] + entry->ambpressure / buehlmann_inertgas_b[j]; - entry->ceilings[j] = deco_allowed_depth(tolerated_by_tissue[j], surface_pressure, dive, 1); - entry->percentages[j] = tissue_inertgas_saturation[j] < entry->ambpressure ? - tissue_inertgas_saturation[j] / entry->ambpressure * AMB_PERCENTAGE : - AMB_PERCENTAGE + (tissue_inertgas_saturation[j] - entry->ambpressure) / (m_value - entry->ambpressure) * (100.0 - AMB_PERCENTAGE); - } + int first_ceiling = 0; + bool first_iteration = true; + int final_tts = 0 , time_clear_ceiling = 0, time_deep_ceiling = 0, deco_time = 0, prev_deco_time = 10000000; + char *cache_data_initial = NULL; + /* For VPM-B outside the planner, cache the initial deco state for CVA iterations */ + if (prefs.deco_mode == VPMB && !in_planner()) + cache_deco_state(&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_time) >= 30) && (count_iteration < 10)) { + for (i = 1; i < pi->nr; i++) { + struct plot_data *entry = pi->entry + i; + int j, t0 = (entry - 1)->sec, t1 = entry->sec; + int time_stepsize = 20; + + entry->ambpressure = depth_to_bar(entry->depth, dive); + entry->gfline = MAX((double)prefs.gflow, (entry->ambpressure - surface_pressure) / (gf_low_pressure_this_dive - surface_pressure) * + (prefs.gflow - prefs.gfhigh) + + prefs.gfhigh) * + (100.0 - AMB_PERCENTAGE) / 100.0 + AMB_PERCENTAGE; + if (t0 > t1) { + fprintf(stderr, "non-monotonous dive stamps %d %d\n", t0, t1); + int xchg = t1; + t1 = t0; + t0 = xchg; + } + if (t0 != t1 && t1 - t0 < time_stepsize) + 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), + &dive->cylinder[entry->cylinderindex].gasmix, time_stepsize, entry->o2pressure.mbar, dive, entry->sac); + if ((t1 - j < time_stepsize) && (j < t1)) + time_stepsize = t1 - j; + } + if (t0 == t1) { + entry->ceiling = (entry - 1)->ceiling; + } else { + /* Keep updating the VPM-B gradients until the start of the ascent phase of the dive. */ + if (prefs.deco_mode == VPMB && !in_planner() && (entry - 1)->ceiling >= first_ceiling && first_iteration == true) { + nuclear_regeneration(t1); + vpmb_start_gradient(); + /* For CVA calculations, start by guessing deco time = dive time remaining */ + deco_time = pi->maxtime - t1; + vpmb_next_gradient(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); + /* If using VPM-B outside the planner, take first_ceiling_pressure as the deepest ceiling */ + if (prefs.deco_mode == VPMB && !in_planner()) { + if (entry->ceiling >= first_ceiling) { + time_deep_ceiling = t1; + first_ceiling = entry->ceiling; + first_ceiling_pressure.mbar = depth_to_mbar(first_ceiling, dive); + if (first_iteration) { + nuclear_regeneration(t1); + vpmb_start_gradient(); + /* For CVA calculations, start by guessing deco time = dive time remaining */ + deco_time = pi->maxtime - t1; + vpmb_next_gradient(deco_time, surface_pressure / 1000.0); + } + } + // Use the point where the ceiling clears as the end of deco phase for CVA calculations + if (entry->ceiling > 0) + time_clear_ceiling = 0; + else if (time_clear_ceiling == 0) + time_clear_ceiling = t1; + } + } + for (j = 0; j < 16; j++) { + double m_value = buehlmann_inertgas_a[j] + entry->ambpressure / buehlmann_inertgas_b[j]; + entry->ceilings[j] = deco_allowed_depth(tolerated_by_tissue[j], surface_pressure, dive, 1); + entry->percentages[j] = tissue_inertgas_saturation[j] < entry->ambpressure ? + tissue_inertgas_saturation[j] / entry->ambpressure * AMB_PERCENTAGE : + AMB_PERCENTAGE + (tissue_inertgas_saturation[j] - entry->ambpressure) / (m_value - entry->ambpressure) * (100.0 - AMB_PERCENTAGE); + } - /* should we do more calculations? - * We don't for print-mode because this info doesn't show up there */ - if (prefs.calcndltts && !print_mode) { - /* only calculate ndl/tts on every 30 seconds */ - if ((entry->sec - last_ndl_tts_calc_time) < 30) { - struct plot_data *prev_entry = (entry - 1); - entry->stoptime_calc = prev_entry->stoptime_calc; - entry->stopdepth_calc = prev_entry->stopdepth_calc; - entry->tts_calc = prev_entry->tts_calc; - entry->ndl_calc = prev_entry->ndl_calc; - continue; + /* should we do more calculations? + * We don't for print-mode because this info doesn't show up there + * If the ceiling hasn't cleared by the last data point, we need tts for VPM-B CVA calculation + * It is not necessary to do these calculation on the first VPMB iteration, except for the last data point */ + if ((prefs.calcndltts && !print_mode && (prefs.deco_mode != VPMB || in_planner() || !first_iteration)) || + (prefs.deco_mode == VPMB && !in_planner() && i == pi->nr - 1)) { + /* only calculate ndl/tts on every 30 seconds */ + if ((entry->sec - last_ndl_tts_calc_time) < 30 && i != pi->nr - 1) { + struct plot_data *prev_entry = (entry - 1); + entry->stoptime_calc = prev_entry->stoptime_calc; + entry->stopdepth_calc = prev_entry->stopdepth_calc; + entry->tts_calc = prev_entry->tts_calc; + entry->ndl_calc = prev_entry->ndl_calc; + continue; + } + last_ndl_tts_calc_time = entry->sec; + + /* We are going to mess up deco state, so store it for later restore */ + char *cache_data = NULL; + cache_deco_state(&cache_data); + calculate_ndl_tts(entry, dive, surface_pressure); + if (prefs.deco_mode == 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); + free(cache_data); } - last_ndl_tts_calc_time = entry->sec; - - /* We are going to mess up deco state, so store it for later restore */ - char *cache_data = NULL; - cache_deco_state(&cache_data); - calculate_ndl_tts(entry, dive, surface_pressure); - /* Restore "real" deco state for next real time step */ - restore_deco_state(cache_data); - free(cache_data); + } + if (prefs.deco_mode == VPMB && !in_planner()) { + prev_deco_time = deco_time; + // Do we need to update deco_time? + if (final_tts > 0) + deco_time = pi->maxtime + final_tts - time_deep_ceiling; + else if (time_clear_ceiling > 0) + deco_time = time_clear_ceiling - time_deep_ceiling; + vpmb_next_gradient(deco_time, surface_pressure / 1000.0); + final_tts = 0; + last_ndl_tts_calc_time = 0; + first_ceiling = 0; + first_iteration = false; + count_iteration ++; + restore_deco_state(cache_data_initial); + } else { + // With Buhlmann, or not in planner, iterating isn't needed. This makes the while condition false. + prev_deco_time = deco_time = 0; } } + free(cache_data_initial); #if DECO_CALC_DEBUG & 1 dump_tissues(); #endif |