accuracy.sh (3134B)
1 #!/bin/sh 2 # accuracy.sh - Compare numerical accuracy between two cngf-pf output files 3 # 4 # Usage: 5 # ./accuracy.sh reference.txt test.txt 6 # ./accuracy.sh -t 1e-6 reference.txt test.txt # Set tolerance 7 # 8 # Computes relative error for each field and reports max/mean errors. 9 # Fields: z, v_x, sigma_n_eff, p_f, mu, gamma_dot_p, phi, I, tau, d_x 10 11 set -e 12 13 TOLERANCE=1e-10 14 FIELDS="z v_x sigma_n_eff p_f mu gamma_dot_p phi I tau d_x" 15 16 usage() { 17 echo "Usage: $0 [-t tolerance] reference.txt test.txt" 18 echo " -t tol Tolerance for pass/fail (default: 1e-10)" 19 exit 1 20 } 21 22 # Parse arguments 23 while [ $# -gt 0 ]; do 24 case "$1" in 25 -t) TOLERANCE="$2"; shift 2 ;; 26 -h|--help) usage ;; 27 -*) usage ;; 28 *) break ;; 29 esac 30 done 31 32 if [ $# -ne 2 ]; then 33 usage 34 fi 35 36 REF="$1" 37 TEST="$2" 38 39 if [ ! -f "$REF" ]; then 40 echo "Error: Reference file not found: $REF" >&2 41 exit 1 42 fi 43 44 if [ ! -f "$TEST" ]; then 45 echo "Error: Test file not found: $TEST" >&2 46 exit 1 47 fi 48 49 # Check line counts match 50 ref_lines=$(wc -l < "$REF" | tr -d ' ') 51 test_lines=$(wc -l < "$TEST" | tr -d ' ') 52 53 if [ "$ref_lines" -ne "$test_lines" ]; then 54 echo "Error: Line count mismatch: reference=$ref_lines, test=$test_lines" >&2 55 exit 1 56 fi 57 58 # Create temporary files for awk processing 59 tmp_ref=$(mktemp) 60 tmp_test=$(mktemp) 61 trap 'rm -f "$tmp_ref" "$tmp_test"' EXIT 62 63 cp "$REF" "$tmp_ref" 64 cp "$TEST" "$tmp_test" 65 66 # Compute relative errors using awk 67 awk -v tol="$TOLERANCE" ' 68 BEGIN { 69 split("z v_x sigma_n_eff p_f mu gamma_dot_p phi I tau d_x", field_names, " ") 70 for (i = 1; i <= 10; i++) { 71 max_err[i] = 0 72 sum_err[i] = 0 73 count[i] = 0 74 } 75 } 76 77 FNR == NR { 78 for (i = 1; i <= NF; i++) { 79 ref[FNR, i] = $i 80 } 81 nlines = FNR 82 next 83 } 84 85 { 86 for (i = 1; i <= NF; i++) { 87 test_val = $i 88 ref_val = ref[FNR, i] 89 90 # Compute relative error 91 if (ref_val == 0 && test_val == 0) { 92 rel_err = 0 93 } else if (ref_val == 0) { 94 rel_err = (test_val > 0) ? test_val : -test_val 95 } else { 96 diff = test_val - ref_val 97 if (diff < 0) diff = -diff 98 denom = ref_val 99 if (denom < 0) denom = -denom 100 rel_err = diff / denom 101 } 102 103 if (rel_err > max_err[i]) max_err[i] = rel_err 104 sum_err[i] += rel_err 105 count[i]++ 106 } 107 } 108 109 END { 110 print "Field Max RelErr Mean RelErr Status" 111 print "---------------- ------------ ------------ ------" 112 113 all_pass = 1 114 for (i = 1; i <= 10; i++) { 115 if (count[i] > 0) { 116 mean_err = sum_err[i] / count[i] 117 } else { 118 mean_err = 0 119 } 120 121 status = (max_err[i] <= tol) ? "PASS" : "FAIL" 122 if (status == "FAIL") all_pass = 0 123 124 printf "%-16s %12.4e %12.4e %s\n", field_names[i], max_err[i], mean_err, status 125 } 126 127 print "" 128 if (all_pass) { 129 print "Overall: PASS (all fields within tolerance " tol ")" 130 exit 0 131 } else { 132 print "Overall: FAIL (some fields exceed tolerance " tol ")" 133 exit 1 134 } 135 } 136 ' "$tmp_ref" "$tmp_test"