summaryrefslogtreecommitdiffstats
path: root/core/gas.c
blob: 757f912b06066b0d3c3e639ad8224a3ffb8a9e91 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// 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_n2(newgasmix) - get_n2(oldgasmix);
	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)));
}

static fraction_t make_fraction(int i)
{
	fraction_t res;
	res.permille = i;
	return res;
}

fraction_t get_gas_component_fraction(struct gasmix mix, enum gas_component component)
{
	switch (component) {
	case O2: return make_fraction(get_o2(mix));
	case N2: return make_fraction(get_n2(mix));
	case HE: return make_fraction(get_he(mix));
	default: return make_fraction(0);
	}
}