File size: 3,235 Bytes
aa1ffa8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""seti-tools: technosignature and biosignature searches on public archives; core, science and thirteen family modules of approaches."""

import importlib
import os
import sys

from setitools.core import quiet_warnings

# one math-library thread per process, so the process cap bounds CPU load
for _v in ("OMP_NUM_THREADS", "OPENBLAS_NUM_THREADS", "MKL_NUM_THREADS"):
    os.environ.setdefault(_v, "1")

USAGE = """    python -I seti.py                              the families
    python -I seti.py <family>                     a family's approaches
    python -I seti.py <family> <approach> --help   an approach's method and modes
    python -I seti.py <family> <approach> <mode>   a run
    python -I seti.py store <command>              the coverage store: summary, table, verify, card, covered, codes
    python -I seti.py selftest [--online]          the package's checks on synthetic data
"""

FAMILIES = {
    "lasers": "laser lines in stellar and sky-fibre spectra",
    "ultraviolet": "ultraviolet lines and photon timing",
    "composition": "short-lived elements, fission products and industrial gases",
    "flashes": "glints, flares, levels and clocks in light curves",
    "transits": "transit shapes, timing, belts and geometry",
    "dimming": "dimming, dips and colour in survey photometry",
    "infrared": "waste heat, dark companions and missing flux",
    "breakthrough": "Breakthrough Listen radio tracks, pulses and drifts",
    "radio_sky": "persistent lines, sidereal tests and lensed receivers in radio surveys",
    "highenergy": "X-ray, gamma-ray, neutrino and cosmic-ray tests",
    "solar_system": "asteroids, comets, meteors and occultations",
    "neighbourhood": "the nearby stars' kinematics, polarisation and companions",
    "biosignatures": "gases of life and their abiotic mimics in temperate worlds' spectra",
}


def family(name):
    """The family module by name, imported on demand."""
    if name not in FAMILIES:
        raise KeyError(name)
    return importlib.import_module("setitools." + name)


def run(argv=None):
    """Dispatch the command line: family, approach, then the approach's own arguments."""
    quiet_warnings()
    argv = list(sys.argv if argv is None else argv)
    prog = os.path.basename(argv[0]) if argv else "seti.py"
    if len(argv) < 2 or argv[1] not in FAMILIES:
        print(USAGE)
        for name, what in FAMILIES.items():
            print("    %-14s %s" % (name, what))
        return 0
    mod = family(argv[1])
    approaches = mod.APPROACHES
    if len(argv) < 3 or argv[2] not in approaches:
        # family summary and each registered approach with the first line of its method
        print((mod.__doc__ or "").strip() + "\n")
        for k, (_, doc) in approaches.items():
            print("    %-16s %s" % (k, doc.strip().split("\n")[0]))
        print("\n    python -I seti.py %s <approach> [mode ...]      (each approach's own modes and options; help lists them)"
              % argv[1])
        return 0
    name = argv[2]
    if len(argv) > 3 and argv[3] in ("-h", "--help", "help"):
        print(approaches[name][1])
        return 0
    sys.argv = ["%s %s %s" % (prog, argv[1], name)] + argv[3:]
    approaches[name][0]()
    return 0