broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el < 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = math.radians(axis_az + 90)
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(perp, u))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: horizon test', [300, 0, 190, 55], [0.0, 'night']],
  ['regression: horizon test (partial repair)', [200, 0, 180, 60], [0.0, 'night']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: horizon test', [60, 0, 20, 45], [0.0, 'night']],
  ['regression: horizon test (partial repair)', [270, 0, 20, 45], [0.0, 'night']],
  ['control 1', [340, 60, 170, 45], [5.725, 'tracking']],
  ['control 2', [300, -5, 20, 45], [0.0, 'night']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: horizon test', [150, 0, 170, 45], [0.0, 'night']],
  ['regression: horizon test (partial repair)', [0, 0, 0, 45], [0.0, 'night']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: horizon test', [100, 0, 190, 45], [0.0, 'night']],
  ['regression: horizon test (partial repair)', [315, 0, 170, 55], [0.0, 'night']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: horizon test', [150, 0, 170, 55], [0.0, 'night']],
  ['regression: horizon test (partial repair)', [60, 0, 170, 45], [0.0, 'night']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= -0.833:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = math.radians(axis_az + 90)
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(perp, u))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: horizon test', [300, 0, 190, 55], [0.0, 'night']],
  ['regression: horizon test (partial repair)', [200, 0, 180, 60], [0.0, 'night']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: horizon test', [60, 0, 20, 45], [0.0, 'night']],
  ['regression: horizon test (partial repair)', [270, 0, 20, 45], [0.0, 'night']],
  ['control 1', [340, 60, 170, 45], [5.725, 'tracking']],
  ['control 2', [300, -5, 20, 45], [0.0, 'night']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: horizon test', [150, 0, 170, 45], [0.0, 'night']],
  ['regression: horizon test (partial repair)', [0, 0, 0, 45], [0.0, 'night']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: horizon test', [100, 0, 190, 45], [0.0, 'night']],
  ['regression: horizon test (partial repair)', [315, 0, 170, 55], [0.0, 'night']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: horizon test', [150, 0, 170, 55], [0.0, 'night']],
  ['regression: horizon test (partial repair)', [60, 0, 170, 45], [0.0, 'night']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
At sunrise the tracker slams to a limit instead of staying flat.

Sun azimuth clockwise from north and elevation in degrees. The horizontal axis points to axis_az; rotation is positive toward azimuth axis_az+90. Sun vector east=cos(el)sin(az), north=cos(el)cos(az), up=sin(el). Rotation = atan2(component along axis_az+90, up). Clamp to +-max_angle (status 'limited', else 'tracking'); sun_el <= 0 returns [0.0, 'night']. Round to 3 decimals.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = math.radians(axis_az - 90)
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(perp, u))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation reference direction', [30, 10, 180, 55], [-55.0, 'limited']],
  ['regression: rotation reference direction (partial repair)', [315, 75, 20, 45],
   [-13.65, 'tracking']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation reference direction', [100, 3, 20, 60], [60.0, 'limited']],
  ['regression: rotation reference direction (partial repair)', [90, 60, 0, 60],
   [30.0, 'tracking']],
  ['control 1', [60, 0, 20, 45], [0.0, 'night']],
  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation reference direction', [0, 10, 190, 60], [44.561, 'tracking']],
  ['regression: rotation reference direction (partial repair)', [100, 20, 180, 45],
   [-45.0, 'limited']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation reference direction', [45, 10, 20, 45], [45.0, 'limited']],
  ['regression: rotation reference direction (partial repair)', [270, 75, 0, 60],
   [-15.0, 'tracking']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation reference direction', [30, 20, 170, 45], [-45.0, 'limited']],
  ['regression: rotation reference direction (partial repair)', [340, 3, 20, 55],
   [-55.0, 'limited']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = math.radians(axis_az)
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(perp, u))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation reference direction', [30, 10, 180, 55], [-55.0, 'limited']],
  ['regression: rotation reference direction (partial repair)', [315, 75, 20, 45],
   [-13.65, 'tracking']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation reference direction', [100, 3, 20, 60], [60.0, 'limited']],
  ['regression: rotation reference direction (partial repair)', [90, 60, 0, 60],
   [30.0, 'tracking']],
  ['control 1', [60, 0, 20, 45], [0.0, 'night']],
  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation reference direction', [0, 10, 190, 60], [44.561, 'tracking']],
  ['regression: rotation reference direction (partial repair)', [100, 20, 180, 45],
   [-45.0, 'limited']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation reference direction', [45, 10, 20, 45], [45.0, 'limited']],
  ['regression: rotation reference direction (partial repair)', [270, 75, 0, 60],
   [-15.0, 'tracking']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation reference direction', [30, 20, 170, 45], [-45.0, 'limited']],
  ['regression: rotation reference direction (partial repair)', [340, 3, 20, 55],
   [-55.0, 'limited']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
The tracker faces west in the morning and east in the afternoon.

Sun azimuth clockwise from north and elevation in degrees. The horizontal axis points to axis_az; rotation is positive toward azimuth axis_az+90. Sun vector east=cos(el)sin(az), north=cos(el)cos(az), up=sin(el). Rotation = atan2(component along axis_az+90, up). Clamp to +-max_angle (status 'limited', else 'tracking'); sun_el <= 0 returns [0.0, 'night']. Round to 3 decimals.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.cos(az)
    n = math.cos(el) * math.sin(az)
    u = math.sin(el)
    pa = math.radians(axis_az + 90)
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(perp, u))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: sun vector azimuth convention', [315, 75, 20, 45], [-13.65, 'tracking']],
  ['regression: sun vector azimuth convention (partial repair)', [180, 60, 190, 45],
   [-5.725, 'tracking']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: sun vector azimuth convention', [100, 3, 20, 60], [60.0, 'limited']],
  ['regression: sun vector azimuth convention (partial repair)', [200, 10, 190, 55],
   [44.561, 'tracking']],
  ['control 1', [60, 0, 20, 45], [0.0, 'night']],
  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: sun vector azimuth convention', [0, 10, 190, 60], [44.561, 'tracking']],
  ['regression: sun vector azimuth convention (partial repair)', [300, 45, 20, 45],
   [-44.561, 'tracking']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: sun vector azimuth convention', [270, 75, 0, 60], [-15.0, 'tracking']],
  ['regression: sun vector azimuth convention (partial repair)', [150, 45, 170, 55],
   [-18.882, 'tracking']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: sun vector azimuth convention', [340, 3, 20, 55], [-55.0, 'limited']],
  ['regression: sun vector azimuth convention (partial repair)', [30, 20, 170, 45],
   [-45.0, 'limited']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = -math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = math.radians(axis_az + 90)
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(perp, u))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: sun vector azimuth convention', [315, 75, 20, 45], [-13.65, 'tracking']],
  ['regression: sun vector azimuth convention (partial repair)', [180, 60, 190, 45],
   [-5.725, 'tracking']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: sun vector azimuth convention', [100, 3, 20, 60], [60.0, 'limited']],
  ['regression: sun vector azimuth convention (partial repair)', [200, 10, 190, 55],
   [44.561, 'tracking']],
  ['control 1', [60, 0, 20, 45], [0.0, 'night']],
  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: sun vector azimuth convention', [0, 10, 190, 60], [44.561, 'tracking']],
  ['regression: sun vector azimuth convention (partial repair)', [300, 45, 20, 45],
   [-44.561, 'tracking']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: sun vector azimuth convention', [270, 75, 0, 60], [-15.0, 'tracking']],
  ['regression: sun vector azimuth convention (partial repair)', [150, 45, 170, 55],
   [-18.882, 'tracking']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: sun vector azimuth convention', [340, 3, 20, 55], [-55.0, 'limited']],
  ['regression: sun vector azimuth convention (partial repair)', [30, 20, 170, 45],
   [-45.0, 'limited']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Rotation angles are wrong for every azimuth except the diagonals.

Sun azimuth clockwise from north and elevation in degrees. The horizontal axis points to axis_az; rotation is positive toward azimuth axis_az+90. Sun vector east=cos(el)sin(az), north=cos(el)cos(az), up=sin(el). Rotation = atan2(component along axis_az+90, up). Clamp to +-max_angle (status 'limited', else 'tracking'); sun_el <= 0 returns [0.0, 'night']. Round to 3 decimals.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = math.radians(axis_az + 90)
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(u, perp))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation angle function', [30, 10, 180, 55], [-55.0, 'limited']],
  ['regression: rotation angle function (partial repair)', [315, 75, 20, 45], [-13.65, 'tracking']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation angle function', [100, 3, 20, 60], [60.0, 'limited']],
  ['regression: rotation angle function (partial repair)', [200, 10, 190, 55],
   [44.561, 'tracking']],
  ['control 1', [60, 0, 20, 45], [0.0, 'night']],
  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation angle function', [0, 10, 190, 60], [44.561, 'tracking']],
  ['regression: rotation angle function (partial repair)', [300, 45, 20, 45],
   [-44.561, 'tracking']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation angle function', [45, 10, 20, 45], [45.0, 'limited']],
  ['regression: rotation angle function (partial repair)', [150, 45, 170, 55],
   [-18.882, 'tracking']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation angle function', [30, 20, 170, 45], [-45.0, 'limited']],
  ['regression: rotation angle function (partial repair)', [340, 3, 20, 55], [-55.0, 'limited']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = math.radians(axis_az + 90)
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.asin(perp))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation angle function', [30, 10, 180, 55], [-55.0, 'limited']],
  ['regression: rotation angle function (partial repair)', [315, 75, 20, 45], [-13.65, 'tracking']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation angle function', [100, 3, 20, 60], [60.0, 'limited']],
  ['regression: rotation angle function (partial repair)', [200, 10, 190, 55],
   [44.561, 'tracking']],
  ['control 1', [60, 0, 20, 45], [0.0, 'night']],
  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation angle function', [0, 10, 190, 60], [44.561, 'tracking']],
  ['regression: rotation angle function (partial repair)', [300, 45, 20, 45],
   [-44.561, 'tracking']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation angle function', [45, 10, 20, 45], [45.0, 'limited']],
  ['regression: rotation angle function (partial repair)', [150, 45, 170, 55],
   [-18.882, 'tracking']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: rotation angle function', [30, 20, 170, 45], [-45.0, 'limited']],
  ['regression: rotation angle function (partial repair)', [340, 3, 20, 55], [-55.0, 'limited']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
The commanded rotation is the complement of the correct angle.

Sun azimuth clockwise from north and elevation in degrees. The horizontal axis points to axis_az; rotation is positive toward azimuth axis_az+90. Sun vector east=cos(el)sin(az), north=cos(el)cos(az), up=sin(el). Rotation = atan2(component along axis_az+90, up). Clamp to +-max_angle (status 'limited', else 'tracking'); sun_el <= 0 returns [0.0, 'night']. Round to 3 decimals.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = math.radians(axis_az + 90)
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(perp, u))
    status = 'tracking'
    if rot > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit', [30, 10, 180, 55], [-55.0, 'limited']],
  ['regression: symmetric rotation limit (partial repair)', [250, 10, 0, 45], [-45.0, 'limited']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit', [150, 10, 170, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit (partial repair)', [100, 20, 170, 60], [-60.0, 'limited']],
  ['control 1', [60, 0, 20, 45], [0.0, 'night']],
  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit', [100, 20, 180, 45], [-45.0, 'limited']],
  ['regression: symmetric rotation limit (partial repair)', [100, 45, 190, 45], [-45.0, 'limited']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit', [90, 3, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit (partial repair)', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit', [30, 20, 170, 45], [-45.0, 'limited']],
  ['regression: symmetric rotation limit (partial repair)', [340, 3, 20, 55], [-55.0, 'limited']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = math.radians(axis_az + 90)
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(perp, u))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = max_angle
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit', [30, 10, 180, 55], [-55.0, 'limited']],
  ['regression: symmetric rotation limit (partial repair)', [250, 10, 0, 45], [-45.0, 'limited']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit', [150, 10, 170, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit (partial repair)', [100, 20, 170, 60], [-60.0, 'limited']],
  ['control 1', [60, 0, 20, 45], [0.0, 'night']],
  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit', [100, 20, 180, 45], [-45.0, 'limited']],
  ['regression: symmetric rotation limit (partial repair)', [100, 45, 190, 45], [-45.0, 'limited']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit', [90, 3, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit (partial repair)', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: symmetric rotation limit', [30, 20, 170, 45], [-45.0, 'limited']],
  ['regression: symmetric rotation limit (partial repair)', [340, 3, 20, 55], [-55.0, 'limited']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
In the morning the tracker is commanded past its east mechanical stop.

Sun azimuth clockwise from north and elevation in degrees. The horizontal axis points to axis_az; rotation is positive toward azimuth axis_az+90. Sun vector east=cos(el)sin(az), north=cos(el)cos(az), up=sin(el). Rotation = atan2(component along axis_az+90, up). Clamp to +-max_angle (status 'limited', else 'tracking'); sun_el <= 0 returns [0.0, 'night']. Round to 3 decimals.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = axis_az + 90
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(perp, u))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: axis azimuth units', [30, 10, 180, 55], [-55.0, 'limited']],
  ['regression: axis azimuth units (partial repair)', [315, 75, 20, 45], [-13.65, 'tracking']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: axis azimuth units', [90, 60, 0, 60], [30.0, 'tracking']],
  ['regression: axis azimuth units (partial repair)', [200, 10, 190, 55], [44.561, 'tracking']],
  ['control 1', [60, 0, 20, 45], [0.0, 'night']],
  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: axis azimuth units', [0, 10, 190, 60], [44.561, 'tracking']],
  ['regression: axis azimuth units (partial repair)', [300, 45, 20, 45], [-44.561, 'tracking']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: axis azimuth units', [45, 10, 20, 45], [45.0, 'limited']],
  ['regression: axis azimuth units (partial repair)', [270, 75, 0, 60], [-15.0, 'tracking']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: axis azimuth units', [30, 20, 170, 45], [-45.0, 'limited']],
  ['regression: axis azimuth units (partial repair)', [150, 89, 180, 60], [-0.5, 'tracking']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(sun_az, sun_el, axis_az, max_angle):
    if sun_el <= 0:
        return [0.0, 'night']
    az = math.radians(sun_az)
    el = math.radians(sun_el)
    e = math.cos(el) * math.sin(az)
    n = math.cos(el) * math.cos(az)
    u = math.sin(el)
    pa = math.radians(axis_az) + 90
    perp = e * math.sin(pa) + n * math.cos(pa)
    rot = math.degrees(math.atan2(perp, u))
    status = 'tracking'
    if abs(rot) > max_angle:
        rot = math.copysign(max_angle, rot)
        status = 'limited'
    return [round(rot, 3), status]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: axis azimuth units', [30, 10, 180, 55], [-55.0, 'limited']],
  ['regression: axis azimuth units (partial repair)', [315, 75, 20, 45], [-13.65, 'tracking']],
  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],
  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: axis azimuth units', [90, 60, 0, 60], [30.0, 'tracking']],
  ['regression: axis azimuth units (partial repair)', [200, 10, 190, 55], [44.561, 'tracking']],
  ['control 1', [60, 0, 20, 45], [0.0, 'night']],
  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: axis azimuth units', [0, 10, 190, 60], [44.561, 'tracking']],
  ['regression: axis azimuth units (partial repair)', [300, 45, 20, 45], [-44.561, 'tracking']],
  ['control 1', [135, 0, 0, 60], [0.0, 'night']],
  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: axis azimuth units', [45, 10, 20, 45], [45.0, 'limited']],
  ['regression: axis azimuth units (partial repair)', [270, 75, 0, 60], [-15.0, 'tracking']],
  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],
  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],
 [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],
  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],
  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],
  ['regression: axis azimuth units', [30, 20, 170, 45], [-45.0, 'limited']],
  ['regression: axis azimuth units (partial repair)', [150, 89, 180, 60], [-0.5, 'tracking']],
  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],
  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Rotation angles look random for any axis orientation.

Sun azimuth clockwise from north and elevation in degrees. The horizontal axis points to axis_az; rotation is positive toward azimuth axis_az+90. Sun vector east=cos(el)sin(az), north=cos(el)cos(az), up=sin(el). Rotation = atan2(component along axis_az+90, up). Clamp to +-max_angle (status 'limited', else 'tracking'); sun_el <= 0 returns [0.0, 'night']. Round to 3 decimals.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ideal, gcr):
    if gcr <= 0:
        return [round(ideal, 3), False]
    temp = abs(math.cos(math.radians(ideal))) * gcr
    if temp < 1:
        corr = -math.copysign(1, ideal) * math.degrees(math.acos(temp))
        return [round(ideal + corr, 3), True]
    return [round(ideal, 3), False]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['regression: coverage ratio scaling', [-10, 0.4], [-10, False]],
  ['regression: coverage ratio scaling (partial repair)', [-44.5, 0.25], [-44.5, False]],
  ['control 1', [30, 0.25], [30, False]], ['control 2', [-29.5, 0.5], [-29.5, False]],
  ['control 3', [-30, 0.4], [-30, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['regression: coverage ratio scaling', [-44.5, 0.6], [-44.5, False]],
  ['regression: coverage ratio scaling (partial repair)', [-79.5, 0.4], [-16.603, True]],
  ['control 1', [-80, 0.35], [-19.745, True]], ['control 2', [-10, 0.35], [-10, False]],
  ['control 3', [75, 0.6], [10.554, True]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['regression: coverage ratio scaling', [-70, 0.4], [-38.765, True]],
  ['regression: coverage ratio scaling (partial repair)', [-79.5, 0.3], [-26.905, True]],
  ['control 1', [0, 0.25], [0, False]], ['control 2', [10.5, 0], [10.5, False]],
  ['control 3', [70, 0.35], [57.742, True]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['regression: coverage ratio scaling', [-45, 0.25], [-45, False]],
  ['regression: coverage ratio scaling (partial repair)', [60, 0.25], [60, False]],
  ['control 1', [-45, 0.5], [-45, False]], ['control 2', [45, 0], [45, False]],
  ['control 3', [-9.5, 0.35], [-9.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['regression: coverage ratio scaling', [60.5, 0.25], [60.5, False]],
  ['regression: coverage ratio scaling (partial repair)', [85.5, 0.4], [6.812, True]],
  ['control 1', [10, 0.35], [10, False]], ['control 2', [-60, 0.3], [-60, False]],
  ['control 3', [70.5, 0.25], [70.5, False]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ideal, gcr):
    if gcr <= 0:
        return [round(ideal, 3), False]
    temp = abs(math.cos(math.radians(ideal))) / (1 - gcr)
    if temp < 1:
        corr = -math.copysign(1, ideal) * math.degrees(math.acos(temp))
        return [round(ideal + corr, 3), True]
    return [round(ideal, 3), False]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['regression: coverage ratio scaling', [-10, 0.4], [-10, False]],
  ['regression: coverage ratio scaling (partial repair)', [-44.5, 0.25], [-44.5, False]],
  ['control 1', [30, 0.25], [30, False]], ['control 2', [-29.5, 0.5], [-29.5, False]],
  ['control 3', [-30, 0.4], [-30, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['regression: coverage ratio scaling', [-44.5, 0.6], [-44.5, False]],
  ['regression: coverage ratio scaling (partial repair)', [-79.5, 0.4], [-16.603, True]],
  ['control 1', [-80, 0.35], [-19.745, True]], ['control 2', [-10, 0.35], [-10, False]],
  ['control 3', [75, 0.6], [10.554, True]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['regression: coverage ratio scaling', [-70, 0.4], [-38.765, True]],
  ['regression: coverage ratio scaling (partial repair)', [-79.5, 0.3], [-26.905, True]],
  ['control 1', [0, 0.25], [0, False]], ['control 2', [10.5, 0], [10.5, False]],
  ['control 3', [70, 0.35], [57.742, True]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['regression: coverage ratio scaling', [-45, 0.25], [-45, False]],
  ['regression: coverage ratio scaling (partial repair)', [60, 0.25], [60, False]],
  ['control 1', [-45, 0.5], [-45, False]], ['control 2', [45, 0], [45, False]],
  ['control 3', [-9.5, 0.35], [-9.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['regression: coverage ratio scaling', [60.5, 0.25], [60.5, False]],
  ['regression: coverage ratio scaling (partial repair)', [85.5, 0.4], [6.812, True]],
  ['control 1', [10, 0.35], [10, False]], ['control 2', [-60, 0.3], [-60, False]],
  ['control 3', [70.5, 0.25], [70.5, False]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Rows backtrack at noon or never backtrack at all.

Horizontal single-axis rows with ground coverage ratio gcr in (0, 1]. temp = |cos(ideal)|/gcr. When temp < 1 the rows would shade each other and the angle is corrected by -sign(ideal)*acos(temp) degrees (backtracking, flag True). gcr <= 0 disables backtracking. Return [angle rounded to 3, backtracking flag].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ideal, gcr):
    if gcr <= 0:
        return [round(ideal, 3), False]
    temp = abs(math.cos(math.radians(ideal))) / gcr
    if temp < 1:
        corr = math.copysign(1, ideal) * math.degrees(math.acos(temp))
        return [round(ideal + corr, 3), True]
    return [round(ideal, 3), False]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: correction direction', [45, 1.0], [0.0, True]],
  ['regression: correction direction (partial repair)', [-70, 0.4], [-38.765, True]],
  ['control 1', [30, 0.25], [30, False]], ['control 2', [-29.5, 0.5], [-29.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: correction direction', [-70, 0.5], [-23.16, True]],
  ['regression: correction direction (partial repair)', [-79.5, 0.4], [-16.603, True]],
  ['control 1', [-80, 0.35], [-19.745, True]], ['control 2', [85.5, 1.0], [0.0, True]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: correction direction', [-70, 0.4], [-38.765, True]],
  ['regression: correction direction (partial repair)', [-79.5, 0.3], [-26.905, True]],
  ['control 1', [0, 0.25], [0, False]], ['control 2', [10.5, 0], [10.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: correction direction', [-60, 1.0], [-0.0, True]],
  ['regression: correction direction (partial repair)', [-80, 0.3], [-25.368, True]],
  ['control 1', [-59.5, 1.0], [0.0, True]], ['control 2', [-45, 0.5], [-45, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: correction direction', [-69.5, 1.0], [0.0, True]],
  ['regression: correction direction (partial repair)', [-60, 1.0], [-0.0, True]],
  ['control 1', [10, 0.35], [10, False]], ['control 2', [-60, 0.3], [-60, False]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ideal, gcr):
    if gcr <= 0:
        return [round(ideal, 3), False]
    temp = abs(math.cos(math.radians(ideal))) / gcr
    if temp < 1:
        corr = -math.degrees(math.acos(temp))
        return [round(ideal + corr, 3), True]
    return [round(ideal, 3), False]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: correction direction', [45, 1.0], [0.0, True]],
  ['regression: correction direction (partial repair)', [-70, 0.4], [-38.765, True]],
  ['control 1', [30, 0.25], [30, False]], ['control 2', [-29.5, 0.5], [-29.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: correction direction', [-70, 0.5], [-23.16, True]],
  ['regression: correction direction (partial repair)', [-79.5, 0.4], [-16.603, True]],
  ['control 1', [-80, 0.35], [-19.745, True]], ['control 2', [85.5, 1.0], [0.0, True]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: correction direction', [-70, 0.4], [-38.765, True]],
  ['regression: correction direction (partial repair)', [-79.5, 0.3], [-26.905, True]],
  ['control 1', [0, 0.25], [0, False]], ['control 2', [10.5, 0], [10.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: correction direction', [-60, 1.0], [-0.0, True]],
  ['regression: correction direction (partial repair)', [-80, 0.3], [-25.368, True]],
  ['control 1', [-59.5, 1.0], [0.0, True]], ['control 2', [-45, 0.5], [-45, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: correction direction', [-69.5, 1.0], [0.0, True]],
  ['regression: correction direction (partial repair)', [-60, 1.0], [-0.0, True]],
  ['control 1', [10, 0.35], [10, False]], ['control 2', [-60, 0.3], [-60, False]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Backtracking steepens the rows instead of flattening them.

Horizontal single-axis rows with ground coverage ratio gcr in (0, 1]. temp = |cos(ideal)|/gcr. When temp < 1 the rows would shade each other and the angle is corrected by -sign(ideal)*acos(temp) degrees (backtracking, flag True). gcr <= 0 disables backtracking. Return [angle rounded to 3, backtracking flag].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ideal, gcr):
    if gcr <= 0:
        return [round(ideal, 3), False]
    temp = abs(math.cos(ideal)) / gcr
    if temp < 1:
        corr = -math.copysign(1, ideal) * math.degrees(math.acos(temp))
        return [round(ideal + corr, 3), True]
    return [round(ideal, 3), False]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: cosine argument units', [45, 1.0], [0.0, True]],
  ['regression: cosine argument units (partial repair)', [-10, 0.4], [-10, False]],
  ['control 1', [30, 0.25], [30, False]], ['control 2', [-29.5, 0.5], [-29.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: cosine argument units', [-29.5, 0.5], [-29.5, False]],
  ['regression: cosine argument units (partial repair)', [-10, 0.5], [-10, False]],
  ['control 1', [-80, 0.35], [-19.745, True]], ['control 2', [85.5, 1.0], [0.0, True]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: cosine argument units', [-70, 0.4], [-38.765, True]],
  ['regression: cosine argument units (partial repair)', [-79.5, 0.3], [-26.905, True]],
  ['control 1', [0, 0.25], [0, False]], ['control 2', [10.5, 0], [10.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: cosine argument units', [-60, 1.0], [-0.0, True]],
  ['regression: cosine argument units (partial repair)', [10, 0.35], [10, False]],
  ['control 1', [-59.5, 1.0], [0.0, True]], ['control 2', [-45, 0.5], [-45, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: cosine argument units', [-69.5, 1.0], [0.0, True]],
  ['regression: cosine argument units (partial repair)', [-9.5, 0.35], [-9.5, False]],
  ['control 1', [10, 0.35], [10, False]], ['control 2', [-60, 0.3], [-60, False]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ideal, gcr):
    if gcr <= 0:
        return [round(ideal, 3), False]
    temp = abs(math.cos(math.radians(abs(ideal) - 90))) / gcr
    if temp < 1:
        corr = -math.copysign(1, ideal) * math.degrees(math.acos(temp))
        return [round(ideal + corr, 3), True]
    return [round(ideal, 3), False]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: cosine argument units', [45, 1.0], [0.0, True]],
  ['regression: cosine argument units (partial repair)', [-10, 0.4], [-10, False]],
  ['control 1', [30, 0.25], [30, False]], ['control 2', [-29.5, 0.5], [-29.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: cosine argument units', [-29.5, 0.5], [-29.5, False]],
  ['regression: cosine argument units (partial repair)', [-10, 0.5], [-10, False]],
  ['control 1', [-80, 0.35], [-19.745, True]], ['control 2', [85.5, 1.0], [0.0, True]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: cosine argument units', [-70, 0.4], [-38.765, True]],
  ['regression: cosine argument units (partial repair)', [-79.5, 0.3], [-26.905, True]],
  ['control 1', [0, 0.25], [0, False]], ['control 2', [10.5, 0], [10.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: cosine argument units', [-60, 1.0], [-0.0, True]],
  ['regression: cosine argument units (partial repair)', [10, 0.35], [10, False]],
  ['control 1', [-59.5, 1.0], [0.0, True]], ['control 2', [-45, 0.5], [-45, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: cosine argument units', [-69.5, 1.0], [0.0, True]],
  ['regression: cosine argument units (partial repair)', [-9.5, 0.35], [-9.5, False]],
  ['control 1', [10, 0.35], [10, False]], ['control 2', [-60, 0.3], [-60, False]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Backtracking switches on and off erratically through the day.

Horizontal single-axis rows with ground coverage ratio gcr in (0, 1]. temp = |cos(ideal)|/gcr. When temp < 1 the rows would shade each other and the angle is corrected by -sign(ideal)*acos(temp) degrees (backtracking, flag True). gcr <= 0 disables backtracking. Return [angle rounded to 3, backtracking flag].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ideal, gcr):
    if gcr <= 0 or gcr >= 1:
        return [round(ideal, 3), False]
    temp = abs(math.cos(math.radians(ideal))) / gcr
    if temp < 1:
        corr = -math.copysign(1, ideal) * math.degrees(math.acos(temp))
        return [round(ideal + corr, 3), True]
    return [round(ideal, 3), False]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: dense row coverage', [45, 1.0], [0.0, True]],
  ['regression: dense row coverage (partial repair)', [85.5, 1.0], [0.0, True]],
  ['control 1', [30, 0.25], [30, False]], ['control 2', [-29.5, 0.5], [-29.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: dense row coverage', [-79.5, 1.0], [0.0, True]],
  ['regression: dense row coverage (partial repair)', [85.5, 1.0], [0.0, True]],
  ['control 1', [-80, 0.35], [-19.745, True]], ['control 2', [-10, 0.35], [-10, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: dense row coverage', [-80, 1.0], [0.0, True]],
  ['regression: dense row coverage (partial repair)', [60.5, 1.0], [0.0, True]],
  ['control 1', [0, 0.25], [0, False]], ['control 2', [10.5, 0], [10.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: dense row coverage', [-60, 1.0], [-0.0, True]],
  ['regression: dense row coverage (partial repair)', [30, 1.0], [0.0, True]],
  ['control 1', [-59.5, 1.0], [0.0, True]], ['control 2', [-45, 0.5], [-45, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: dense row coverage', [-69.5, 1.0], [0.0, True]],
  ['regression: dense row coverage (partial repair)', [-60, 1.0], [-0.0, True]],
  ['control 1', [10, 0.35], [10, False]], ['control 2', [-60, 0.3], [-60, False]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ideal, gcr):
    if gcr <= 0 or gcr > 0.99:
        return [round(ideal, 3), False]
    temp = abs(math.cos(math.radians(ideal))) / gcr
    if temp < 1:
        corr = -math.copysign(1, ideal) * math.degrees(math.acos(temp))
        return [round(ideal + corr, 3), True]
    return [round(ideal, 3), False]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: dense row coverage', [45, 1.0], [0.0, True]],
  ['regression: dense row coverage (partial repair)', [85.5, 1.0], [0.0, True]],
  ['control 1', [30, 0.25], [30, False]], ['control 2', [-29.5, 0.5], [-29.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: dense row coverage', [-79.5, 1.0], [0.0, True]],
  ['regression: dense row coverage (partial repair)', [85.5, 1.0], [0.0, True]],
  ['control 1', [-80, 0.35], [-19.745, True]], ['control 2', [-10, 0.35], [-10, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: dense row coverage', [-80, 1.0], [0.0, True]],
  ['regression: dense row coverage (partial repair)', [60.5, 1.0], [0.0, True]],
  ['control 1', [0, 0.25], [0, False]], ['control 2', [10.5, 0], [10.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: dense row coverage', [-60, 1.0], [-0.0, True]],
  ['regression: dense row coverage (partial repair)', [30, 1.0], [0.0, True]],
  ['control 1', [-59.5, 1.0], [0.0, True]], ['control 2', [-45, 0.5], [-45, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: dense row coverage', [-69.5, 1.0], [0.0, True]],
  ['regression: dense row coverage (partial repair)', [-60, 1.0], [-0.0, True]],
  ['control 1', [10, 0.35], [10, False]], ['control 2', [-60, 0.3], [-60, False]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Rows with a coverage ratio of 1 track steeply and shade each other.

Horizontal single-axis rows with ground coverage ratio gcr in (0, 1]. temp = |cos(ideal)|/gcr. When temp < 1 the rows would shade each other and the angle is corrected by -sign(ideal)*acos(temp) degrees (backtracking, flag True). gcr <= 0 disables backtracking. Return [angle rounded to 3, backtracking flag].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ideal, gcr):
    if gcr <= 0:
        return [round(ideal, 3), False]
    temp = abs(math.cos(math.radians(ideal))) / gcr
    if temp < 1:
        corr = -math.copysign(1, ideal) * math.degrees(math.acos(temp))
        return [round(corr, 3), True]
    return [round(ideal, 3), False]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: corrected angle base', [45, 1.0], [0.0, True]],
  ['regression: corrected angle base (partial repair)', [-70, 0.4], [-38.765, True]],
  ['control 1', [30, 0.25], [30, False]], ['control 2', [-29.5, 0.5], [-29.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: corrected angle base', [-70, 0.5], [-23.16, True]],
  ['regression: corrected angle base (partial repair)', [-79.5, 0.4], [-16.603, True]],
  ['control 1', [-80, 0.35], [-19.745, True]], ['control 2', [85.5, 1.0], [0.0, True]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: corrected angle base', [-70, 0.4], [-38.765, True]],
  ['regression: corrected angle base (partial repair)', [-79.5, 0.3], [-26.905, True]],
  ['control 1', [0, 0.25], [0, False]], ['control 2', [10.5, 0], [10.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: corrected angle base', [-60, 1.0], [-0.0, True]],
  ['regression: corrected angle base (partial repair)', [30, 1.0], [0.0, True]],
  ['control 1', [-59.5, 1.0], [0.0, True]], ['control 2', [-45, 0.5], [-45, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: corrected angle base', [-69.5, 1.0], [0.0, True]],
  ['regression: corrected angle base (partial repair)', [85.5, 0.4], [6.812, True]],
  ['control 1', [10, 0.35], [10, False]], ['control 2', [-60, 0.3], [-60, False]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ideal, gcr):
    if gcr <= 0:
        return [round(ideal, 3), False]
    temp = abs(math.cos(math.radians(ideal))) / gcr
    if temp < 1:
        corr = -math.copysign(1, ideal) * math.degrees(math.acos(temp))
        return [round(ideal - corr, 3), True]
    return [round(ideal, 3), False]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: corrected angle base', [45, 1.0], [0.0, True]],
  ['regression: corrected angle base (partial repair)', [-70, 0.4], [-38.765, True]],
  ['control 1', [30, 0.25], [30, False]], ['control 2', [-29.5, 0.5], [-29.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: corrected angle base', [-70, 0.5], [-23.16, True]],
  ['regression: corrected angle base (partial repair)', [-79.5, 0.4], [-16.603, True]],
  ['control 1', [-80, 0.35], [-19.745, True]], ['control 2', [85.5, 1.0], [0.0, True]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: corrected angle base', [-70, 0.4], [-38.765, True]],
  ['regression: corrected angle base (partial repair)', [-79.5, 0.3], [-26.905, True]],
  ['control 1', [0, 0.25], [0, False]], ['control 2', [10.5, 0], [10.5, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: corrected angle base', [-60, 1.0], [-0.0, True]],
  ['regression: corrected angle base (partial repair)', [30, 1.0], [0.0, True]],
  ['control 1', [-59.5, 1.0], [0.0, True]], ['control 2', [-45, 0.5], [-45, False]]],
 [['boundary: noon never backtracks', [0, 0.4], [0, False]],
  ['normal: steep morning angle backtracks', [-75, 0.4], [-25.319, True]],
  ['boundary: continuous rows', [60, 1.0], [0.0, True]],
  ['regression: corrected angle base', [-69.5, 1.0], [0.0, True]],
  ['regression: corrected angle base (partial repair)', [85.5, 0.4], [6.812, True]],
  ['control 1', [10, 0.35], [10, False]], ['control 2', [-60, 0.3], [-60, False]]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Backtracking outputs a small angle with the wrong magnitude.

Horizontal single-axis rows with ground coverage ratio gcr in (0, 1]. temp = |cos(ideal)|/gcr. When temp < 1 the rows would shade each other and the angle is corrected by -sign(ideal)*acos(temp) degrees (backtracking, flag True). gcr <= 0 disables backtracking. Return [angle rounded to 3, backtracking flag].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(tilt, pan_az, sun_az, sun_el):
    if sun_el <= 0:
        return [None, 0.0, 'night']
    zen = math.radians(sun_el)
    t = math.radians(tilt)
    c = math.cos(zen) * math.cos(t) + math.sin(zen) * math.sin(t) * math.cos(math.radians(sun_az - pan_az))
    c = max(-1.0, min(1.0, c))
    aoi = math.degrees(math.acos(c))
    side = 'front' if c >= 0 else 'back'
    return [round(aoi, 3), round(max(c, 0.0), 4), side]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: zenith from elevation', [30, 135, 0, 10], [101.408, 0.0, 'back']],
  ['regression: zenith from elevation (partial repair)', [10, 225, 60, 89],
   [10.969, 0.9817, 'front']],
  ['control 1', [0, 180, 225, -5], [None, 0.0, 'night']],
  ['control 2', [0, 135, 150, 45], [45.0, 0.7071, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: zenith from elevation', [20, 225, 270, 3], [73.101, 0.2907, 'front']],
  ['regression: zenith from elevation (partial repair)', [0, 90, 225, 60], [30.0, 0.866, 'front']],
  ['control 1', [25, 180, 60, 10], [92.907, 0.0, 'back']],
  ['control 2', [60, 225, 270, 20], [41.716, 0.7465, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: zenith from elevation', [30, 270, 225, 10], [60.095, 0.4986, 'front']],
  ['regression: zenith from elevation (partial repair)', [10, 135, 30, 45],
   [48.35, 0.6646, 'front']],
  ['control 1', [60, 90, 135, 30], [38.709, 0.7803, 'front']],
  ['control 2', [45, 270, 60, 89], [45.868, 0.6963, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: zenith from elevation', [30, 135, 100, 10], [56.376, 0.5537, 'front']],
  ['regression: zenith from elevation (partial repair)', [20, 225, 270, 3],
   [73.101, 0.2907, 'front']],
  ['control 1', [45, 180, 315, 0], [None, 0.0, 'night']],
  ['control 2', [30, 90, 225, 45], [68.754, 0.3624, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: zenith from elevation', [10, 180, 100, 30], [58.767, 0.5185, 'front']],
  ['regression: zenith from elevation (partial repair)', [30, 225, 270, 60],
   [22.062, 0.9268, 'front']],
  ['control 1', [45, 180, 0, 75], [60.0, 0.5, 'front']],
  ['control 2', [45, 225, 270, -5], [None, 0.0, 'night']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(tilt, pan_az, sun_az, sun_el):
    if sun_el <= 0:
        return [None, 0.0, 'night']
    zen = math.radians(90 + sun_el)
    t = math.radians(tilt)
    c = math.cos(zen) * math.cos(t) + math.sin(zen) * math.sin(t) * math.cos(math.radians(sun_az - pan_az))
    c = max(-1.0, min(1.0, c))
    aoi = math.degrees(math.acos(c))
    side = 'front' if c >= 0 else 'back'
    return [round(aoi, 3), round(max(c, 0.0), 4), side]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: zenith from elevation', [30, 135, 0, 10], [101.408, 0.0, 'back']],
  ['regression: zenith from elevation (partial repair)', [10, 225, 60, 89],
   [10.969, 0.9817, 'front']],
  ['control 1', [0, 180, 225, -5], [None, 0.0, 'night']],
  ['control 2', [0, 135, 150, 45], [45.0, 0.7071, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: zenith from elevation', [20, 225, 270, 3], [73.101, 0.2907, 'front']],
  ['regression: zenith from elevation (partial repair)', [0, 90, 225, 60], [30.0, 0.866, 'front']],
  ['control 1', [25, 180, 60, 10], [92.907, 0.0, 'back']],
  ['control 2', [60, 225, 270, 20], [41.716, 0.7465, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: zenith from elevation', [30, 270, 225, 10], [60.095, 0.4986, 'front']],
  ['regression: zenith from elevation (partial repair)', [10, 135, 30, 45],
   [48.35, 0.6646, 'front']],
  ['control 1', [60, 90, 135, 30], [38.709, 0.7803, 'front']],
  ['control 2', [45, 270, 60, 89], [45.868, 0.6963, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: zenith from elevation', [30, 135, 100, 10], [56.376, 0.5537, 'front']],
  ['regression: zenith from elevation (partial repair)', [20, 225, 270, 3],
   [73.101, 0.2907, 'front']],
  ['control 1', [45, 180, 315, 0], [None, 0.0, 'night']],
  ['control 2', [30, 90, 225, 45], [68.754, 0.3624, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: zenith from elevation', [10, 180, 100, 30], [58.767, 0.5185, 'front']],
  ['regression: zenith from elevation (partial repair)', [30, 225, 270, 60],
   [22.062, 0.9268, 'front']],
  ['control 1', [45, 180, 0, 75], [60.0, 0.5, 'front']],
  ['control 2', [45, 225, 270, -5], [None, 0.0, 'night']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Panels appear best lit at dawn and worst at noon.

Panel tilted by tilt degrees from horizontal, facing pan_az (clockwise from north). zenith = 90 - sun_el. cos(aoi) = cos(zen)cos(tilt) + sin(zen)sin(tilt)cos(sun_az - pan_az), clamped to [-1, 1]. Return [aoi degrees rounded 3, max(cos aoi, 0) rounded 4, 'front' or 'back'], or [None, 0.0, 'night'] when sun_el <= 0.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(tilt, pan_az, sun_az, sun_el):
    if sun_el <= 0:
        return [None, 0.0, 'night']
    zen = math.radians(90 - sun_el)
    t = math.radians(tilt)
    c = math.cos(zen) * math.cos(t) + math.sin(zen) * math.sin(t) * math.cos(math.radians(sun_az + pan_az))
    c = max(-1.0, min(1.0, c))
    aoi = math.degrees(math.acos(c))
    side = 'front' if c >= 0 else 'back'
    return [round(aoi, 3), round(max(c, 0.0), 4), side]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: relative azimuth', [10, 225, 60, 89], [10.969, 0.9817, 'front']],
  ['regression: relative azimuth (partial repair)', [30, 135, 0, 10], [101.408, 0.0, 'back']],
  ['control 1', [0, 180, 225, -5], [None, 0.0, 'night']],
  ['control 2', [0, 135, 150, 45], [45.0, 0.7071, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: relative azimuth', [20, 225, 270, 3], [73.101, 0.2907, 'front']],
  ['regression: relative azimuth (partial repair)', [90, 180, 250, 45], [76.005, 0.2418, 'front']],
  ['control 1', [25, 180, 60, 10], [92.907, 0.0, 'back']],
  ['control 2', [60, 225, 270, 20], [41.716, 0.7465, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: relative azimuth', [10, 135, 30, 45], [48.35, 0.6646, 'front']],
  ['regression: relative azimuth (partial repair)', [30, 270, 225, 10], [60.095, 0.4986, 'front']],
  ['control 1', [60, 90, 135, 30], [38.709, 0.7803, 'front']],
  ['control 2', [45, 270, 60, 89], [45.868, 0.6963, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: relative azimuth', [30, 135, 100, 10], [56.376, 0.5537, 'front']],
  ['regression: relative azimuth (partial repair)', [20, 225, 270, 3], [73.101, 0.2907, 'front']],
  ['control 1', [45, 180, 315, 0], [None, 0.0, 'night']],
  ['control 2', [30, 90, 225, 45], [68.754, 0.3624, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: relative azimuth', [30, 225, 270, 60], [22.062, 0.9268, 'front']],
  ['regression: relative azimuth (partial repair)', [10, 180, 100, 30], [58.767, 0.5185, 'front']],
  ['control 1', [45, 180, 0, 75], [60.0, 0.5, 'front']],
  ['control 2', [45, 225, 270, -5], [None, 0.0, 'night']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(tilt, pan_az, sun_az, sun_el):
    if sun_el <= 0:
        return [None, 0.0, 'night']
    zen = math.radians(90 - sun_el)
    t = math.radians(tilt)
    c = math.cos(zen) * math.cos(t) + math.sin(zen) * math.sin(t) * math.cos(math.radians(sun_az - pan_az - 180))
    c = max(-1.0, min(1.0, c))
    aoi = math.degrees(math.acos(c))
    side = 'front' if c >= 0 else 'back'
    return [round(aoi, 3), round(max(c, 0.0), 4), side]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: relative azimuth', [10, 225, 60, 89], [10.969, 0.9817, 'front']],
  ['regression: relative azimuth (partial repair)', [30, 135, 0, 10], [101.408, 0.0, 'back']],
  ['control 1', [0, 180, 225, -5], [None, 0.0, 'night']],
  ['control 2', [0, 135, 150, 45], [45.0, 0.7071, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: relative azimuth', [20, 225, 270, 3], [73.101, 0.2907, 'front']],
  ['regression: relative azimuth (partial repair)', [90, 180, 250, 45], [76.005, 0.2418, 'front']],
  ['control 1', [25, 180, 60, 10], [92.907, 0.0, 'back']],
  ['control 2', [60, 225, 270, 20], [41.716, 0.7465, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: relative azimuth', [10, 135, 30, 45], [48.35, 0.6646, 'front']],
  ['regression: relative azimuth (partial repair)', [30, 270, 225, 10], [60.095, 0.4986, 'front']],
  ['control 1', [60, 90, 135, 30], [38.709, 0.7803, 'front']],
  ['control 2', [45, 270, 60, 89], [45.868, 0.6963, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: relative azimuth', [30, 135, 100, 10], [56.376, 0.5537, 'front']],
  ['regression: relative azimuth (partial repair)', [20, 225, 270, 3], [73.101, 0.2907, 'front']],
  ['control 1', [45, 180, 315, 0], [None, 0.0, 'night']],
  ['control 2', [30, 90, 225, 45], [68.754, 0.3624, 'front']]],
 [['boundary: sun on horizon', [30, 180, 180, 0], [None, 0.0, 'night']],
  ['normal: sun normal to panel', [30, 180, 180, 60], [0.0, 1.0, 'front']],
  ['boundary: sun behind vertical panel', [90, 180, 0, 20], [160.0, 0.0, 'back']],
  ['regression: relative azimuth', [30, 225, 270, 60], [22.062, 0.9268, 'front']],
  ['regression: relative azimuth (partial repair)', [10, 180, 100, 30], [58.767, 0.5185, 'front']],
  ['control 1', [45, 180, 0, 75], [60.0, 0.5, 'front']],
  ['control 2', [45, 225, 270, -5], [None, 0.0, 'night']]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
South-facing panels look best lit by a northern sun.

Panel tilted by tilt degrees from horizontal, facing pan_az (clockwise from north). zenith = 90 - sun_el. cos(aoi) = cos(zen)cos(tilt) + sin(zen)sin(tilt)cos(sun_az - pan_az), clamped to [-1, 1]. Return [aoi degrees rounded 3, max(cos aoi, 0) rounded 4, 'front' or 'back'], or [None, 0.0, 'night'] when sun_el <= 0.

split: open-access