commit 5bde959937eaf8935c9a775544a26db3282b4272
parent 78e6b89f34cc0cf007dbe1c2cc42d9f43360d60c
Author: Eduardo Fontana Lazzari <edufonlaz@gmail.com>
Date: Mon, 6 Apr 2026 12:56:19 +0200
Replace standard deviation by standartd error in outputs
The standard deviation measures the spread of individual samples, while
the standard error measures the precision of the estimated mean. Since
the outputs report mean values, the standard error is a better
uncertainty metric. It is also more consistent with the edstar
ecosystem.
Diffstat:
7 files changed, 57 insertions(+), 73 deletions(-)
diff --git a/doc/star-phor-output.scd b/doc/star-phor-output.scd
@@ -58,37 +58,35 @@ The syntax rules enabling the description of a photoreactor are as follows:
...
<observable-output> ::= <combined-estimator>
- <per-sensor-estimators>
- [<per-component-estimators>]
+ <per-sensor-estimator>
+ ...
+ [<per-component-estimator>
+ ...]
<combined-estimator> ::= <observable>:\\
- <expected-value>:\\
- <standard-deviation>
+ <mean-value>:\\
+ <standard-error>
-<per-sensor-estimators> ::= <observable>:\\
+<per-sensor-estimator> ::= <observable>:\\
<sensor-name>:\\
- <expected-value>:\\
- <standard-deviation>
- ...
+ <mean-value>:\\
+ <standard-error>
-<per-component-estimators> ::= <observable>:\\
+<per-component-estimator> ::= <observable>:\\
<sensor-name>:\\
<component-name>:\\
- <expected-value>:\\
- <standard-deviation>
- ...
+ <mean-value>:\\
+ <standard-error>
-<observable-name> ::= MVREA | LOSSES
+<observable> ::= MVREA | LOSSES
<sensor-name> ::= <volume-name> | <surface-name>
<volume-name> ::= 'string'
<surface-name> ::= 'string'
<component-name> ::= 'string'
-<expected-value> ::= 'real'
-<standard-deviation> ::= 'real'
+<mean-value> ::= 'real'
+<standard-error> ::= 'real'
```
-# EXAMPLES
-
# SEE ALSO
_star-phor_(1), _sphin-lint_(1), _star-phor-input_(5)
diff --git a/src/sphor_accum.c b/src/sphor_accum.c
@@ -134,7 +134,7 @@ accum_compute_estim
double samples = 0;
double mean = 0;
double var = 0;
- double std = 0;
+ double std_err = 0;
ASSERT(NULL != accum);
ASSERT(NULL != estim);
@@ -143,13 +143,15 @@ accum_compute_estim
sum = accum->sum;
sum2 = accum->sum2;
- mean = sum/samples;
+ mean = sum / samples;
+ /* Compute the sample variance. This formula is equivalent to
+ * var = 1 / (n-1) sum(x_i - <x>)^2 */
var = (sum2 - sum * sum / samples) / (samples - 1);
- std = sqrt(var);
+ std_err = sqrt (var / samples);
estim->mean = mean;
estim->var = var;
- estim->std = std;
+ estim->std_err = std_err;
}
extern LOCAL_SYM void
@@ -170,18 +172,18 @@ write_accum_estim
str_cget(&accum->observable),
str_cget(&accum->sensor),
str_cget(&accum->component),
- estim.mean, estim.std);
+ estim.mean, estim.std_err);
} else if (0 != strcmp("\0", str_cget(&accum->sensor))){
fprintf
(stream, "%s:%s:%lf:%lf\n",
str_cget(&accum->observable),
str_cget(&accum->sensor),
- estim.mean, estim.std);
+ estim.mean, estim.std_err);
} else {
fprintf
(stream, "%s:%lf:%lf\n",
str_cget(&accum->observable),
- estim.mean, estim.std);
+ estim.mean, estim.std_err);
}
}
diff --git a/src/sphor_accum.h b/src/sphor_accum.h
@@ -50,7 +50,7 @@ static const struct accum ACCUM_NULL = ACCUM_NULL__;
struct estim {
double mean;
double var;
- double std;
+ double std_err;
};
#define ESTIM_NULL__ {0}
static const struct estim ESTIM_NULL = ESTIM_NULL__;
diff --git a/src/test_sphor_MVREA_analytical1.c b/src/test_sphor_MVREA_analytical1.c
@@ -30,7 +30,6 @@
#include <rsys/str.h>
#include <rsys/text_reader.h>
-#include <math.h>
#include <stdio.h>
static void write_stl(
@@ -175,8 +174,7 @@ main(int argc, char** argv)
char input_filename[] = "input";
char output_filename[] = "output";
double avg = 0;
- double std = 0;
- double nsamples = 0;
+ double std_err = 0;
FILE* fp = NULL;
@@ -207,8 +205,6 @@ main(int argc, char** argv)
str_init(NULL, &line);
CHK(txtrdr_stream(NULL, fp, output_filename, '#', &txtrdr) == RES_OK);
- nsamples = (double)args.samples;
-
/* Verify first level: total scene MVREA */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
CHK(str_set(&line, txtrdr_get_cline(txtrdr)) == RES_OK);
@@ -216,9 +212,9 @@ main(int argc, char** argv)
CHK(strcmp(token, "MVREA") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 1 - 0.5 * (exp(-1) + exp(-2)), 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 1 - 0.5 * (exp(-1) + exp(-2)), 2 * std_err));
/* Verify second level: per volume MVREA */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
@@ -229,9 +225,9 @@ main(int argc, char** argv)
CHK(strcmp(token, "reactional_volume") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 1 - 0.5 * (exp(-1) + exp(-2)), 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 1 - 0.5 * (exp(-1) + exp(-2)), 2 * std_err));
/* Verify third level: per prop_rad MVREA */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
@@ -244,9 +240,9 @@ main(int argc, char** argv)
CHK(strcmp(token, "sigma_a") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 1 - 0.5 * (exp(-1) + exp(-2)), 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 1 - 0.5 * (exp(-1) + exp(-2)), 2 * std_err));
/* Verify first level: total scene losses */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
@@ -255,9 +251,9 @@ main(int argc, char** argv)
CHK(strcmp(token, "LOSSES") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 0.5 * exp(-1), 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 0.5 * exp(-1), 2 * std_err));
/* Verify second level: per surface losses */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
@@ -268,9 +264,9 @@ main(int argc, char** argv)
CHK(strcmp(token, "mirror") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 0.5 * exp(-1), 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 0.5 * exp(-1), 2 * std_err));
CHK(fclose(fp) == 0);
diff --git a/src/test_sphor_MVREA_btdf_keep_current_dir.c b/src/test_sphor_MVREA_btdf_keep_current_dir.c
@@ -30,7 +30,6 @@
#include <rsys/str.h>
#include <rsys/text_reader.h>
-#include <math.h>
#include <stdio.h>
static void
@@ -192,8 +191,7 @@ int main(int argc, char** argv)
char input_filename[] = "input";
char output_filename[] = "output";
double avg = 0;
- double std = 0;
- double nsamples = 0;
+ double std_err = 0;
FILE* fp = NULL;
@@ -224,8 +222,6 @@ int main(int argc, char** argv)
str_init(NULL, &line);
CHK(txtrdr_stream(NULL, fp, output_filename, '#', &txtrdr) == RES_OK);
- nsamples = (double)args.samples;
-
/* Verify first level: total scene MVREA */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
CHK(str_set(&line, txtrdr_get_cline(txtrdr)) == RES_OK);
@@ -233,9 +229,9 @@ int main(int argc, char** argv)
CHK(strcmp(token, "MVREA") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 0, 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 0, 2 * std_err));
/* Verify first level: total scene losses */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
@@ -244,9 +240,9 @@ int main(int argc, char** argv)
CHK(strcmp(token, "LOSSES") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 1, 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 1, 2 * std_err));
/* Verify second level: per surface losses */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
@@ -257,9 +253,9 @@ int main(int argc, char** argv)
CHK(strcmp(token, "absorber") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 1, 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 1, 2 * std_err));
CHK(fclose(fp) == 0);
diff --git a/src/test_sphor_MVREA_btdf_lambertian.c b/src/test_sphor_MVREA_btdf_lambertian.c
@@ -30,7 +30,6 @@
#include <rsys/str.h>
#include <rsys/text_reader.h>
-#include <math.h>
#include <stdio.h>
static void
@@ -192,8 +191,7 @@ int main(int argc, char** argv)
char input_filename[] = "input";
char output_filename[] = "output";
double avg = 0;
- double std = 0;
- double nsamples = 0;
+ double std_err = 0;
FILE* fp = NULL;
@@ -224,8 +222,6 @@ int main(int argc, char** argv)
str_init(NULL, &line);
CHK(txtrdr_stream(NULL, fp, output_filename, '#', &txtrdr) == RES_OK);
- nsamples = (double)args.samples;
-
/* Verify first level: total scene MVREA */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
CHK(str_set(&line, txtrdr_get_cline(txtrdr)) == RES_OK);
@@ -233,9 +229,9 @@ int main(int argc, char** argv)
CHK(strcmp(token, "MVREA") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 0, 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 0, 2 * std_err));
/* Verify first level: total scene losses */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
@@ -244,7 +240,7 @@ int main(int argc, char** argv)
CHK(strcmp(token, "LOSSES") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare against the analytical view factor.
*
* This computes the exact configuration (view) factor F12 between two
@@ -267,7 +263,7 @@ int main(int argc, char** argv)
* that reaches the absorbing surface, weighted by the surface area ratio of
* the emitting surface and the absorbing surface.
*/
- CHK(eq_eps(avg, 0.4152532835771472, 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 0.4152532835771472, 2 * std_err));
/* Verify second level: per surface losses */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
@@ -278,8 +274,8 @@ int main(int argc, char** argv)
CHK(strcmp(token, "absorber") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
- CHK(eq_eps(avg, 0.4152532835771472, 2 * std / sqrt(nsamples)));
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
+ CHK(eq_eps(avg, 0.4152532835771472, 2 * std_err));
CHK(fclose(fp) == 0);
diff --git a/src/test_sphor_MVREA_btdf_snell_dielectric.c b/src/test_sphor_MVREA_btdf_snell_dielectric.c
@@ -30,7 +30,6 @@
#include <rsys/str.h>
#include <rsys/text_reader.h>
-#include <math.h>
#include <stdio.h>
static void
@@ -229,8 +228,7 @@ int main(int argc, char** argv)
char input_filename[] = "input";
char output_filename[] = "output";
double avg = 0;
- double std = 0;
- double nsamples = 0;
+ double std_err = 0;
FILE* fp = NULL;
@@ -261,8 +259,6 @@ int main(int argc, char** argv)
str_init(NULL, &line);
CHK(txtrdr_stream(NULL, fp, output_filename, '#', &txtrdr) == RES_OK);
- nsamples = (double)args.samples;
-
/* Verify first level: total scene MVREA */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
CHK(str_set(&line, txtrdr_get_cline(txtrdr)) == RES_OK);
@@ -270,9 +266,9 @@ int main(int argc, char** argv)
CHK(strcmp(token, "MVREA") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 0, 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 0, 2 * std_err));
/* Verify first level: total scene losses */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
@@ -281,9 +277,9 @@ int main(int argc, char** argv)
CHK(strcmp(token, "LOSSES") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 1, 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 1, 2 * std_err));
/* Verify second level: per surface losses */
CHK(txtrdr_read_line(txtrdr) == RES_OK);
@@ -294,9 +290,9 @@ int main(int argc, char** argv)
CHK(strcmp(token, "absorber") == 0);
token = strtok_r(NULL, ":", &token_ptr);
CHK(cstr_to_double(token, &avg) == RES_OK);
- CHK(cstr_to_double(token_ptr, &std) == RES_OK);
+ CHK(cstr_to_double(token_ptr, &std_err) == RES_OK);
/* Compare to analytical solution */
- CHK(eq_eps(avg, 1, 2 * std / sqrt(nsamples)));
+ CHK(eq_eps(avg, 1, 2 * std_err));
CHK(fclose(fp) == 0);