{"abstract":"Incidence angles come out negative when the sun is toward the low end of the axis.","category":"Solar tracker geometry","checks":7,"contract":"The axis points toward axis_az rising by axis_tilt: A = (sin a cos b, cos a cos b, sin b). The zero-rotation panel normal is N0 = (-sin a sin b, -cos a sin b, cos b) and positive rotation turns toward R = (cos a, -sin a, 0). With unit sun vector s, rotation = atan2(s.R, s.N0) and the incidence at ideal tracking is asin(|s.A|). Return [rotation, incidence] rounded to 3, or None when sun_el <= 0.","evaluation_group":"w2-solar_tracker_geometry-tilted-axis-frame","failed_approach":"Squaring the component changes its magnitude.","family":"w2-solar_tracker_geometry-tilted-axis-frame-incidence-magnitude","id":"FA-93706","implementations":{"attempt":{"sha256":"25e487d88475605f76b2699c11abac0b105deb620c345e1022937e3c1f944265","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(sun_az, sun_el, axis_az, axis_tilt):\n    if sun_el <= 0:\n        return None\n    az = math.radians(sun_az)\n    el = math.radians(sun_el)\n    a = math.radians(axis_az)\n    b = math.radians(axis_tilt)\n    s = [math.cos(el) * math.sin(az), math.cos(el) * math.cos(az), math.sin(el)]\n    A = [math.sin(a) * math.cos(b), math.cos(a) * math.cos(b), math.sin(b)]\n    N0 = [-math.sin(a) * math.sin(b), -math.cos(a) * math.sin(b), math.cos(b)]\n    R = [math.cos(a), -math.sin(a), 0.0]\n    dot = lambda u, v: sum(p * q for p, q in zip(u, v))\n    theta = math.degrees(math.atan2(dot(s, R), dot(s, N0)))\n    aoi = math.degrees(math.asin(min(1.0, dot(s, A) ** 2)))\n    return [round(theta, 3), round(aoi, 3)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [180, 20, 0, 5], [0.0, 65.0]],\n  ['regression: incidence magnitude (partial repair)', [0, 89, 180, 5], [-0.0, 4.0]],\n  ['control 1', [300, 0, 180, 0], None], ['control 2', [225, 3, 180, 20], [105.236, 42.957]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [315, 10, 180, 0], [75.998, 44.136]],\n  ['regression: incidence magnitude (partial repair)', [225, 89, 180, 5], [0.711, 5.707]],\n  ['control 1', [45, 60, 170, 10], [-24.406, 7.588]],\n  ['control 2', [135, 75, 170, 20], [-10.079, 31.978]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [315, 10, 170, 10], [61.157, 49.845]],\n  ['regression: incidence magnitude (partial repair)', [225, 30, 180, 10], [57.771, 43.622]],\n  ['control 1', [340, 45, 170, 20], [7.747, 24.363]],\n  ['control 2', [340, 10, 180, 20], [35.076, 54.117]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [100, 30, 0, 5], [59.062, 6.098]],\n  ['regression: incidence magnitude (partial repair)', [150, 60, 170, 0], [-11.17, 28.024]],\n  ['control 1', [340, 20, 180, 0], [43.219, 62.009]],\n  ['control 2', [30, 3, 0, 20], [116.285, 56.159]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [225, 10, 0, 10], [-67.255, 40.968]],\n  ['regression: incidence magnitude (partial repair)', [340, 30, 0, 0], [-30.642, 54.469]],\n  ['control 1', [100, 30, 0, 5], [59.062, 6.098]],\n  ['control 2', [135, 75, 180, 10], [-11.257, 20.363]]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"broken":{"sha256":"968e3ec35dc5f9750dc64ac049ce46b45717f83dcc156301bea15ce4d8db7932","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(sun_az, sun_el, axis_az, axis_tilt):\n    if sun_el <= 0:\n        return None\n    az = math.radians(sun_az)\n    el = math.radians(sun_el)\n    a = math.radians(axis_az)\n    b = math.radians(axis_tilt)\n    s = [math.cos(el) * math.sin(az), math.cos(el) * math.cos(az), math.sin(el)]\n    A = [math.sin(a) * math.cos(b), math.cos(a) * math.cos(b), math.sin(b)]\n    N0 = [-math.sin(a) * math.sin(b), -math.cos(a) * math.sin(b), math.cos(b)]\n    R = [math.cos(a), -math.sin(a), 0.0]\n    dot = lambda u, v: sum(p * q for p, q in zip(u, v))\n    theta = math.degrees(math.atan2(dot(s, R), dot(s, N0)))\n    aoi = math.degrees(math.asin(min(1.0, dot(s, A))))\n    return [round(theta, 3), round(aoi, 3)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [180, 20, 0, 5], [0.0, 65.0]],\n  ['regression: incidence magnitude (partial repair)', [0, 89, 180, 5], [-0.0, 4.0]],\n  ['control 1', [300, 0, 180, 0], None], ['control 2', [225, 3, 180, 20], [105.236, 42.957]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [315, 10, 180, 0], [75.998, 44.136]],\n  ['regression: incidence magnitude (partial repair)', [225, 89, 180, 5], [0.711, 5.707]],\n  ['control 1', [45, 60, 170, 10], [-24.406, 7.588]],\n  ['control 2', [135, 75, 170, 20], [-10.079, 31.978]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [315, 10, 170, 10], [61.157, 49.845]],\n  ['regression: incidence magnitude (partial repair)', [225, 30, 180, 10], [57.771, 43.622]],\n  ['control 1', [340, 45, 170, 20], [7.747, 24.363]],\n  ['control 2', [340, 10, 180, 20], [35.076, 54.117]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [100, 30, 0, 5], [59.062, 6.098]],\n  ['regression: incidence magnitude (partial repair)', [150, 60, 170, 0], [-11.17, 28.024]],\n  ['control 1', [340, 20, 180, 0], [43.219, 62.009]],\n  ['control 2', [30, 3, 0, 20], [116.285, 56.159]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [225, 10, 0, 10], [-67.255, 40.968]],\n  ['regression: incidence magnitude (partial repair)', [340, 30, 0, 0], [-30.642, 54.469]],\n  ['control 1', [100, 30, 0, 5], [59.062, 6.098]],\n  ['control 2', [135, 75, 180, 10], [-11.257, 20.363]]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"fixed":{"sha256":"cd64ba8086a8f07a4c420b37f6ccaa11f22b777aaaf2585aa7bfb569d35a3d6b","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(sun_az, sun_el, axis_az, axis_tilt):\n    if sun_el <= 0:\n        return None\n    az = math.radians(sun_az)\n    el = math.radians(sun_el)\n    a = math.radians(axis_az)\n    b = math.radians(axis_tilt)\n    s = [math.cos(el) * math.sin(az), math.cos(el) * math.cos(az), math.sin(el)]\n    A = [math.sin(a) * math.cos(b), math.cos(a) * math.cos(b), math.sin(b)]\n    N0 = [-math.sin(a) * math.sin(b), -math.cos(a) * math.sin(b), math.cos(b)]\n    R = [math.cos(a), -math.sin(a), 0.0]\n    dot = lambda u, v: sum(p * q for p, q in zip(u, v))\n    theta = math.degrees(math.atan2(dot(s, R), dot(s, N0)))\n    aoi = math.degrees(math.asin(min(1.0, abs(dot(s, A)))))\n    return [round(theta, 3), round(aoi, 3)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [180, 20, 0, 5], [0.0, 65.0]],\n  ['regression: incidence magnitude (partial repair)', [0, 89, 180, 5], [-0.0, 4.0]],\n  ['control 1', [300, 0, 180, 0], None], ['control 2', [225, 3, 180, 20], [105.236, 42.957]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [315, 10, 180, 0], [75.998, 44.136]],\n  ['regression: incidence magnitude (partial repair)', [225, 89, 180, 5], [0.711, 5.707]],\n  ['control 1', [45, 60, 170, 10], [-24.406, 7.588]],\n  ['control 2', [135, 75, 170, 20], [-10.079, 31.978]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [315, 10, 170, 10], [61.157, 49.845]],\n  ['regression: incidence magnitude (partial repair)', [225, 30, 180, 10], [57.771, 43.622]],\n  ['control 1', [340, 45, 170, 20], [7.747, 24.363]],\n  ['control 2', [340, 10, 180, 20], [35.076, 54.117]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [100, 30, 0, 5], [59.062, 6.098]],\n  ['regression: incidence magnitude (partial repair)', [150, 60, 170, 0], [-11.17, 28.024]],\n  ['control 1', [340, 20, 180, 0], [43.219, 62.009]],\n  ['control 2', [30, 3, 0, 20], [116.285, 56.159]]],\n [['normal: horizontal axis at noon', [180, 60, 180, 0], [0.0, 30.0]],\n  ['normal: tilted axis morning', [100, 20, 180, 10], [-71.564, 12.714]],\n  ['boundary: night', [270, 0, 180, 10], None],\n  ['regression: incidence magnitude', [225, 10, 0, 10], [-67.255, 40.968]],\n  ['regression: incidence magnitude (partial repair)', [340, 30, 0, 0], [-30.642, 54.469]],\n  ['control 1', [100, 30, 0, 5], [59.062, 6.098]],\n  ['control 2', [135, 75, 180, 10], [-11.257, 20.363]]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"}},"limitations":"Deterministic stipulated toy contract for teaching; no claim of conformance with any standard, vendor protocol or production controller. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.","method":"Deterministic executable model with adversarial boundary fixtures.","provenance":{"created_by":"Failure Map","dependencies":"Python standard library","family":"w2-solar_tracker_geometry-tilted-axis-frame-incidence-magnitude","generated_at":"2026-09-29T14:51:57.544779+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Single-axis and dual-axis solar trackers turn a sun direction into actuator commands; a sign, frame or limit mistake points a whole plant away from the sun or into a mechanical stop.","repair":"Incidence = asin(|s.A|).","root_cause":"The along-axis component is used without its absolute value.","sha256":"ab428cdb718001f533a50bd085dffd14950878fcc0dfefeab146e86e52e82060","title":"Tilted single-axis tracker frame: incidence magnitude · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":39.296,"exit_code":1,"observations":[{"actual":[0.0,14.478],"check":"normal: horizontal axis at noon","expected":[0.0,30.0],"passed":false},{"actual":[-71.564,2.776],"check":"normal: tilted axis morning","expected":[-71.564,12.714],"passed":false},{"actual":null,"check":"boundary: night","expected":null,"passed":true},{"actual":[0.0,55.225],"check":"regression: incidence magnitude","expected":[0.0,65.0],"passed":false},{"actual":[-0.0,0.279],"check":"regression: incidence magnitude (partial repair)","expected":[-0.0,4.0],"passed":false},{"actual":null,"check":"control 1","expected":null,"passed":true},{"actual":[105.236,27.67],"check":"control 2","expected":[105.236,42.957],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"normal: horizontal axis at noon\", \"actual\": [0.0, 14.478], \"expected\": [0.0, 30.0], \"passed\": false}, {\"check\": \"normal: tilted axis morning\", \"actual\": [-71.564, 2.776], \"expected\": [-71.564, 12.714], \"passed\": false}, {\"check\": \"boundary: night\", \"actual\": null, \"expected\": null, \"passed\": true}, {\"check\": \"regression: incidence magnitude\", \"actual\": [0.0, 55.225], \"expected\": [0.0, 65.0], \"passed\": false}, {\"check\": \"regression: incidence magnitude (partial repair)\", \"actual\": [-0.0, 0.279], \"expected\": [-0.0, 4.0], \"passed\": false}, {\"check\": \"control 1\", \"actual\": null, \"expected\": null, \"passed\": true}, {\"check\": \"control 2\", \"actual\": [105.236, 27.67], \"expected\": [105.236, 42.957], \"passed\": false}], \"passed\": false}\n"},"broken":{"elapsed_ms":40.543,"exit_code":1,"observations":[{"actual":[0.0,30.0],"check":"normal: horizontal axis at noon","expected":[0.0,30.0],"passed":true},{"actual":[-71.564,12.714],"check":"normal: tilted axis morning","expected":[-71.564,12.714],"passed":true},{"actual":null,"check":"boundary: night","expected":null,"passed":true},{"actual":[0.0,-65.0],"check":"regression: incidence magnitude","expected":[0.0,65.0],"passed":false},{"actual":[-0.0,4.0],"check":"regression: incidence magnitude (partial repair)","expected":[-0.0,4.0],"passed":true},{"actual":null,"check":"control 1","expected":null,"passed":true},{"actual":[105.236,42.957],"check":"control 2","expected":[105.236,42.957],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"normal: horizontal axis at noon\", \"actual\": [0.0, 30.0], \"expected\": [0.0, 30.0], \"passed\": true}, {\"check\": \"normal: tilted axis morning\", \"actual\": [-71.564, 12.714], \"expected\": [-71.564, 12.714], \"passed\": true}, {\"check\": \"boundary: night\", \"actual\": null, \"expected\": null, \"passed\": true}, {\"check\": \"regression: incidence magnitude\", \"actual\": [0.0, -65.0], \"expected\": [0.0, 65.0], \"passed\": false}, {\"check\": \"regression: incidence magnitude (partial repair)\", \"actual\": [-0.0, 4.0], \"expected\": [-0.0, 4.0], \"passed\": true}, {\"check\": \"control 1\", \"actual\": null, \"expected\": null, \"passed\": true}, {\"check\": \"control 2\", \"actual\": [105.236, 42.957], \"expected\": [105.236, 42.957], \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":42.451,"exit_code":0,"observations":[{"actual":[0.0,30.0],"check":"normal: horizontal axis at noon","expected":[0.0,30.0],"passed":true},{"actual":[-71.564,12.714],"check":"normal: tilted axis morning","expected":[-71.564,12.714],"passed":true},{"actual":null,"check":"boundary: night","expected":null,"passed":true},{"actual":[0.0,65.0],"check":"regression: incidence magnitude","expected":[0.0,65.0],"passed":true},{"actual":[-0.0,4.0],"check":"regression: incidence magnitude (partial repair)","expected":[-0.0,4.0],"passed":true},{"actual":null,"check":"control 1","expected":null,"passed":true},{"actual":[105.236,42.957],"check":"control 2","expected":[105.236,42.957],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"normal: horizontal axis at noon\", \"actual\": [0.0, 30.0], \"expected\": [0.0, 30.0], \"passed\": true}, {\"check\": \"normal: tilted axis morning\", \"actual\": [-71.564, 12.714], \"expected\": [-71.564, 12.714], \"passed\": true}, {\"check\": \"boundary: night\", \"actual\": null, \"expected\": null, \"passed\": true}, {\"check\": \"regression: incidence magnitude\", \"actual\": [0.0, 65.0], \"expected\": [0.0, 65.0], \"passed\": true}, {\"check\": \"regression: incidence magnitude (partial repair)\", \"actual\": [-0.0, 4.0], \"expected\": [-0.0, 4.0], \"passed\": true}, {\"check\": \"control 1\", \"actual\": null, \"expected\": null, \"passed\": true}, {\"check\": \"control 2\", \"actual\": [105.236, 42.957], \"expected\": [105.236, 42.957], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}