From 22a310506886425ccaed321a2bd5333fd4792023 Mon Sep 17 00:00:00 2001 From: jpekkila Date: Sat, 14 Dec 2019 07:27:11 +0200 Subject: [PATCH] Finished the latest version of autotesting (utility library). Uses ulps to determine the acceptable error instead of the relative error used previously --- src/utils/verification.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/utils/verification.c b/src/utils/verification.c index dbf0db2..0d8f12c 100644 --- a/src/utils/verification.c +++ b/src/utils/verification.c @@ -94,6 +94,11 @@ get_minimum_magnitude(const AcReal* field, const AcMeshInfo info) return minimum; } +// Get the maximum absolute error. Works well if all the values in the mesh are approximately +// in the same range. +// Finding the maximum ulp error is not useful, as it picks up on the noise beyond the +// floating-point precision range and gives huge errors with values that should be considered +// zero (f.ex. 1e-19 and 1e-22 give error of around 1e4 ulps) static Error get_max_abs_error(const VertexBufferHandle vtxbuf_handle, const AcMesh model_mesh, const AcMesh candidate_mesh) @@ -131,37 +136,54 @@ print_error_to_file(const char* path, const int n, const Error error) static bool is_acceptable(const Error error) { - // TODO FIXME - const AcReal range = error.maximum_magnitude - error.minimum_magnitude; - if (error.abs_error < range * AC_REAL_EPSILON) + // Accept the error if the relative error is < max_ulp_error ulps. + // Also consider the error zero if it is less than the minimum value in the mesh scaled to + // machine epsilon + const long double max_ulp_error = 5; + + if (error.ulp_error < max_ulp_error) + return true; + else if (error.abs_error < error.minimum_magnitude * AC_REAL_EPSILON) return true; else return false; } -static void +static bool print_error_to_screen(const Error error) { + bool errors_found = false; + printf("\t%-15s... ", vtxbuf_names[error.handle]); if (is_acceptable(error)) { printf(GRN "OK! " RESET); } else { printf(RED "FAIL! " RESET); + errors_found = true; } - fprintf(stdout, "| %.2Lg (abs), %.2Lg (ulps), %.2Lg (rel). Range: [%.2g, %.2g]\n", // + fprintf(stdout, "| %.3Lg (abs), %.3Lg (ulps), %.3Lg (rel). Range: [%.3g, %.3g]\n", // error.abs_error, error.ulp_error, error.rel_error, // (double)error.minimum_magnitude, (double)error.maximum_magnitude); + + return errors_found; } +/** Returns true when successful, false if errors were found. */ bool acVerifyMesh(const AcMesh model, const AcMesh candidate) { + printf("Errors at the point of the maximum absolute error:\n"); + + bool errors_found = false; for (int i = 0; i < NUM_VTXBUF_HANDLES; ++i) { Error field_error = get_max_abs_error(i, model, candidate); - print_error_to_screen(field_error); + errors_found |= print_error_to_screen(field_error); } - printf("WARNING: is_acceptable() not yet complete\n"); - return true; + + printf("%s\n", errors_found ? "Failure. Found errors in one or more vertex buffers" + : "Success. No errors found."); + + return !errors_found; }