Cleanup: move gas-functions to own translation unit

But only functions that operate only on gases. Functions concerning
cylinders or dives remain in dive.c or are moved to equipment.c

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2019-06-04 13:52:48 +02:00 committed by Dirk Hohndel
parent 8352274758
commit 619d3fb1fd
8 changed files with 174 additions and 149 deletions

View file

@ -86,6 +86,8 @@ set(SUBSURFACE_CORE_LIB_SRCS
file.h
format.cpp
format.h
gas.c
gas.h
gas-model.c
gaspressures.c
gaspressures.h

View file

@ -866,13 +866,6 @@ static void update_min_max_temperatures(struct dive *dive, temperature_t tempera
}
}
int gas_volume(const cylinder_t *cyl, pressure_t p)
{
double bar = p.mbar / 1000.0;
double z_factor = gas_compressibility_factor(cyl->gasmix, bar);
return lrint(cyl->type.size.mliter * bar_to_atm(bar) / z_factor);
}
/*
* If the cylinder tank pressures are within half a bar
* (about 8 PSI) of the sample pressures, we consider it
@ -948,31 +941,6 @@ void update_setpoint_events(const struct dive *dive, struct divecomputer *dc)
}
}
void sanitize_gasmix(struct gasmix *mix)
{
unsigned int o2, he;
o2 = mix->o2.permille;
he = mix->he.permille;
/* Regular air: leave empty */
if (!he) {
if (!o2)
return;
/* 20.8% to 21% O2 is just air */
if (gasmix_is_air(*mix)) {
mix->o2.permille = 0;
return;
}
}
/* Sane mix? */
if (o2 <= 1000 && he <= 1000 && o2 + he <= 1000)
return;
fprintf(stderr, "Odd gasmix: %u O2 %u He\n", o2, he);
memset(mix, 0, sizeof(*mix));
}
/*
* See if the size/workingpressure looks like some standard cylinder
* size, eg "AL80".
@ -1059,23 +1027,6 @@ static void sanitize_cylinder_info(struct dive *dive)
}
}
/* Perform isobaric counterdiffusion calculations for gas changes in trimix dives.
* Here we use the rule-of-fifths where, during a change involving trimix gas, the increase in nitrogen
* should not exceed one fifth of the decrease in helium.
* Parameters: 1) pointers to two gas mixes, the gas being switched from and the gas being switched to.
* 2) a pointer to an icd_data structure.
* Output: i) The icd_data stucture is filled with the delta_N2 and delta_He numbers (as permille).
* ii) Function returns a boolean indicating an exceeding of the rule-of-fifths. False = no icd problem.
*/
bool isobaric_counterdiffusion(struct gasmix oldgasmix, struct gasmix newgasmix, struct icd_data *results)
{
if (!prefs.show_icd)
return false;
results->dN2 = get_he(oldgasmix) + get_o2(oldgasmix) - get_he(newgasmix) - get_o2(newgasmix);
results->dHe = get_he(newgasmix) - get_he(oldgasmix);
return get_he(oldgasmix) > 0 && results->dN2 > 0 && results->dHe < 0 && get_he(oldgasmix) && results->dN2 > 0 && 5 * results->dN2 > -results->dHe;
}
/* some events should never be thrown away */
static bool is_potentially_redundant(const struct event *event)
{
@ -1464,29 +1415,6 @@ static void fixup_dive_pressures(struct dive *dive, struct divecomputer *dc)
simplify_dc_pressures(dc);
}
int find_best_gasmix_match(struct gasmix mix, const cylinder_t array[], unsigned int used)
{
int i;
int best = -1, score = INT_MAX;
for (i = 0; i < MAX_CYLINDERS; i++) {
const cylinder_t *match;
int distance;
if (used & (1 << i))
continue;
match = array + i;
if (cylinder_nodata(match))
continue;
distance = gasmix_distance(mix, match->gasmix);
if (distance >= score)
continue;
best = i;
score = distance;
}
return best;
}
/*
* Match a gas change event against the cylinders we have
*/
@ -2031,17 +1959,6 @@ extern int get_cylinder_idx_by_use(const struct dive *dive, enum cylinderuse cyl
return -1; // negative number means cylinder_use_type not found in list of cylinders
}
int gasmix_distance(struct gasmix a, struct gasmix b)
{
int a_o2 = get_o2(a), b_o2 = get_o2(b);
int a_he = get_he(a), b_he = get_he(b);
int delta_o2 = a_o2 - b_o2, delta_he = a_he - b_he;
delta_he = delta_he * delta_he;
delta_o2 = delta_o2 * delta_o2;
return delta_he + delta_o2;
}
/* fill_pressures(): Compute partial gas pressures in bar from gasmix and ambient pressures, possibly for OC or CCR, to be
* extended to PSCT. This function does the calculations of gas pressures applicable to a single point on the dive profile.
* The structure "pressures" is used to return calculated gas pressures to the calling software.
@ -2052,7 +1969,7 @@ int gasmix_distance(struct gasmix a, struct gasmix b)
* divemode = the dive mode pertaining to this point in the dive profile.
* This function called by: calculate_gas_information_new() in profile.c; add_segment() in deco.c.
*/
extern void fill_pressures(struct gas_pressures *pressures, const double amb_pressure, struct gasmix mix, double po2, enum divemode_t divemode)
void fill_pressures(struct gas_pressures *pressures, const double amb_pressure, struct gasmix mix, double po2, enum divemode_t divemode)
{
if ((divemode != OC) && po2) { // This is a rebreather dive where pressures->o2 is defined
if (po2 >= amb_pressure) {
@ -2180,20 +2097,6 @@ void cylinder_renumber(struct dive *dive, int mapping[])
dc_cylinder_renumber(dive, dc, mapping);
}
static bool gasmix_is_invalid(struct gasmix mix)
{
return mix.o2.permille < 0;
}
int same_gasmix(struct gasmix a, struct gasmix b)
{
if (gasmix_is_invalid(a) || gasmix_is_invalid(b))
return 0;
if (gasmix_is_air(a) && gasmix_is_air(b))
return 1;
return a.o2.permille == b.o2.permille && a.he.permille == b.he.permille;
}
int same_gasmix_cylinder(cylinder_t *cyl, int cylid, struct dive *dive, bool check_unused)
{
struct gasmix mygas = cyl->gasmix;
@ -3922,13 +3825,6 @@ fraction_t best_he(depth_t depth, const struct dive *dive)
return fhe;
}
bool gasmix_is_air(struct gasmix gasmix)
{
int o2 = gasmix.o2.permille;
int he = gasmix.he.permille;
return (he == 0) && (o2 == 0 || ((o2 >= O2_IN_AIR - 1) && (o2 <= O2_IN_AIR + 1)));
}
void invalidate_dive_cache(struct dive *dive)
{
memset(dive->git_id, 0, 20);

View file

@ -27,13 +27,6 @@ extern const char *cylinderuse_text[];
extern const char *divemode_text_ui[];
extern const char *divemode_text[];
struct icd_data { // This structure provides communication between function isobaric_counterdiffusion() and the calling software.
int dN2; // The change in fraction (permille) of nitrogen during the change
int dHe; // The change in fraction (permille) of helium during the change
};
extern bool isobaric_counterdiffusion(struct gasmix oldgasmix, struct gasmix newgasmix, struct icd_data *results);
/*
* Events are currently based straight on what libdivecomputer gives us.
* We need to wrap these into our own events at some point to remove some of the limitations.
@ -63,35 +56,8 @@ struct event {
extern int event_is_gaschange(const struct event *ev);
/* Volume in mliter of a cylinder at pressure 'p' */
extern int gas_volume(const cylinder_t *cyl, pressure_t p);
extern double gas_compressibility_factor(struct gasmix gas, double bar);
extern double isothermal_pressure(struct gasmix gas, double p1, int volume1, int volume2);
extern double gas_density(struct gasmix gas, int pressure);
extern int same_gasmix(struct gasmix a, struct gasmix b);
static inline int get_o2(struct gasmix mix)
{
return mix.o2.permille ?: O2_IN_AIR;
}
static inline int get_he(struct gasmix mix)
{
return mix.he.permille;
}
struct gas_pressures {
double o2, n2, he;
};
extern void fill_pressures(struct gas_pressures *pressures, const double amb_pressure, struct gasmix mix, double po2, enum divemode_t dctype);
extern void sanitize_gasmix(struct gasmix *mix);
extern int gasmix_distance(struct gasmix a, struct gasmix b);
extern int find_best_gasmix_match(struct gasmix mix, const cylinder_t array[], unsigned int used);
extern bool gasmix_is_air(struct gasmix gasmix);
/* Linear interpolation between 'a' and 'b', when we are 'part'way into the 'whole' distance from a to b */
static inline int interpolate(int a, int b, int part, int whole)
{

View file

@ -10,6 +10,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <limits.h>
#include "equipment.h"
#include "gettext.h"
#include "dive.h"
@ -101,6 +102,36 @@ const char *gasname(struct gasmix gasmix)
return gas;
}
int gas_volume(const cylinder_t *cyl, pressure_t p)
{
double bar = p.mbar / 1000.0;
double z_factor = gas_compressibility_factor(cyl->gasmix, bar);
return lrint(cyl->type.size.mliter * bar_to_atm(bar) / z_factor);
}
int find_best_gasmix_match(struct gasmix mix, const cylinder_t array[], unsigned int used)
{
int i;
int best = -1, score = INT_MAX;
for (i = 0; i < MAX_CYLINDERS; i++) {
const cylinder_t *match;
int distance;
if (used & (1 << i))
continue;
match = array + i;
if (cylinder_nodata(match))
continue;
distance = gasmix_distance(mix, match->gasmix);
if (distance >= score)
continue;
best = i;
score = distance;
}
return best;
}
bool weightsystem_none(const weightsystem_t *ws)
{
return !ws->weight.grams && !ws->description;

View file

@ -2,7 +2,7 @@
#ifndef EQUIPMENT_H
#define EQUIPMENT_H
#include "units.h"
#include "gas.h"
#ifdef __cplusplus
extern "C" {
@ -10,15 +10,6 @@ extern "C" {
struct dive;
// o2 == 0 && he == 0 -> air
// o2 < 0 -> invalid
struct gasmix {
fraction_t o2;
fraction_t he;
};
static const struct gasmix gasmix_invalid = { { -1 }, { -1 } };
static const struct gasmix gasmix_air = { { 0 }, { 0 } };
enum cylinderuse {OC_GAS, DILUENT, OXYGEN, NOT_USED, NUM_GAS_USE}; // The different uses for cylinders
typedef struct
@ -63,6 +54,8 @@ extern bool weightsystem_none(const weightsystem_t *ws);
extern void remove_cylinder(struct dive *dive, int idx);
extern void remove_weightsystem(struct dive *dive, int idx);
extern void reset_cylinders(struct dive *dive, bool track_gas);
extern int gas_volume(const cylinder_t *cyl, pressure_t p); /* Volume in mliter of a cylinder at pressure 'p' */
extern int find_best_gasmix_match(struct gasmix mix, const cylinder_t array[], unsigned int used);
#ifdef DEBUG_CYL
extern void dump_cylinders(struct dive *dive, bool verbose);
#endif

79
core/gas.c Normal file
View file

@ -0,0 +1,79 @@
// SPDX-License-Identifier: GPL-2.0
#include "gas.h"
#include "pref.h"
#include <stdio.h>
#include <string.h>
/* Perform isobaric counterdiffusion calculations for gas changes in trimix dives.
* Here we use the rule-of-fifths where, during a change involving trimix gas, the increase in nitrogen
* should not exceed one fifth of the decrease in helium.
* Parameters: 1) pointers to two gas mixes, the gas being switched from and the gas being switched to.
* 2) a pointer to an icd_data structure.
* Output: i) The icd_data stucture is filled with the delta_N2 and delta_He numbers (as permille).
* ii) Function returns a boolean indicating an exceeding of the rule-of-fifths. False = no icd problem.
*/
bool isobaric_counterdiffusion(struct gasmix oldgasmix, struct gasmix newgasmix, struct icd_data *results)
{
if (!prefs.show_icd)
return false;
results->dN2 = get_he(oldgasmix) + get_o2(oldgasmix) - get_he(newgasmix) - get_o2(newgasmix);
results->dHe = get_he(newgasmix) - get_he(oldgasmix);
return get_he(oldgasmix) > 0 && results->dN2 > 0 && results->dHe < 0 && get_he(oldgasmix) && results->dN2 > 0 && 5 * results->dN2 > -results->dHe;
}
static bool gasmix_is_invalid(struct gasmix mix)
{
return mix.o2.permille < 0;
}
int same_gasmix(struct gasmix a, struct gasmix b)
{
if (gasmix_is_invalid(a) || gasmix_is_invalid(b))
return 0;
if (gasmix_is_air(a) && gasmix_is_air(b))
return 1;
return a.o2.permille == b.o2.permille && a.he.permille == b.he.permille;
}
void sanitize_gasmix(struct gasmix *mix)
{
unsigned int o2, he;
o2 = mix->o2.permille;
he = mix->he.permille;
/* Regular air: leave empty */
if (!he) {
if (!o2)
return;
/* 20.8% to 21% O2 is just air */
if (gasmix_is_air(*mix)) {
mix->o2.permille = 0;
return;
}
}
/* Sane mix? */
if (o2 <= 1000 && he <= 1000 && o2 + he <= 1000)
return;
fprintf(stderr, "Odd gasmix: %u O2 %u He\n", o2, he);
memset(mix, 0, sizeof(*mix));
}
int gasmix_distance(struct gasmix a, struct gasmix b)
{
int a_o2 = get_o2(a), b_o2 = get_o2(b);
int a_he = get_he(a), b_he = get_he(b);
int delta_o2 = a_o2 - b_o2, delta_he = a_he - b_he;
delta_he = delta_he * delta_he;
delta_o2 = delta_o2 * delta_o2;
return delta_he + delta_o2;
}
bool gasmix_is_air(struct gasmix gasmix)
{
int o2 = gasmix.o2.permille;
int he = gasmix.he.permille;
return (he == 0) && (o2 == 0 || ((o2 >= O2_IN_AIR - 1) && (o2 <= O2_IN_AIR + 1)));
}

57
core/gas.h Normal file
View file

@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
#ifndef GAS_H
#define GAS_H
#include "units.h"
#ifdef __cplusplus
extern "C" {
#else
#include <stdbool.h>
#endif
// o2 == 0 && he == 0 -> air
// o2 < 0 -> invalid
struct gasmix {
fraction_t o2;
fraction_t he;
};
static const struct gasmix gasmix_invalid = { { -1 }, { -1 } };
static const struct gasmix gasmix_air = { { 0 }, { 0 } };
struct icd_data { // This structure provides communication between function isobaric_counterdiffusion() and the calling software.
int dN2; // The change in fraction (permille) of nitrogen during the change
int dHe; // The change in fraction (permille) of helium during the change
};
extern bool isobaric_counterdiffusion(struct gasmix oldgasmix, struct gasmix newgasmix, struct icd_data *results);
extern double gas_compressibility_factor(struct gasmix gas, double bar);
extern double isothermal_pressure(struct gasmix gas, double p1, int volume1, int volume2);
extern double gas_density(struct gasmix gas, int pressure);
extern int same_gasmix(struct gasmix a, struct gasmix b);
static inline int get_o2(struct gasmix mix)
{
return mix.o2.permille ?: O2_IN_AIR;
}
static inline int get_he(struct gasmix mix)
{
return mix.he.permille;
}
struct gas_pressures {
double o2, n2, he;
};
extern void sanitize_gasmix(struct gasmix *mix);
extern int gasmix_distance(struct gasmix a, struct gasmix b);
extern bool gasmix_is_air(struct gasmix gasmix);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -67,6 +67,7 @@ SOURCES += ../../subsurface-mobile-main.cpp \
../../core/deco.c \
../../core/divesite.c \
../../core/equipment.c \
../../core/gas.c \
../../core/membuffer.c \
../../core/sha1.c \
../../core/strtod.c \