#!/usr/bin/env python3 """The Sun in the 24 hours before the S0 News upload of October 27, 2026. Fact-Checked Science, "S0 News, October 27, 2026", section 6 ("Our analysis"). Standard library only. Run it python3 -I sun_window.py [folder] The folder (default: the script's own) must hold the three extracts published beside this page: goes18-flares-2026-10-20-27.csv NOAA SWPC's GOES-18 X-ray flare list for the 7 days to Oct 27, 09:34 UTC swpc-events-2026-10-26-27.csv the X-ray, optical-flare and radio-burst lines of SWPC's Edited Events, Oct 26-27 cactus-cmes-2026-10-21-27.csv the CME list of CACTus (SIDC, Royal Observatory of Belgium), from SOHO/LASCO C2 and C3, issued Oct 27, 13:55 UTC NOAA's files roll over, so these extracts, made on October 27, 2026, at about 16:30 UTC, are the record we used. What it prints For the window 2026-10-26 12:22:43 to 2026-10-27 12:22:43 UTC (the video went up at 05:22:43 Arizona time): the flares by class (A < 1e-7 <= B < 1e-6 <= C < 1e-5 <= M < 1e-4 <= X, peak 0.1-0.8 nm flux in W/m2), any M- or X-class flare in the whole 7-day list, the Edited Events lines in the window, and the CACTus CMEs whose onset falls in the window or on October 26. CACTus's position angle runs counterclockwise from solar north, so about 0-180 degrees is the east limb and 180-360 the west limb. """ import csv import datetime as dt import os import sys UPLOAD = dt.datetime(2026, 10, 27, 12, 22, 43, tzinfo=dt.timezone.utc) START = UPLOAD - dt.timedelta(hours=24) def utc(s, fmt): return dt.datetime.strptime(s, fmt).replace(tzinfo=dt.timezone.utc) def main(): sys.stdout.reconfigure(encoding="utf-8") folder = sys.argv[1] if len(sys.argv) > 1 else os.path.dirname(os.path.abspath(__file__)) rd = lambda name: list(csv.DictReader(open(os.path.join(folder, name), encoding="utf-8"))) flares = rd("goes18-flares-2026-10-20-27.csv") events = rd("swpc-events-2026-10-26-27.csv") cmes = rd("cactus-cmes-2026-10-21-27.csv") print(f"Window: {START:%Y-%m-%d %H:%M:%S} to {UPLOAD:%Y-%m-%d %H:%M:%S} UTC") win = [f for f in flares if START <= utc(f["max_utc"], "%Y-%m-%dT%H:%M:%SZ") < UPLOAD] by = {} for f in win: by[f["max_class"][0]] = by.get(f["max_class"][0], 0) + 1 print(f"\nGOES-18 flares in the window: {len(win)} (" + ", ".join(f"{k} {v}" for k, v in sorted(by.items())) + ")") for f in win: print(f" peak {f['max_utc'][:16].replace('T', ' ')} {f['max_class']}") big = [f for f in flares if f["max_class"][0] in "MX"] print(f"M- or X-class flares in the 7-day list ({flares[0]['max_utc'][:16]} to {flares[-1]['max_utc'][:16]}): " + (", ".join(f"{f['max_class']} {f['max_utc']}" for f in big) or "none")) print("\nSWPC Edited Events in the window (XRA = GOES X-ray event, FLA = optical flare, RBR = radio burst):") for e in events: hhmm = e["max"] if e["max"] != "////" else e["begin"] t = utc(f"{e['date']} {hhmm}", "%Y-%m-%d %H%M") if START <= t < UPLOAD: print(f" {e['date']} {hhmm[:2]}:{hhmm[2:]} event {e['event']} {e['type']} {e['loc_or_freq']} " f"{e['particulars']} region {e['region'] or '-'}") print("\nCACTus CMEs with onset on October 26 or in the window:") for c in cmes: if c["table"] != "CME": continue t = utc(c["onset_utc"], "%Y-%m-%d %H:%M") if t.date() == dt.date(2026, 10, 26) or START <= t < UPLOAD: pa = int(c["position_angle_deg"]) side = "east limb" if 0 < pa < 180 else ("west limb" if 180 < pa < 360 else "pole") tag = "in the window" if START <= t < UPLOAD else "before the window" print(f" CME {c['number']} onset {c['onset_utc']} angle {pa} ({side}) width {c['width_deg']} " f"median {c['median_speed_km_s']} km/s halo: {c['halo'] or 'no'} [{tag}]") if __name__ == "__main__": main()